import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
+import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
public class Activator implements BundleActivator {
public final static String PROP_SLC_OSGI_START = "slc.osgi.start";
+ public final static String PROP_SLC_OSGI_BUNDLES = "slc.osgi.bundles";
public final static String PROP_SLC_OSGI_DEV_BASES = "slc.osgi.devBases";
public final static String PROP_SLC_OSGI_DEV_PATTERNS = "slc.osgi.devPatterns";
public final static String PROP_SLC_OSGI_LOCATIONS = "slc.osgi.locations";
installUrls(bundleContext, getDevLocationsUrls());
installUrls(bundleContext, getLocationsUrls());
+ installUrls(bundleContext, getBundlesUrls());
List<String> urls = getMavenUrls();
installUrls(bundleContext, urls);
return urls;
}
+ protected List<String> getBundlesUrls() {
+ List<String> urls = new ArrayList<String>();
+
+ List<BundlesSet> bundlesSets = new ArrayList<BundlesSet>();
+ String bundles = getProperty(PROP_SLC_OSGI_BUNDLES);
+ if (bundles == null)
+ return urls;
+ info(PROP_SLC_OSGI_BUNDLES + "=" + bundles);
+
+ StringTokenizer st = new StringTokenizer(bundles, ",");
+ while (st.hasMoreTokens()) {
+ bundlesSets.add(new BundlesSet(st.nextToken()));
+ }
+
+ List<String> included = new ArrayList<String>();
+ PathMatcher matcher = new AntPathMatcher();
+ for (BundlesSet bundlesSet : bundlesSets)
+ for (String pattern : bundlesSet.getIncludes())
+ match(matcher, included, bundlesSet.getDir(), null, pattern);
+
+ List<String> excluded = new ArrayList<String>();
+ for (BundlesSet bundlesSet : bundlesSets)
+ for (String pattern : bundlesSet.getExcludes())
+ match(matcher, excluded, bundlesSet.getDir(), null, pattern);
+
+ for (String fullPath : included) {
+ if (!excluded.contains(fullPath))
+ urls.add("reference:file:" + fullPath);
+ }
+
+ return urls;
+ }
+
+ private class BundlesSet {
+ private String baseUrl = "reference:file";
+ private final String dir;
+ private List<String> includes = new ArrayList<String>();
+ private List<String> excludes = new ArrayList<String>();
+
+ public BundlesSet(String def) {
+ StringTokenizer st = new StringTokenizer(def, ";");
+
+ if (!st.hasMoreTokens())
+ throw new RuntimeException("Base dir not defined.");
+ try {
+ String dirPath = st.nextToken();
+ dir = new File(dirPath.replace('/', File.separatorChar))
+ .getCanonicalPath();
+ if (debug)
+ debug("Base dir: " + dir);
+ } catch (IOException e) {
+ throw new RuntimeException("Cannot convert to absolute path", e);
+ }
+
+ while (st.hasMoreTokens()) {
+ String tk = st.nextToken();
+ StringTokenizer stEq = new StringTokenizer(tk, "=");
+ String type = stEq.nextToken();
+ String pattern = stEq.nextToken();
+ if ("in".equals(type) || "include".equals(type)) {
+ includes.add(pattern);
+ } else if ("ex".equals(type) || "exclude".equals(type)) {
+ excludes.add(pattern);
+ } else if ("baseUrl".equals(type)) {
+ baseUrl = pattern;
+ } else {
+ System.err.println("Unkown bundles pattern type " + type);
+ }
+ }
+ }
+
+ public String getDir() {
+ return dir;
+ }
+
+ public List<String> getIncludes() {
+ return includes;
+ }
+
+ public List<String> getExcludes() {
+ return excludes;
+ }
+
+ public String getBaseUrl() {
+ return baseUrl;
+ }
+
+ }
+
protected void match(PathMatcher matcher, List<String> matched,
String base, String currentPath, String pattern) {
if (currentPath == null) {
}
for (File file : files)
- if (file.isDirectory())
match(matcher, matched, base, file.getName(), pattern);
} else {
- String fullPath = base + currentPath;
+ String fullPath = base + '/' + currentPath;
if (matched.contains(fullPath))
return;// don't try deeper if already matched
matched.add(fullPath);
return;
} else {
- File[] files = new File((base + currentPath).replace('/',
- File.separatorChar)).listFiles();
- for (File file : files)
- if (file.isDirectory()) {
- String newCurrentPath = currentPath + '/'
- + file.getName();
- if (matcher.matchStart(pattern, newCurrentPath)) {
- // recurse only if start matches
- match(matcher, matched, base, newCurrentPath,
- pattern);
- } else {
- if (debug)
- debug(newCurrentPath
- + " does not start match with "
- + pattern);
-
+ String newFullPath = (base + '/' + currentPath).replace('/',
+ File.separatorChar);
+ File[] files = new File(newFullPath).listFiles();
+ if (files != null) {
+ for (File file : files)
+ if (file.isDirectory()) {
+ String newCurrentPath = currentPath + '/'
+ + file.getName();
+ if (matcher.matchStart(pattern, newCurrentPath)) {
+ // recurse only if start matches
+ match(matcher, matched, base, newCurrentPath,
+ pattern);
+ } else {
+ if (debug)
+ debug(newCurrentPath
+ + " does not start match with "
+ + pattern);
+
+ }
}
- }
+ } else {
+ warn("Not a directory: " + newFullPath);
+ }
}
}
}
try {
bundle.start();
} catch (Exception e) {
- warn("Bundle " + name + " cannot be started: " + e.getMessage());
+ warn("Bundle " + name + " cannot be started: "
+ + e.getMessage());
}
else
warn("Bundle " + name + " not installed.");
package org.argeo.slc.equinox;
-import java.util.ArrayList;
-import java.util.Iterator;
-import java.util.List;
-
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.argeo.slc.SlcException;
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 {
+ BundleContextAware, FrameworkListener, InitializingBean {
private final static Log log = LogFactory
.getLog(ExecutionCommandProvider.class);
- private List<ExecutionModule> executionModules;
private BundleContext bundleContext;
+ private String lastModuleName = null;
+ private String lastExecutionName = null;
+
+ 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();
+
String moduleName = null;
+ // First check whether we have a bundleId
Long bundleId = null;
try {
bundleId = Long.parseLong(firstArg);
// silent
}
+ // Look for bundle names containing pattern
Bundle bundle = null;
if (bundleId != null) {
bundle = bundleContext.getBundle(bundleId);
if (bundle != null) {
moduleName = bundle.getSymbolicName();
- // try {
- // bundle.stop();
- // bundle.update();
- // bundle.start();
- //
- // // FIXME: potential infinite loop
- // while (bundle.getState() == Bundle.STARTING) {
- // try {
- // Thread.sleep(500);
- // } catch (InterruptedException e) {
- // // silent
- // }
- // }
- // } catch (BundleException e) {
- // throw new SlcException(
- // "Could not update the bundle for module " + moduleName,
- // e);
- // }
+ lastModuleName = moduleName;
+ lastExecutionName = executionName;
+ } else {
+ log
+ .warn("Could not find any execution module matching these requirements.");
+ return null;
}
// Find module
ExecutionModule module = null;
- if (moduleName != null) {
- for (Iterator<ExecutionModule> it = executionModules.iterator(); it
- .hasNext();) {
- ExecutionModule moduleT = it.next();
- if (moduleT.getName().equals(moduleName)) {
- 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);
+ 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);
- } else
- log
- .warn("Could not find any execution module matching these requirements.");
+ 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);
+ }
- return null;
+ return "COMMAND COMPLETED";
}
public String getHelp() {
StringBuffer buf = new StringBuffer();
buf.append("---SLC Execution Commands---\n");
buf
- .append("\tslc_exec (<id>|<segment of bsn>) <execution bean> - execute an execution flow\n");
+ .append("\tslc (<id>|<segment of bsn>) <execution bean> - execute an execution flow (without arg, execute last)\n");
return buf.toString();
}
- public void setExecutionModules(List<ExecutionModule> 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 > 10000)
+ throw new SlcException("Update of bundle "
+ + bundle.getSymbolicName()
+ + " timed out. Bundle state = " + bundle.getState());
+ } while (waiting);
+
+ if (log.isDebugEnabled())
+ 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 > 30000)
+ throw new SlcException("Start of bundle "
+ + bundle.getSymbolicName()
+ + " timed out. Bundle state = " + bundle.getState());
+ } while (waiting);
+
+ if (log.isDebugEnabled())
+ 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 > 30000)
+ throw new SlcException("Stop of bundle "
+ + bundle.getSymbolicName()
+ + " timed out. Bundle state = " + bundle.getState());
+ } while (waiting);
+
+ if (log.isDebugEnabled())
+ 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(30000);
+ log.debug("NOT INTERRUPTED");
+ } catch (InterruptedException e) {
+ log.debug("INTERRUPTED");
+ // silent
+ }
+ }
+
+ if (log.isDebugEnabled())
+ 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 > 30000)
+ 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);
+ }
+
}