diff --git a/_ext/eclipse-base/CHANGES.md b/_ext/eclipse-base/CHANGES.md index 5e28d4bd59..815f29e320 100644 --- a/_ext/eclipse-base/CHANGES.md +++ b/_ext/eclipse-base/CHANGES.md @@ -1,5 +1,9 @@ # spotless-eclipse-base +### Version 3.2.0 - June 30th 2019 ([artifact]([jcenter](https://bintray.com/diffplug/opensource/spotless-eclipse-base))) + +* Added support of Eclipse 4.12 framework wiring. ([#413](https://github.com/diffplug/spotless/issues/413)) + ### Version 3.1.1 - June 4th 2019 ([artifact]([jcenter](https://bintray.com/diffplug/opensource/spotless-eclipse-base))) * Fixed problem handling URL escaped characters in JAR file location. ([#401](https://github.com/diffplug/spotless/issues/401)) diff --git a/_ext/eclipse-base/gradle.properties b/_ext/eclipse-base/gradle.properties index 3c42ae3abe..6737e08912 100644 --- a/_ext/eclipse-base/gradle.properties +++ b/_ext/eclipse-base/gradle.properties @@ -1,7 +1,7 @@ # Mayor versions correspond to the supported Eclipse core version. # Minor version is incremented for features or incompatible changes (including changes to supported dependency versions). # Patch version is incremented for backward compatible patches of this library. -ext_version=3.1.1 +ext_version=3.2.0 ext_artifactId=spotless-eclipse-base ext_description=Eclipse bundle controller and services for Spotless @@ -12,7 +12,7 @@ ext_group=com.diffplug.spotless ext_VER_JAVA=1.8 # Compile dependencies -VER_ECLIPSE_CORE_RESOURCES=[3.11.1,4.0.0[ +VER_ECLIPSE_CORE_RESOURCES=[3.13.400,4.0.0[ # Provided dependencies VER_SLF4J=[1.6,2.0[ \ No newline at end of file diff --git a/_ext/eclipse-base/src/main/java/com/diffplug/spotless/extra/eclipse/base/SpotlessEclipseFramework.java b/_ext/eclipse-base/src/main/java/com/diffplug/spotless/extra/eclipse/base/SpotlessEclipseFramework.java index 03e8c37d95..2a7a59b79b 100644 --- a/_ext/eclipse-base/src/main/java/com/diffplug/spotless/extra/eclipse/base/SpotlessEclipseFramework.java +++ b/_ext/eclipse-base/src/main/java/com/diffplug/spotless/extra/eclipse/base/SpotlessEclipseFramework.java @@ -25,6 +25,7 @@ import javax.xml.parsers.SAXParserFactory; +import org.eclipse.core.internal.runtime.InternalPlatform; import org.osgi.framework.Bundle; import org.osgi.framework.BundleActivator; import org.osgi.framework.BundleContext; @@ -226,6 +227,13 @@ private void addPlugin(int state, BundleActivator plugin) throws BundleException if (!coreConfigStarted) { //The SAXParserFactory.class is required for parsing the plugin XML files addMandatoryServiceIfMissing(SAXParserFactory.class, SAXParserFactory.newInstance()); + /* + * Since org.eclipse.core.runtime version 3.15.300, the Eclipse bundle look-up is accomplished + * via the wiring framework, which requires a stat of the InternalPlatform. + * The internal platform initialization is customized by the services + * registered to the controller. + */ + InternalPlatform.getDefault().start(controller); startFrameworkBundles(); coreConfigStarted = true; } diff --git a/_ext/eclipse-base/src/main/java/com/diffplug/spotless/extra/eclipse/base/osgi/BundleController.java b/_ext/eclipse-base/src/main/java/com/diffplug/spotless/extra/eclipse/base/osgi/BundleController.java index 8ee9b8c7be..3956b2d30c 100644 --- a/_ext/eclipse-base/src/main/java/com/diffplug/spotless/extra/eclipse/base/osgi/BundleController.java +++ b/_ext/eclipse-base/src/main/java/com/diffplug/spotless/extra/eclipse/base/osgi/BundleController.java @@ -28,6 +28,7 @@ import org.osgi.framework.Filter; import org.osgi.framework.InvalidSyntaxException; import org.osgi.framework.ServiceReference; +import org.osgi.framework.wiring.FrameworkWiring; /** * OSGi bundle controller allowing a minimal Eclipse platform setup @@ -63,8 +64,11 @@ public BundleController() throws BundleException { bundles.add(systemBundle); services = new ServiceCollection(systemBundle, properties); + //Eclipse core (InternalPlatform) still uses PackageAdmin for looking up bundles - services.add(org.osgi.service.packageadmin.PackageAdmin.class, new EclipseBundleLookup(bundles)); + EclipseBundleLookup bundleLookup = new EclipseBundleLookup(systemBundle, bundles); + services.add(org.osgi.service.packageadmin.PackageAdmin.class, bundleLookup); + services.add(FrameworkWiring.class, bundleLookup); //Redirect framework activator requests to the the org.eclipse.osgi bundle to this instance. bundles.add(new SimpleBundle(systemBundle, ECLIPSE_LAUNCHER_SYMBOLIC_NAME, Bundle.ACTIVE)); diff --git a/_ext/eclipse-base/src/main/java/com/diffplug/spotless/extra/eclipse/base/osgi/EclipseBundleLookup.java b/_ext/eclipse-base/src/main/java/com/diffplug/spotless/extra/eclipse/base/osgi/EclipseBundleLookup.java index 601825bbfd..0ec091a58b 100644 --- a/_ext/eclipse-base/src/main/java/com/diffplug/spotless/extra/eclipse/base/osgi/EclipseBundleLookup.java +++ b/_ext/eclipse-base/src/main/java/com/diffplug/spotless/extra/eclipse/base/osgi/EclipseBundleLookup.java @@ -15,26 +15,48 @@ */ package com.diffplug.spotless.extra.eclipse.base.osgi; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.List; +import java.util.Set; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +import org.eclipse.osgi.internal.framework.FilterImpl; import org.osgi.framework.Bundle; +import org.osgi.framework.FrameworkListener; +import org.osgi.framework.InvalidSyntaxException; +import org.osgi.framework.namespace.IdentityNamespace; +import org.osgi.framework.wiring.BundleCapability; +import org.osgi.framework.wiring.FrameworkWiring; +import org.osgi.resource.Namespace; +import org.osgi.resource.Requirement; import org.osgi.service.packageadmin.ExportedPackage; import org.osgi.service.packageadmin.PackageAdmin; import org.osgi.service.packageadmin.RequiredBundle; /** - * {@link PackageAdmin} service for bundle look-up and bypassing wiring. + * + * {@link PackageAdmin} and {@link FrameworkWiring} service for bundle look-up. *

