]> git.argeo.org Git - gpl/argeo-slc.git/blobdiff - runtime/org.argeo.slc.support.osgi/src/main/java/org/argeo/slc/osgi/BundlesManager.java
Flow XSD documentation.
[gpl/argeo-slc.git] / runtime / org.argeo.slc.support.osgi / src / main / java / org / argeo / slc / osgi / BundlesManager.java
index 6d1c79faf17d7da5ee0d861e072837f069e1aabd..e24b7223b7736299125d5aae7f6ddd29b5a4d0f6 100644 (file)
@@ -13,21 +13,31 @@ import org.osgi.framework.InvalidSyntaxException;
 import org.osgi.framework.ServiceReference;
 import org.osgi.service.packageadmin.PackageAdmin;
 import org.osgi.util.tracker.ServiceTracker;
+import org.springframework.beans.factory.DisposableBean;
 import org.springframework.beans.factory.InitializingBean;
 import org.springframework.context.ApplicationContext;
 import org.springframework.osgi.context.BundleContextAware;
+import org.springframework.osgi.context.event.OsgiBundleApplicationContextEvent;
+import org.springframework.osgi.context.event.OsgiBundleApplicationContextListener;
+import org.springframework.osgi.context.event.OsgiBundleContextClosedEvent;
+import org.springframework.osgi.context.event.OsgiBundleContextFailedEvent;
+import org.springframework.osgi.context.event.OsgiBundleContextRefreshedEvent;
 import org.springframework.osgi.util.OsgiFilterUtils;
 import org.springframework.util.Assert;
 
 /** Wraps low-level access to a {@link BundleContext} */
 public class BundlesManager implements BundleContextAware, FrameworkListener,
