]> git.argeo.org Git - gpl/argeo-slc.git/blobdiff - runtime/org.argeo.slc.detached/src/main/java/org/argeo/slc/detached/admin/MinimalBundlesManager.java
Improve detached
[gpl/argeo-slc.git] / runtime / org.argeo.slc.detached / src / main / java / org / argeo / slc / detached / admin / MinimalBundlesManager.java
diff --git a/runtime/org.argeo.slc.detached/src/main/java/org/argeo/slc/detached/admin/MinimalBundlesManager.java b/runtime/org.argeo.slc.detached/src/main/java/org/argeo/slc/detached/admin/MinimalBundlesManager.java
new file mode 100644 (file)
index 0000000..602fe15
--- /dev/null
@@ -0,0 +1,258 @@
+package org.argeo.slc.detached.admin;
+
+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;
+
+/**
+ * Wraps low-level access to a {@link BundleContext}. Hacked from the related
+ * class in org.argeo.slc.support.osgi.
+ */
+class MinimalBundlesManager implements FrameworkListener {
+       private final BundleContext bundleContext;
+
+       private long defaultTimeout = 10000l;
+       private final Object refreshedPackageSem = new Object();
+
+       private boolean debug = true;
+
+       public MinimalBundlesManager(BundleContext bundleContext) {
+               this.bundleContext = bundleContext;
+               bundleContext.addFrameworkListener(this);
+       }
+
+       protected void finalize() throws Throwable {
+               bundleContext.removeFrameworkListener(this);
+       }
+
+       /**
+        * Stop the module, update it, refresh it and restart it. All synchronously.
+        */
+       public void upgradeSynchronous(Bundle bundle) {
+               try {
+                       stopSynchronous(bundle);
+                       updateSynchronous(bundle);
+                       // Refresh in case there are fragments
+                       refreshSynchronous(bundle);
+                       startSynchronous(bundle);
+
+                       String filter = "(Bundle-SymbolicName=" + bundle.getSymbolicName()
+                                       + ")";
+                       // Wait for application context to be ready
+                       // TODO: use service tracker
+                       getServiceRefSynchronous(
+                                       "org.springframework.context.ApplicationContext", filter);
+
+                       if (debug)
+                               debug("Bundle " + bundle.getSymbolicName()
+                                               + " ready to be used at latest version.");
+               } catch (Exception e) {
+                       throw new RuntimeException("Cannot update bundle "
+                                       + bundle.getSymbolicName(), e);
+               }
+       }
+
+       /** 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 > defaultTimeout)
+                               throw new RuntimeException("Update of bundle "
+                                               + bundle.getSymbolicName()
+                                               + " timed out. Bundle state = " + bundle.getState());
+               } while (waiting);
+
+               if (debug)
+                       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 > defaultTimeout)
+                               throw new RuntimeException("Start of bundle "
+                                               + bundle.getSymbolicName()
+                                               + " timed out. Bundle state = " + bundle.getState());
+               } while (waiting);
+
+               if (debug)
+                       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 > defaultTimeout)
+                               throw new RuntimeException("Stop of bundle "
+                                               + bundle.getSymbolicName()
+                                               + " timed out. Bundle state = " + bundle.getState());
+               } while (waiting);
+
+               if (debug)
+                       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(defaultTimeout);
+                       } catch (InterruptedException e) {
+                               // silent
+                       }
+               }
+
+               if (debug)
+                       debug("Bundle " + bundle.getSymbolicName() + " refreshed.");
+       }
+
+       public void frameworkEvent(FrameworkEvent event) {
+               if (event.getType() == FrameworkEvent.PACKAGES_REFRESHED) {
+                       synchronized (refreshedPackageSem) {
+                               refreshedPackageSem.notifyAll();
+                       }
+               }
+       }
+
+       public ServiceReference[] getServiceRefSynchronous(String clss,
+                       String filter) throws InvalidSyntaxException {
+               if (debug)
+                       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 > defaultTimeout)
+                               throw new RuntimeException("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 ServiceTracker newTracker(Class<?> clss) { ServiceTracker st = new
+        * ServiceTracker(bundleContext, clss.getName(), null); st.open(); return
+        * st; }
+        * 
+        * @SuppressWarnings(value = { "unchecked" }) public <T> T
+        * getSingleService(Class<T> clss, String filter) {
+        * Assert.isTrue(OsgiFilterUtils.isValidFilter(filter), "valid filter");
+        * ServiceReference[] sfs; try { sfs =
+        * bundleContext.getServiceReferences(clss.getName(), filter); } catch
+        * (InvalidSyntaxException e) { throw new
+        * SlcException("Cannot retrieve service reference for " + filter, e); }
+        * 
+        * if (sfs == null || sfs.length == 0) return null; else if (sfs.length > 1)
+        * throw new SlcException("More than one execution flow found for " +
+        * filter); return (T) bundleContext.getService(sfs[0]); }
+        * 
+        * public <T> T getSingleServiceStrict(Class<T> clss, String filter) { T
+        * service = getSingleService(clss, filter); if (service == null) throw new
+        * SlcException("No execution flow found for " + filter); else return
+        * service; }
+        * 
+        * public Bundle findRelatedBundle(OsgiBundle osgiBundle) { Bundle bundle =
+        * null; if (osgiBundle.getInternalBundleId() != null) { bundle =
+        * bundleContext.getBundle(osgiBundle.getInternalBundleId()); Assert.isTrue(
+        * osgiBundle.getName().equals(bundle.getSymbolicName()),
+        * "symbolic name consistent");
+        * Assert.isTrue(osgiBundle.getVersion().equals(
+        * bundle.getHeaders().get(Constants.BUNDLE_VERSION)),
+        * "version consistent"); } else { for (Bundle b :
+        * bundleContext.getBundles()) { if
+        * (b.getSymbolicName().equals(osgiBundle.getName())) { if
+        * (b.getHeaders().get(Constants.BUNDLE_VERSION).equals(
+        * osgiBundle.getVersion())) { bundle = b;
+        * osgiBundle.setInternalBundleId(b.getBundleId()); } } } } return bundle; }
+        * 
+        * public OsgiBundle findFromPattern(String pattern) { OsgiBundle osgiBundle
+        * = null; for (Bundle b : bundleContext.getBundles()) { if
+        * (b.getSymbolicName().contains(pattern)) { osgiBundle = new OsgiBundle(b);
+        * break; } } return osgiBundle; }
+        * 
+        * public OsgiBundle getBundle(Long bundleId) { Bundle bundle =
+        * bundleContext.getBundle(bundleId); return new OsgiBundle(bundle); }
+        * 
+        * public void setBundleContext(BundleContext bundleContext) {
+        * this.bundleContext = bundleContext; }
+        * 
+        * public void afterPropertiesSet() throws Exception {
+        * bundleContext.addFrameworkListener(this); }
+        * 
+        * public void setDefaultTimeout(Long defaultTimeout) { this.defaultTimeout
+        * = defaultTimeout; }
+        * 
+        * BundleContext getBundleContext() { return bundleContext; }
+        */
+
+       protected void debug(Object obj) {
+               if (debug)
+                       System.out.println("#OSGiMANAGER DEBUG# " + obj);
+       }
+
+       protected void sleep(long ms) {
+               try {
+                       Thread.sleep(ms);
+               } catch (InterruptedException e) {
+                       // silent
+               }
+       }
+
+}