The feature is completely broken as the {{BundleWires#wiring}} map is never
modified.
Please revert and try with a again correct fix ;-)2017-02-06 16:00 GMT+01:00 <[email protected]>: > Repository: karaf > Updated Branches: > refs/heads/master d2f944057 -> 9ce324f57 > > > [KARAF-4973] Refactoring of features extension > > > Project: http://git-wip-us.apache.org/repos/asf/karaf/repo > Commit: http://git-wip-us.apache.org/repos/asf/karaf/commit/9ce324f5 > Tree: http://git-wip-us.apache.org/repos/asf/karaf/tree/9ce324f5 > Diff: http://git-wip-us.apache.org/repos/asf/karaf/diff/9ce324f5 > > Branch: refs/heads/master > Commit: 9ce324f577d427d501558740b440f264eb6e2d27 > Parents: d2f9440 > Author: Christian Schneider <[email protected]> > Authored: Wed Feb 1 15:07:42 2017 +0100 > Committer: Christian Schneider <[email protected]> > Committed: Mon Feb 6 15:44:34 2017 +0100 > > ---------------------------------------------------------------------- > .../karaf/features/extension/Activator.java | 214 +++---------------- > .../karaf/features/extension/BundleWires.java | 140 ++++++++++++ > .../extension/StoredWiringResolver.java | 112 ++++++++++ > 3 files changed, 284 insertions(+), 182 deletions(-) > ---------------------------------------------------------------------- > > > http://git-wip-us.apache.org/repos/asf/karaf/blob/9ce324f5/ > features/extension/src/main/java/org/apache/karaf/ > features/extension/Activator.java > ---------------------------------------------------------------------- > diff --git a/features/extension/src/main/java/org/apache/karaf/ > features/extension/Activator.java b/features/extension/src/main/ > java/org/apache/karaf/features/extension/Activator.java > index f0be0e8..19e2769 100644 > --- a/features/extension/src/main/java/org/apache/karaf/ > features/extension/Activator.java > +++ b/features/extension/src/main/java/org/apache/karaf/ > features/extension/Activator.java > @@ -16,35 +16,25 @@ > */ > package org.apache.karaf.features.extension; > > -import org.osgi.framework.*; > -import org.osgi.framework.hooks.resolver.ResolverHook; > -import org.osgi.framework.hooks.resolver.ResolverHookFactory; > -import org.osgi.framework.namespace.HostNamespace; > -import org.osgi.framework.namespace.IdentityNamespace; > -import org.osgi.framework.wiring.*; > -import org.osgi.resource.Capability; > -import org.osgi.resource.Namespace; > -import org.osgi.resource.Requirement; > -import org.osgi.resource.Resource; > - > -import java.io.*; > -import java.nio.file.Files; > -import java.nio.file.Path; > -import java.nio.file.StandardOpenOption; > -import java.util.*; > -import java.util.stream.Collectors; > +import java.util.Arrays; > > -public class Activator implements BundleActivator, ResolverHook, > SynchronousBundleListener, ResolverHookFactory { > +import org.osgi.framework.BundleActivator; > +import org.osgi.framework.BundleContext; > +import org.osgi.framework.BundleEvent; > +import org.osgi.framework.ServiceRegistration; > +import org.osgi.framework.SynchronousBundleListener; > +import org.osgi.framework.hooks.resolver.ResolverHookFactory; > +import org.osgi.framework.wiring.FrameworkWiring; > > +public class Activator implements BundleActivator, > SynchronousBundleListener { > private static final String WIRING_PATH = "wiring"; > - > - private final Map<Long, Map<String, String>> wiring = new HashMap<>(); > - private BundleContext bundleContext; > + private StoredWiringResolver resolver; > + private BundleContext context; > > @Override > public void start(BundleContext context) throws Exception { > - this.bundleContext = context; > - load(); > + this.context = context; > + resolver = new StoredWiringResolver(context. > getDataFile(WIRING_PATH).toPath()); > context.addBundleListener(this); > } > > @@ -53,163 +43,23 @@ public class Activator implements BundleActivator, > ResolverHook, SynchronousBund > context.removeBundleListener(this); > } > > - @Override > - public void bundleChanged(BundleEvent event) { > - if (event.getBundle().getBundleId() == 0 && event.getType() == > BundleEvent.STARTED) { > - ServiceRegistration<ResolverHookFactory> registration = > bundleContext.registerService(ResolverHookFactory.class, this, null); > - try { > - List<Bundle> bundles = wiring.keySet().stream() > - .map(id -> bundleContext.getBundle(id)) > - .collect(Collectors.toList()); > - bundleContext.getBundle().adapt(FrameworkWiring.class) > - .resolveBundles(bundles); > - } finally { > - registration.unregister(); > - } > - } else if (event.getType() == BundleEvent.RESOLVED || > event.getType() == BundleEvent.UNRESOLVED) { > - synchronized (wiring) { > - long id = event.getBundle().getBundleId(); > - if (event.getType() == BundleEvent.RESOLVED) { > - Map<String, String> bw = new HashMap<>(); > - for (BundleWire wire : event.getBundle().adapt( > BundleWiring.class).getRequiredWires(null)) { > - bw.put(getRequirementId(wire.getRequirement()), > getCapabilityId(wire.getCapability())); > - } > - wiring.put(id, bw); > - saveWiring(id, bw); > - } else { > - wiring.remove(id); > - saveWiring(id, null); > - } > - } > - } > - } > - > - @Override > - public void filterResolvable(Collection<BundleRevision> candidates) { > - } > - > - @Override > - public void filterSingletonCollisions(BundleCapability singleton, > Collection<BundleCapability> collisionCandidates) { > - } > - > - @Override > - public void filterMatches(BundleRequirement requirement, > Collection<BundleCapability> candidates) { > - long sourceId = requirement.getRevision(). > getBundle().getBundleId(); > - if (isFragment(requirement.getRevision()) > - && > !requirement.getNamespace().equals(HostNamespace.HOST_NAMESPACE)) > { > - sourceId = wiring.get(sourceId).entrySet().stream() > - .filter(e -> e.getKey().startsWith( > HostNamespace.HOST_NAMESPACE)) > - .map(Map.Entry::getValue) > - .mapToLong(s -> { > - int idx = s.indexOf(';'); > - if (idx > 0) { > - s = s.substring(0, idx); > - } > - return Long.parseLong(s.trim()); > - }) > - .findFirst() > - .orElse(-1); > - } > - Map<String, String> bw = wiring.get(sourceId); > - String cap = bw.get(getRequirementId(requirement)); > - for (Iterator<BundleCapability> candIter = candidates.iterator(); > candIter.hasNext();) { > - BundleCapability cand = candIter.next(); > - if (cap != null && !cap.equals(getCapabilityId(cand)) > - || cap == null && > cand.getRevision().getBundle().getBundleId() > != sourceId) { > - candIter.remove(); > - } > - } > - } > - > - @Override > - public void end() { > - } > - > - @Override > - public ResolverHook begin(Collection<BundleRevision> triggers) { > - return this; > - } > - > - private void load() { > - try { > - Path dir = bundleContext.getDataFile(WIRING_PATH).toPath(); > - Files.createDirectories(dir); > - Files.list(dir).forEach(p -> { > - String name = p.getFileName().toString(); > - if (name.matches("[0-9]+")) { > - try (BufferedReader reader = > Files.newBufferedReader(p)) { > - long id = Long.parseLong(name); > - Map<String, String> map = new HashMap<>(); > - while (true) { > - String key = reader.readLine(); > - String val = reader.readLine(); > - if (key != null && val != null) { > - map.put(key, val); > - } else { > - break; > - } > - } > - wiring.put(id, map); > - } catch (IOException e) { > - throw new UncheckedIOException(e); > - } > - } > - }); > - } catch (IOException e) { > - throw new UncheckedIOException(e); > - } > - } > - > - private void saveWiring(long id, Map<String, String> wiring) { > - try { > - Path dir = bundleContext.getDataFile(WIRING_PATH).toPath(); > - Files.createDirectories(dir); > - Path file = dir.resolve(Long.toString(id)); > - if (wiring != null) { > - Files.createDirectories(file.getParent()); > - try (BufferedWriter fw = Files.newBufferedWriter(file, > - StandardOpenOption.TRUNCATE_EXISTING, > - StandardOpenOption.WRITE, > - StandardOpenOption.CREATE)) { > - for (Map.Entry<String, String> wire : > wiring.entrySet()) { > - fw.append(wire.getKey()).append('\n'); > - fw.append(wire.getValue()).append('\n'); > - } > - } > - } else { > - Files.deleteIfExists(file); > - } > - } catch (IOException e) { > - throw new UncheckedIOException(e); > - } > - } > - > - private String getRequirementId(Requirement requirement) { > - String filter = requirement.getDirectives(). > get(Namespace.REQUIREMENT_FILTER_DIRECTIVE); > - if (filter != null) { > - return requirement.getNamespace() + "; " + filter; > - } else { > - return requirement.getNamespace(); > - } > - } > - > - private String getCapabilityId(BundleCapability capability) { > - StringBuilder sb = new StringBuilder(64); > - sb.append(capability.getRevision().getBundle().getBundleId()); > - Object v = capability.getAttributes().get(Constants.VERSION_ > ATTRIBUTE); > - if (v != null) { > - sb.append("; version=").append(v.toString()); > - } > - return sb.toString(); > - } > - > - private static boolean isFragment(Resource resource) { > - for (Capability cap : resource.getCapabilities(null)) { > - if > (IdentityNamespace.IDENTITY_NAMESPACE.equals(cap.getNamespace())) > { > - return IdentityNamespace.TYPE_FRAGMENT.equals( > - cap.getAttributes().get( > IdentityNamespace.CAPABILITY_TYPE_ATTRIBUTE)); > - } > - } > - return false; > - } > + @Override > + public void bundleChanged(BundleEvent event) { > + if (event.getBundle().getBundleId() == 0 && > event.getType() == BundleEvent.STARTED) { > + resolveAll(); > + } else if (event.getType() == BundleEvent.RESOLVED) { > + resolver.update(event.getBundle()); > + } else if (event.getType() == BundleEvent.UNRESOLVED) { > + resolver.delete(event.getBundle()); > + } > + } > + > + private void resolveAll() { > + ServiceRegistration<ResolverHookFactory> registration = > context.registerService(ResolverHookFactory.class, (triggers) -> > resolver, null); > + try { > + context.getBundle().adapt(FrameworkWiring.class). > resolveBundles(Arrays.asList(context.getBundles())); > + } finally { > + registration.unregister(); > + } > + } > } > > http://git-wip-us.apache.org/repos/asf/karaf/blob/9ce324f5/ > features/extension/src/main/java/org/apache/karaf/features/extension/ > BundleWires.java > ---------------------------------------------------------------------- > diff --git a/features/extension/src/main/java/org/apache/karaf/ > features/extension/BundleWires.java b/features/extension/src/main/ > java/org/apache/karaf/features/extension/BundleWires.java > new file mode 100644 > index 0000000..48b289a > --- /dev/null > +++ b/features/extension/src/main/java/org/apache/karaf/ > features/extension/BundleWires.java > @@ -0,0 +1,140 @@ > +/* > + * Licensed to the Apache Software Foundation (ASF) under one or more > + * contributor license agreements. See the NOTICE file distributed with > + * this work for additional information regarding copyright ownership. > + * The ASF licenses this file to You 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 org.apache.karaf.features.extension; > + > +import static java.nio.file.StandardOpenOption.CREATE; > +import static java.nio.file.StandardOpenOption.TRUNCATE_EXISTING; > +import static java.nio.file.StandardOpenOption.WRITE; > + > +import java.io.BufferedReader; > +import java.io.BufferedWriter; > +import java.io.IOException; > +import java.io.UncheckedIOException; > +import java.nio.file.Files; > +import java.nio.file.Path; > +import java.util.Collection; > +import java.util.HashMap; > +import java.util.Iterator; > +import java.util.Map; > + > +import org.osgi.framework.Bundle; > +import org.osgi.framework.Constants; > +import org.osgi.framework.namespace.HostNamespace; > +import org.osgi.framework.wiring.BundleCapability; > +import org.osgi.framework.wiring.BundleRequirement; > +import org.osgi.framework.wiring.BundleWire; > +import org.osgi.framework.wiring.BundleWiring; > +import org.osgi.resource.Namespace; > +import org.osgi.resource.Requirement; > + > +class BundleWires { > + long bundleId; > + Map<String, String> wiring; > + > + BundleWires(Bundle bundle) { > + this.bundleId = bundle.getBundleId(); > + this.wiring = new HashMap<>(); > + Map<String, String> bw = new HashMap<>(); > + for (BundleWire wire : > bundle.adapt(BundleWiring.class).getRequiredWires(null)) > { > + bw.put(getRequirementId(wire.getRequirement()), > getCapabilityId(wire.getCapability())); > + } > + } > + > + BundleWires(BufferedReader reader) throws IOException { > + Map<String, String> map = new HashMap<>(); > + while (true) { > + String key = reader.readLine(); > + String val = reader.readLine(); > + if (key != null && val != null) { > + map.put(key, val); > + } else { > + break; > + } > + } > + } > + > + void save(Path path) { > + try { > + Files.createDirectories(path); > + Path file = path.resolve(Long.toString( > this.bundleId)); > + Files.createDirectories(file.getParent()); > + try (BufferedWriter fw = > Files.newBufferedWriter(file, TRUNCATE_EXISTING, WRITE, CREATE)) { > + for (Map.Entry<String, String> wire : > wiring.entrySet()) { > + fw.append(wire.getKey()). > append('\n'); > + fw.append(wire.getValue()). > append('\n'); > + } > + } > + } catch (IOException e) { > + throw new UncheckedIOException(e); > + } > + } > + > + void delete(Path path) { > + try { > + Files.createDirectories(path); > + Path file = path.resolve(Long.toString( > this.bundleId)); > + Files.deleteIfExists(file); > + } catch (IOException e) { > + throw new UncheckedIOException(e); > + } > + } > + > + long getFragmentHost() { > + return wiring.entrySet().stream() > + .filter(e -> e.getKey().startsWith(HostNamespace.HOST_NAMESPACE)) > + .map(Map.Entry::getValue) > + .mapToLong(s -> { > + int idx = s.indexOf(';'); > + if (idx > 0) { > + s = s.substring(0, idx); > + } > + return Long.parseLong(s.trim()); > + }) > + .findFirst() > + .orElse(-1); > + } > + > + void filterMatches(BundleRequirement requirement, > Collection<BundleCapability> candidates) { > + String cap = wiring.get(getRequirementId(requirement)); > + for (Iterator<BundleCapability> candIter = candidates.iterator(); > candIter.hasNext();) { > + BundleCapability cand = candIter.next(); > + if (cap != null && !cap.equals(getCapabilityId(cand)) > + || cap == null && > cand.getRevision().getBundle().getBundleId() > != this.bundleId) { > + candIter.remove(); > + } > + } > + } > + > + private String getRequirementId(Requirement requirement) { > + String filter = requirement.getDirectives(). > get(Namespace.REQUIREMENT_FILTER_DIRECTIVE); > + if (filter != null) { > + return requirement.getNamespace() + "; " + filter; > + } else { > + return requirement.getNamespace(); > + } > + } > + > + private String getCapabilityId(BundleCapability capability) { > + StringBuilder sb = new StringBuilder(64); > + sb.append(capability.getRevision().getBundle().getBundleId()); > + Object v = capability.getAttributes().get(Constants.VERSION_ > ATTRIBUTE); > + if (v != null) { > + sb.append("; version=").append(v.toString()); > + } > + return sb.toString(); > + } > +} > > http://git-wip-us.apache.org/repos/asf/karaf/blob/9ce324f5/ > features/extension/src/main/java/org/apache/karaf/features/extension/ > StoredWiringResolver.java > ---------------------------------------------------------------------- > diff --git a/features/extension/src/main/java/org/apache/karaf/ > features/extension/StoredWiringResolver.java > b/features/extension/src/main/java/org/apache/karaf/features/extension/ > StoredWiringResolver.java > new file mode 100644 > index 0000000..3ebd8b4 > --- /dev/null > +++ b/features/extension/src/main/java/org/apache/karaf/ > features/extension/StoredWiringResolver.java > @@ -0,0 +1,112 @@ > +/* > + * Licensed to the Apache Software Foundation (ASF) under one or more > + * contributor license agreements. See the NOTICE file distributed with > + * this work for additional information regarding copyright ownership. > + * The ASF licenses this file to You 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 org.apache.karaf.features.extension; > + > +import java.io.BufferedReader; > +import java.io.IOException; > +import java.io.UncheckedIOException; > +import java.nio.file.Files; > +import java.nio.file.Path; > +import java.util.Collection; > +import java.util.HashMap; > +import java.util.Map; > + > +import org.osgi.framework.Bundle; > +import org.osgi.framework.hooks.resolver.ResolverHook; > +import org.osgi.framework.namespace.HostNamespace; > +import org.osgi.framework.namespace.IdentityNamespace; > +import org.osgi.framework.wiring.BundleCapability; > +import org.osgi.framework.wiring.BundleRequirement; > +import org.osgi.framework.wiring.BundleRevision; > +import org.osgi.resource.Capability; > +import org.osgi.resource.Resource; > + > +class StoredWiringResolver implements ResolverHook { > + private final Map<Long, BundleWires> wiring = new HashMap<>(); > + private Path path; > + > + StoredWiringResolver(Path path) { > + this.path = path; > + load(); > + } > + > + void load() { > + try { > + Files.createDirectories(path); > + Files.list(path).forEach(p -> { > + String name = p.getFileName().toString(); > + if (name.matches("[0-9]+")) { > + try (BufferedReader reader = > Files.newBufferedReader(p)) { > + long id = Long.parseLong(name); > + wiring.put(id, new BundleWires(reader)); > + } catch (IOException e) { > + throw new UncheckedIOException(e); > + } > + } > + }); > + } catch (IOException e) { > + throw new UncheckedIOException(e); > + } > + } > + > + @Override > + public void filterResolvable(Collection<BundleRevision> candidates) { > + } > + > + @Override > + public void filterSingletonCollisions(BundleCapability singleton, > Collection<BundleCapability> collisionCandidates) { > + } > + > + @Override > + public void filterMatches(BundleRequirement requirement, > Collection<BundleCapability> candidates) { > + long sourceId = getBundleId(requirement); > + wiring.get(sourceId).filterMatches(requirement, candidates); > + } > + > + @Override > + public void end() { > + } > + > + private long getBundleId(BundleRequirement requirement) { > + long sourceId = requirement.getRevision(). > getBundle().getBundleId(); > + if (isFragment(requirement.getRevision()) > + && > !requirement.getNamespace().equals(HostNamespace.HOST_NAMESPACE)) > { > + sourceId = wiring.get(sourceId).getFragmentHost(); > + } > + return sourceId; > + } > + > + private static boolean isFragment(Resource resource) { > + for (Capability cap : resource.getCapabilities(null)) { > + if > (IdentityNamespace.IDENTITY_NAMESPACE.equals(cap.getNamespace())) > { > + return IdentityNamespace.TYPE_FRAGMENT.equals( > + cap.getAttributes().get( > IdentityNamespace.CAPABILITY_TYPE_ATTRIBUTE)); > + } > + } > + return false; > + } > + > + synchronized void update(Bundle bundle) { > + BundleWires bw = new BundleWires(bundle); > + bw.save(path); > + wiring.put(bundle.getBundleId(), bw); > + } > + > + synchronized void delete(Bundle bundle) { > + wiring.get(bundle.getBundleId()).delete(path); > + } > +} > > -- ------------------------ Guillaume Nodet