-               InitializingBean {
+               InitializingBean, DisposableBean, OsgiBundleApplicationContextListener {
        private final static Log log = LogFactory.getLog(BundlesManager.class);
 
        private BundleContext bundleContext;
 
        private Long defaultTimeout = 10000l;
+       private Long pollingPeriod = 100l;
+
+       // Refresh sync objects
        private final Object refreshedPackageSem = new Object();
+       private Boolean packagesRefreshed = false;
 
        /**
         * Stop the module, update it, refresh it and restart it. All synchronously.
@@ -35,21 +45,68 @@ public class BundlesManager implements BundleContextAware, FrameworkListener,
        public void upgradeSynchronous(OsgiBundle osgiBundle) {
                try {
                        Bundle bundle = findRelatedBundle(osgiBundle);
+
+                       long begin = System.currentTimeMillis();
+
+                       long bStop = begin;
                        stopSynchronous(bundle);
+
+                       long bUpdate = System.currentTimeMillis();
                        updateSynchronous(bundle);
+
                        // Refresh in case there are fragments
+                       long bRefresh = System.currentTimeMillis();
                        refreshSynchronous(bundle);
+
+                       long bStart = System.currentTimeMillis();
                        startSynchronous(bundle);
 
+                       long aStart = System.currentTimeMillis();
+                       if (log.isDebugEnabled()) {
+                               log.debug("OSGi upgrade performed in " + (aStart - begin)
+                                               + "ms for bundle " + osgiBundle);
+                               log.debug(" stop \t: " + (bUpdate - bStop) + "ms");
+                               log.debug(" update\t: " + (bRefresh - bUpdate) + "ms");
+                               log.debug(" refresh\t: " + (bStart - bRefresh) + "ms");
+                               log.debug(" start\t: " + (aStart - bStart) + "ms");
+                               log.debug(" TOTAL\t: " + (aStart - begin) + "ms");
+                       }
+
+                       long bAppContext = System.currentTimeMillis();
                        String filter = "(Bundle-SymbolicName=" + bundle.getSymbolicName()
                                        + ")";
                        // Wait for application context to be ready
                        // TODO: use service tracker
-                       getServiceRefSynchronous(ApplicationContext.class.getName(), filter);
+                       ServiceReference[] srs = getServiceRefSynchronous(
+                                       ApplicationContext.class.getName(), filter);
+                       ServiceReference sr = srs[0];
+                       long aAppContext = System.currentTimeMillis();
+                       long end = aAppContext;
+
+                       if (log.isDebugEnabled()) {
+                               log.debug("Application context refresh performed in "
+                                               + (aAppContext - bAppContext) + "ms for bundle "
+                                               + osgiBundle);
+                               log.debug(" TOTAL\t: " + (aAppContext - bAppContext) + "ms");
+                       }
 
-                       if (log.isDebugEnabled())
+                       if (log.isDebugEnabled()) {
                                log.debug("Bundle " + bundle.getSymbolicName()
-                                               + " ready to be used at latest version.");
+                                               + " ready to be used at latest version."
+                                               + " (upgrade performed in " + (end - begin) + "ms).");
+                               log.debug(" TOTAL\t: " + (end - begin) + "ms");
+
+                               ApplicationContext applicationContext = (ApplicationContext) bundleContext
+                                               .getService(sr);
+                               int beanDefCount = applicationContext.getBeanDefinitionCount();
+                               log.debug(" " + beanDefCount + " beans in app context of "
+                                               + bundle.getSymbolicName()
+                                               + ", average init time per bean=" + (end - begin)
+                                               / beanDefCount + "ms");
+                       }
+
+                       bundleContext.ungetService(sr);
+
                } catch (Exception e) {
                        throw new SlcException("Cannot update bundle " + osgiBundle, e);
                }
@@ -57,7 +114,6 @@ public class BundlesManager implements BundleContextAware, FrameworkListener,
 
        /** Updates bundle synchronously. */
        protected void updateSynchronous(Bundle bundle) throws BundleException {
-               // int originalState = bundle.getState();
                bundle.update();
                boolean waiting = true;
 
@@ -68,11 +124,9 @@ public class BundlesManager implements BundleContextAware, FrameworkListener,
                                        || state == Bundle.RESOLVED)
                                waiting = false;
 
-                       sleep(100);
-                       if (System.currentTimeMillis() - begin > defaultTimeout)
-                               throw new SlcException("Update of bundle "
-                                               + bundle.getSymbolicName()
-                                               + " timed out. Bundle state = " + bundle.getState());
+                       sleepWhenPolling();
+                       checkTimeout(begin, "Update of bundle " + bundle.getSymbolicName()
+                                       + " timed out. Bundle state = " + bundle.getState());
                } while (waiting);
 
                if (log.isTraceEnabled())
@@ -93,11 +147,9 @@ public class BundlesManager implements BundleContextAware, FrameworkListener,
                        if (bundle.getState() == Bundle.ACTIVE)
                                waiting = false;
 
-                       sleep(100);
-                       if (System.currentTimeMillis() - begin > defaultTimeout)
-                               throw new SlcException("Start of bundle "
-                                               + bundle.getSymbolicName()
-                                               + " timed out. Bundle state = " + bundle.getState());
+                       sleepWhenPolling();
+                       checkTimeout(begin, "Start of bundle " + bundle.getSymbolicName()
+                                       + " timed out. Bundle state = " + bundle.getState());
                } while (waiting);
 
                if (log.isTraceEnabled())
@@ -119,11 +171,9 @@ public class BundlesManager implements BundleContextAware, FrameworkListener,
                                        && bundle.getState() != Bundle.STOPPING)
                                waiting = false;
 
-                       sleep(100);
-                       if (System.currentTimeMillis() - begin > defaultTimeout)
-                               throw new SlcException("Stop of bundle "
-                                               + bundle.getSymbolicName()
-                                               + " timed out. Bundle state = " + bundle.getState());
+                       sleepWhenPolling();
+                       checkTimeout(begin, "Stop of bundle " + bundle.getSymbolicName()
+                                       + " timed out. Bundle state = " + bundle.getState());
                } while (waiting);
 
                if (log.isTraceEnabled())
@@ -137,14 +187,23 @@ public class BundlesManager implements BundleContextAware, FrameworkListener,
                PackageAdmin packageAdmin = (PackageAdmin) bundleContext
                                .getService(packageAdminRef);
                Bundle[] bundles = { bundle };
-               packageAdmin.refreshPackages(bundles);
 
