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);
+ }
+}