Introduce distribution URL booting
authorMathieu Baudier <mbaudier@argeo.org>
Wed, 7 Nov 2012 12:35:37 +0000 (12:35 +0000)
committerMathieu Baudier <mbaudier@argeo.org>
Wed, 7 Nov 2012 12:35:37 +0000 (12:35 +0000)
git-svn-id: https://svn.argeo.org/commons/trunk@5717 4cfe0d0a-d680-48aa-b62c-e0a02a3f76cc

base/runtime/org.argeo.osgi.boot/src/main/java/org/argeo/osgi/boot/DistributionBundle.java [new file with mode: 0644]
base/runtime/org.argeo.osgi.boot/src/main/java/org/argeo/osgi/boot/OsgiBoot.java
base/runtime/org.argeo.osgi.boot/src/main/java/org/argeo/osgi/boot/OsgiBootException.java [new file with mode: 0644]

diff --git a/base/runtime/org.argeo.osgi.boot/src/main/java/org/argeo/osgi/boot/DistributionBundle.java b/base/runtime/org.argeo.osgi.boot/src/main/java/org/argeo/osgi/boot/DistributionBundle.java
new file mode 100644 (file)
index 0000000..ab9c46b
--- /dev/null
@@ -0,0 +1,197 @@
+package org.argeo.osgi.boot;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.net.URL;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.StringTokenizer;
+import java.util.jar.JarEntry;
+import java.util.jar.JarInputStream;
+import java.util.jar.Manifest;
+
+import org.osgi.framework.Constants;
+
+/**
+ * A distribution bundle is a bundle within a maven-like distribution
+ * groupId:Bundle-SymbolicName:Bundle-Version which references others OSGi
+ * bundle. It is not required to be OSGi complete also it will generally be
+ * expected that it is. The root of the repository is computed based on the file
+ * name of the URL and of the content of the index.
+ */
+public class DistributionBundle {
+       private final static String INDEX_FILE_NAME = "modularDistribution.csv";
+
+       private final String url;
+
+       private Manifest manifest;
+       private String symbolicName;
+       private String version;
+
+       /** can be null */
+       private String baseUrl;
+       /** can be null */
+       private String relativeUrl;
+
+       private List/* <OsgiArtifact> */artifacts;
+
+       private String separator = ",";
+
+       public DistributionBundle(String url) {
+               this.url = url;
+       }
+
+       public DistributionBundle(String baseUrl, String relativeUrl) {
+               if (baseUrl == null || !baseUrl.endsWith("/"))
+                       throw new OsgiBootException("Base url " + baseUrl
+                                       + " badly formatted");
+               if (relativeUrl.startsWith("http") || relativeUrl.startsWith("file:"))
+                       throw new OsgiBootException("Relative URL " + relativeUrl
+                                       + " badly formatted");
+               this.url = baseUrl + relativeUrl;
+               this.baseUrl = baseUrl;
+               this.relativeUrl = relativeUrl;
+       }
+
+       public void processUrl() {
+               JarInputStream jarIn = null;
+               try {
+                       URL u = new URL(url);
+                       jarIn = new JarInputStream(u.openStream());
+
+                       // meta data
+                       manifest = jarIn.getManifest();
+                       symbolicName = manifest.getMainAttributes().getValue(
+                                       Constants.BUNDLE_SYMBOLICNAME);
+                       version = manifest.getMainAttributes().getValue(
+                                       Constants.BUNDLE_VERSION);
+
+                       JarEntry indexEntry;
+                       while ((indexEntry = jarIn.getNextJarEntry()) != null) {
+                               String entryName = indexEntry.getName();
+                               if (entryName.equals(INDEX_FILE_NAME)) {
+                                       break;
+                               }
+                               jarIn.closeEntry();
+                       }
+
+                       // list artifacts
+                       if (indexEntry == null)
+                               throw new OsgiBootException("No index " + INDEX_FILE_NAME
+                                               + " in " + url);
+                       artifacts = listArtifacts(jarIn);
+                       jarIn.closeEntry();
+
+                       // find base URL
+                       // won't work if distribution artifact is not listed
+                       for (int i = 0; i < artifacts.size(); i++) {
+                               OsgiArtifact osgiArtifact = (OsgiArtifact) artifacts.get(i);
+                               if (osgiArtifact.getSymbolicName().equals(symbolicName)
+                                               && osgiArtifact.getVersion().equals(version)) {
+                                       String relativeUrl = osgiArtifact.getRelativeUrl();
+                                       if (url.endsWith(relativeUrl)) {
+                                               baseUrl = url.substring(0, url.length()
+                                                               - osgiArtifact.getRelativeUrl().length());
+                                               break;
+                                       }
+                               }
+                       }
+               } catch (Exception e) {
+                       throw new OsgiBootException("Cannot list URLs from " + url, e);
+               } finally {
+                       if (jarIn != null)
+                               try {
+                                       jarIn.close();
+                               } catch (IOException e) {
+                                       // silent
+                               }
+               }
+       }
+
+       protected List/* <OsgiArtifact> */listArtifacts(InputStream in) {
+               List osgiArtifacts = new ArrayList();
+               BufferedReader reader = null;
+               try {
+                       reader = new BufferedReader(new InputStreamReader(in));
+                       String line = null;
+                       while ((line = reader.readLine()) != null) {
+                               StringTokenizer st = new StringTokenizer(line, separator);
+                               String moduleName = st.nextToken();
+                               String moduleVersion = st.nextToken();
+                               String relativeUrl = st.nextToken();
+                               osgiArtifacts.add(new OsgiArtifact(moduleName, moduleVersion,
+                                               relativeUrl));
+                       }
+               } catch (Exception e) {
+                       throw new OsgiBootException("Cannot list artifacts", e);
+               }
+               return osgiArtifacts;
+       }
+
+       /** Convenience method */
+       public static DistributionBundle processUrl(String baseUrl,
+                       String realtiveUrl) {
+               DistributionBundle distributionBundle = new DistributionBundle(baseUrl,
+                               realtiveUrl);
+               distributionBundle.processUrl();
+               return distributionBundle;
+       }
+
+       /**
+        * List full URLs of the bunmdles, based on base URL, usable directly for
+        * download.
+        */
+       public List/* <String> */listUrls() {
+               if (baseUrl == null)
+                       throw new OsgiBootException("Base URL is not set");
+
+               if (artifacts == null)
+                       throw new OsgiBootException("Artifact list not initialized");
+
+               List/* <String> */urls = new ArrayList();
+               for (int i = 0; i < artifacts.size(); i++) {
+                       OsgiArtifact osgiArtifact = (OsgiArtifact) artifacts.get(i);
+                       urls.add(baseUrl + osgiArtifact.getRelativeUrl());
+               }
+               return urls;
+       }
+
+       public void setBaseUrl(String baseUrl) {
+               this.baseUrl = baseUrl;
+       }
+
+       /** Separator used to parse the tabular file */
+       public void setSeparator(String modulesUrlSeparator) {
+               this.separator = modulesUrlSeparator;
+       }
+
+       /** One of the listed artifact */
+       protected static class OsgiArtifact {
+               private final String symbolicName;
+               private final String version;
+               private final String relativeUrl;
+
+               public OsgiArtifact(String symbolicName, String version,
+                               String relativeUrl) {
+                       super();
+                       this.symbolicName = symbolicName;
+                       this.version = version;
+                       this.relativeUrl = relativeUrl;
+               }
+
+               public String getSymbolicName() {
+                       return symbolicName;
+               }
+
+               public String getVersion() {
+                       return version;
+               }
+
+               public String getRelativeUrl() {
+                       return relativeUrl;
+               }
+
+       }
+}
index 7e608103c23c8fbf08de4fa0038fd02c4be77b2c..eaafef47937172b0f529df7d9a4ab784cd2bde03 100644 (file)
@@ -58,8 +58,9 @@ public class OsgiBoot {
        public final static String PROP_ARGEO_OSGI_BUNDLES = "argeo.osgi.bundles";
        public final static String PROP_ARGEO_OSGI_LOCATIONS = "argeo.osgi.locations";
        public final static String PROP_ARGEO_OSGI_BASE_URL = "argeo.osgi.baseUrl";
-       /** Use org.argeo.osgi */
+       /** @deprecated */
        public final static String PROP_ARGEO_OSGI_MODULES_URL = "argeo.osgi.modulesUrl";
+       public final static String PROP_ARGEO_OSGI_DISTRIBUTION_URL = "argeo.osgi.distributionUrl";
 
        // booleans
        public final static String PROP_ARGEO_OSGI_BOOT_DEBUG = "argeo.osgi.boot.debug";
@@ -80,7 +81,7 @@ public class OsgiBoot {
        public final static String INSTANCE_AREA_DEFAULT_PROP = "osgi.instance.area.default";
 
        private boolean debug = Boolean.valueOf(
-                       System.getProperty(PROP_ARGEO_OSGI_BOOT_DEBUG, "false"))
+                       System.getProperty(PROP_ARGEO_OSGI_BOOT_DEBUG, "true"))
                        .booleanValue();
        /** Exclude svn metadata implicitely(a bit costly) */
        private boolean excludeSvn = Boolean.valueOf(
@@ -159,6 +160,7 @@ public class OsgiBoot {
                installUrls(getBundlesUrls());
                installUrls(getLocationsUrls());
                installUrls(getModulesUrls());
+               installUrls(getDistributionUrls());
                checkUnresolved();
                startBundles();
                long duration = System.currentTimeMillis() - begin;
@@ -568,6 +570,34 @@ public class OsgiBoot {
                return urls;
        }
 
+       /*
+        * DISTRIBUTION JAR INSTALLATION
+        */
+       public List getDistributionUrls() {
+               List urls = new ArrayList();
+               String distributionUrl = OsgiBootUtils
+                               .getProperty(PROP_ARGEO_OSGI_DISTRIBUTION_URL);
+               if (distributionUrl == null)
+                       return urls;
+               String baseUrl = OsgiBootUtils.getProperty(PROP_ARGEO_OSGI_BASE_URL);
+
+               DistributionBundle distributionBundle;
+               if (baseUrl != null
+                               && !(distributionUrl.startsWith("http") || distributionUrl
+                                               .startsWith("file"))) {
+                       // relative url
+                       distributionBundle = new DistributionBundle(baseUrl,
+                                       distributionUrl);
+               } else {
+                       distributionBundle = new DistributionBundle(distributionUrl);
+                       if (baseUrl != null)
+                               distributionBundle.setBaseUrl(baseUrl);
+
+               }
+               distributionBundle.processUrl();
+               return distributionBundle.listUrls();
+       }
+
        /*
         * MODULES LIST INSTALLATION (${argeo.osgi.modulesUrl})
         */
@@ -577,6 +607,8 @@ public class OsgiBoot {
         * If ${argeo.osgi.baseUrl} is set, URLs will be considered relative paths
         * and be concatenated with the base URL, typically the root of a Maven
         * repository.
+        * 
+        * @deprecated
         */
        public List getModulesUrls() {
                List urls = new ArrayList();
diff --git a/base/runtime/org.argeo.osgi.boot/src/main/java/org/argeo/osgi/boot/OsgiBootException.java b/base/runtime/org.argeo.osgi.boot/src/main/java/org/argeo/osgi/boot/OsgiBootException.java
new file mode 100644 (file)
index 0000000..5b19146
--- /dev/null
@@ -0,0 +1,18 @@
+package org.argeo.osgi.boot;
+
+/** OsgiBoot specific exceptions */
+public class OsgiBootException extends RuntimeException {
+       private static final long serialVersionUID = 2414011711711425353L;
+
+       public OsgiBootException() {
+       }
+
+       public OsgiBootException(String message) {
+               super(message);
+       }
+
+       public OsgiBootException(String message, Throwable cause) {
+               super(message, cause);
+       }
+
+}