Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix: API tool reports fictitious changes to execution environment #1302

Merged
merged 1 commit into from
Jul 7, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*******************************************************************************
* Copyright (c) 2009, 2018 IBM Corporation and others.
* Copyright (c) 2009, 2024 IBM Corporation and others.
*
* This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0
Expand All @@ -13,6 +13,8 @@
*******************************************************************************/
package org.eclipse.pde.api.tools.builder.tests.compatibility;

import static org.junit.Assert.assertArrayEquals;

import java.util.ArrayList;
import java.util.HashSet;
import java.util.Iterator;
Expand Down Expand Up @@ -66,13 +68,13 @@ protected int getDefaultProblemId() {
}

/**
* Returns the type container associated with the "bundle.a" project in the
* Returns the type container associated with the given project in the
* workspace.
*/
protected IApiTypeContainer getTypeContainer() throws CoreException {
protected IApiTypeContainer getTypeContainer(String projectName) throws CoreException {
IApiBaseline baseline = ApiBaselineManager.getManager().getWorkspaceBaseline();
assertNotNull("Missing workspace baseline", baseline); //$NON-NLS-1$
IApiComponent component = baseline.getApiComponent(getEnv().getProject("bundle.a")); //$NON-NLS-1$
IApiComponent component = baseline.getApiComponent(getEnv().getProject(projectName));
assertNotNull("Missing API component", component); //$NON-NLS-1$
IApiTypeContainer[] containers = component.getApiTypeContainers();
assertEquals("Wrong number of API type containers", 1, containers.length); //$NON-NLS-1$
Expand Down Expand Up @@ -154,11 +156,26 @@ protected Set<String> collectAllTypeNames() throws CoreException {
return names;
}

/**
* Tests whether the execution environment can be extracted from both the
* {@code Bundle-RequiredExecutionEnvironment} and the
* {@code Require-Capability} header.
*/
public void testExecutionEnvironment() throws CoreException {
IApiTypeContainer bundleA = getTypeContainer("bundle.a"); //$NON-NLS-1$
assertArrayEquals("Unable to find BREE for bundle using 'Bundle-RequiredExecutionEvironment'", //$NON-NLS-1$
new String[] { "J2SE-1.5" }, bundleA.getApiComponent().getExecutionEnvironments()); //$NON-NLS-1$

IApiTypeContainer bundleB = getTypeContainer("bundle.b"); //$NON-NLS-1$
assertArrayEquals("Unable to find BREE for bundle using 'Require-Capability'", //$NON-NLS-1$
new String[] { "JavaSE-17" }, bundleB.getApiComponent().getExecutionEnvironments()); //$NON-NLS-1$
}

/**
* Tests all packages are returned.
*/
public void testPackageNames() throws CoreException {
IApiTypeContainer container = getTypeContainer();
IApiTypeContainer container = getTypeContainer("bundle.a"); //$NON-NLS-1$
assertEquals("Should be a project type container", IApiTypeContainer.FOLDER, container.getContainerType()); //$NON-NLS-1$

// build expected list
Expand All @@ -184,7 +201,7 @@ public void testPackageNames() throws CoreException {
* Test type lookup.
*/
public void testFindType() throws CoreException {
IApiTypeContainer container = getTypeContainer();
IApiTypeContainer container = getTypeContainer("bundle.a"); //$NON-NLS-1$
IApiTypeRoot root = container.findTypeRoot("a.classes.fields.AddPrivateField"); //$NON-NLS-1$
assertNotNull("Unable to find type 'a.classes.fields.AddPrivateField'", root); //$NON-NLS-1$
IApiType structure = root.getStructure();
Expand All @@ -195,7 +212,7 @@ public void testFindType() throws CoreException {
* Test that type lookup fails for a type that is not in the project.
*/
public void testMissingType() throws CoreException {
IApiTypeContainer container = getTypeContainer();
IApiTypeContainer container = getTypeContainer("bundle.a"); //$NON-NLS-1$
IApiTypeRoot root = container.findTypeRoot("some.bogus.Type"); //$NON-NLS-1$
assertNull("Should not be able to find type 'some.bogus.Type'", root); //$NON-NLS-1$
}
Expand All @@ -218,7 +235,7 @@ public void visit(String packageName, IApiTypeRoot typeroot) {
typeNames.add(typeroot.getTypeName());
}
};
getTypeContainer().accept(visitor);
getTypeContainer("bundle.a").accept(visitor); //$NON-NLS-1$

// validate type names
Set<String> set = collectAllTypeNames();
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<classpath>
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/>
<classpathentry kind="con" path="org.eclipse.pde.core.requiredPlugins"/>
<classpathentry kind="src" path="src"/>
<classpathentry kind="output" path="bin"/>
</classpath>
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
<?xml version="1.0" encoding="UTF-8"?>
<projectDescription>
<name>bundle.b</name>
<comment></comment>
<projects>
</projects>
<buildSpec>
<buildCommand>
<name>org.eclipse.jdt.core.javabuilder</name>
<arguments>
</arguments>
</buildCommand>
<buildCommand>
<name>org.eclipse.pde.ManifestBuilder</name>
<arguments>
</arguments>
</buildCommand>
<buildCommand>
<name>org.eclipse.pde.SchemaBuilder</name>
<arguments>
</arguments>
</buildCommand>
</buildSpec>
<natures>
<nature>org.eclipse.pde.PluginNature</nature>
<nature>org.eclipse.jdt.core.javanature</nature>
</natures>
</projectDescription>
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
Manifest-Version: 1.0
Bundle-ManifestVersion: 2
Bundle-Name: API Tools Tests Plug-in B
Bundle-SymbolicName: bundle.b
Bundle-Version: 1.0.0
Require-Capability: osgi.ee;filter:="(&(osgi.ee=JavaSE)(version=17))"
Export-Package: test
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
source.. = src/
output.. = bin/
bin.includes = META-INF/,\
.
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
package test;
public class Stub {}
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*******************************************************************************
* Copyright (c) 2007, 2021 IBM Corporation and others.
* Copyright (c) 2007, 2024 IBM Corporation and others.
*
* This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0
Expand Down Expand Up @@ -82,7 +82,6 @@
import org.osgi.framework.Constants;
import org.osgi.framework.FrameworkUtil;
import org.osgi.framework.Version;
import org.osgi.framework.namespace.ExecutionEnvironmentNamespace;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;

Expand All @@ -93,8 +92,6 @@
*/
public class BundleComponent extends Component {

private static final String[] NO_EXECUTION_ENRIONMENTS = new String[0];

static final String TMP_API_FILE_PREFIX = "api"; //$NON-NLS-1$

/**
Expand Down Expand Up @@ -164,7 +161,7 @@ public class BundleComponent extends Component {
* @see #getExecutionEnvironments()
* @see #hasDeclaredRequiredEE(Map)
*/
private volatile boolean fHasDeclaredRequiredEE;
private volatile String[] fdeclaredRequiredEE;

/**
* Constructs a new API component from the specified location in the file
Expand Down Expand Up @@ -312,7 +309,7 @@ protected void init() throws CoreException {
BundleDescription bundleDescription = getBundleDescription(manifest, fLocation, fBundleId);
fSymbolicName = bundleDescription.getSymbolicName();
fVersion = bundleDescription.getVersion();
fHasDeclaredRequiredEE = hasDeclaredRequiredEE(manifest);
fdeclaredRequiredEE = ManifestUtils.getRequiredExecutionEnvironments(bundleDescription).toArray(String[]::new);
setName(manifest.get(Constants.BUNDLE_NAME));
fBundleDescription = bundleDescription;
} catch (BundleException e) {
Expand Down Expand Up @@ -889,7 +886,7 @@ private static InputStream loadFixedBundleApiDescription(String bundleAndVersion
public String[] getExecutionEnvironments() throws CoreException {
// Return the EE from the description only if explicitly specified in the
// manifest.
return fHasDeclaredRequiredEE ? getBundleDescription().getExecutionEnvironments() : NO_EXECUTION_ENRIONMENTS;
return fdeclaredRequiredEE;
}

@Override
Expand Down Expand Up @@ -1204,28 +1201,4 @@ protected void baselineDisposed(IApiBaseline baseline) throws CoreException {
throw new CoreException(new Status(IStatus.ERROR, ApiPlugin.PLUGIN_ID, ApiPlugin.REPORT_BASELINE_IS_DISPOSED,
NLS.bind(Messages.BundleApiComponent_baseline_disposed, getName(), baseline.getName()), disposeSource));
}

/*
* This is a copy of
* org.eclipse.pde.internal.core.MinimalState.hasDeclaredRequiredEE(Map<String,
* String>). PDE ends up adding a synthetic EE to the manifest when that method
* returns false, and that ends up in the bundle description such that we cannot
* determine whether the EE was actually present or was synthesized. So we
* repeat that computation here
*/
@SuppressWarnings("deprecation")
private boolean hasDeclaredRequiredEE(Map<String, String> manifest) {
if (manifest.containsKey(Constants.BUNDLE_REQUIREDEXECUTIONENVIRONMENT)) {
return true;
}
try {
String capability = manifest.get(Constants.REQUIRE_CAPABILITY);
ManifestElement[] header = ManifestElement.parseHeader(Constants.REQUIRE_CAPABILITY, capability);
return header != null && Arrays.stream(header).map(ManifestElement::getValue)
.anyMatch(ExecutionEnvironmentNamespace.EXECUTION_ENVIRONMENT_NAMESPACE::equals);
} catch (BundleException e) {
return false; // ignore
}
}

}
Loading