Rename A2 framework package.
authorMathieu Baudier <mbaudier@argeo.org>
Tue, 17 Dec 2019 09:53:29 +0000 (10:53 +0100)
committerMathieu Baudier <mbaudier@argeo.org>
Tue, 17 Dec 2019 09:53:29 +0000 (10:53 +0100)
29 files changed:
org.argeo.osgi.boot/ext/test/org/argeo/osgi/a2/ClasspathSourceTest.java [new file with mode: 0644]
org.argeo.osgi.boot/ext/test/org/argeo/osgi/boot/a2/ClasspathSourceTest.java [deleted file]
org.argeo.osgi.boot/src/org/argeo/osgi/a2/A2Branch.java [new file with mode: 0644]
org.argeo.osgi.boot/src/org/argeo/osgi/a2/A2Component.java [new file with mode: 0644]
org.argeo.osgi.boot/src/org/argeo/osgi/a2/A2Contribution.java [new file with mode: 0644]
org.argeo.osgi.boot/src/org/argeo/osgi/a2/A2Exception.java [new file with mode: 0644]
org.argeo.osgi.boot/src/org/argeo/osgi/a2/A2Module.java [new file with mode: 0644]
org.argeo.osgi.boot/src/org/argeo/osgi/a2/A2Source.java [new file with mode: 0644]
org.argeo.osgi.boot/src/org/argeo/osgi/a2/AbstractProvisioningSource.java [new file with mode: 0644]
org.argeo.osgi.boot/src/org/argeo/osgi/a2/ClasspathSource.java [new file with mode: 0644]
org.argeo.osgi.boot/src/org/argeo/osgi/a2/FsA2Source.java [new file with mode: 0644]
org.argeo.osgi.boot/src/org/argeo/osgi/a2/FsM2Source.java [new file with mode: 0644]
org.argeo.osgi.boot/src/org/argeo/osgi/a2/OsgiContext.java [new file with mode: 0644]
org.argeo.osgi.boot/src/org/argeo/osgi/a2/ProvisioningManager.java [new file with mode: 0644]
org.argeo.osgi.boot/src/org/argeo/osgi/a2/ProvisioningSource.java [new file with mode: 0644]
org.argeo.osgi.boot/src/org/argeo/osgi/boot/OsgiBoot.java
org.argeo.osgi.boot/src/org/argeo/osgi/boot/a2/A2Branch.java [deleted file]
org.argeo.osgi.boot/src/org/argeo/osgi/boot/a2/A2Component.java [deleted file]
org.argeo.osgi.boot/src/org/argeo/osgi/boot/a2/A2Contribution.java [deleted file]
org.argeo.osgi.boot/src/org/argeo/osgi/boot/a2/A2Exception.java [deleted file]
org.argeo.osgi.boot/src/org/argeo/osgi/boot/a2/A2Module.java [deleted file]
org.argeo.osgi.boot/src/org/argeo/osgi/boot/a2/A2Source.java [deleted file]
org.argeo.osgi.boot/src/org/argeo/osgi/boot/a2/AbstractProvisioningSource.java [deleted file]
org.argeo.osgi.boot/src/org/argeo/osgi/boot/a2/ClasspathSource.java [deleted file]
org.argeo.osgi.boot/src/org/argeo/osgi/boot/a2/FsA2Source.java [deleted file]
org.argeo.osgi.boot/src/org/argeo/osgi/boot/a2/FsM2Source.java [deleted file]
org.argeo.osgi.boot/src/org/argeo/osgi/boot/a2/OsgiContext.java [deleted file]
org.argeo.osgi.boot/src/org/argeo/osgi/boot/a2/ProvisioningManager.java [deleted file]
org.argeo.osgi.boot/src/org/argeo/osgi/boot/a2/ProvisioningSource.java [deleted file]

