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 * getSingleService(Class 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 getSingleServiceStrict(Class 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 } } }