- * The wiring information will always claim that all required bundles are present. - * Other functionality is not supported. - * Unsupported methods are marked as deprecated and throw an {@link UnsupportedOperationException}. + * The wiring information will always claim that all required bundles are present, since + * Spotlss does on purpose not provide all dependencies requested by plugins, since + * only small parts of the plugins are used. + * Removal and addition requests for bundles will always claim that there is nothing to do. *

- * Interface is deprecated, but for example the InternalPlatform still uses PackageAdmin. + * PackageAdmin interface is deprecated, but might still be used by bundles. + * It is kept for backward compatibility until removed from Eclipse. */ @SuppressWarnings("deprecation") -class EclipseBundleLookup implements PackageAdmin { +class EclipseBundleLookup implements FrameworkWiring, PackageAdmin { + private static final Set OSGI_KEYS_FOR_SYMBOLIC_NAMES = Collections.unmodifiableSet(Stream.of(IdentityNamespace.IDENTITY_NAMESPACE, IdentityNamespace.TYPE_BUNDLE).collect(Collectors.toSet())); + private final Bundle systemBundle; private final BundleSet bundles; - EclipseBundleLookup(final BundleSet bundles) { + EclipseBundleLookup(final Bundle systemBundle, final BundleSet bundles) { + this.systemBundle = systemBundle; this.bundles = bundles; } @@ -97,4 +119,64 @@ public int getBundleType(Bundle bundle) { return 0; //No fragments } + @Override + public Bundle getBundle() { + return systemBundle; + } + + @Override + public void refreshBundles(Collection bundles, FrameworkListener... listeners) { + //Spotless bundles cannot be loaded dynamically + } + + @Override + public boolean resolveBundles(Collection bundles) { + return true; + } + + @Override + public Collection getRemovalPendingBundles() { + return Collections.emptyList(); //Nothing to remove + } + + @Override + public Collection getDependencyClosure(Collection bundles) { + return Collections.emptyList(); //No dependencies + } + + @Override + public Collection findProviders(Requirement requirement) { + // requirement must not be null (according to interface description)! + String filterSpec = requirement.getDirectives().get(Namespace.REQUIREMENT_FILTER_DIRECTIVE); + if (null == filterSpec) { + throw new IllegalArgumentException("Requirement filter diretive '" + Namespace.REQUIREMENT_FILTER_DIRECTIVE + "' not found."); + } + try { + FilterImpl requirementFilter = FilterImpl.newInstance(filterSpec); + Collection requiredSymbolicNames = getRequestedSymbolicNames(requirementFilter); + Collection capabilities = new ArrayList(requiredSymbolicNames.size()); + requiredSymbolicNames.forEach(symbolicName -> { + Bundle bundle = bundles.get(symbolicName); + if (bundle != null) { + capabilities.add(new SimpleBundleCapability(bundle)); + } + }); + return capabilities; + } catch (InvalidSyntaxException e) { + throw new IllegalArgumentException("Filter specifiation invalid:\n" + filterSpec, e); + } + } + + /** + * Simplified parser irgnoreing the version. + * Parser is incomplete since it ignores the filter operation. + * It basicall implements the bespoke way Eclipse maps its old style bundle handling to OSGI. + */ + private static Collection getRequestedSymbolicNames(FilterImpl filter) { + List symbolicNames = filter.getStandardOSGiAttributes().entrySet().stream().filter(entry -> OSGI_KEYS_FOR_SYMBOLIC_NAMES.contains(entry.getKey())).map(entry -> entry.getValue()).collect(Collectors.toList()); + filter.getChildren().forEach(childFilter -> { + symbolicNames.addAll(getRequestedSymbolicNames(childFilter)); + }); + return symbolicNames; + } } diff --git a/_ext/eclipse-base/src/main/java/com/diffplug/spotless/extra/eclipse/base/osgi/SimpleBundle.java b/_ext/eclipse-base/src/main/java/com/diffplug/spotless/extra/eclipse/base/osgi/SimpleBundle.java index 3a7e305975..5234855dc5 100644 --- a/_ext/eclipse-base/src/main/java/com/diffplug/spotless/extra/eclipse/base/osgi/SimpleBundle.java +++ b/_ext/eclipse-base/src/main/java/com/diffplug/spotless/extra/eclipse/base/osgi/SimpleBundle.java @@ -69,6 +69,35 @@ private SimpleBundle(BundleContext context, int state, ResourceAccessor resource name = master.name; } + @Override + public A adapt(Class type) { + /* + * The adaptation is currently used by the InternalPlugin to get the framework wiring + * implementation from the system bundle. + * The original purpose to provide more specialized access to the Bundle object, + * seems not be used by Eclipse at all. + * Hence the call is mapped to old-style Eclipse services. + */ + try { + + ServiceReference[] references = context.getAllServiceReferences(type.getName(), ""); + if ((null != references) && (0 != references.length)) { + if (1 != references.length) { + throw new IllegalArgumentException("Multiple services found for " + type.getName()); //In Spotless services should always be unique + } + Object obj = context.getService(references[0]); + try { + return type.cast(obj); + } catch (ClassCastException e) { + throw new IllegalArgumentException("Received unexpected class for reference filter " + type.getName(), e); + } + } + return null; + } catch (InvalidSyntaxException e) { + throw new IllegalArgumentException("Unexpected syntax exception", e); //Should never be thrown by Spotless bundle controller + } + } + @Override public int getState() { return state; diff --git a/_ext/eclipse-base/src/main/java/com/diffplug/spotless/extra/eclipse/base/osgi/SimpleBundleCapability.java b/_ext/eclipse-base/src/main/java/com/diffplug/spotless/extra/eclipse/base/osgi/SimpleBundleCapability.java new file mode 100644 index 0000000000..66f331807d --- /dev/null +++ b/_ext/eclipse-base/src/main/java/com/diffplug/spotless/extra/eclipse/base/osgi/SimpleBundleCapability.java @@ -0,0 +1,114 @@ +/* + * Copyright 2016 DiffPlug + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.diffplug.spotless.extra.eclipse.base.osgi; + +import java.util.Collections; +import java.util.List; +import java.util.Map; + +import org.osgi.framework.Bundle; +import org.osgi.framework.Version; +import org.osgi.framework.wiring.BundleCapability; +import org.osgi.framework.wiring.BundleRequirement; +import org.osgi.framework.wiring.BundleRevision; +import org.osgi.framework.wiring.BundleWiring; +import org.osgi.resource.Capability; +import org.osgi.resource.Requirement; + +/** + * Simplified bundle capability ignoring internal wiring and versions + *

+ * Since multiple versions/implementations of bundles for the same + * capability is not supported a split of bundle capability and revision is not required. + */ +class SimpleBundleCapability implements BundleCapability, BundleRevision { + private final Bundle bundle; + + SimpleBundleCapability(Bundle bundle) { + this.bundle = bundle; + } + + @Override + public BundleRevision getRevision() { + return this; + } + + @Override + public String getNamespace() { + return this.getClass().getName(); //All bundles live in th same namespace + } + + @Override + public Map getDirectives() { + return Collections.emptyMap(); + } + + @Override + public Map getAttributes() { + return Collections.emptyMap(); + } + + @Override + public BundleRevision getResource() { + return this; + } + + @Override + public Bundle getBundle() { + return bundle; + } + + @Override + public String getSymbolicName() { + return bundle.getSymbolicName(); + } + + @Override + public Version getVersion() { + return bundle.getVersion(); + } + + @Override + public List getDeclaredCapabilities(String namespace) { + return Collections.emptyList(); + } + + @Override + public List getDeclaredRequirements(String namespace) { + return Collections.emptyList(); + } + + @Override + public int getTypes() { + return 0; //It does not matter whether this bunddle is a fragment of not since all bundles are initially provided + } + + @Override + public BundleWiring getWiring() { + return null; //No wiring information + } + + @Override + public List getCapabilities(String namespace) { + return Collections.emptyList(); + } + + @Override + public List getRequirements(String namespace) { + return Collections.emptyList(); + } + +}