From a9c8741503194937709bdef6b5a7a1a89afcf938 Mon Sep 17 00:00:00 2001 From: Mathieu Baudier Date: Sat, 4 Apr 2009 20:53:24 +0000 Subject: [PATCH] Improve OSGi boot git-svn-id: https://svn.argeo.org/slc/trunk@2321 4cfe0d0a-d680-48aa-b62c-e0a02a3f76cc --- demo/site/org.argeo.slc.demo.deploy/pom.xml | 4 +- .../src/main/ant/osgiboot.xml | 1 + .../org/argeo/slc/osgiboot/Activator.java | 137 ++++++++-- .../slc/equinox/ExecutionCommandProvider.java | 257 +++++++++++++++--- .../main/resources/META-INF/spring/osgi.xml | 6 +- 5 files changed, 334 insertions(+), 71 deletions(-) diff --git a/demo/site/org.argeo.slc.demo.deploy/pom.xml b/demo/site/org.argeo.slc.demo.deploy/pom.xml index 1646d8393..26bfa0952 100644 --- a/demo/site/org.argeo.slc.demo.deploy/pom.xml +++ b/demo/site/org.argeo.slc.demo.deploy/pom.xml @@ -51,17 +51,20 @@ + + @@ -128,7 +131,6 @@ org.argeo.slc.runtime org.argeo.slc.support.equinox - org.argeo.slc.demo org.argeo.slc.demo.basic diff --git a/runtime/org.argeo.slc.osgiboot/src/main/ant/osgiboot.xml b/runtime/org.argeo.slc.osgiboot/src/main/ant/osgiboot.xml index 99d9d5787..0abc7bfb8 100644 --- a/runtime/org.argeo.slc.osgiboot/src/main/ant/osgiboot.xml +++ b/runtime/org.argeo.slc.osgiboot/src/main/ant/osgiboot.xml @@ -36,6 +36,7 @@ osgi.bundles=reference:file:${osgiBootBundle}@start + 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 0051c1b91..56bcff5a6 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,6 +3,7 @@ package org.argeo.slc.osgiboot; import java.io.BufferedReader; import java.io.File; import java.io.FileReader; +import java.io.IOException; import java.util.ArrayList; import java.util.HashMap; import java.util.List; @@ -19,6 +20,7 @@ import org.osgi.framework.BundleException; public class Activator implements BundleActivator { public final static String PROP_SLC_OSGI_START = "slc.osgi.start"; + public final static String PROP_SLC_OSGI_BUNDLES = "slc.osgi.bundles"; public final static String PROP_SLC_OSGI_DEV_BASES = "slc.osgi.devBases"; public final static String PROP_SLC_OSGI_DEV_PATTERNS = "slc.osgi.devPatterns"; public final static String PROP_SLC_OSGI_LOCATIONS = "slc.osgi.locations"; @@ -32,6 +34,7 @@ public class Activator implements BundleActivator { installUrls(bundleContext, getDevLocationsUrls()); installUrls(bundleContext, getLocationsUrls()); + installUrls(bundleContext, getBundlesUrls()); List urls = getMavenUrls(); installUrls(bundleContext, urls); @@ -129,6 +132,95 @@ public class Activator implements BundleActivator { return urls; } + protected List getBundlesUrls() { + List urls = new ArrayList(); + + List bundlesSets = new ArrayList(); + String bundles = getProperty(PROP_SLC_OSGI_BUNDLES); + if (bundles == null) + return urls; + info(PROP_SLC_OSGI_BUNDLES + "=" + bundles); + + StringTokenizer st = new StringTokenizer(bundles, ","); + while (st.hasMoreTokens()) { + bundlesSets.add(new BundlesSet(st.nextToken())); + } + + List included = new ArrayList(); + PathMatcher matcher = new AntPathMatcher(); + for (BundlesSet bundlesSet : bundlesSets) + for (String pattern : bundlesSet.getIncludes()) + match(matcher, included, bundlesSet.getDir(), null, pattern); + + List excluded = new ArrayList(); + for (BundlesSet bundlesSet : bundlesSets) + for (String pattern : bundlesSet.getExcludes()) + match(matcher, excluded, bundlesSet.getDir(), null, pattern); + + for (String fullPath : included) { + if (!excluded.contains(fullPath)) + urls.add("reference:file:" + fullPath); + } + + return urls; + } + + private class BundlesSet { + private String baseUrl = "reference:file"; + private final String dir; + private List includes = new ArrayList(); + private List excludes = new ArrayList(); + + public BundlesSet(String def) { + StringTokenizer st = new StringTokenizer(def, ";"); + + if (!st.hasMoreTokens()) + throw new RuntimeException("Base dir not defined."); + try { + String dirPath = st.nextToken(); + dir = new File(dirPath.replace('/', File.separatorChar)) + .getCanonicalPath(); + if (debug) + debug("Base dir: " + dir); + } catch (IOException e) { + throw new RuntimeException("Cannot convert to absolute path", e); + } + + while (st.hasMoreTokens()) { + String tk = st.nextToken(); + StringTokenizer stEq = new StringTokenizer(tk, "="); + String type = stEq.nextToken(); + String pattern = stEq.nextToken(); + if ("in".equals(type) || "include".equals(type)) { + includes.add(pattern); + } else if ("ex".equals(type) || "exclude".equals(type)) { + excludes.add(pattern); + } else if ("baseUrl".equals(type)) { + baseUrl = pattern; + } else { + System.err.println("Unkown bundles pattern type " + type); + } + } + } + + public String getDir() { + return dir; + } + + public List getIncludes() { + return includes; + } + + public List getExcludes() { + return excludes; + } + + public String getBaseUrl() { + return baseUrl; + } + + } + protected void match(PathMatcher matcher, List matched, String base, String currentPath, String pattern) { if (currentPath == null) { @@ -144,10 +236,9 @@ public class Activator implements BundleActivator { } for (File file : files) - if (file.isDirectory()) match(matcher, matched, base, file.getName(), pattern); } else { - String fullPath = base + currentPath; + String fullPath = base + '/' + currentPath; if (matched.contains(fullPath)) return;// don't try deeper if already matched @@ -159,24 +250,29 @@ public class Activator implements BundleActivator { matched.add(fullPath); return; } else { - File[] files = new File((base + currentPath).replace('/', - File.separatorChar)).listFiles(); - for (File file : files) - if (file.isDirectory()) { - String newCurrentPath = currentPath + '/' - + file.getName(); - if (matcher.matchStart(pattern, newCurrentPath)) { - // recurse only if start matches - match(matcher, matched, base, newCurrentPath, - pattern); - } else { - if (debug) - debug(newCurrentPath - + " does not start match with " - + pattern); - + String newFullPath = (base + '/' + currentPath).replace('/', + File.separatorChar); + File[] files = new File(newFullPath).listFiles(); + if (files != null) { + for (File file : files) + if (file.isDirectory()) { + String newCurrentPath = currentPath + '/' + + file.getName(); + if (matcher.matchStart(pattern, newCurrentPath)) { + // recurse only if start matches + match(matcher, matched, base, newCurrentPath, + pattern); + } else { + if (debug) + debug(newCurrentPath + + " does not start match with " + + pattern); + + } } - } + } else { + warn("Not a directory: " + newFullPath); + } } } } @@ -222,7 +318,8 @@ public class Activator implements BundleActivator { try { bundle.start(); } catch (Exception e) { - warn("Bundle " + name + " cannot be started: " + e.getMessage()); + warn("Bundle " + name + " cannot be started: " + + e.getMessage()); } else warn("Bundle " + name + " not installed."); diff --git a/runtime/org.argeo.slc.support.equinox/src/main/java/org/argeo/slc/equinox/ExecutionCommandProvider.java b/runtime/org.argeo.slc.support.equinox/src/main/java/org/argeo/slc/equinox/ExecutionCommandProvider.java index ae064f652..f8e02ad02 100644 --- a/runtime/org.argeo.slc.support.equinox/src/main/java/org/argeo/slc/equinox/ExecutionCommandProvider.java +++ b/runtime/org.argeo.slc.support.equinox/src/main/java/org/argeo/slc/equinox/ExecutionCommandProvider.java @@ -1,9 +1,5 @@ package org.argeo.slc.equinox; -import java.util.ArrayList; -import java.util.Iterator; -import java.util.List; - import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.argeo.slc.SlcException; @@ -14,23 +10,51 @@ import org.eclipse.osgi.framework.console.CommandProvider; import org.osgi.framework.Bundle; import org.osgi.framework.BundleContext; import org.osgi.framework.BundleException; +import org.osgi.framework.FrameworkEvent; +import org.osgi.framework.FrameworkListener; +import org.osgi.framework.InvalidSyntaxException; import org.osgi.framework.ServiceReference; +import org.osgi.service.packageadmin.PackageAdmin; +import org.springframework.beans.factory.InitializingBean; +import org.springframework.context.ApplicationContext; import org.springframework.osgi.context.BundleContextAware; public class ExecutionCommandProvider implements CommandProvider, - BundleContextAware { + BundleContextAware, FrameworkListener, InitializingBean { private final static Log log = LogFactory .getLog(ExecutionCommandProvider.class); - private List executionModules; private BundleContext bundleContext; + private String lastModuleName = null; + private String lastExecutionName = null; + + private final Object refreshedPackageSem = new Object(); + + /** @deprecated Use slc command instead. */ public Object _slc_exec(CommandInterpreter ci) { + return _slc(ci); + } + + public Object _slc(CommandInterpreter ci) { // TODO: check version String firstArg = ci.nextArgument(); + if (firstArg == null) { + if (lastModuleName != null) { + String cmd = "slc " + lastModuleName + " " + lastExecutionName; + if (log.isDebugEnabled()) + log.debug("Execute again last command: " + cmd); + return ci.execute(cmd); + } else { + ci.execute("help"); + throw new SlcException("Command not properly formatted"); + } + } String executionName = ci.nextArgument(); + String moduleName = null; + // First check whether we have a bundleId Long bundleId = null; try { bundleId = Long.parseLong(firstArg); @@ -38,6 +62,7 @@ public class ExecutionCommandProvider implements CommandProvider, // silent } + // Look for bundle names containing pattern Bundle bundle = null; if (bundleId != null) { bundle = bundleContext.getBundle(bundleId); @@ -52,66 +77,208 @@ public class ExecutionCommandProvider implements CommandProvider, if (bundle != null) { moduleName = bundle.getSymbolicName(); - // try { - // bundle.stop(); - // bundle.update(); - // bundle.start(); - // - // // FIXME: potential infinite loop - // while (bundle.getState() == Bundle.STARTING) { - // try { - // Thread.sleep(500); - // } catch (InterruptedException e) { - // // silent - // } - // } - // } catch (BundleException e) { - // throw new SlcException( - // "Could not update the bundle for module " + moduleName, - // e); - // } + lastModuleName = moduleName; + lastExecutionName = executionName; + } else { + log + .warn("Could not find any execution module matching these requirements."); + return null; } // Find module ExecutionModule module = null; - if (moduleName != null) { - for (Iterator it = executionModules.iterator(); it - .hasNext();) { - ExecutionModule moduleT = it.next(); - if (moduleT.getName().equals(moduleName)) { - module = moduleT; - break; - } + ServiceReference serviceRef = null; + try { + stopSynchronous(bundle); + updateSynchronous(bundle); + // Refresh in case there are fragments + refreshSynchronous(bundle); + startSynchronous(bundle); + + String filter = "(Bundle-SymbolicName=" + moduleName + ")"; + // Wait for application context to be ready + getServiceRefSynchronous(ApplicationContext.class.getName(), filter); + ServiceReference[] sfs = getServiceRefSynchronous( + ExecutionModule.class.getName(), filter); + + if (sfs.length > 1) + log + .warn("More than one execution module service found in module " + + moduleName); + + if (sfs.length > 0) { + serviceRef = sfs[0]; + module = (ExecutionModule) bundleContext.getService(serviceRef); } - } - if (module != null) { - ExecutionFlowDescriptor descriptor = new ExecutionFlowDescriptor(); - descriptor.setName(executionName); - module.execute(descriptor); - log.info("Executed " + executionName + " from " + moduleName); - } else - log - .warn("Could not find any execution module matching these requirements."); + if (module != null) { + ExecutionFlowDescriptor descriptor = new ExecutionFlowDescriptor(); + descriptor.setName(executionName); + module.execute(descriptor); + log.info("Executed " + executionName + " from " + moduleName); + } + + } catch (Exception e) { + throw new SlcException("Cannot find or update module.", e); + } finally { + if (serviceRef != null) + bundleContext.ungetService(serviceRef); + } - return null; + return "COMMAND COMPLETED"; } public String getHelp() { StringBuffer buf = new StringBuffer(); buf.append("---SLC Execution Commands---\n"); buf - .append("\tslc_exec (|) - execute an execution flow\n"); + .append("\tslc (|) - execute an execution flow (without arg, execute last)\n"); return buf.toString(); } - public void setExecutionModules(List executionModules) { - this.executionModules = executionModules; + /** Updates bundle synchronously. */ + protected void updateSynchronous(Bundle bundle) throws BundleException { +// int originalState = bundle.getState(); + bundle.update(); + boolean waiting = true; + + long begin = System.currentTimeMillis(); + do { + int state = bundle.getState(); + if (state == Bundle.INSTALLED || state == Bundle.ACTIVE + || state == Bundle.RESOLVED) + waiting = false; + + sleep(100); + if (System.currentTimeMillis() - begin > 10000) + throw new SlcException("Update of bundle " + + bundle.getSymbolicName() + + " timed out. Bundle state = " + bundle.getState()); + } while (waiting); + + if (log.isDebugEnabled()) + log.debug("Bundle " + bundle.getSymbolicName() + " updated."); + } + + /** Starts bundle synchronously. Does nothing if already started. */ + protected void startSynchronous(Bundle bundle) throws BundleException { + int originalState = bundle.getState(); + if (originalState == Bundle.ACTIVE) + return; + + bundle.start(); + boolean waiting = true; + + long begin = System.currentTimeMillis(); + do { + if (bundle.getState() == Bundle.ACTIVE) + waiting = false; + + sleep(100); + if (System.currentTimeMillis() - begin > 30000) + throw new SlcException("Start of bundle " + + bundle.getSymbolicName() + + " timed out. Bundle state = " + bundle.getState()); + } while (waiting); + + if (log.isDebugEnabled()) + log.debug("Bundle " + bundle.getSymbolicName() + " started."); + } + + /** Stops bundle synchronously. Does nothing if already started. */ + protected void stopSynchronous(Bundle bundle) throws BundleException { + int originalState = bundle.getState(); + if (originalState != Bundle.ACTIVE) + return; + + bundle.stop(); + boolean waiting = true; + + long begin = System.currentTimeMillis(); + do { + if (bundle.getState() != Bundle.ACTIVE + && bundle.getState() != Bundle.STOPPING) + waiting = false; + + sleep(100); + if (System.currentTimeMillis() - begin > 30000) + throw new SlcException("Stop of bundle " + + bundle.getSymbolicName() + + " timed out. Bundle state = " + bundle.getState()); + } while (waiting); + + if (log.isDebugEnabled()) + log.debug("Bundle " + bundle.getSymbolicName() + " stopped."); + } + + /** Refresh bundle synchronously. Does nothing if already started. */ + protected void refreshSynchronous(Bundle bundle) throws BundleException { + ServiceReference packageAdminRef = bundleContext + .getServiceReference(PackageAdmin.class.getName()); + PackageAdmin packageAdmin = (PackageAdmin) bundleContext + .getService(packageAdminRef); + Bundle[] bundles = { bundle }; + packageAdmin.refreshPackages(bundles); + + synchronized (refreshedPackageSem) { + try { + refreshedPackageSem.wait(30000); + log.debug("NOT INTERRUPTED"); + } catch (InterruptedException e) { + log.debug("INTERRUPTED"); + // silent + } + } + + if (log.isDebugEnabled()) + log.debug("Bundle " + bundle.getSymbolicName() + " refreshed."); + } + + public void frameworkEvent(FrameworkEvent event) { + if (event.getType() == FrameworkEvent.PACKAGES_REFRESHED) { + synchronized (refreshedPackageSem) { + refreshedPackageSem.notifyAll(); + } + } + } + + protected ServiceReference[] getServiceRefSynchronous(String clss, + String filter) throws InvalidSyntaxException { + if (log.isTraceEnabled()) + log.debug("Filter: '" + filter + "'"); + ServiceReference[] sfs = null; + boolean waiting = true; + long begin = System.currentTimeMillis(); + do { + sfs = bundleContext.getServiceReferences(clss, filter); + + if (sfs != null) + waiting = false; + + sleep(100); + if (System.currentTimeMillis() - begin > 30000) + throw new SlcException("Search of services " + clss + + " with filter " + filter + " timed out."); + } while (waiting); + + return sfs; + } + + protected void sleep(long ms) { + try { + Thread.sleep(ms); + } catch (InterruptedException e) { + // silent + } } public void setBundleContext(BundleContext bundleContext) { this.bundleContext = bundleContext; } + public void afterPropertiesSet() throws Exception { + bundleContext.addFrameworkListener(this); + } + } diff --git a/runtime/org.argeo.slc.support.equinox/src/main/resources/META-INF/spring/osgi.xml b/runtime/org.argeo.slc.support.equinox/src/main/resources/META-INF/spring/osgi.xml index 606cb2a51..609e8e5df 100644 --- a/runtime/org.argeo.slc.support.equinox/src/main/resources/META-INF/spring/osgi.xml +++ b/runtime/org.argeo.slc.support.equinox/src/main/resources/META-INF/spring/osgi.xml @@ -7,10 +7,6 @@ http://www.springframework.org/schema/beans/spring-beans-2.5.xsd"> - - - + - - \ No newline at end of file -- 2.39.5