From: Mathieu Baudier Date: Wed, 7 Nov 2012 12:35:37 +0000 (+0000) Subject: Introduce distribution URL booting X-Git-Tag: argeo-commons-2.1.30~779 X-Git-Url: http://git.argeo.org/?a=commitdiff_plain;h=18ba85433f8d8a719098a59953beda9e848bc9fb;p=lgpl%2Fargeo-commons.git Introduce distribution URL booting git-svn-id: https://svn.argeo.org/commons/trunk@5717 4cfe0d0a-d680-48aa-b62c-e0a02a3f76cc --- 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 index 000000000..ab9c46bd7 --- /dev/null +++ b/base/runtime/org.argeo.osgi.boot/src/main/java/org/argeo/osgi/boot/DistributionBundle.java @@ -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/* */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/* */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/* */listUrls() { + if (baseUrl == null) + throw new OsgiBootException("Base URL is not set"); + + if (artifacts == null) + throw new OsgiBootException("Artifact list not initialized"); + + List/* */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; + } + + } +} diff --git a/base/runtime/org.argeo.osgi.boot/src/main/java/org/argeo/osgi/boot/OsgiBoot.java b/base/runtime/org.argeo.osgi.boot/src/main/java/org/argeo/osgi/boot/OsgiBoot.java index 7e608103c..eaafef479 100644 --- a/base/runtime/org.argeo.osgi.boot/src/main/java/org/argeo/osgi/boot/OsgiBoot.java +++ b/base/runtime/org.argeo.osgi.boot/src/main/java/org/argeo/osgi/boot/OsgiBoot.java @@ -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 index 000000000..5b191466b --- /dev/null +++ b/base/runtime/org.argeo.osgi.boot/src/main/java/org/argeo/osgi/boot/OsgiBootException.java @@ -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); + } + +}