+               long begin = System.currentTimeMillis();
                synchronized (refreshedPackageSem) {
+                       packagesRefreshed = false;
+                       packageAdmin.refreshPackages(bundles);
                        try {
                                refreshedPackageSem.wait(defaultTimeout);
                        } catch (InterruptedException e) {
                                // silent
                        }
+                       if (!packagesRefreshed) {
+                               long now = System.currentTimeMillis();
+                               throw new SlcException("Packages not refreshed after "
+                                               + (now - begin) + "ms");
+                       } else {
+                               packagesRefreshed = false;
+                       }
                }
 
                if (log.isTraceEnabled())
@@ -154,6 +213,7 @@ public class BundlesManager implements BundleContextAware, FrameworkListener,
        public void frameworkEvent(FrameworkEvent event) {
                if (event.getType() == FrameworkEvent.PACKAGES_REFRESHED) {
                        synchronized (refreshedPackageSem) {
+                               packagesRefreshed = true;
                                refreshedPackageSem.notifyAll();
                        }
                }
@@ -172,18 +232,25 @@ public class BundlesManager implements BundleContextAware, FrameworkListener,
                        if (sfs != null)
                                waiting = false;
 
-                       sleep(100);
-                       if (System.currentTimeMillis() - begin > defaultTimeout)
-                               throw new SlcException("Search of services " + clss
-                                               + " with filter " + filter + " timed out.");
+                       sleepWhenPolling();
+                       checkTimeout(begin, "Search of services " + clss + " with filter "
+                                       + filter + " timed out.");
                } while (waiting);
 
                return sfs;
        }
 
-       protected void sleep(long ms) {
+       protected void checkTimeout(long begin, String msg) {
+               long now = System.currentTimeMillis();
+               if (now - begin > defaultTimeout)
+                       throw new SlcException(msg + " (timeout after " + (now - begin)
+                                       + "ms)");
+
+       }
+
+       protected void sleepWhenPolling() {
                try {
-                       Thread.sleep(ms);
+                       Thread.sleep(pollingPeriod);
                } catch (InterruptedException e) {
                        // silent
                }
@@ -232,16 +299,23 @@ public class BundlesManager implements BundleContextAware, FrameworkListener,
                        Assert.isTrue(
                                        osgiBundle.getName().equals(bundle.getSymbolicName()),
                                        "symbolic name consistent");
-                       Assert.isTrue(osgiBundle.getVersion().equals(
-                                       bundle.getHeaders().get(Constants.BUNDLE_VERSION)),
-                                       "version consistent");
+                       if (osgiBundle.getVersion() != null)
+                               Assert.isTrue(osgiBundle.getVersion().equals(
+                                               bundle.getHeaders().get(Constants.BUNDLE_VERSION)),
+                                               "version consistent");
                } else {
-                       for (Bundle b : bundleContext.getBundles()) {
+                       bundles: for (Bundle b : bundleContext.getBundles()) {
                                if (b.getSymbolicName().equals(osgiBundle.getName())) {
+                                       if (osgiBundle.getVersion() == null) {
+                                               bundle = b;
+                                               break bundles;
+                                       }
+
                                        if (b.getHeaders().get(Constants.BUNDLE_VERSION).equals(
                                                        osgiBundle.getVersion())) {
                                                bundle = b;
                                                osgiBundle.setInternalBundleId(b.getBundleId());
+                                               break bundles;
                                        }
                                }
                        }
@@ -274,6 +348,10 @@ public class BundlesManager implements BundleContextAware, FrameworkListener,
                bundleContext.addFrameworkListener(this);
        }
 
+       public void destroy() throws Exception {
+               bundleContext.removeFrameworkListener(this);
+       }
+
        public void setDefaultTimeout(Long defaultTimeout) {
                this.defaultTimeout = defaultTimeout;
        }
@@ -283,4 +361,20 @@ public class BundlesManager implements BundleContextAware, FrameworkListener,
                return bundleContext;
        }
 
+       public void setPollingPeriod(Long pollingPeriod) {
+               this.pollingPeriod = pollingPeriod;
+       }
+
+       public void onOsgiApplicationEvent(OsgiBundleApplicationContextEvent event) {
+               if (event instanceof OsgiBundleContextRefreshedEvent) {
+                       log.debug("App context refreshed: " + event);
+               } else if (event instanceof OsgiBundleContextFailedEvent) {
+                       log.debug("App context failed: " + event);
+               }
+               if (event instanceof OsgiBundleContextClosedEvent) {
+                       log.debug("App context closed: " + event);
+               }
+
+       }
+
 }