diff --git a/org.argeo.osgi.boot/ext/test/org/argeo/osgi/a2/ClasspathSourceTest.java b/org.argeo.osgi.boot/ext/test/org/argeo/osgi/a2/ClasspathSourceTest.java
new file mode 100644 (file)
index 0000000..d087e5a
--- /dev/null
@@ -0,0 +1,31 @@
+package org.argeo.osgi.a2;
+
+import java.io.IOException;
+
+import org.argeo.osgi.a2.ClasspathSource;
+import org.argeo.osgi.a2.ProvisioningManager;
+import org.argeo.osgi.boot.equinox.EquinoxUtils;
+import org.junit.Test;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleException;
+import org.osgi.framework.launch.Framework;
+
+public class ClasspathSourceTest {
+       @Test
+       public void testProvisioning() throws IOException {
+               Framework framework = EquinoxUtils.launch(null);
+               ProvisioningManager provisioningManager = new ProvisioningManager(framework.getBundleContext());
+               ClasspathSource classpathSource = new ClasspathSource();
+               classpathSource.load();
+               provisioningManager.addSource(classpathSource);
+               provisioningManager.install(null);
+               for (Bundle bundle : framework.getBundleContext().getBundles()) {
+                       System.out.println(bundle.getSymbolicName() + ":" + bundle.getVersion());
+               }
+               try {
+                       framework.stop();
+               } catch (BundleException e) {
+                       // silent
+               }
+       }
+}
diff --git a/org.argeo.osgi.boot/ext/test/org/argeo/osgi/boot/a2/ClasspathSourceTest.java b/org.argeo.osgi.boot/ext/test/org/argeo/osgi/boot/a2/ClasspathSourceTest.java
deleted file mode 100644 (file)
index 6f4b467..0000000
+++ /dev/null
@@ -1,29 +0,0 @@
-package org.argeo.osgi.boot.a2;
-
-import java.io.IOException;
-
-import org.argeo.osgi.boot.equinox.EquinoxUtils;
-import org.junit.Test;
-import org.osgi.framework.Bundle;
-import org.osgi.framework.BundleException;
-import org.osgi.framework.launch.Framework;
-
-public class ClasspathSourceTest {
-       @Test
-       public void testProvisioning() throws IOException {
-               Framework framework = EquinoxUtils.launch(null);
-               ProvisioningManager provisioningManager = new ProvisioningManager(framework.getBundleContext());
-               ClasspathSource classpathSource = new ClasspathSource();
-               classpathSource.load();
-               provisioningManager.addSource(classpathSource);
-               provisioningManager.install(null);
-               for (Bundle bundle : framework.getBundleContext().getBundles()) {
-                       System.out.println(bundle.getSymbolicName() + ":" + bundle.getVersion());
-               }
-               try {
-                       framework.stop();
-               } catch (BundleException e) {
-                       // silent
-               }
-       }
-}
diff --git a/org.argeo.osgi.boot/src/org/argeo/osgi/a2/A2Branch.java b/org.argeo.osgi.boot/src/org/argeo/osgi/a2/A2Branch.java
new file mode 100644 (file)
index 0000000..070830e
--- /dev/null
@@ -0,0 +1,85 @@
+package org.argeo.osgi.a2;
+
+import java.util.Collections;
+import java.util.SortedMap;
+import java.util.TreeMap;
+
+import org.argeo.osgi.boot.OsgiBootUtils;
+import org.osgi.framework.Version;
+
+/**
+ * A logical linear sequence of versions of a given {@link A2Component}. This is
+ * typically a combination of major and minor version, indicating backward
+ * compatibility.
+ */
+public class A2Branch implements Comparable<A2Branch> {
+       private final A2Component component;
+       private final String id;
+
+       final SortedMap<Version, A2Module> modules = Collections.synchronizedSortedMap(new TreeMap<>());
+
+       public A2Branch(A2Component component, String id) {
+               this.component = component;
+               this.id = id;
+               component.branches.put(id, this);
+       }
+
+       A2Module getOrAddModule(Version version, Object locator) {
+               if (modules.containsKey(version)) {
+                       A2Module res = modules.get(version);
+                       if (OsgiBootUtils.isDebug() && !res.getLocator().equals(locator)) {
+                               OsgiBootUtils.debug("Inconsistent locator " + locator + " (registered: " + res.getLocator() + ")");
+                       }
+                       return res;
+               } else
+                       return new A2Module(this, version, locator);
+       }
+
+       A2Module last() {
+               return modules.get(modules.lastKey());
+       }
+
+       A2Module first() {
+               return modules.get(modules.firstKey());
+       }
+
+       A2Component getComponent() {
+               return component;
+       }
+
+       String getId() {
+               return id;
+       }
+
+       @Override
+       public int compareTo(A2Branch o) {
+               return id.compareTo(id);
+       }
+
+       @Override
+       public int hashCode() {
+               return id.hashCode();
+       }
+
+       @Override
+       public boolean equals(Object obj) {
+               if (obj instanceof A2Branch) {
+                       A2Branch o = (A2Branch) obj;
+                       return component.equals(o.component) && id.equals(o.id);
+               } else
+                       return false;
+       }
+
+       @Override
+       public String toString() {
+               return getCoordinates();
+       }
+
+       public String getCoordinates() {
+               return component + ":" + id;
+       }
+
+       static String versionToBranchId(Version version) {
+               return version.getMajor() + "." + version.getMinor();
+       }
+}
diff --git a/org.argeo.osgi.boot/src/org/argeo/osgi/a2/A2Component.java b/org.argeo.osgi.boot/src/org/argeo/osgi/a2/A2Component.java
new file mode 100644 (file)
index 0000000..0b5d13c
--- /dev/null
@@ -0,0 +1,100 @@
+package org.argeo.osgi.a2;
+
+import java.util.Collections;
+import java.util.SortedMap;
+import java.util.TreeMap;
+
+import org.osgi.framework.Version;
+
+/**
+ * The logical name of a software package. In OSGi's case this is
+ * <code>Bundle-SymbolicName</code>. This is the equivalent of Maven's artifact
+ * id.
+ */
+public class A2Component implements Comparable<A2Component> {
+       private final A2Contribution contribution;
+       private final String id;
+
+       final SortedMap<String, A2Branch> branches = Collections.synchronizedSortedMap(new TreeMap<>());
+
+       public A2Component(A2Contribution contribution, String id) {
+               this.contribution = contribution;
+               this.id = id;
+               contribution.components.put(id, this);
+       }
+
+       A2Branch getOrAddBranch(String branchId) {
+               if (branches.containsKey(branchId))
+                       return branches.get(branchId);
+               else
+                       return new A2Branch(this, branchId);
+       }
+
+       A2Module getOrAddModule(Version version, Object locator) {
+               A2Branch branch = getOrAddBranch(A2Branch.versionToBranchId(version));
+               A2Module module = branch.getOrAddModule(version, locator);
+               return module;
+       }
+
+       A2Branch last() {
+               return branches.get(branches.lastKey());
+       }
+
+       A2Contribution getContribution() {
+               return contribution;
+       }
+
+       String getId() {
+               return id;
+       }
+
+       @Override
+       public int compareTo(A2Component o) {
+               return id.compareTo(o.id);
+       }
+
+       @Override
+       public int hashCode() {
+               return id.hashCode();
+       }
+
+       @Override
+       public boolean equals(Object obj) {
+               if (obj instanceof A2Component) {
+                       A2Component o = (A2Component) obj;
+                       return contribution.equals(o.contribution) && id.equals(o.id);
+               } else
+                       return false;
+       }
+
+       @Override
+       public String toString() {
+               return contribution.getId() + ":" + id;
+       }
+
+       void asTree(String prefix, StringBuffer buf) {
+               if (prefix == null)
+                       prefix = "";
+               A2Branch lastBranch = last();
+               SortedMap<String, A2Branch> displayMap = new TreeMap<>(Collections.reverseOrder());
+               displayMap.putAll(branches);
+               for (String branchId : displayMap.keySet()) {
+                       A2Branch branch = displayMap.get(branchId);
+                       if (!lastBranch.equals(branch)) {
+                               buf.append('\n');
+                               buf.append(prefix);
+                       } else {
+                               buf.append(" -");
+                       }
+                       buf.append(prefix);
+                       buf.append(branchId);
+                       A2Module first = branch.first();
+                       A2Module last = branch.last();
+                       buf.append(" (").append(last.getVersion());
+                       if (!first.equals(last))
+                               buf.append(" ... ").append(first.getVersion());
+                       buf.append(')');
+               }
+       }
+
+}
diff --git a/org.argeo.osgi.boot/src/org/argeo/osgi/a2/A2Contribution.java b/org.argeo.osgi.boot/src/org/argeo/osgi/a2/A2Contribution.java
new file mode 100644 (file)
index 0000000..35d5f9b
--- /dev/null
@@ -0,0 +1,84 @@
+package org.argeo.osgi.a2;
+
+import java.util.Collections;
+import java.util.Map;
+import java.util.TreeMap;
+
+/**
+ * A category grouping a set of {@link A2Component}, typically based on the
+ * provider of these components. This is the equivalent of Maven's group Id.
+ */
+public class A2Contribution implements Comparable<A2Contribution> {
+       final static String BOOT = "boot";
+       final static String RUNTIME = "runtime";
+       final static String CLASSPATH = "classpath";
+
+       private final ProvisioningSource source;
+       private final String id;
+
+       final Map<String, A2Component> components = Collections.synchronizedSortedMap(new TreeMap<>());
+
+       /**
+        * The contribution must be added to the source. Rather use
+        * {@link AbstractProvisioningSource#getOrAddContribution(String)} than this
+        * contructor directly.
+        */
+       public A2Contribution(ProvisioningSource context, String id) {
+               this.source = context;
+               this.id = id;
+//             if (context != null)
+//                     context.contributions.put(id, this);
+       }
+
+       A2Component getOrAddComponent(String componentId) {
+               if (components.containsKey(componentId))
+                       return components.get(componentId);
+               else
+                       return new A2Component(this, componentId);
+       }
+
+       public ProvisioningSource getSource() {
+               return source;
+       }
+
+       public String getId() {
+               return id;
+       }
+
+       @Override
+       public int compareTo(A2Contribution o) {
+               return id.compareTo(o.id);
+       }
+
+       @Override
+       public int hashCode() {
+               return id.hashCode();
+       }
+
+       @Override
+       public boolean equals(Object obj) {
+               if (obj instanceof A2Contribution) {
+                       A2Contribution o = (A2Contribution) obj;
+                       return id.equals(o.id);
+               } else
+                       return false;
+       }
+
+       @Override
+       public String toString() {
+               return id;
+       }
+
+       void asTree(String prefix, StringBuffer buf) {
+               if (prefix == null)
+                       prefix = "";
+               for (String componentId : components.keySet()) {
+                       buf.append(prefix);
+                       buf.append(componentId);
+                       A2Component component = components.get(componentId);
+                       component.asTree(prefix, buf);
+                       buf.append('\n');
+               }
+       }
+
+}
diff --git a/org.argeo.osgi.boot/src/org/argeo/osgi/a2/A2Exception.java b/org.argeo.osgi.boot/src/org/argeo/osgi/a2/A2Exception.java
new file mode 100644 (file)
index 0000000..83c743a
--- /dev/null
@@ -0,0 +1,15 @@
+package org.argeo.osgi.a2;
+
+/** Unchecked A2 provisioning exception. */
+public class A2Exception extends RuntimeException {
+       private static final long serialVersionUID = 1927603558545397360L;
+
+       public A2Exception(String message, Throwable e) {
+               super(message, e);
+       }
+
+       public A2Exception(String message) {
+               super(message);
+       }
+
+}
diff --git a/org.argeo.osgi.boot/src/org/argeo/osgi/a2/A2Module.java b/org.argeo.osgi.boot/src/org/argeo/osgi/a2/A2Module.java
new file mode 100644 (file)
index 0000000..77f81d1
--- /dev/null
@@ -0,0 +1,62 @@
+package org.argeo.osgi.a2;
+
+import org.osgi.framework.Version;
+
+/**
+ * An identified software package. In OSGi's case this is the combination of
+ * <code>Bundle-SymbolicName</code> and <code>Bundle-version</code>. This is the
+ * equivalent of the full coordinates of a Maven artifact version.
+ */
+class A2Module implements Comparable<A2Module> {
+       private final A2Branch branch;
+       private final Version version;
+       private final Object locator;
+
+       public A2Module(A2Branch branch, Version version, Object locator) {
+               this.branch = branch;
+               this.version = version;
+               this.locator = locator;
+               branch.modules.put(version, this);
+       }
+
+       A2Branch getBranch() {
+               return branch;
+       }
+
+       Version getVersion() {
+               return version;
+       }
+
+       Object getLocator() {
+               return locator;
+       }
+
+       @Override
+       public int compareTo(A2Module o) {
+               return version.compareTo(o.version);
+       }
+
+       @Override
+       public int hashCode() {
+               return version.hashCode();
+       }
+
+       @Override
+       public boolean equals(Object obj) {
+               if (obj instanceof A2Module) {
+                       A2Module o = (A2Module) obj;
+                       return branch.equals(o.branch) && version.equals(o.version);
+               } else
+                       return false;
+       }
+
+       @Override
+       public String toString() {
+               return getCoordinates();
+       }
+
+       public String getCoordinates() {
+               return branch.getComponent() + ":" + version;
+       }
+
+}
diff --git a/org.argeo.osgi.boot/src/org/argeo/osgi/a2/A2Source.java b/org.argeo.osgi.boot/src/org/argeo/osgi/a2/A2Source.java
new file mode 100644 (file)
index 0000000..2c88a38
--- /dev/null
@@ -0,0 +1,7 @@
+package org.argeo.osgi.a2;
+
+/** A provisioning source in A2 format. */
+public interface A2Source extends ProvisioningSource {
+       final static String SCHEME_A2 = "a2";
+       final static String DEFAULT_A2_URI = SCHEME_A2 + ":///";
+}
diff --git a/org.argeo.osgi.boot/src/org/argeo/osgi/a2/AbstractProvisioningSource.java b/org.argeo.osgi.boot/src/org/argeo/osgi/a2/AbstractProvisioningSource.java
new file mode 100644 (file)
index 0000000..32c175d
--- /dev/null
@@ -0,0 +1,212 @@
+package org.argeo.osgi.a2;
+
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.URL;
+import java.nio.file.FileVisitResult;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.SimpleFileVisitor;
+import java.nio.file.attribute.BasicFileAttributes;
+import java.util.Collections;
+import java.util.Map;
+import java.util.SortedMap;
+import java.util.TreeMap;
+import java.util.jar.JarInputStream;
+import java.util.jar.JarOutputStream;
+import java.util.jar.Manifest;
+import java.util.zip.ZipEntry;
+
+import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.BundleException;
+import org.osgi.framework.Constants;
+import org.osgi.framework.Version;
+
+/** Where components are retrieved from. */
+public abstract class AbstractProvisioningSource implements ProvisioningSource {
+       protected final Map<String, A2Contribution> contributions = Collections.synchronizedSortedMap(new TreeMap<>());
+
+       public Iterable<A2Contribution> listContributions(Object filter) {
+               return contributions.values();
+       }
+
+       @Override
+       public Bundle install(BundleContext bc, A2Module module) {
+               try {
+                       Path tempJar = null;
+                       if (module.getLocator() instanceof Path && Files.isDirectory((Path) module.getLocator()))
+                               tempJar = toTempJar((Path) module.getLocator());
+                       Bundle bundle;
+                       try (InputStream in = newInputStream(tempJar != null ? tempJar : module.getLocator())) {
+                               bundle = bc.installBundle(module.getBranch().getCoordinates(), in);
+                       }
+                       if (tempJar != null)
+                               Files.deleteIfExists(tempJar);
+                       return bundle;
+               } catch (BundleException | IOException e) {
+                       throw new A2Exception("Cannot install module " + module, e);
+               }
+       }
+
+       @Override
+       public void update(Bundle bundle, A2Module module) {
+               try {
+                       Path tempJar = null;
+                       if (module.getLocator() instanceof Path && Files.isDirectory((Path) module.getLocator()))
+                               tempJar = toTempJar((Path) module.getLocator());
+                       try (InputStream in = newInputStream(tempJar != null ? tempJar : module.getLocator())) {
+                               bundle.update(in);
+                       }
+                       if (tempJar != null)
+                               Files.deleteIfExists(tempJar);
+               } catch (BundleException | IOException e) {
+                       throw new A2Exception("Cannot update module " + module, e);
+               }
+       }
+
+       @Override
+       public A2Branch findBranch(String componentId, Version version) {
+               A2Component component = findComponent(componentId);
+               if (component == null)
+                       return null;
+               String branchId = version.getMajor() + "." + version.getMinor();
+               if (!component.branches.containsKey(branchId))
+                       return null;
+               return component.branches.get(branchId);
+       }
+
+       protected A2Contribution getOrAddContribution(String contributionId) {
+               if (contributions.containsKey(contributionId))
+                       return contributions.get(contributionId);
+               else {
+                       A2Contribution contribution = new A2Contribution(this, contributionId);
+                       contributions.put(contributionId, contribution);
+                       return contribution;
+               }
+       }
+
+       protected void asTree(String prefix, StringBuffer buf) {
+               if (prefix == null)
+                       prefix = "";
+               for (String contributionId : contributions.keySet()) {
+                       buf.append(prefix);
+                       buf.append(contributionId);
+                       buf.append('\n');
+                       A2Contribution contribution = contributions.get(contributionId);
+                       contribution.asTree(prefix + " ", buf);
+               }
+       }
+
+       protected void asTree() {
+               StringBuffer buf = new StringBuffer();
+               asTree("", buf);
+               System.out.println(buf);
+       }
+
+       protected A2Component findComponent(String componentId) {
+               SortedMap<A2Contribution, A2Component> res = new TreeMap<>();
+               for (A2Contribution contribution : contributions.values()) {
+                       components: for (String componentIdKey : contribution.components.keySet()) {
+                               if (componentId.equals(componentIdKey)) {
+                                       res.put(contribution, contribution.components.get(componentIdKey));
+                                       break components;
+                               }
+                       }
+               }
+               if (res.size() == 0)
+                       return null;
+               // TODO explicit contribution priorities
+               return res.get(res.lastKey());
+
+       }
+
+       protected String readVersionFromModule(Path modulePath) {
+               Manifest manifest;
+               if (Files.isDirectory(modulePath)) {
+                       manifest = findManifest(modulePath);
+               } else {
+                       try (JarInputStream in = new JarInputStream(newInputStream(modulePath))) {
+                               manifest = in.getManifest();
+                       } catch (IOException e) {
+                               throw new A2Exception("Cannot read manifest from " + modulePath, e);
+                       }
+               }
+               String versionStr = manifest.getMainAttributes().getValue(Constants.BUNDLE_VERSION);
+               return versionStr;
+       }
+
+       protected String readSymbolicNameFromModule(Path modulePath) {
+               Manifest manifest;
+               if (Files.isDirectory(modulePath)) {
+                       manifest = findManifest(modulePath);
+               } else {
+                       try (JarInputStream in = new JarInputStream(newInputStream(modulePath))) {
+                               manifest = in.getManifest();
+                       } catch (IOException e) {
+                               throw new A2Exception("Cannot read manifest from " + modulePath, e);
+                       }
+               }
+               String symbolicName = manifest.getMainAttributes().getValue(Constants.BUNDLE_SYMBOLICNAME);
+               int semiColIndex = symbolicName.indexOf(';');
+               if (semiColIndex >= 0)
+                       symbolicName = symbolicName.substring(0, semiColIndex);
+               return symbolicName;
+       }
+
+       private static Manifest findManifest(Path currentPath) {
+               Path metaInfPath = currentPath.resolve("META-INF");
+               if (Files.exists(metaInfPath) && Files.isDirectory(metaInfPath)) {
+                       Path manifestPath = metaInfPath.resolve("MANIFEST.MF");
+                       try {
+                               try (InputStream in = Files.newInputStream(manifestPath)) {
+                                       Manifest manifest = new Manifest(in);
+                                       return manifest;
+                               }
+                       } catch (IOException e) {
+                               throw new A2Exception("Cannot read manifest from " + manifestPath, e);
+                       }
+               } else {
+                       Path parentPath = currentPath.getParent();
+                       if (parentPath == null)
+                               throw new A2Exception("MANIFEST.MF file not found.");
+                       return findManifest(currentPath.getParent());
+               }
+       }
+
+       private static Path toTempJar(Path dir) {
+               try {
+                       Manifest manifest = findManifest(dir);
+                       Path jarPath = Files.createTempFile("a2Source", ".jar");
+                       try (JarOutputStream zos = new JarOutputStream(new FileOutputStream(jarPath.toFile()), manifest)) {
+                               Files.walkFileTree(dir, new SimpleFileVisitor<Path>() {
+                                       public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
+                                               Path relPath = dir.relativize(file);
+                                               // skip MANIFEST from folder
+                                               if (relPath.toString().contentEquals("META-INF/MANIFEST.MF"))
+                                                       return FileVisitResult.CONTINUE;
+                                               zos.putNextEntry(new ZipEntry(relPath.toString()));
+                                               Files.copy(file, zos);
+                                               zos.closeEntry();
+                                               return FileVisitResult.CONTINUE;
+                                       }
+                               });
+                       }
+                       return jarPath;
+               } catch (IOException e) {
+                       throw new A2Exception("Cannot install OSGi bundle from " + dir, e);
+               }
+
+       }
+
+       private InputStream newInputStream(Object locator) throws IOException {
+               if (locator instanceof Path) {
+                       return Files.newInputStream((Path) locator);
+               } else if (locator instanceof URL) {
+                       return ((URL) locator).openStream();
+               } else {
+                       throw new IllegalArgumentException("Unsupported module locator type " + locator.getClass());
+               }
+       }
+}
diff --git a/org.argeo.osgi.boot/src/org/argeo/osgi/a2/ClasspathSource.java b/org.argeo.osgi.boot/src/org/argeo/osgi/a2/ClasspathSource.java
new file mode 100644 (file)
index 0000000..ea34666
--- /dev/null
@@ -0,0 +1,38 @@
+package org.argeo.osgi.a2;
+
+import java.io.File;
+import java.io.IOException;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.Arrays;
+import java.util.List;
+
+import org.argeo.osgi.boot.OsgiBootUtils;
+import org.osgi.framework.Version;
+
+/**
+ * A provisioning source based on the linear classpath with which the JCM has
+ * been started.
+ */
+public class ClasspathSource extends AbstractProvisioningSource {
+       void load() throws IOException {
+               A2Contribution classpathContribution = getOrAddContribution( A2Contribution.CLASSPATH);
+               List<String> classpath = Arrays.asList(System.getProperty("java.class.path").split(File.pathSeparator));
+               parts: for (String part : classpath) {
+                       Path file = Paths.get(part);
+                       Version version;
+                       try {
+                               version = new Version(readVersionFromModule(file));
+                       } catch (Exception e) {
+                               // ignore non OSGi
+                               continue parts;
+                       }
+                       String moduleName = readSymbolicNameFromModule(file);
+                       A2Component component = classpathContribution.getOrAddComponent(moduleName);
+                       A2Module module = component.getOrAddModule(version, file);
+                       if (OsgiBootUtils.isDebug())
+                               OsgiBootUtils.debug("Registered " + module);
+               }
+
+       }
+}
diff --git a/org.argeo.osgi.boot/src/org/argeo/osgi/a2/FsA2Source.java b/org.argeo.osgi.boot/src/org/argeo/osgi/a2/FsA2Source.java
new file mode 100644 (file)
index 0000000..eea59de
--- /dev/null
@@ -0,0 +1,88 @@
+package org.argeo.osgi.a2;
+
+import java.io.IOException;
+import java.nio.file.DirectoryStream;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.SortedSet;
+import java.util.TreeSet;
+
+import org.argeo.osgi.boot.OsgiBootUtils;
+import org.osgi.framework.Version;
+
+/** A file system {@link AbstractProvisioningSource} in A2 format. */
+public class FsA2Source extends AbstractProvisioningSource implements A2Source {
+       private final Path base;
+
+       public FsA2Source(Path base) {
+               super();
+               this.base = base;
+       }
+
+       void load() throws IOException {
+               DirectoryStream<Path> contributionPaths = Files.newDirectoryStream(base);
+               SortedSet<A2Contribution> contributions = new TreeSet<>();
+               contributions: for (Path contributionPath : contributionPaths) {
+                       if (Files.isDirectory(contributionPath)) {
+                               String contributionId = contributionPath.getFileName().toString();
+                               if (A2Contribution.BOOT.equals(contributionId))// skip boot
+                                       continue contributions;
+                               A2Contribution contribution = getOrAddContribution(contributionId);
+                               contributions.add(contribution);
+                       }
+               }
+
+               for (A2Contribution contribution : contributions) {
+                       DirectoryStream<Path> modulePaths = Files.newDirectoryStream(base.resolve(contribution.getId()));
+                       modules: for (Path modulePath : modulePaths) {
+                               if (!Files.isDirectory(modulePath)) {
+                                       // OsgiBootUtils.debug("Registering " + modulePath);
+                                       String moduleFileName = modulePath.getFileName().toString();
+                                       int lastDot = moduleFileName.lastIndexOf('.');
+                                       String ext = moduleFileName.substring(lastDot + 1);
+                                       if (!"jar".equals(ext))
+                                               continue modules;
+                                       String moduleName = moduleFileName.substring(0, lastDot);
+                                       if (moduleName.endsWith("-SNAPSHOT"))
+                                               moduleName = moduleName.substring(0, moduleName.length() - "-SNAPSHOT".length());
+                                       int lastDash = moduleName.lastIndexOf('-');
+                                       String versionStr = moduleName.substring(lastDash + 1);
+                                       String componentName = moduleName.substring(0, lastDash);
+                                       // if(versionStr.endsWith("-SNAPSHOT")) {
+                                       // versionStr = readVersionFromModule(modulePath);
+                                       // }
+                                       Version version;
+                                       try {
+                                               version = new Version(versionStr);
+                                       } catch (Exception e) {
+                                               versionStr = readVersionFromModule(modulePath);
+                                               if (versionStr != null) {
+                                                       version = new Version(versionStr);
+                                               } else {
+                                                       OsgiBootUtils.debug("Ignore " + modulePath + " (" + e.getMessage() + ")");
+                                                       continue modules;
+                                               }
+                                       }
+                                       A2Component component = contribution.getOrAddComponent(componentName);
+                                       A2Module module = component.getOrAddModule(version, modulePath);
+                                       if (OsgiBootUtils.isDebug())
+                                               OsgiBootUtils.debug("Registered " + module);
+                               }
+                       }
+               }
+
+       }
+
+       public static void main(String[] args) {
+               try {
+                       FsA2Source context = new FsA2Source(Paths.get(
+                                       "/home/mbaudier/dev/git/apache2/argeo-commons/dist/argeo-node/target/argeo-node-2.1.77-SNAPSHOT/share/osgi"));
+                       context.load();
+                       context.asTree();
+               } catch (Exception e) {
+                       e.printStackTrace();
+               }
+       }
+
+}
diff --git a/org.argeo.osgi.boot/src/org/argeo/osgi/a2/FsM2Source.java b/org.argeo.osgi.boot/src/org/argeo/osgi/a2/FsM2Source.java
new file mode 100644 (file)
index 0000000..a4c3ed5
--- /dev/null
@@ -0,0 +1,66 @@
+package org.argeo.osgi.a2;
+
+import java.io.File;
+import java.io.IOException;
+import java.nio.file.FileVisitResult;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.nio.file.SimpleFileVisitor;
+import java.nio.file.attribute.BasicFileAttributes;
+
+import org.argeo.osgi.boot.OsgiBootUtils;
+import org.osgi.framework.Version;
+
+/** A file system {@link AbstractProvisioningSource} in Maven 2 format. */
+public class FsM2Source extends AbstractProvisioningSource {
+       private final Path base;
+
+       public FsM2Source(Path base) {
+               super();
+               this.base = base;
+       }
+
+       void load() throws IOException {
+               Files.walkFileTree(base, new ArtifactFileVisitor());
+       }
+
+       class ArtifactFileVisitor extends SimpleFileVisitor<Path> {
+
+               @Override
+               public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
+                       // OsgiBootUtils.debug("Processing " + file);
+                       if (file.toString().endsWith(".jar")) {
+                               Version version;
+                               try {
+                                       version = new Version(readVersionFromModule(file));
+                               } catch (Exception e) {
+                                       // ignore non OSGi
+                                       return FileVisitResult.CONTINUE;
+                               }
+                               String moduleName = readSymbolicNameFromModule(file);
+                               Path groupPath = file.getParent().getParent().getParent();
+                               Path relGroupPath = base.relativize(groupPath);
+                               String contributionName = relGroupPath.toString().replace(File.separatorChar, '.');
+                               A2Contribution contribution = getOrAddContribution(contributionName);
+                               A2Component component = contribution.getOrAddComponent(moduleName);
+                               A2Module module = component.getOrAddModule(version, file);
+                               if (OsgiBootUtils.isDebug())
+                                       OsgiBootUtils.debug("Registered " + module);
+                       }
+                       return super.visitFile(file, attrs);
+               }
+
+       }
+
+       public static void main(String[] args) {
+               try {
+                       FsM2Source context = new FsM2Source(Paths.get("/home/mbaudier/.m2/repository"));
+                       context.load();
+                       context.asTree();
+               } catch (Exception e) {
+                       e.printStackTrace();
+               }
+       }
+
+}
diff --git a/org.argeo.osgi.boot/src/org/argeo/osgi/a2/OsgiContext.java b/org.argeo.osgi.boot/src/org/argeo/osgi/a2/OsgiContext.java
new file mode 100644 (file)
index 0000000..8630dc2
--- /dev/null
@@ -0,0 +1,39 @@
+package org.argeo.osgi.a2;
+
+import org.argeo.osgi.boot.OsgiBootUtils;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.FrameworkUtil;
+import org.osgi.framework.Version;
+
+/** A running OSGi bundle context seen as a {@link AbstractProvisioningSource}. */
+class OsgiContext extends AbstractProvisioningSource {
+       private final BundleContext bc;
+
+       public OsgiContext(BundleContext bc) {
+               super();
+               this.bc = bc;
+       }
+
+       public OsgiContext() {
+               Bundle bundle = FrameworkUtil.getBundle(OsgiContext.class);
+               if (bundle == null)
+                       throw new IllegalArgumentException(
+                                       "OSGi Boot bundle must be started or a bundle context must be specified");
+               this.bc = bundle.getBundleContext();
+       }
+
+       void load() {
+               A2Contribution runtimeContribution = getOrAddContribution( A2Contribution.RUNTIME);
+               for (Bundle bundle : bc.getBundles()) {
+                       // OsgiBootUtils.debug(bundle.getDataFile("/"));
+                       String componentId = bundle.getSymbolicName();
+                       Version version = bundle.getVersion();
+                       A2Component component = runtimeContribution.getOrAddComponent(componentId);
+                       A2Module module = component.getOrAddModule(version, bundle);
+                       if (OsgiBootUtils.isDebug())
+                               OsgiBootUtils.debug("Registered " + module + " (location id: " + bundle.getLocation() + ")");
+               }
+
+       }
+}
diff --git a/org.argeo.osgi.boot/src/org/argeo/osgi/a2/ProvisioningManager.java b/org.argeo.osgi.boot/src/org/argeo/osgi/a2/ProvisioningManager.java
new file mode 100644 (file)
index 0000000..dd7fa3b
--- /dev/null
@@ -0,0 +1,197 @@
+package org.argeo.osgi.a2;
+
+import java.io.File;
+import java.net.URI;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import org.argeo.osgi.boot.OsgiBootUtils;
+import org.eclipse.osgi.launch.EquinoxFactory;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.Constants;
+import org.osgi.framework.Version;
+import org.osgi.framework.launch.Framework;
+import org.osgi.framework.wiring.FrameworkWiring;
+
+/** Loads provisioning sources into an OSGi context. */
+public class ProvisioningManager {
+       BundleContext bc;
+       OsgiContext osgiContext;
+       List<ProvisioningSource> sources = Collections.synchronizedList(new ArrayList<>());
+
+       public ProvisioningManager(BundleContext bc) {
+               this.bc = bc;
+               osgiContext = new OsgiContext(bc);
+               osgiContext.load();
+       }
+
+       protected void addSource(ProvisioningSource source) {
+               sources.add(source);
+       }
+
+       void installWholeSource(ProvisioningSource source) {
+               Set<Bundle> updatedBundles = new HashSet<>();
+               for (A2Contribution contribution : source.listContributions(null)) {
+                       for (A2Component component : contribution.components.values()) {
+                               A2Module module = component.last().last();
+                               Bundle bundle = installOrUpdate(module);
+                               if (bundle != null)
+                                       updatedBundles.add(bundle);
+                       }
+               }
+               FrameworkWiring frameworkWiring = bc.getBundle(0).adapt(FrameworkWiring.class);
+               frameworkWiring.refreshBundles(updatedBundles);
+       }
+
+       public void registerSource(String uri) {
+               try {
+                       URI u = new URI(uri);
+                       if (A2Source.SCHEME_A2.equals(u.getScheme())) {
+                               if (u.getHost() == null || "".equals(u.getHost())) {
+                                       String baseStr = u.getPath();
+                                       if (File.separatorChar == '\\') {// MS Windows
+                                               baseStr = baseStr.substring(1).replace('/', File.separatorChar);
+                                       }
+                                       Path base = Paths.get(baseStr);
+                                       FsA2Source source = new FsA2Source(base);
+                                       source.load();
+                                       addSource(source);
+                               }
+                       }
+               } catch (Exception e) {
+                       throw new A2Exception("Cannot add source " + uri, e);
+               }
+       }
+
+       public boolean registerDefaultSource() {
+               String frameworkLocation = bc.getProperty("osgi.framework");
+               try {
+                       URI frameworkLocationUri = new URI(frameworkLocation);
+                       if ("file".equals(frameworkLocationUri.getScheme())) {
+                               Path frameworkPath = Paths.get(frameworkLocationUri);
+                               if (frameworkPath.getParent().getFileName().toString().equals(A2Contribution.BOOT)) {
+                                       Path base = frameworkPath.getParent().getParent();
+                                       String baseStr = base.toString();
+                                       if (File.separatorChar == '\\')// MS Windows
+                                               baseStr = '/' + baseStr.replace(File.separatorChar, '/');
+                                       URI baseUri = new URI(A2Source.SCHEME_A2, null, null, 0, baseStr, null, null);
+                                       registerSource(baseUri.toString());
+                                       OsgiBootUtils.info("Registered " + baseUri + " as default source");
+                                       return true;
+                               }
+                       }
+               } catch (Exception e) {
+                       OsgiBootUtils.error("Cannot register default source based on framework location " + frameworkLocation, e);
+               }
+               return false;
+       }
+
+       public void install(String spec) {
+               if (spec == null) {
+                       for (ProvisioningSource source : sources) {
+                               installWholeSource(source);
+                       }
+               }
+       }
+
+       /** @return the new/updated bundle, or null if nothing was done. */
+       protected Bundle installOrUpdate(A2Module module) {
+               try {
+                       ProvisioningSource moduleSource = module.getBranch().getComponent().getContribution().getSource();
+                       Version moduleVersion = module.getVersion();
+                       A2Branch osgiBranch = osgiContext.findBranch(module.getBranch().getComponent().getId(), moduleVersion);
+                       if (osgiBranch == null) {
+//                             Bundle bundle = bc.installBundle(module.getBranch().getCoordinates(),
+//                                             moduleSource.newInputStream(module.getLocator()));
+                               Bundle bundle = moduleSource.install(bc, module);
+                               if (OsgiBootUtils.isDebug())
+                                       OsgiBootUtils.debug("Installed bundle " + bundle.getLocation() + " with version " + moduleVersion);
+                               return bundle;
+                       } else {
+                               A2Module lastOsgiModule = osgiBranch.last();
+                               int compare = moduleVersion.compareTo(lastOsgiModule.getVersion());
+                               if (compare > 0) {// update
+                                       Bundle bundle = (Bundle) lastOsgiModule.getLocator();
+//                                     bundle.update(moduleSource.newInputStream(module.getLocator()));
+                                       moduleSource.update(bundle, module);
+                                       OsgiBootUtils.info("Updated bundle " + bundle.getLocation() + " to version " + moduleVersion);
+                                       return bundle;
+                               }
+                       }
+               } catch (Exception e) {
+                       OsgiBootUtils.error("Could not install module " + module + ": " + e.getMessage(), e);
+               }
+               return null;
+       }
+
+       public Collection<Bundle> update() {
+               boolean fragmentsUpdated = false;
+               Set<Bundle> updatedBundles = new HashSet<>();
+               bundles: for (Bundle bundle : bc.getBundles()) {
+                       for (ProvisioningSource source : sources) {
+                               String componentId = bundle.getSymbolicName();
+                               Version version = bundle.getVersion();
+                               A2Branch branch = source.findBranch(componentId, version);
+                               if (branch == null)
+                                       continue bundles;
+                               A2Module module = branch.last();
+                               Version moduleVersion = module.getVersion();
+                               int compare = moduleVersion.compareTo(version);
+                               if (compare > 0) {// update
+                                       try {
+                                               source.update(bundle, module);
+//                                             bundle.update(in);
+                                               String fragmentHost = bundle.getHeaders().get(Constants.FRAGMENT_HOST);
+                                               if (fragmentHost != null)
+                                                       fragmentsUpdated = true;
+                                               OsgiBootUtils.info("Updated bundle " + bundle.getLocation() + " to version " + moduleVersion);
+                                               updatedBundles.add(bundle);
+                                       } catch (Exception e) {
+                                               OsgiBootUtils.error("Cannot update with module " + module, e);
+                                       }
+                               }
+                       }
+               }
+               FrameworkWiring frameworkWiring = bc.getBundle(0).adapt(FrameworkWiring.class);
+               if (fragmentsUpdated)// refresh all
+                       frameworkWiring.refreshBundles(null);
+               else
+                       frameworkWiring.refreshBundles(updatedBundles);
+               return updatedBundles;
+       }
+
+       public static void main(String[] args) {
+               Map<String, String> configuration = new HashMap<>();
+               configuration.put("osgi.console", "2323");
+               Framework framework = OsgiBootUtils.launch(new EquinoxFactory(), configuration);
+               try {
+                       ProvisioningManager pm = new ProvisioningManager(framework.getBundleContext());
+                       FsA2Source context = new FsA2Source(Paths.get(
+                                       "/home/mbaudier/dev/git/apache2/argeo-commons/dist/argeo-node/target/argeo-node-2.1.74-SNAPSHOT/argeo-node/share/osgi"));
+                       context.load();
+                       if (framework.getBundleContext().getBundles().length == 1) {// initial
+                               pm.install(null);
+                       } else {
+                               pm.update();
+                       }
+               } catch (Exception e) {
+                       e.printStackTrace();
+               } finally {
+                       try {
+                               // framework.stop();
+                       } catch (Exception e) {
+                               e.printStackTrace();
+                       }
+               }
+       }
+
+}
diff --git a/org.argeo.osgi.boot/src/org/argeo/osgi/a2/ProvisioningSource.java b/org.argeo.osgi.boot/src/org/argeo/osgi/a2/ProvisioningSource.java
new file mode 100644 (file)
index 0000000..7d6fadf
--- /dev/null
@@ -0,0 +1,21 @@
+package org.argeo.osgi.a2;
+
+import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.Version;
+
+/** Where components are retrieved from. */
+public interface ProvisioningSource {
+       /** List all contributions of this source. */
+       Iterable<A2Contribution> listContributions(Object filter);
+
+       /** Install a module in the OSGi runtime. */
+       Bundle install(BundleContext bc, A2Module module);
+
+       /** Update a module in the OSGi runtime. */
+       void update(Bundle bundle, A2Module module);
+
+       /** Finds the {@link A2Branch} related to this component and version. */
+       A2Branch findBranch(String componentId, Version version);
+
+}
index 6824ecaf549c9c2c3a335c011cdfb1d6940838a5..38da0479f6d5579742f9d00c655c35fd2c254416 100644 (file)
@@ -32,8 +32,8 @@ import java.util.SortedMap;
 import java.util.StringTokenizer;
 import java.util.TreeMap;
 
