]> git.argeo.org Git - gpl/argeo-slc.git/commitdiff
Improve OSGi boot
authorMathieu Baudier <mbaudier@argeo.org>
Sat, 4 Apr 2009 20:53:24 +0000 (20:53 +0000)
committerMathieu Baudier <mbaudier@argeo.org>
Sat, 4 Apr 2009 20:53:24 +0000 (20:53 +0000)
git-svn-id: https://svn.argeo.org/slc/trunk@2321 4cfe0d0a-d680-48aa-b62c-e0a02a3f76cc

demo/site/org.argeo.slc.demo.deploy/pom.xml
runtime/org.argeo.slc.osgiboot/src/main/ant/osgiboot.xml
runtime/org.argeo.slc.osgiboot/src/main/java/org/argeo/slc/osgiboot/Activator.java
runtime/org.argeo.slc.support.equinox/src/main/java/org/argeo/slc/equinox/ExecutionCommandProvider.java
runtime/org.argeo.slc.support.equinox/src/main/resources/META-INF/spring/osgi.xml

index 1646d8393d3552e6ebf5cdf4450349f680f82910..26bfa0952fe451c0cded5c3180f15c28effba9b7 100644 (file)
                                <configuration>
                                        <tasks>
                                                <path id="slc.osgi.locations.raw">
+                                               <!-- 
                                                        <dirset dir="${user.dir}/..">
                                                                <include name="*" />
                                                                <exclude name=".svn" />
                                                                <exclude name="*.deploy" />
                                                        </dirset>
+                                                        -->
                                                        <path refid="maven.compile.classpath" />
                                                </path>
                                                <pathconvert dirsep="/" property="slc.osgi.locations"
                                                        refid="slc.osgi.locations.raw" />
 
                                                <property name="slc.osgi.start" value="${bundlesToStart}" />
+                                               <property name="slc.osgi.bundles" value="${user.dir}/..;in=*;ex=.svn;ex=*.deploy;ex=.settings" />
                                                <ant antfile="target/equinox/osgiboot.xml" />
 
                                        </tasks>
                        <groupId>org.argeo.slc.runtime</groupId>
                        <artifactId>org.argeo.slc.support.equinox</artifactId>
                </dependency>
-
                <dependency>
                        <groupId>org.argeo.slc.demo</groupId>
                        <artifactId>org.argeo.slc.demo.basic</artifactId>
index 99d9d5787e63f356eb5c2bd7a8d46ef5c1e214d3..0abc7bfb8ef5bcf9be8fef3ca68dfea3cc95904b 100644 (file)
@@ -36,6 +36,7 @@ osgi.bundles=reference:file:${osgiBootBundle}@start
 
                <addProperty name="slc.osgi.locations" />
                <addProperty name="slc.osgi.start" />
+               <addProperty name="slc.osgi.bundles" />
                <addProperty name="slc.osgi.devBases" />
                <addProperty name="slc.osgi.devPatterns" />
                <addProperty name="slc.maven.dependencyFile" />
index 0051c1b91264494ce15d5aee52700fb0a12b8c50..56bcff5a6f242d231c0069e2a4358592dad69063 100644 (file)
@@ -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<String> urls = getMavenUrls();
                        installUrls(bundleContext, urls);
@@ -129,6 +132,95 @@ public class Activator implements BundleActivator {
                return urls;
        }
 
+       protected List<String> getBundlesUrls() {
+               List<String> urls = new ArrayList<String>();
+
+               List<BundlesSet> bundlesSets = new ArrayList<BundlesSet>();
+               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<String> included = new ArrayList<String>();
+               PathMatcher matcher = new AntPathMatcher();
+               for (BundlesSet bundlesSet : bundlesSets)
+                       for (String pattern : bundlesSet.getIncludes())
+                               match(matcher, included, bundlesSet.getDir(), null, pattern);
+
+               List<String> excluded = new ArrayList<String>();
+               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<String> includes = new ArrayList<String>();
+               private List<String> excludes = new ArrayList<String>();
+
+               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<String> getIncludes() {
+                       return includes;
+               }
+
+               public List<String> getExcludes() {
+                       return excludes;
+               }
+
+               public String getBaseUrl() {
+                       return baseUrl;
+               }
+
+       }
+
        protected void match(PathMatcher matcher, List<String> 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.");
index ae064f65274a60fbf402a31a7c807215d3c2efb7..f8e02ad0217d8e0f89e69459db18915e32040d9b 100644 (file)
@@ -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<ExecutionModule> 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<ExecutionModule> 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 (<id>|<segment of bsn>) <execution bean>  - execute an execution flow\n");
+                               .append("\tslc (<id>|<segment of bsn>) <execution bean>  - execute an execution flow (without arg, execute last)\n");
                return buf.toString();
 
        }
 
-       public void setExecutionModules(List<ExecutionModule> 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);
+       }
+
 }
index 606cb2a510f2fc22242db33921b37d3cf58e7b24..609e8e5df095a2429cece2f6eeefb93f780860f5 100644 (file)
@@ -7,10 +7,6 @@
        http://www.springframework.org/schema/beans/spring-beans-2.5.xsd">\r
 \r
        <service interface="org.eclipse.osgi.framework.console.CommandProvider">\r
-               <beans:bean class="org.argeo.slc.equinox.ExecutionCommandProvider">\r
-                       <beans:property name="executionModules" ref="executionModules" />\r
-               </beans:bean>\r
+               <beans:bean class="org.argeo.slc.equinox.ExecutionCommandProvider" />\r
        </service>\r
-\r
-       <list id="executionModules" interface="org.argeo.slc.execution.ExecutionModule" cardinality="0..N"/>\r
 </beans:beans>
\ No newline at end of file