X-Git-Url: http://git.argeo.org/?a=blobdiff_plain;f=runtime%2Forg.argeo.slc.support.equinox%2Fsrc%2Fmain%2Fjava%2Forg%2Fargeo%2Fslc%2Fequinox%2FExecutionCommandProvider.java;h=f94ded602504f72f828dea8c7280925bb0873fd7;hb=3f86e5c908d7db1d85e3f12b0798104654a1e12b;hp=ca49e8fdc6b8db7370f79ed26d0343b2d215c5c3;hpb=1f0b304d0a789fff4fec7005a59dedaa40a0b61d;p=gpl%2Fargeo-slc.git diff --git a/runtime/org.argeo.slc.support.equinox/src/main/java/org/argeo/slc/equinox/ExecutionCommandProvider.java b/runtime/org.argeo.slc.support.equinox/src/main/java/org/argeo/slc/equinox/ExecutionCommandProvider.java index ca49e8fdc..f94ded602 100644 --- a/runtime/org.argeo.slc.support.equinox/src/main/java/org/argeo/slc/equinox/ExecutionCommandProvider.java +++ b/runtime/org.argeo.slc.support.equinox/src/main/java/org/argeo/slc/equinox/ExecutionCommandProvider.java @@ -1,47 +1,293 @@ package org.argeo.slc.equinox; -import java.util.List; - +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.argeo.slc.SlcException; +import org.argeo.slc.execution.ExecutionFlowDescriptor; import org.argeo.slc.execution.ExecutionModule; -import org.argeo.slc.process.SlcExecution; import org.eclipse.osgi.framework.console.CommandInterpreter; 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, FrameworkListener, InitializingBean { + private final static Log log = LogFactory + .getLog(ExecutionCommandProvider.class); + + private Long defaultTimeout = 10000l; + + private BundleContext bundleContext; -public class ExecutionCommandProvider implements CommandProvider { - private List executionModules; + private String lastModuleName = null; + private String lastExecutionName = null; - public Object _slc_execute(CommandInterpreter ci) { - String moduleName = ci.nextArgument(); + 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(); - - SlcExecution slcExecution = new SlcExecution(); - slcExecution.getAttributes().put("slc.flows", executionName); + String moduleName = null; + + // First check whether we have a bundleId + Long bundleId = null; + try { + bundleId = Long.parseLong(firstArg); + } catch (NumberFormatException e) { + // silent + } + + // Look for bundle names containing pattern + Bundle bundle = null; + if (bundleId != null) { + bundle = bundleContext.getBundle(bundleId); + } else { + for (Bundle b : bundleContext.getBundles()) { + if (b.getSymbolicName().contains(firstArg)) { + bundle = b; + break; + } + } + } + + if (bundle != null) { + moduleName = bundle.getSymbolicName(); + lastModuleName = moduleName; + lastExecutionName = executionName; + } else { + log + .warn("Could not find any execution module matching these requirements."); + return null; + } + + // Find module ExecutionModule module = null; - for (ExecutionModule moduleT : executionModules) { - if(moduleT.getName().equals(moduleName)){ - // TODO: check version - 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); + + if (log.isDebugEnabled()) + log.debug("Bundle " + bundle.getSymbolicName() + + " ready to be used at latest version."); + + 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); } + + } catch (Exception e) { + throw new SlcException("Cannot find or update module.", e); + } finally { + if (serviceRef != null) + bundleContext.ungetService(serviceRef); } - if(module!=null) - module.execute(slcExecution); - - return null; + return "COMMAND COMPLETED"; } public String getHelp() { StringBuffer buf = new StringBuffer(); buf.append("---SLC Execution Commands---\n"); - buf.append("\tslc_execute - Execute an execution flow\n"); + buf + .append("\tslc (|) - execute an execution flow (without arg, execute last)\n"); return buf.toString(); } - public void setExecutionModules(List 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 > defaultTimeout) + throw new SlcException("Update of bundle " + + bundle.getSymbolicName() + + " timed out. Bundle state = " + bundle.getState()); + } while (waiting); + + if (log.isTraceEnabled()) + 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 > defaultTimeout) + throw new SlcException("Start of bundle " + + bundle.getSymbolicName() + + " timed out. Bundle state = " + bundle.getState()); + } while (waiting); + + if (log.isTraceEnabled()) + 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 > defaultTimeout) + throw new SlcException("Stop of bundle " + + bundle.getSymbolicName() + + " timed out. Bundle state = " + bundle.getState()); + } while (waiting); + + if (log.isTraceEnabled()) + 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(defaultTimeout); + } catch (InterruptedException e) { + // silent + } + } + + if (log.isTraceEnabled()) + 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 > defaultTimeout) + 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); + } + + public void setDefaultTimeout(Long defaultTimeout) { + this.defaultTimeout = defaultTimeout; } }