Skip to content

Commit dbf857a

Browse files
authored
OSGI framework wiring support as required by latest Eclipse internal platform (#414)
Support of OSGI framework wiring as require by Eclipse internal platform since 4.12.
1 parent 92749a5 commit dbf857a

File tree

7 files changed

+251
-10
lines changed

7 files changed

+251
-10
lines changed

_ext/eclipse-base/CHANGES.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,9 @@
11
# spotless-eclipse-base
22

3+
### Version 3.2.0 - June 30th 2019 ([artifact]([jcenter](https://bintray.com/diffplug/opensource/spotless-eclipse-base)))
4+
5+
* Added support of Eclipse 4.12 framework wiring. ([#413](https://github.com/diffplug/spotless/issues/413))
6+
37
### Version 3.1.1 - June 4th 2019 ([artifact]([jcenter](https://bintray.com/diffplug/opensource/spotless-eclipse-base)))
48

59
* Fixed problem handling URL escaped characters in JAR file location. ([#401](https://github.com/diffplug/spotless/issues/401))

_ext/eclipse-base/gradle.properties

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
# Mayor versions correspond to the supported Eclipse core version.
22
# Minor version is incremented for features or incompatible changes (including changes to supported dependency versions).
33
# Patch version is incremented for backward compatible patches of this library.
4-
ext_version=3.1.1
4+
ext_version=3.2.0
55
ext_artifactId=spotless-eclipse-base
66
ext_description=Eclipse bundle controller and services for Spotless
77

@@ -12,7 +12,7 @@ ext_group=com.diffplug.spotless
1212
ext_VER_JAVA=1.8
1313

1414
# Compile dependencies
15-
VER_ECLIPSE_CORE_RESOURCES=[3.11.1,4.0.0[
15+
VER_ECLIPSE_CORE_RESOURCES=[3.13.400,4.0.0[
1616

1717
# Provided dependencies
1818
VER_SLF4J=[1.6,2.0[

_ext/eclipse-base/src/main/java/com/diffplug/spotless/extra/eclipse/base/SpotlessEclipseFramework.java

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525

2626
import javax.xml.parsers.SAXParserFactory;
2727

28+
import org.eclipse.core.internal.runtime.InternalPlatform;
2829
import org.osgi.framework.Bundle;
2930
import org.osgi.framework.BundleActivator;
3031
import org.osgi.framework.BundleContext;
@@ -226,6 +227,13 @@ private void addPlugin(int state, BundleActivator plugin) throws BundleException
226227
if (!coreConfigStarted) {
227228
//The SAXParserFactory.class is required for parsing the plugin XML files
228229
addMandatoryServiceIfMissing(SAXParserFactory.class, SAXParserFactory.newInstance());
230+
/*
231+
* Since org.eclipse.core.runtime version 3.15.300, the Eclipse bundle look-up is accomplished
232+
* via the wiring framework, which requires a stat of the InternalPlatform.
233+
* The internal platform initialization is customized by the services
234+
* registered to the controller.
235+
*/
236+
InternalPlatform.getDefault().start(controller);
229237
startFrameworkBundles();
230238
coreConfigStarted = true;
231239
}

_ext/eclipse-base/src/main/java/com/diffplug/spotless/extra/eclipse/base/osgi/BundleController.java

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
import org.osgi.framework.Filter;
2929
import org.osgi.framework.InvalidSyntaxException;
3030
import org.osgi.framework.ServiceReference;
31+
import org.osgi.framework.wiring.FrameworkWiring;
3132

3233
/**
3334
* OSGi bundle controller allowing a minimal Eclipse platform setup
@@ -63,8 +64,11 @@ public BundleController() throws BundleException {
6364
bundles.add(systemBundle);
6465

6566
services = new ServiceCollection(systemBundle, properties);
67+
6668
//Eclipse core (InternalPlatform) still uses PackageAdmin for looking up bundles
67-
services.add(org.osgi.service.packageadmin.PackageAdmin.class, new EclipseBundleLookup(bundles));
69+
EclipseBundleLookup bundleLookup = new EclipseBundleLookup(systemBundle, bundles);
70+
services.add(org.osgi.service.packageadmin.PackageAdmin.class, bundleLookup);
71+
services.add(FrameworkWiring.class, bundleLookup);
6872

6973
//Redirect framework activator requests to the the org.eclipse.osgi bundle to this instance.
7074
bundles.add(new SimpleBundle(systemBundle, ECLIPSE_LAUNCHER_SYMBOLIC_NAME, Bundle.ACTIVE));

_ext/eclipse-base/src/main/java/com/diffplug/spotless/extra/eclipse/base/osgi/EclipseBundleLookup.java

Lines changed: 89 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -15,26 +15,48 @@
1515
*/
1616
package com.diffplug.spotless.extra.eclipse.base.osgi;
1717

18+
import java.util.ArrayList;
19+
import java.util.Collection;
20+
import java.util.Collections;
21+
import java.util.List;
22+
import java.util.Set;
23+
import java.util.stream.Collectors;
24+
import java.util.stream.Stream;
25+
26+
import org.eclipse.osgi.internal.framework.FilterImpl;
1827
import org.osgi.framework.Bundle;
28+
import org.osgi.framework.FrameworkListener;
29+
import org.osgi.framework.InvalidSyntaxException;
30+
import org.osgi.framework.namespace.IdentityNamespace;
31+
import org.osgi.framework.wiring.BundleCapability;
32+
import org.osgi.framework.wiring.FrameworkWiring;
33+
import org.osgi.resource.Namespace;
34+
import org.osgi.resource.Requirement;
1935
import org.osgi.service.packageadmin.ExportedPackage;
2036
import org.osgi.service.packageadmin.PackageAdmin;
2137
import org.osgi.service.packageadmin.RequiredBundle;
2238

2339
/**
24-
* {@link PackageAdmin} service for bundle look-up and bypassing wiring.
40+
*
41+
* {@link PackageAdmin} and {@link FrameworkWiring} service for bundle look-up.
2542
* <p>
26-
* The wiring information will always claim that all required bundles are present.
27-
* Other functionality is not supported.
28-
* Unsupported methods are marked as deprecated and throw an {@link UnsupportedOperationException}.
43+
* The wiring information will always claim that all required bundles are present, since
44+
* Spotlss does on purpose not provide all dependencies requested by plugins, since
45+
* only small parts of the plugins are used.
46+
* Removal and addition requests for bundles will always claim that there is nothing to do.
2947
* <p>
30-
* Interface is deprecated, but for example the InternalPlatform still uses PackageAdmin.
48+
* PackageAdmin interface is deprecated, but might still be used by bundles.
49+
* It is kept for backward compatibility until removed from Eclipse.
3150
*/
3251
@SuppressWarnings("deprecation")
33-
class EclipseBundleLookup implements PackageAdmin {
52+
class EclipseBundleLookup implements FrameworkWiring, PackageAdmin {
3453

54+
private static final Set<String> OSGI_KEYS_FOR_SYMBOLIC_NAMES = Collections.unmodifiableSet(Stream.of(IdentityNamespace.IDENTITY_NAMESPACE, IdentityNamespace.TYPE_BUNDLE).collect(Collectors.toSet()));
55+
private final Bundle systemBundle;
3556
private final BundleSet bundles;
3657

37-
EclipseBundleLookup(final BundleSet bundles) {
58+
EclipseBundleLookup(final Bundle systemBundle, final BundleSet bundles) {
59+
this.systemBundle = systemBundle;
3860
this.bundles = bundles;
3961
}
4062

@@ -97,4 +119,64 @@ public int getBundleType(Bundle bundle) {
97119
return 0; //No fragments
98120
}
99121

122+
@Override
123+
public Bundle getBundle() {
124+
return systemBundle;
125+
}
126+
127+
@Override
128+
public void refreshBundles(Collection<Bundle> bundles, FrameworkListener... listeners) {
129+
//Spotless bundles cannot be loaded dynamically
130+
}
131+
132+
@Override
133+
public boolean resolveBundles(Collection<Bundle> bundles) {
134+
return true;
135+
}
136+
137+
@Override
138+
public Collection<Bundle> getRemovalPendingBundles() {
139+
return Collections.emptyList(); //Nothing to remove
140+
}
141+
142+
@Override
143+
public Collection<Bundle> getDependencyClosure(Collection<Bundle> bundles) {
144+
return Collections.emptyList(); //No dependencies
145+
}
146+
147+
@Override
148+
public Collection<BundleCapability> findProviders(Requirement requirement) {
149+
// requirement must not be null (according to interface description)!
150+
String filterSpec = requirement.getDirectives().get(Namespace.REQUIREMENT_FILTER_DIRECTIVE);
151+
if (null == filterSpec) {
152+
throw new IllegalArgumentException("Requirement filter diretive '" + Namespace.REQUIREMENT_FILTER_DIRECTIVE + "' not found.");
153+
}
154+
try {
155+
FilterImpl requirementFilter = FilterImpl.newInstance(filterSpec);
156+
Collection<String> requiredSymbolicNames = getRequestedSymbolicNames(requirementFilter);
157+
Collection<BundleCapability> capabilities = new ArrayList<BundleCapability>(requiredSymbolicNames.size());
158+
requiredSymbolicNames.forEach(symbolicName -> {
159+
Bundle bundle = bundles.get(symbolicName);
160+
if (bundle != null) {
161+
capabilities.add(new SimpleBundleCapability(bundle));
162+
}
163+
});
164+
return capabilities;
165+
} catch (InvalidSyntaxException e) {
166+
throw new IllegalArgumentException("Filter specifiation invalid:\n" + filterSpec, e);
167+
}
168+
}
169+
170+
/**
171+
* Simplified parser irgnoreing the version.
172+
* Parser is incomplete since it ignores the filter operation.
173+
* It basicall implements the bespoke way Eclipse maps its old style bundle handling to OSGI.
174+
*/
175+
private static Collection<String> getRequestedSymbolicNames(FilterImpl filter) {
176+
List<String> symbolicNames = filter.getStandardOSGiAttributes().entrySet().stream().filter(entry -> OSGI_KEYS_FOR_SYMBOLIC_NAMES.contains(entry.getKey())).map(entry -> entry.getValue()).collect(Collectors.toList());
177+
filter.getChildren().forEach(childFilter -> {
178+
symbolicNames.addAll(getRequestedSymbolicNames(childFilter));
179+
});
180+
return symbolicNames;
181+
}
100182
}

_ext/eclipse-base/src/main/java/com/diffplug/spotless/extra/eclipse/base/osgi/SimpleBundle.java

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,35 @@ private SimpleBundle(BundleContext context, int state, ResourceAccessor resource
6969
name = master.name;
7070
}
7171

72+
@Override
73+
public <A> A adapt(Class<A> type) {
74+
/*
75+
* The adaptation is currently used by the InternalPlugin to get the framework wiring
76+
* implementation from the system bundle.
77+
* The original purpose to provide more specialized access to the Bundle object,
78+
* seems not be used by Eclipse at all.
79+
* Hence the call is mapped to old-style Eclipse services.
80+
*/
81+
try {
82+
83+
ServiceReference<?>[] references = context.getAllServiceReferences(type.getName(), "");
84+
if ((null != references) && (0 != references.length)) {
85+
if (1 != references.length) {
86+
throw new IllegalArgumentException("Multiple services found for " + type.getName()); //In Spotless services should always be unique
87+
}
88+
Object obj = context.getService(references[0]);
89+
try {
90+
return type.cast(obj);
91+
} catch (ClassCastException e) {
92+
throw new IllegalArgumentException("Received unexpected class for reference filter " + type.getName(), e);
93+
}
94+
}
95+
return null;
96+
} catch (InvalidSyntaxException e) {
97+
throw new IllegalArgumentException("Unexpected syntax exception", e); //Should never be thrown by Spotless bundle controller
98+
}
99+
}
100+
72101
@Override
73102
public int getState() {
74103
return state;
Lines changed: 114 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,114 @@
1+
/*
2+
* Copyright 2016 DiffPlug
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package com.diffplug.spotless.extra.eclipse.base.osgi;
17+
18+
import java.util.Collections;
19+
import java.util.List;
20+
import java.util.Map;
21+
22+
import org.osgi.framework.Bundle;
23+
import org.osgi.framework.Version;
24+
import org.osgi.framework.wiring.BundleCapability;
25+
import org.osgi.framework.wiring.BundleRequirement;
26+
import org.osgi.framework.wiring.BundleRevision;
27+
import org.osgi.framework.wiring.BundleWiring;
28+
import org.osgi.resource.Capability;
29+
import org.osgi.resource.Requirement;
30+
31+
/**
32+
* Simplified bundle capability ignoring internal wiring and versions
33+
* <p/>
34+
* Since multiple versions/implementations of bundles for the same
35+
* capability is not supported a split of bundle capability and revision is not required.
36+
*/
37+
class SimpleBundleCapability implements BundleCapability, BundleRevision {
38+
private final Bundle bundle;
39+
40+
SimpleBundleCapability(Bundle bundle) {
41+
this.bundle = bundle;
42+
}
43+
44+
@Override
45+
public BundleRevision getRevision() {
46+
return this;
47+
}
48+
49+
@Override
50+
public String getNamespace() {
51+
return this.getClass().getName(); //All bundles live in th same namespace
52+
}
53+
54+
@Override
55+
public Map<String, String> getDirectives() {
56+
return Collections.emptyMap();
57+
}
58+
59+
@Override
60+
public Map<String, Object> getAttributes() {
61+
return Collections.emptyMap();
62+
}
63+
64+
@Override
65+
public BundleRevision getResource() {
66+
return this;
67+
}
68+
69+
@Override
70+
public Bundle getBundle() {
71+
return bundle;
72+
}
73+
74+
@Override
75+
public String getSymbolicName() {
76+
return bundle.getSymbolicName();
77+
}
78+
79+
@Override
80+
public Version getVersion() {
81+
return bundle.getVersion();
82+
}
83+
84+
@Override
85+
public List<BundleCapability> getDeclaredCapabilities(String namespace) {
86+
return Collections.emptyList();
87+
}
88+
89+
@Override
90+
public List<BundleRequirement> getDeclaredRequirements(String namespace) {
91+
return Collections.emptyList();
92+
}
93+
94+
@Override
95+
public int getTypes() {
96+
return 0; //It does not matter whether this bunddle is a fragment of not since all bundles are initially provided
97+
}
98+
99+
@Override
100+
public BundleWiring getWiring() {
101+
return null; //No wiring information
102+
}
103+
104+
@Override
105+
public List<Capability> getCapabilities(String namespace) {
106+
return Collections.emptyList();
107+
}
108+
109+
@Override
110+
public List<Requirement> getRequirements(String namespace) {
111+
return Collections.emptyList();
112+
}
113+
114+
}

0 commit comments

Comments
 (0)