From: Mathieu Baudier Date: Wed, 22 Jul 2009 15:23:18 +0000 (+0000) Subject: Introduce DetachedLauncher based on osgiboot X-Git-Tag: argeo-slc-2.1.7~1662 X-Git-Url: http://git.argeo.org/?a=commitdiff_plain;h=8eb028e332cb2be50ed311a0501f7efce5849d44;p=gpl%2Fargeo-slc.git Introduce DetachedLauncher based on osgiboot git-svn-id: https://svn.argeo.org/slc/trunk@2723 4cfe0d0a-d680-48aa-b62c-e0a02a3f76cc --- diff --git a/runtime/org.argeo.slc.core/src/main/java/org/argeo/slc/core/execution/DefaultExecutionFlowDescriptorConverter.java b/runtime/org.argeo.slc.core/src/main/java/org/argeo/slc/core/execution/DefaultExecutionFlowDescriptorConverter.java index d8429d192..b2b613494 100644 --- a/runtime/org.argeo.slc.core/src/main/java/org/argeo/slc/core/execution/DefaultExecutionFlowDescriptorConverter.java +++ b/runtime/org.argeo.slc.core/src/main/java/org/argeo/slc/core/execution/DefaultExecutionFlowDescriptorConverter.java @@ -86,7 +86,7 @@ public class DefaultExecutionFlowDescriptorConverter implements Assert.notNull(executionSpec.getName()); Map values = new TreeMap(); - attrs: for (String key : executionSpec.getAttributes().keySet()) { + for (String key : executionSpec.getAttributes().keySet()) { ExecutionSpecAttribute attribute = executionSpec .getAttributes().get(key); diff --git a/runtime/org.argeo.slc.core/src/main/java/org/argeo/slc/core/execution/tasks/JvmProcess.java b/runtime/org.argeo.slc.core/src/main/java/org/argeo/slc/core/execution/tasks/JvmProcess.java index ba1d67eb5..8c0bfebe9 100644 --- a/runtime/org.argeo.slc.core/src/main/java/org/argeo/slc/core/execution/tasks/JvmProcess.java +++ b/runtime/org.argeo.slc.core/src/main/java/org/argeo/slc/core/execution/tasks/JvmProcess.java @@ -1,6 +1,8 @@ package org.argeo.slc.core.execution.tasks; import java.io.File; +import java.io.FileNotFoundException; +import java.io.FileOutputStream; import java.io.IOException; import java.util.ArrayList; import java.util.List; @@ -8,10 +10,15 @@ import java.util.Map; import java.util.Properties; import org.apache.commons.exec.CommandLine; +import org.apache.commons.io.IOUtils; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; import org.argeo.slc.SlcException; import org.springframework.core.io.Resource; public class JvmProcess extends SystemCall { + private final static Log log = LogFactory.getLog(JvmProcess.class); + private Properties systemProperties = new Properties(); private List classpath = new ArrayList(); private List pBootClasspath = new ArrayList(); @@ -29,10 +36,9 @@ public class JvmProcess extends SystemCall { cl = new CommandLine("java"); if (pBootClasspath.size() > 0) { - StringBuffer buf = new StringBuffer("-Xbootclasspath/p:"); + StringBuffer buf = new StringBuffer("-Xbootclasspath/p"); for (Resource res : pBootClasspath) { - if (buf.length() != 0) - buf.append(File.pathSeparatorChar); + buf.append(File.pathSeparatorChar); buf.append(asFile(res)); } cl.addArgument(buf.toString()); @@ -62,19 +68,38 @@ public class JvmProcess extends SystemCall { cl.addArgument(arg); } + if (log.isDebugEnabled()) + log.debug("Command line:\n" + cl.toString() + "\n"); + return cl; } protected File asFile(Resource res) { - // TODO: implements local copy try { return res.getFile().getCanonicalFile(); + } catch (FileNotFoundException e) { + return copyToTempFile(res); } catch (IOException e) { throw new SlcException("Cannot convert resource to file", e); } } + protected File copyToTempFile(Resource res) { + File tempFile; + FileOutputStream fos; + try { + tempFile = File.createTempFile("slcJvmProcess-", res.getFilename()); + tempFile.deleteOnExit(); + fos = new FileOutputStream(tempFile); + IOUtils.copy(res.getInputStream(), fos); + } catch (IOException e) { + throw new SlcException("Cannot copy " + res + " to temp file.", e); + } + IOUtils.closeQuietly(fos); + return tempFile; + } + public Properties getSystemProperties() { return systemProperties; } diff --git a/runtime/org.argeo.slc.detached/pom.xml b/runtime/org.argeo.slc.detached/pom.xml index 33dafd584..9a307e017 100644 --- a/runtime/org.argeo.slc.detached/pom.xml +++ b/runtime/org.argeo.slc.detached/pom.xml @@ -28,16 +28,19 @@ org.w3c.dom;version="0.0.0", javax.xml.*;version="0.0.0", - org.apache.xerces.jaxp, + * + + diff --git a/runtime/org.argeo.slc.lib.detached/src/main/java/org/argeo/slc/lib/detached/DetachedLauncher.java b/runtime/org.argeo.slc.lib.detached/src/main/java/org/argeo/slc/lib/detached/DetachedLauncher.java new file mode 100644 index 000000000..505fa6663 --- /dev/null +++ b/runtime/org.argeo.slc.lib.detached/src/main/java/org/argeo/slc/lib/detached/DetachedLauncher.java @@ -0,0 +1,123 @@ +package org.argeo.slc.lib.detached; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.argeo.slc.SlcException; +import org.argeo.slc.core.execution.tasks.JvmProcess; +import org.osgi.framework.Bundle; +import org.osgi.framework.BundleContext; +import org.springframework.beans.factory.InitializingBean; +import org.springframework.context.ResourceLoaderAware; +import org.springframework.core.io.Resource; +import org.springframework.core.io.ResourceLoader; +import org.springframework.osgi.context.BundleContextAware; + +public class DetachedLauncher extends JvmProcess implements BundleContextAware, + InitializingBean, ResourceLoaderAware { + private final static Log log = LogFactory.getLog(DetachedLauncher.class); + + private BundleContext bundleContext = null; + private ResourceLoader resourceLoader = null; + + private Resource osgiFramework = null; + private String osgibootBundleName = "org.argeo.slc.osgiboot"; + private String equinoxBundleName = "org.eclipse.osgi"; + private String xmlapisBundleName = "com.springsource.org.apache.xmlcommons"; + private String xercesBundleName = "com.springsource.org.apache.xerces"; + + /** + * Required by Spring for JDK 1.4. see + * http://forum.springsource.org/showthread.php?t=74555 + */ + private Boolean prependXmlJars = false; + + public DetachedLauncher() { + // Override defaults + setSynchronous(false); + setMainClass("org.argeo.slc.osgiboot.Launcher"); + } + + public void afterPropertiesSet() throws Exception { + if (bundleContext == null) + throw new SlcException("An OSGi bundle context is required."); + + // Equinox jar + if (osgiFramework == null) + getClasspath() + .add(asResource(System.getProperty("osgi.framework"))); + else + getClasspath().add(osgiFramework); + + StringBuffer osgiLocations = new StringBuffer(""); + bundles: for (Bundle bundle : bundleContext.getBundles()) { + String name = bundle.getSymbolicName(); + + // Special bundles + if (osgibootBundleName.equals(name)) + getClasspath().add(findOsgiboot(bundle)); + else if (equinoxBundleName.equals(name)) + continue bundles;// skip framework + else if (xmlapisBundleName.equals(name) && prependXmlJars) + getPBootClasspath().add(asResource(bundle.getLocation())); + else if (xercesBundleName.equals(name) && prependXmlJars) + getPBootClasspath().add(asResource(bundle.getLocation())); + + if (osgiLocations.length() != 0) + osgiLocations.append(','); + osgiLocations.append(bundle.getLocation()); + } + + getSystemProperties().setProperty("osgi.bundles", + osgiLocations.toString()); + } + + protected Resource findOsgiboot(Bundle bundle) { + String location = bundle.getLocation(); + if (location.startsWith("initial@reference:file:")) + location = System.getProperty("osgi.install.area") + "/../" + + location.substring("initial@reference:file:".length()); + if (location.charAt(location.length() - 1) == '/') + location.substring(0, location.length() - 1); + return asResource(location); + } + + protected Resource asResource(String location) { + Resource res = resourceLoader.getResource(location); + if (log.isDebugEnabled()) + log.debug("Converted " + location + " to " + res); + return res; + } + + public void setBundleContext(BundleContext bundleContext) { + this.bundleContext = bundleContext; + } + + public void setResourceLoader(ResourceLoader resourceLoader) { + this.resourceLoader = resourceLoader; + } + + public void setOsgibootBundleName(String osgibootBundleName) { + this.osgibootBundleName = osgibootBundleName; + } + + public void setXmlapisBundleName(String xmlapisBundleName) { + this.xmlapisBundleName = xmlapisBundleName; + } + + public void setXercesBundleName(String xercesBundleName) { + this.xercesBundleName = xercesBundleName; + } + + public void setOsgiFramework(Resource osgiFramework) { + this.osgiFramework = osgiFramework; + } + + public void setEquinoxBundleName(String equinoxBundleName) { + this.equinoxBundleName = equinoxBundleName; + } + + public void setPrependXmlJars(Boolean prependXmlJars) { + this.prependXmlJars = prependXmlJars; + } + +} diff --git a/runtime/org.argeo.slc.osgiboot/src/main/java/org/argeo/slc/osgiboot/Activator.java b/runtime/org.argeo.slc.osgiboot/src/main/java/org/argeo/slc/osgiboot/Activator.java index 0945ca719..80ec7b7f2 100644 --- a/runtime/org.argeo.slc.osgiboot/src/main/java/org/argeo/slc/osgiboot/Activator.java +++ b/runtime/org.argeo.slc.osgiboot/src/main/java/org/argeo/slc/osgiboot/Activator.java @@ -3,21 +3,27 @@ package org.argeo.slc.osgiboot; import org.osgi.framework.BundleActivator; import org.osgi.framework.BundleContext; +/** + * An OSGi configurator. See http: + * //wiki.eclipse.org/Configurator + */ public class Activator implements BundleActivator { public void start(BundleContext bundleContext) throws Exception { - try { - OsgiBoot.info("SLC OSGi bootstrap starting..."); - OsgiBoot osgiBoot = new OsgiBoot(bundleContext); - osgiBoot.installUrls(osgiBoot.getBundlesUrls()); - osgiBoot.installUrls(osgiBoot.getLocationsUrls()); - osgiBoot.installUrls(osgiBoot.getModulesUrls()); - osgiBoot.startBundles(); - OsgiBoot.info("SLC OSGi bootstrap completed"); - } catch (Exception e) { - e.printStackTrace(); - throw e; - } + OsgiBoot osgiBoot = new OsgiBoot(bundleContext); + osgiBoot.bootstrap(); +// try { +// OsgiBoot.info("SLC OSGi bootstrap starting..."); +// osgiBoot.installUrls(osgiBoot.getBundlesUrls()); +// osgiBoot.installUrls(osgiBoot.getLocationsUrls()); +// osgiBoot.installUrls(osgiBoot.getModulesUrls()); +// osgiBoot.startBundles(); +// OsgiBoot.info("SLC OSGi bootstrap completed"); +// } catch (Exception e) { +// e.printStackTrace(); +// throw e; +// } } public void stop(BundleContext context) throws Exception { diff --git a/runtime/org.argeo.slc.osgiboot/src/main/java/org/argeo/slc/osgiboot/Launcher.java b/runtime/org.argeo.slc.osgiboot/src/main/java/org/argeo/slc/osgiboot/Launcher.java new file mode 100644 index 000000000..8116b71f3 --- /dev/null +++ b/runtime/org.argeo.slc.osgiboot/src/main/java/org/argeo/slc/osgiboot/Launcher.java @@ -0,0 +1,111 @@ +package org.argeo.slc.osgiboot; + +import java.lang.reflect.Method; +import java.util.List; +import java.util.Properties; +import java.util.Vector; + +import org.eclipse.core.runtime.adaptor.EclipseStarter; +import org.osgi.framework.BundleContext; + +public class Launcher { + + public static void main(String[] args) { + startMainClass(); + + BundleContext bundleContext = null; + try { + bundleContext = EclipseStarter.startup(args, null); + } catch (Exception e) { + throw new RuntimeException("Cannot start Equinox.", e); + } + + OsgiBoot osgiBoot = new OsgiBoot(bundleContext); + osgiBoot.bootstrap(); + } +// +// protected static void startEquinox(Properties config) throws Exception { +// info("java.home=" + System.getProperty("java.home")); +// info("java.class.path=" + System.getProperty("java.class.path")); +// +// File baseDir = new File(System.getProperty("user.dir")) +// .getCanonicalFile(); +// String equinoxConfigurationPath = baseDir.getPath() + File.separator +// + "slc-detached" + File.separator + "equinoxConfiguration"; +// +// String equinoxArgsLineDefault = "-console -noExit -clean -debug -configuration " +// + equinoxConfigurationPath; +// String equinoxArgsLine = config.getProperty(PROP_SLC_OSGI_EQUINOX_ARGS, +// equinoxArgsLineDefault); +// // String[] equinoxArgs = { "-console", "-noExit", "-clean", "-debug", +// // "-configuration", equinoxConfigurationPath }; +// String[] equinoxArgs = equinoxArgsLine.split(" "); +// +// BundleContext context = EclipseStarter.startup(equinoxArgs, null); +// } + + protected static void startMainClass() { + Properties config = System.getProperties(); + String className = config.getProperty("slc.detached.appclass"); + String[] uiArgs = readArgumentsFromLine(config.getProperty( + "slc.detached.appargs", "")); + try { + // Launch main method using reflection + Class clss = Class.forName(className); + Class[] mainArgsClasses = new Class[] { uiArgs.getClass() }; + Object[] mainArgs = { uiArgs }; + Method mainMethod = clss.getMethod("main", mainArgsClasses); + mainMethod.invoke(null, mainArgs); + } catch (Exception e) { + throw new RuntimeException("Cannot start main class.", e); + } + + } + + /** + * Transform a line into an array of arguments, taking "" as single + * arguments. (nested \" are not supported) + */ + private static String[] readArgumentsFromLine(String lineOrig) { + + String line = lineOrig.trim();// remove trailing spaces + // System.out.println("line=" + line); + List args = new Vector(); + StringBuffer curr = new StringBuffer(""); + boolean inQuote = false; + char[] arr = line.toCharArray(); + for (int i = 0; i < arr.length; i++) { + char c = arr[i]; + switch (c) { + case '\"': + inQuote = !inQuote; + break; + case ' ': + if (!inQuote) {// otherwise, no break: goes to default + if (curr.length() > 0) { + args.add(curr.toString()); + curr = new StringBuffer(""); + } + break; + } + default: + curr.append(c); + break; + } + } + + // Add last arg + if (curr.length() > 0) { + args.add(curr.toString()); + curr = null; + } + + String[] res = new String[args.size()]; + for (int i = 0; i < args.size(); i++) { + res[i] = args.get(i).toString(); + // System.out.println("res[i]=" + res[i]); + } + return res; + } + +} diff --git a/runtime/org.argeo.slc.osgiboot/src/main/java/org/argeo/slc/osgiboot/OsgiBoot.java b/runtime/org.argeo.slc.osgiboot/src/main/java/org/argeo/slc/osgiboot/OsgiBoot.java index dd2b1b691..fcefc8345 100644 --- a/runtime/org.argeo.slc.osgiboot/src/main/java/org/argeo/slc/osgiboot/OsgiBoot.java +++ b/runtime/org.argeo.slc.osgiboot/src/main/java/org/argeo/slc/osgiboot/OsgiBoot.java @@ -45,6 +45,15 @@ public class OsgiBoot { this.bundleContext = bundleContext; } + public void bootstrap() { + info("SLC OSGi bootstrap starting..."); + installUrls(getBundlesUrls()); + installUrls(getLocationsUrls()); + installUrls(getModulesUrls()); + startBundles(); + info("SLC OSGi bootstrap completed"); + } + public void installUrls(List urls) { Map installedBundles = getInstalledBundles(); for (int i = 0; i < urls.size(); i++) { @@ -109,12 +118,12 @@ public class OsgiBoot { } - public void startBundles() throws Exception { + public void startBundles() { String bundlesToStart = getProperty(PROP_SLC_OSGI_START); startBundles(bundlesToStart); } - public void startBundles(String bundlesToStartStr) throws Exception { + public void startBundles(String bundlesToStartStr) { if (bundlesToStartStr == null) return; @@ -127,7 +136,7 @@ public class OsgiBoot { startBundles(bundlesToStart); } - public void startBundles(List bundlesToStart) throws Exception { + public void startBundles(List bundlesToStart) { if (bundlesToStart.size() == 0) return; @@ -299,7 +308,7 @@ public class OsgiBoot { StringTokenizer st = new StringTokenizer(bundleLocations, File.pathSeparator); while (st.hasMoreTokens()) { - urls.add(baseUrl + st.nextToken().trim()); + urls.add(locationToUrl(baseUrl, st.nextToken().trim())); } return urls; } @@ -349,7 +358,7 @@ public class OsgiBoot { for (int i = 0; i < included.size(); i++) { String fullPath = (String) included.get(i); if (!excluded.contains(fullPath)) - urls.add(baseUrl + fullPath); + urls.add(locationToUrl(baseUrl, fullPath)); } return urls; @@ -419,6 +428,18 @@ public class OsgiBoot { } } + protected String locationToUrl(String baseUrl, String location) { + int extInd = location.lastIndexOf('.'); + String ext = null; + if (extInd > 0) + ext = location.substring(extInd); + + if (baseUrl.startsWith("reference:") && ".jar".equals(ext)) + return "file:" + location; + else + return baseUrl + location; + } + /** Transforms a relative path in a full system path. */ protected String relativeToFullPath(String basePath, String relativePath) { return (basePath + '/' + relativePath).replace('/', File.separatorChar);