-import org.argeo.osgi.boot.a2.A2Source;
-import org.argeo.osgi.boot.a2.ProvisioningManager;
+import org.argeo.osgi.a2.A2Source;
+import org.argeo.osgi.a2.ProvisioningManager;
 import org.argeo.osgi.boot.internal.springutil.AntPathMatcher;
 import org.argeo.osgi.boot.internal.springutil.PathMatcher;
 import org.argeo.osgi.boot.internal.springutil.SystemPropertyUtils;
diff --git a/org.argeo.osgi.boot/src/org/argeo/osgi/boot/a2/A2Branch.java b/org.argeo.osgi.boot/src/org/argeo/osgi/boot/a2/A2Branch.java
deleted file mode 100644 (file)
index 9e3f81d..0000000
+++ /dev/null
@@ -1,85 +0,0 @@
-package org.argeo.osgi.boot.a2;
-
-import java.util.Collections;
-import java.util.SortedMap;
-import java.util.TreeMap;
-
-import org.argeo.osgi.boot.OsgiBootUtils;
-import org.osgi.framework.Version;
-
-/**
- * A logical linear sequence of versions of a given {@link A2Component}. This is
- * typically a combination of major and minor version, indicating backward
- * compatibility.
- */
-public class A2Branch implements Comparable<A2Branch> {
-       private final A2Component component;
-       private final String id;
-
-       final SortedMap<Version, A2Module> modules = Collections.synchronizedSortedMap(new TreeMap<>());
-
-       public A2Branch(A2Component component, String id) {
-               this.component = component;
-               this.id = id;
-               component.branches.put(id, this);
-       }
-
-       A2Module getOrAddModule(Version version, Object locator) {
-               if (modules.containsKey(version)) {
-                       A2Module res = modules.get(version);
-                       if (OsgiBootUtils.isDebug() && !res.getLocator().equals(locator)) {
-                               OsgiBootUtils.debug("Inconsistent locator " + locator + " (registered: " + res.getLocator() + ")");
-                       }
-                       return res;
-               } else
-                       return new A2Module(this, version, locator);
-       }
-
-       A2Module last() {
-               return modules.get(modules.lastKey());
-       }
-
-       A2Module first() {
-               return modules.get(modules.firstKey());
-       }
-
-       A2Component getComponent() {
-               return component;
-       }
-
-       String getId() {
-               return id;
-       }
-
-       @Override
-       public int compareTo(A2Branch o) {
-               return id.compareTo(id);
-       }
-
-       @Override
-       public int hashCode() {
-               return id.hashCode();
-       }
-
-       @Override
-       public boolean equals(Object obj) {
-               if (obj instanceof A2Branch) {
-                       A2Branch o = (A2Branch) obj;
-                       return component.equals(o.component) && id.equals(o.id);
-               } else
-                       return false;
-       }
-
-       @Override
-       public String toString() {
-               return getCoordinates();
-       }
-
-       public String getCoordinates() {
-               return component + ":" + id;
-       }
-
-       static String versionToBranchId(Version version) {
-               return version.getMajor() + "." + version.getMinor();
-       }
-}
diff --git a/org.argeo.osgi.boot/src/org/argeo/osgi/boot/a2/A2Component.java b/org.argeo.osgi.boot/src/org/argeo/osgi/boot/a2/A2Component.java
deleted file mode 100644 (file)
index a2d5fac..0000000
+++ /dev/null
@@ -1,100 +0,0 @@
-package org.argeo.osgi.boot.a2;
-
-import java.util.Collections;
-import java.util.SortedMap;
-import java.util.TreeMap;
-
-import org.osgi.framework.Version;
-
-/**
- * The logical name of a software package. In OSGi's case this is
- * <code>Bundle-SymbolicName</code>. This is the equivalent of Maven's artifact
- * id.
- */
-public class A2Component implements Comparable<A2Component> {
-       private final A2Contribution contribution;
-       private final String id;
-
-       final SortedMap<String, A2Branch> branches = Collections.synchronizedSortedMap(new TreeMap<>());
-
-       public A2Component(A2Contribution contribution, String id) {
-               this.contribution = contribution;
-               this.id = id;
-               contribution.components.put(id, this);
-       }
-
-       A2Branch getOrAddBranch(String branchId) {
-               if (branches.containsKey(branchId))
-                       return branches.get(branchId);
-               else
-                       return new A2Branch(this, branchId);
-       }
-
-       A2Module getOrAddModule(Version version, Object locator) {
-               A2Branch branch = getOrAddBranch(A2Branch.versionToBranchId(version));
-               A2Module module = branch.getOrAddModule(version, locator);
-               return module;
-       }
-
-       A2Branch last() {
-               return branches.get(branches.lastKey());
-       }
-
-       A2Contribution getContribution() {
-               return contribution;
-       }
-
-       String getId() {
-               return id;
-       }
-
-       @Override
-       public int compareTo(A2Component o) {
-               return id.compareTo(o.id);
-       }
-
-       @Override
-       public int hashCode() {
-               return id.hashCode();
-       }
-
-       @Override
-       public boolean equals(Object obj) {
-               if (obj instanceof A2Component) {
-                       A2Component o = (A2Component) obj;
-                       return contribution.equals(o.contribution) && id.equals(o.id);
-               } else
-                       return false;
-       }
-
-       @Override
-       public String toString() {
-               return contribution.getId() + ":" + id;
-       }
-
-       void asTree(String prefix, StringBuffer buf) {
-               if (prefix == null)
-                       prefix = "";
-               A2Branch lastBranch = last();
-               SortedMap<String, A2Branch> displayMap = new TreeMap<>(Collections.reverseOrder());
-               displayMap.putAll(branches);
-               for (String branchId : displayMap.keySet()) {
-                       A2Branch branch = displayMap.get(branchId);
-                       if (!lastBranch.equals(branch)) {
-                               buf.append('\n');
-                               buf.append(prefix);
-                       } else {
-                               buf.append(" -");
-                       }
-                       buf.append(prefix);
-                       buf.append(branchId);
-                       A2Module first = branch.first();
-                       A2Module last = branch.last();
-                       buf.append(" (").append(last.getVersion());
-                       if (!first.equals(last))
-                               buf.append(" ... ").append(first.getVersion());
-                       buf.append(')');
-               }
-       }
-
-}
diff --git a/org.argeo.osgi.boot/src/org/argeo/osgi/boot/a2/A2Contribution.java b/org.argeo.osgi.boot/src/org/argeo/osgi/boot/a2/A2Contribution.java
deleted file mode 100644 (file)
index e81ecad..0000000
+++ /dev/null
@@ -1,84 +0,0 @@
-package org.argeo.osgi.boot.a2;
-
-import java.util.Collections;
-import java.util.Map;
-import java.util.TreeMap;
-
-/**
- * A category grouping a set of {@link A2Component}, typically based on the
- * provider of these components. This is the equivalent of Maven's group Id.
- */
-public class A2Contribution implements Comparable<A2Contribution> {
-       final static String BOOT = "boot";
-       final static String RUNTIME = "runtime";
-       final static String CLASSPATH = "classpath";
-
-       private final ProvisioningSource source;
-       private final String id;
-
-       final Map<String, A2Component> components = Collections.synchronizedSortedMap(new TreeMap<>());
-
-       /**
-        * The contribution must be added to the source. Rather use
-        * {@link AbstractProvisioningSource#getOrAddContribution(String)} than this
-        * contructor directly.
-        */
-       public A2Contribution(ProvisioningSource context, String id) {
-               this.source = context;
-               this.id = id;
-//             if (context != null)
-//                     context.contributions.put(id, this);
-       }
-
-       A2Component getOrAddComponent(String componentId) {
-               if (components.containsKey(componentId))
-                       return components.get(componentId);
-               else
-                       return new A2Component(this, componentId);
-       }
-
-       public ProvisioningSource getSource() {
-               return source;
-       }
-
-       public String getId() {
-               return id;
-       }
-
-       @Override
-       public int compareTo(A2Contribution o) {
-               return id.compareTo(o.id);
-       }
-
-       @Override
-       public int hashCode() {
-               return id.hashCode();
-       }
-
-       @Override
-       public boolean equals(Object obj) {
-               if (obj instanceof A2Contribution) {
-                       A2Contribution o = (A2Contribution) obj;
-                       return id.equals(o.id);
-               } else
-                       return false;
-       }
-
-       @Override
-       public String toString() {
-               return id;
-       }
-
-       void asTree(String prefix, StringBuffer buf) {
-               if (prefix == null)
-                       prefix = "";
-               for (String componentId : components.keySet()) {
-                       buf.append(prefix);
-                       buf.append(componentId);
-                       A2Component component = components.get(componentId);
-                       component.asTree(prefix, buf);
-                       buf.append('\n');
-               }
-       }
-
-}
diff --git a/org.argeo.osgi.boot/src/org/argeo/osgi/boot/a2/A2Exception.java b/org.argeo.osgi.boot/src/org/argeo/osgi/boot/a2/A2Exception.java
deleted file mode 100644 (file)
index 129d38f..0000000
+++ /dev/null
@@ -1,15 +0,0 @@
-package org.argeo.osgi.boot.a2;
-
-/** Unchecked A2 provisioning exception. */
-public class A2Exception extends RuntimeException {
-       private static final long serialVersionUID = 1927603558545397360L;
-
-       public A2Exception(String message, Throwable e) {
-               super(message, e);
-       }
-
-       public A2Exception(String message) {
-               super(message);
-       }
-
-}
diff --git a/org.argeo.osgi.boot/src/org/argeo/osgi/boot/a2/A2Module.java b/org.argeo.osgi.boot/src/org/argeo/osgi/boot/a2/A2Module.java
deleted file mode 100644 (file)
index 44f94e3..0000000
+++ /dev/null
@@ -1,62 +0,0 @@
-package org.argeo.osgi.boot.a2;
-
-import org.osgi.framework.Version;
-
-/**
- * An identified software package. In OSGi's case this is the combination of
- * <code>Bundle-SymbolicName</code> and <code>Bundle-version</code>. This is the
- * equivalent of the full coordinates of a Maven artifact version.
- */
-class A2Module implements Comparable<A2Module> {
-       private final A2Branch branch;
-       private final Version version;
-       private final Object locator;
-
-       public A2Module(A2Branch branch, Version version, Object locator) {
-               this.branch = branch;
-               this.version = version;
-               this.locator = locator;
-               branch.modules.put(version, this);
-       }
-
-       A2Branch getBranch() {
-               return branch;
-       }
-
-       Version getVersion() {
-               return version;
-       }
-
-       Object getLocator() {
-               return locator;
-       }
-
-       @Override
-       public int compareTo(A2Module o) {
-               return version.compareTo(o.version);
-       }
-
-       @Override
-       public int hashCode() {
-               return version.hashCode();
-       }
-
-       @Override
-       public boolean equals(Object obj) {
-               if (obj instanceof A2Module) {
-                       A2Module o = (A2Module) obj;
-                       return branch.equals(o.branch) && version.equals(o.version);
-               } else
-                       return false;
-       }
-
-       @Override
-       public String toString() {
-               return getCoordinates();
-       }
-
-       public String getCoordinates() {
-               return branch.getComponent() + ":" + version;
-       }
-
-}
diff --git a/org.argeo.osgi.boot/src/org/argeo/osgi/boot/a2/A2Source.java b/org.argeo.osgi.boot/src/org/argeo/osgi/boot/a2/A2Source.java
deleted file mode 100644 (file)
index eb23845..0000000
+++ /dev/null
@@ -1,7 +0,0 @@
-package org.argeo.osgi.boot.a2;
-
-/** A provisioning source in A2 format. */
-public interface A2Source extends ProvisioningSource {
-       final static String SCHEME_A2 = "a2";
-       final static String DEFAULT_A2_URI = SCHEME_A2 + ":///";
-}
diff --git a/org.argeo.osgi.boot/src/org/argeo/osgi/boot/a2/AbstractProvisioningSource.java b/org.argeo.osgi.boot/src/org/argeo/osgi/boot/a2/AbstractProvisioningSource.java
deleted file mode 100644 (file)
index c8497d0..0000000
+++ /dev/null
@@ -1,212 +0,0 @@
-package org.argeo.osgi.boot.a2;
-
-import java.io.FileOutputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.net.URL;
-import java.nio.file.FileVisitResult;
-import java.nio.file.Files;
-import java.nio.file.Path;
-import java.nio.file.SimpleFileVisitor;
-import java.nio.file.attribute.BasicFileAttributes;
-import java.util.Collections;
-import java.util.Map;
-import java.util.SortedMap;
-import java.util.TreeMap;
-import java.util.jar.JarInputStream;
-import java.util.jar.JarOutputStream;
-import java.util.jar.Manifest;
-import java.util.zip.ZipEntry;
-
-import org.osgi.framework.Bundle;
-import org.osgi.framework.BundleContext;
-import org.osgi.framework.BundleException;
-import org.osgi.framework.Constants;
-import org.osgi.framework.Version;
-
-/** Where components are retrieved from. */
-public abstract class AbstractProvisioningSource implements ProvisioningSource {
-       protected final Map<String, A2Contribution> contributions = Collections.synchronizedSortedMap(new TreeMap<>());
-
-       public Iterable<A2Contribution> listContributions(Object filter) {
-               return contributions.values();
-       }
-
-       @Override
-       public Bundle install(BundleContext bc, A2Module module) {
-               try {
-                       Path tempJar = null;
-                       if (module.getLocator() instanceof Path && Files.isDirectory((Path) module.getLocator()))
-                               tempJar = toTempJar((Path) module.getLocator());
-                       Bundle bundle;
-                       try (InputStream in = newInputStream(tempJar != null ? tempJar : module.getLocator())) {
-                               bundle = bc.installBundle(module.getBranch().getCoordinates(), in);
-                       }
-                       if (tempJar != null)
-                               Files.deleteIfExists(tempJar);
-                       return bundle;
-               } catch (BundleException | IOException e) {
-                       throw new A2Exception("Cannot install module " + module, e);
-               }
-       }
-
-       @Override
-       public void update(Bundle bundle, A2Module module) {
-               try {
-                       Path tempJar = null;
-                       if (module.getLocator() instanceof Path && Files.isDirectory((Path) module.getLocator()))
-                               tempJar = toTempJar((Path) module.getLocator());
-                       try (InputStream in = newInputStream(tempJar != null ? tempJar : module.getLocator())) {
-                               bundle.update(in);
-                       }
-                       if (tempJar != null)
-                               Files.deleteIfExists(tempJar);
-               } catch (BundleException | IOException e) {
-                       throw new A2Exception("Cannot update module " + module, e);
-               }
-       }
-
-       @Override
-       public A2Branch findBranch(String componentId, Version version) {
-               A2Component component = findComponent(componentId);
-               if (component == null)
-                       return null;
-               String branchId = version.getMajor() + "." + version.getMinor();
-               if (!component.branches.containsKey(branchId))
-                       return null;
-               return component.branches.get(branchId);
-       }
-
-       protected A2Contribution getOrAddContribution(String contributionId) {
-               if (contributions.containsKey(contributionId))
-                       return contributions.get(contributionId);
-               else {
-                       A2Contribution contribution = new A2Contribution(this, contributionId);
-                       contributions.put(contributionId, contribution);
-                       return contribution;
-               }
-       }
-
-       protected void asTree(String prefix, StringBuffer buf) {
-               if (prefix == null)
-                       prefix = "";
-               for (String contributionId : contributions.keySet()) {
-                       buf.append(prefix);
-                       buf.append(contributionId);
-                       buf.append('\n');
-                       A2Contribution contribution = contributions.get(contributionId);
-                       contribution.asTree(prefix + " ", buf);
-               }
-       }
-
-       protected void asTree() {
-               StringBuffer buf = new StringBuffer();
-               asTree("", buf);
-               System.out.println(buf);
-       }
-
-       protected A2Component findComponent(String componentId) {
-               SortedMap<A2Contribution, A2Component> res = new TreeMap<>();
-               for (A2Contribution contribution : contributions.values()) {
-                       components: for (String componentIdKey : contribution.components.keySet()) {
-                               if (componentId.equals(componentIdKey)) {
-                                       res.put(contribution, contribution.components.get(componentIdKey));
-                                       break components;
-                               }
-                       }
-               }
-               if (res.size() == 0)
-                       return null;
-               // TODO explicit contribution priorities
-               return res.get(res.lastKey());
-
-       }
-
-       protected String readVersionFromModule(Path modulePath) {
-               Manifest manifest;
-               if (Files.isDirectory(modulePath)) {
-                       manifest = findManifest(modulePath);
-               } else {
-                       try (JarInputStream in = new JarInputStream(newInputStream(modulePath))) {
-                               manifest = in.getManifest();
-                       } catch (IOException e) {
-                               throw new A2Exception("Cannot read manifest from " + modulePath, e);
-                       }
-               }
-               String versionStr = manifest.getMainAttributes().getValue(Constants.BUNDLE_VERSION);
-               return versionStr;
-       }
-
-       protected String readSymbolicNameFromModule(Path modulePath) {
-               Manifest manifest;
-               if (Files.isDirectory(modulePath)) {
-                       manifest = findManifest(modulePath);
-               } else {
-                       try (JarInputStream in = new JarInputStream(newInputStream(modulePath))) {
-                               manifest = in.getManifest();
-                       } catch (IOException e) {
-                               throw new A2Exception("Cannot read manifest from " + modulePath, e);
-                       }
-               }
-               String symbolicName = manifest.getMainAttributes().getValue(Constants.BUNDLE_SYMBOLICNAME);
-               int semiColIndex = symbolicName.indexOf(';');
-               if (semiColIndex >= 0)
-                       symbolicName = symbolicName.substring(0, semiColIndex);
-               return symbolicName;
-       }
-
-       private static Manifest findManifest(Path currentPath) {
-               Path metaInfPath = currentPath.resolve("META-INF");
-               if (Files.exists(metaInfPath) && Files.isDirectory(metaInfPath)) {
-                       Path manifestPath = metaInfPath.resolve("MANIFEST.MF");
-                       try {
-                               try (InputStream in = Files.newInputStream(manifestPath)) {
-                                       Manifest manifest = new Manifest(in);
-                                       return manifest;
-                               }
-                       } catch (IOException e) {
-                               throw new A2Exception("Cannot read manifest from " + manifestPath, e);
-                       }
-               } else {
-                       Path parentPath = currentPath.getParent();
-                       if (parentPath == null)
-                               throw new A2Exception("MANIFEST.MF file not found.");
-                       return findManifest(currentPath.getParent());
-               }
-       }
-
-       private static Path toTempJar(Path dir) {
-               try {
-                       Manifest manifest = findManifest(dir);
-                       Path jarPath = Files.createTempFile("a2Source", ".jar");
-                       try (JarOutputStream zos = new JarOutputStream(new FileOutputStream(jarPath.toFile()), manifest)) {
-                               Files.walkFileTree(dir, new SimpleFileVisitor<Path>() {
-                                       public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
-                                               Path relPath = dir.relativize(file);
-                                               // skip MANIFEST from folder
-                                               if (relPath.toString().contentEquals("META-INF/MANIFEST.MF"))
-                                                       return FileVisitResult.CONTINUE;
-                                               zos.putNextEntry(new ZipEntry(relPath.toString()));
-                                               Files.copy(file, zos);
-                                               zos.closeEntry();
-                                               return FileVisitResult.CONTINUE;
-                                       }
-                               });
-                       }
-                       return jarPath;
-               } catch (IOException e) {
-                       throw new A2Exception("Cannot install OSGi bundle from " + dir, e);
-               }
-
-       }
-
-       private InputStream newInputStream(Object locator) throws IOException {
-               if (locator instanceof Path) {
-                       return Files.newInputStream((Path) locator);
-               } else if (locator instanceof URL) {
-                       return ((URL) locator).openStream();
-               } else {
-                       throw new IllegalArgumentException("Unsupported module locator type " + locator.getClass());
-               }
-       }
-}
diff --git a/org.argeo.osgi.boot/src/org/argeo/osgi/boot/a2/ClasspathSource.java b/org.argeo.osgi.boot/src/org/argeo/osgi/boot/a2/ClasspathSource.java
deleted file mode 100644 (file)
index 330f66a..0000000
+++ /dev/null
@@ -1,38 +0,0 @@
-package org.argeo.osgi.boot.a2;
-
-import java.io.File;
-import java.io.IOException;
-import java.nio.file.Path;
-import java.nio.file.Paths;
-import java.util.Arrays;
-import java.util.List;
-
-import org.argeo.osgi.boot.OsgiBootUtils;
-import org.osgi.framework.Version;
-
-/**
- * A provisioning source based on the linear classpath with which the JCM has
- * been started.
- */
-public class ClasspathSource extends AbstractProvisioningSource {
-       void load() throws IOException {
-               A2Contribution classpathContribution = getOrAddContribution( A2Contribution.CLASSPATH);
-               List<String> classpath = Arrays.asList(System.getProperty("java.class.path").split(File.pathSeparator));
-               parts: for (String part : classpath) {
-                       Path file = Paths.get(part);
-                       Version version;
-                       try {
-                               version = new Version(readVersionFromModule(file));
-                       } catch (Exception e) {
-                               // ignore non OSGi
-                               continue parts;
-                       }
-                       String moduleName = readSymbolicNameFromModule(file);
-                       A2Component component = classpathContribution.getOrAddComponent(moduleName);
-                       A2Module module = component.getOrAddModule(version, file);
-                       if (OsgiBootUtils.isDebug())
-                               OsgiBootUtils.debug("Registered " + module);
-               }
-
-       }
-}
diff --git a/org.argeo.osgi.boot/src/org/argeo/osgi/boot/a2/FsA2Source.java b/org.argeo.osgi.boot/src/org/argeo/osgi/boot/a2/FsA2Source.java
deleted file mode 100644 (file)
index bea8db3..0000000
+++ /dev/null
@@ -1,88 +0,0 @@
-package org.argeo.osgi.boot.a2;
-
-import java.io.IOException;
-import java.nio.file.DirectoryStream;
-import java.nio.file.Files;
-import java.nio.file.Path;
-import java.nio.file.Paths;
-import java.util.SortedSet;
-import java.util.TreeSet;
-
-import org.argeo.osgi.boot.OsgiBootUtils;
-import org.osgi.framework.Version;
-
-/** A file system {@link AbstractProvisioningSource} in A2 format. */
-public class FsA2Source extends AbstractProvisioningSource implements A2Source {
-       private final Path base;
-
-       public FsA2Source(Path base) {
-               super();
-               this.base = base;
-       }
-
-       void load() throws IOException {
-               DirectoryStream<Path> contributionPaths = Files.newDirectoryStream(base);
-               SortedSet<A2Contribution> contributions = new TreeSet<>();
-               contributions: for (Path contributionPath : contributionPaths) {
-                       if (Files.isDirectory(contributionPath)) {
-                               String contributionId = contributionPath.getFileName().toString();
-                               if (A2Contribution.BOOT.equals(contributionId))// skip boot
-                                       continue contributions;
-                               A2Contribution contribution = getOrAddContribution(contributionId);
-                               contributions.add(contribution);
-                       }
-               }
-
-               for (A2Contribution contribution : contributions) {
-                       DirectoryStream<Path> modulePaths = Files.newDirectoryStream(base.resolve(contribution.getId()));
-                       modules: for (Path modulePath : modulePaths) {
-                               if (!Files.isDirectory(modulePath)) {
-                                       // OsgiBootUtils.debug("Registering " + modulePath);
-                                       String moduleFileName = modulePath.getFileName().toString();
-                                       int lastDot = moduleFileName.lastIndexOf('.');
-                                       String ext = moduleFileName.substring(lastDot + 1);
-                                       if (!"jar".equals(ext))
-                                               continue modules;
-                                       String moduleName = moduleFileName.substring(0, lastDot);
-                                       if (moduleName.endsWith("-SNAPSHOT"))
-                                               moduleName = moduleName.substring(0, moduleName.length() - "-SNAPSHOT".length());
-                                       int lastDash = moduleName.lastIndexOf('-');
-                                       String versionStr = moduleName.substring(lastDash + 1);
-                                       String componentName = moduleName.substring(0, lastDash);
-                                       // if(versionStr.endsWith("-SNAPSHOT")) {
-                                       // versionStr = readVersionFromModule(modulePath);
-                                       // }
-                                       Version version;
-                                       try {
-                                               version = new Version(versionStr);
-                                       } catch (Exception e) {
-                                               versionStr = readVersionFromModule(modulePath);
-                                               if (versionStr != null) {
-                                                       version = new Version(versionStr);
-                                               } else {
-                                                       OsgiBootUtils.debug("Ignore " + modulePath + " (" + e.getMessage() + ")");
-                                                       continue modules;
-                                               }
-                                       }
-                                       A2Component component = contribution.getOrAddComponent(componentName);
-                                       A2Module module = component.getOrAddModule(version, modulePath);
-                                       if (OsgiBootUtils.isDebug())
-                                               OsgiBootUtils.debug("Registered " + module);
-                               }
-                       }
-               }
-
-       }
-
-       public static void main(String[] args) {
-               try {
-                       FsA2Source context = new FsA2Source(Paths.get(
-                                       "/home/mbaudier/dev/git/apache2/argeo-commons/dist/argeo-node/target/argeo-node-2.1.77-SNAPSHOT/share/osgi"));
-                       context.load();
-                       context.asTree();
-               } catch (Exception e) {
-                       e.printStackTrace();
-               }
-       }
-
-}
diff --git a/org.argeo.osgi.boot/src/org/argeo/osgi/boot/a2/FsM2Source.java b/org.argeo.osgi.boot/src/org/argeo/osgi/boot/a2/FsM2Source.java
deleted file mode 100644 (file)
index 8814522..0000000
+++ /dev/null
@@ -1,66 +0,0 @@
-package org.argeo.osgi.boot.a2;
-
-import java.io.File;
-import java.io.IOException;
-import java.nio.file.FileVisitResult;
-import java.nio.file.Files;
-import java.nio.file.Path;
-import java.nio.file.Paths;
-import java.nio.file.SimpleFileVisitor;
-import java.nio.file.attribute.BasicFileAttributes;
-
-import org.argeo.osgi.boot.OsgiBootUtils;
-import org.osgi.framework.Version;
-
-/** A file system {@link AbstractProvisioningSource} in Maven 2 format. */
-public class FsM2Source extends AbstractProvisioningSource {
-       private final Path base;
-
-       public FsM2Source(Path base) {
-               super();
-               this.base = base;
-       }
-
-       void load() throws IOException {
-               Files.walkFileTree(base, new ArtifactFileVisitor());
-       }
-
-       class ArtifactFileVisitor extends SimpleFileVisitor<Path> {
-
-               @Override
-               public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
-                       // OsgiBootUtils.debug("Processing " + file);
-                       if (file.toString().endsWith(".jar")) {
-                               Version version;
-                               try {
-                                       version = new Version(readVersionFromModule(file));
-                               } catch (Exception e) {
-                                       // ignore non OSGi
-                                       return FileVisitResult.CONTINUE;
-                               }
-                               String moduleName = readSymbolicNameFromModule(file);
-                               Path groupPath = file.getParent().getParent().getParent();
-                               Path relGroupPath = base.relativize(groupPath);
-                               String contributionName = relGroupPath.toString().replace(File.separatorChar, '.');
-                               A2Contribution contribution = getOrAddContribution(contributionName);
-                               A2Component component = contribution.getOrAddComponent(moduleName);
-                               A2Module module = component.getOrAddModule(version, file);
-                               if (OsgiBootUtils.isDebug())
-                                       OsgiBootUtils.debug("Registered " + module);
-                       }
-                       return super.visitFile(file, attrs);
-               }
-
-       }
-
-       public static void main(String[] args) {
-               try {
-                       FsM2Source context = new FsM2Source(Paths.get("/home/mbaudier/.m2/repository"));
-                       context.load();
-                       context.asTree();
-               } catch (Exception e) {
-                       e.printStackTrace();
-               }
-       }
-
-}
diff --git a/org.argeo.osgi.boot/src/org/argeo/osgi/boot/a2/OsgiContext.java b/org.argeo.osgi.boot/src/org/argeo/osgi/boot/a2/OsgiContext.java
deleted file mode 100644 (file)
index b4f1018..0000000
+++ /dev/null
@@ -1,39 +0,0 @@
-package org.argeo.osgi.boot.a2;
-
-import org.argeo.osgi.boot.OsgiBootUtils;
-import org.osgi.framework.Bundle;
-import org.osgi.framework.BundleContext;
-import org.osgi.framework.FrameworkUtil;
-import org.osgi.framework.Version;
-
-/** A running OSGi bundle context seen as a {@link AbstractProvisioningSource}. */
-class OsgiContext extends AbstractProvisioningSource {
-       private final BundleContext bc;
-
-       public OsgiContext(BundleContext bc) {
-               super();
-               this.bc = bc;
-       }
-
-       public OsgiContext() {
-               Bundle bundle = FrameworkUtil.getBundle(OsgiContext.class);
-               if (bundle == null)
-                       throw new IllegalArgumentException(
-                                       "OSGi Boot bundle must be started or a bundle context must be specified");
-               this.bc = bundle.getBundleContext();
-       }
-
-       void load() {
-               A2Contribution runtimeContribution = getOrAddContribution( A2Contribution.RUNTIME);
-               for (Bundle bundle : bc.getBundles()) {
-                       // OsgiBootUtils.debug(bundle.getDataFile("/"));
-                       String componentId = bundle.getSymbolicName();
-                       Version version = bundle.getVersion();
-                       A2Component component = runtimeContribution.getOrAddComponent(componentId);
-                       A2Module module = component.getOrAddModule(version, bundle);
-                       if (OsgiBootUtils.isDebug())
-                               OsgiBootUtils.debug("Registered " + module + " (location id: " + bundle.getLocation() + ")");
-               }
-
-       }
-}
diff --git a/org.argeo.osgi.boot/src/org/argeo/osgi/boot/a2/ProvisioningManager.java b/org.argeo.osgi.boot/src/org/argeo/osgi/boot/a2/ProvisioningManager.java
deleted file mode 100644 (file)
index c88af39..0000000
+++ /dev/null
@@ -1,197 +0,0 @@
-package org.argeo.osgi.boot.a2;
-
-import java.io.File;
-import java.net.URI;
-import java.nio.file.Path;
-import java.nio.file.Paths;
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-
-import org.argeo.osgi.boot.OsgiBootUtils;
-import org.eclipse.osgi.launch.EquinoxFactory;
-import org.osgi.framework.Bundle;
-import org.osgi.framework.BundleContext;
-import org.osgi.framework.Constants;
-import org.osgi.framework.Version;
-import org.osgi.framework.launch.Framework;
-import org.osgi.framework.wiring.FrameworkWiring;
-
-/** Loads provisioning sources into an OSGi context. */
-public class ProvisioningManager {
-       BundleContext bc;
-       OsgiContext osgiContext;
-       List<ProvisioningSource> sources = Collections.synchronizedList(new ArrayList<>());
-
-       public ProvisioningManager(BundleContext bc) {
-               this.bc = bc;
-               osgiContext = new OsgiContext(bc);
-               osgiContext.load();
-       }
-
-       protected void addSource(ProvisioningSource source) {
-               sources.add(source);
-       }
-
-       void installWholeSource(ProvisioningSource source) {
-               Set<Bundle> updatedBundles = new HashSet<>();
-               for (A2Contribution contribution : source.listContributions(null)) {
-                       for (A2Component component : contribution.components.values()) {
-                               A2Module module = component.last().last();
-                               Bundle bundle = installOrUpdate(module);
-                               if (bundle != null)
-                                       updatedBundles.add(bundle);
-                       }
-               }
-               FrameworkWiring frameworkWiring = bc.getBundle(0).adapt(FrameworkWiring.class);
-               frameworkWiring.refreshBundles(updatedBundles);
-       }
-
-       public void registerSource(String uri) {
-               try {
-                       URI u = new URI(uri);
-                       if (A2Source.SCHEME_A2.equals(u.getScheme())) {
-                               if (u.getHost() == null || "".equals(u.getHost())) {
-                                       String baseStr = u.getPath();
-                                       if (File.separatorChar == '\\') {// MS Windows
-                                               baseStr = baseStr.substring(1).replace('/', File.separatorChar);
-                                       }
-                                       Path base = Paths.get(baseStr);
-                                       FsA2Source source = new FsA2Source(base);
-                                       source.load();
-                                       addSource(source);
-                               }
-                       }
-               } catch (Exception e) {
-                       throw new A2Exception("Cannot add source " + uri, e);
-               }
-       }
-
-       public boolean registerDefaultSource() {
-               String frameworkLocation = bc.getProperty("osgi.framework");
-               try {
-                       URI frameworkLocationUri = new URI(frameworkLocation);
-                       if ("file".equals(frameworkLocationUri.getScheme())) {
-                               Path frameworkPath = Paths.get(frameworkLocationUri);
-                               if (frameworkPath.getParent().getFileName().toString().equals(A2Contribution.BOOT)) {
-                                       Path base = frameworkPath.getParent().getParent();
-                                       String baseStr = base.toString();
-                                       if (File.separatorChar == '\\')// MS Windows
-                                               baseStr = '/' + baseStr.replace(File.separatorChar, '/');
-                                       URI baseUri = new URI(A2Source.SCHEME_A2, null, null, 0, baseStr, null, null);
-                                       registerSource(baseUri.toString());
-                                       OsgiBootUtils.info("Registered " + baseUri + " as default source");
-                                       return true;
-                               }
-                       }
-               } catch (Exception e) {
-                       OsgiBootUtils.error("Cannot register default source based on framework location " + frameworkLocation, e);
-               }
-               return false;
-       }
-
-       public void install(String spec) {
-               if (spec == null) {
-                       for (ProvisioningSource source : sources) {
-                               installWholeSource(source);
-                       }
-               }
-       }
-
-       /** @return the new/updated bundle, or null if nothing was done. */
-       protected Bundle installOrUpdate(A2Module module) {
-               try {
-                       ProvisioningSource moduleSource = module.getBranch().getComponent().getContribution().getSource();
-                       Version moduleVersion = module.getVersion();
-                       A2Branch osgiBranch = osgiContext.findBranch(module.getBranch().getComponent().getId(), moduleVersion);
-                       if (osgiBranch == null) {
-//                             Bundle bundle = bc.installBundle(module.getBranch().getCoordinates(),
-//                                             moduleSource.newInputStream(module.getLocator()));
-                               Bundle bundle = moduleSource.install(bc, module);
-                               if (OsgiBootUtils.isDebug())
-                                       OsgiBootUtils.debug("Installed bundle " + bundle.getLocation() + " with version " + moduleVersion);
-                               return bundle;
-                       } else {
-                               A2Module lastOsgiModule = osgiBranch.last();
-                               int compare = moduleVersion.compareTo(lastOsgiModule.getVersion());
-                               if (compare > 0) {// update
-                                       Bundle bundle = (Bundle) lastOsgiModule.getLocator();
-//                                     bundle.update(moduleSource.newInputStream(module.getLocator()));
-                                       moduleSource.update(bundle, module);
-                                       OsgiBootUtils.info("Updated bundle " + bundle.getLocation() + " to version " + moduleVersion);
-                                       return bundle;
-                               }
-                       }
-               } catch (Exception e) {
-                       OsgiBootUtils.error("Could not install module " + module + ": " + e.getMessage(), e);
-               }
-               return null;
-       }
-
-       public Collection<Bundle> update() {
-               boolean fragmentsUpdated = false;
-               Set<Bundle> updatedBundles = new HashSet<>();
-               bundles: for (Bundle bundle : bc.getBundles()) {
-                       for (ProvisioningSource source : sources) {
-                               String componentId = bundle.getSymbolicName();
-                               Version version = bundle.getVersion();
-                               A2Branch branch = source.findBranch(componentId, version);
-                               if (branch == null)
-                                       continue bundles;
-                               A2Module module = branch.last();
-                               Version moduleVersion = module.getVersion();
-                               int compare = moduleVersion.compareTo(version);
-                               if (compare > 0) {// update
-                                       try {
-                                               source.update(bundle, module);
-//                                             bundle.update(in);
-                                               String fragmentHost = bundle.getHeaders().get(Constants.FRAGMENT_HOST);
-                                               if (fragmentHost != null)
-                                                       fragmentsUpdated = true;
-                                               OsgiBootUtils.info("Updated bundle " + bundle.getLocation() + " to version " + moduleVersion);
-                                               updatedBundles.add(bundle);
-                                       } catch (Exception e) {
-                                               OsgiBootUtils.error("Cannot update with module " + module, e);
-                                       }
-                               }
-                       }
-               }
-               FrameworkWiring frameworkWiring = bc.getBundle(0).adapt(FrameworkWiring.class);
-               if (fragmentsUpdated)// refresh all
-                       frameworkWiring.refreshBundles(null);
-               else
-                       frameworkWiring.refreshBundles(updatedBundles);
-               return updatedBundles;
-       }
-
-       public static void main(String[] args) {
-               Map<String, String> configuration = new HashMap<>();
-               configuration.put("osgi.console", "2323");
-               Framework framework = OsgiBootUtils.launch(new EquinoxFactory(), configuration);
-               try {
-                       ProvisioningManager pm = new ProvisioningManager(framework.getBundleContext());
-                       FsA2Source context = new FsA2Source(Paths.get(
-                                       "/home/mbaudier/dev/git/apache2/argeo-commons/dist/argeo-node/target/argeo-node-2.1.74-SNAPSHOT/argeo-node/share/osgi"));
-                       context.load();
-                       if (framework.getBundleContext().getBundles().length == 1) {// initial
-                               pm.install(null);
-                       } else {
-                               pm.update();
-                       }
-               } catch (Exception e) {
-                       e.printStackTrace();
-               } finally {
-                       try {
-                               // framework.stop();
-                       } catch (Exception e) {
-                               e.printStackTrace();
-                       }
-               }
-       }
-
-}
diff --git a/org.argeo.osgi.boot/src/org/argeo/osgi/boot/a2/ProvisioningSource.java b/org.argeo.osgi.boot/src/org/argeo/osgi/boot/a2/ProvisioningSource.java
deleted file mode 100644 (file)
index 62d7042..0000000
+++ /dev/null
@@ -1,21 +0,0 @@
-package org.argeo.osgi.boot.a2;
-
-import org.osgi.framework.Bundle;
-import org.osgi.framework.BundleContext;
-import org.osgi.framework.Version;
-
-/** Where components are retrieved from. */
-public interface ProvisioningSource {
-       /** List all contributions of this source. */
-       Iterable<A2Contribution> listContributions(Object filter);
-
-       /** Install a module in the OSGi runtime. */
-       Bundle install(BundleContext bc, A2Module module);
-
-       /** Update a module in the OSGi runtime. */
-       void update(Bundle bundle, A2Module module);
-
-       /** Finds the {@link A2Branch} related to this component and version. */
-       A2Branch findBranch(String componentId, Version version);
-
-}