X-Git-Url: http://git.argeo.org/?a=blobdiff_plain;ds=sidebyside;f=runtime%2Forg.argeo.slc.support.osgi%2Fsrc%2Fmain%2Fjava%2Forg%2Fargeo%2Fslc%2Fosgi%2FBundlesManager.java;h=e24b7223b7736299125d5aae7f6ddd29b5a4d0f6;hb=44d72c1a645ca69e28ad03d46367cd4a9dde99bd;hp=6d1c79faf17d7da5ee0d861e072837f069e1aabd;hpb=ee6c3543a0ff9403420ce6a9c647723269f14331;p=gpl%2Fargeo-slc.git diff --git a/runtime/org.argeo.slc.support.osgi/src/main/java/org/argeo/slc/osgi/BundlesManager.java b/runtime/org.argeo.slc.support.osgi/src/main/java/org/argeo/slc/osgi/BundlesManager.java index 6d1c79faf..e24b7223b 100644 --- a/runtime/org.argeo.slc.support.osgi/src/main/java/org/argeo/slc/osgi/BundlesManager.java +++ b/runtime/org.argeo.slc.support.osgi/src/main/java/org/argeo/slc/osgi/BundlesManager.java @@ -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); + } + + } + }