From a17824ea2422474f25e2ea0eeae310f4dd9e6361 Mon Sep 17 00:00:00 2001 From: Mathieu Baudier Date: Sun, 3 Mar 2013 19:29:22 +0000 Subject: [PATCH 1/1] Working command line SLC git-svn-id: https://svn.argeo.org/slc/trunk@6094 4cfe0d0a-d680-48aa-b62c-e0a02a3f76cc --- dep/org.argeo.slc.dep.minimal/pom.xml | 48 +++- .../META-INF/spring/jcr-osgi.xml | 4 +- .../META-INF/spring/jcr.xml | 5 + .../ui/controllers/ProcessController.java | 2 +- runtime/org.argeo.slc.core/pom.xml | 8 +- .../slc/core/execution/DefaultAgent.java | 76 ++++++- .../slc/core/execution/DefaultAgentCli.java | 119 ++++++++++ ...faultExecutionFlowDescriptorConverter.java | 4 +- .../slc/core/execution/ExecutionThread.java | 1 + .../core/execution/DefaultAgentCliTest.java | 18 ++ runtime/org.argeo.slc.launcher/jaas.config | 3 + runtime/org.argeo.slc.launcher/pom.xml | 38 ---- .../main/java/org/argeo/slc/cli/SlcMain.java | 206 +++++++----------- .../execution/ExecutionFlowDescriptor.java | 14 +- .../execution/ExecutionModuleDescriptor.java | 32 +++ .../org/argeo/slc/execution/SlcAgent.java | 20 +- .../org/argeo/slc/execution/SlcAgentCli.java | 14 ++ .../org/argeo/slc/jcr/execution/JcrAgent.java | 8 +- .../slc/jcr/execution/JcrProcessThread.java | 185 ++++------------ .../slc/jcr/execution/JcrRealizedFlow.java | 6 +- .../org/argeo/slc/osgi/BundlesManager.java | 9 + .../slc/osgi/OsgiExecutionModulesManager.java | 23 +- 22 files changed, 509 insertions(+), 334 deletions(-) create mode 100644 runtime/org.argeo.slc.core/src/main/java/org/argeo/slc/core/execution/DefaultAgentCli.java create mode 100644 runtime/org.argeo.slc.core/src/test/java/org/argeo/slc/core/execution/DefaultAgentCliTest.java create mode 100644 runtime/org.argeo.slc.launcher/jaas.config create mode 100644 runtime/org.argeo.slc.specs/src/main/java/org/argeo/slc/execution/SlcAgentCli.java diff --git a/dep/org.argeo.slc.dep.minimal/pom.xml b/dep/org.argeo.slc.dep.minimal/pom.xml index 680839f93..22f85a351 100644 --- a/dep/org.argeo.slc.dep.minimal/pom.xml +++ b/dep/org.argeo.slc.dep.minimal/pom.xml @@ -25,15 +25,55 @@ + + org.apache.maven.plugins + maven-dependency-plugin + + + copy-dependencies + package + + copy-dependencies + + + + + org.argeo.slc - org.argeo.slc.launcher + org.argeo.slc.core + 1.1.12-SNAPSHOT + + + org.argeo.slc + org.argeo.slc.support.osgi 1.1.12-SNAPSHOT + + org.argeo.slc + org.argeo.slc.agent + 1.1.12-SNAPSHOT + + + org.argeo.commons.base + org.argeo.osgi.boot + ${version.argeo-commons} + + + org.argeo.tp + org.springframework.osgi.extender + + + org.argeo.commons.base + org.argeo.dep.log4j + ${version.argeo-commons} + pom + + org.argeo.slc org.argeo.slc.support.jcr @@ -50,6 +90,12 @@ 1.1.12-SNAPSHOT + + + org.argeo.slc + org.argeo.slc.launcher + 1.1.12-SNAPSHOT + diff --git a/modules/org.argeo.slc.agent.jcr/META-INF/spring/jcr-osgi.xml b/modules/org.argeo.slc.agent.jcr/META-INF/spring/jcr-osgi.xml index 52deee9a9..5432dad00 100644 --- a/modules/org.argeo.slc.agent.jcr/META-INF/spring/jcr-osgi.xml +++ b/modules/org.argeo.slc.agent.jcr/META-INF/spring/jcr-osgi.xml @@ -21,10 +21,12 @@ - + + + \ No newline at end of file diff --git a/modules/org.argeo.slc.agent.jcr/META-INF/spring/jcr.xml b/modules/org.argeo.slc.agent.jcr/META-INF/spring/jcr.xml index dffc68eb0..5dd41b799 100644 --- a/modules/org.argeo.slc.agent.jcr/META-INF/spring/jcr.xml +++ b/modules/org.argeo.slc.agent.jcr/META-INF/spring/jcr.xml @@ -9,6 +9,11 @@ + + + + + diff --git a/plugins/org.argeo.slc.client.ui/src/main/java/org/argeo/slc/client/ui/controllers/ProcessController.java b/plugins/org.argeo.slc.client.ui/src/main/java/org/argeo/slc/client/ui/controllers/ProcessController.java index abf41dc5b..8b66bd89a 100644 --- a/plugins/org.argeo.slc.client.ui/src/main/java/org/argeo/slc/client/ui/controllers/ProcessController.java +++ b/plugins/org.argeo.slc.client.ui/src/main/java/org/argeo/slc/client/ui/controllers/ProcessController.java @@ -56,7 +56,7 @@ public class ProcessController { SlcAgent slcAgent = findAgent(processNode); if (slcAgent == null) throw new SlcException("Cannot find agent for " + processNode); - slcAgent.kill(process); + slcAgent.kill(process.getUuid()); } catch (Exception e) { if (!process.getStatus().equals(ExecutionProcess.ERROR)) process.setStatus(ExecutionProcess.ERROR); diff --git a/runtime/org.argeo.slc.core/pom.xml b/runtime/org.argeo.slc.core/pom.xml index 63017d913..d8c556708 100644 --- a/runtime/org.argeo.slc.core/pom.xml +++ b/runtime/org.argeo.slc.core/pom.xml @@ -1,5 +1,6 @@ - + 4.0.0 org.argeo.slc @@ -48,6 +49,11 @@ org.argeo.util ${version.argeo-commons} + + org.argeo.commons.security + org.argeo.security.core + ${version.argeo-commons} + org.argeo.tp diff --git a/runtime/org.argeo.slc.core/src/main/java/org/argeo/slc/core/execution/DefaultAgent.java b/runtime/org.argeo.slc.core/src/main/java/org/argeo/slc/core/execution/DefaultAgent.java index 7d6ff315e..9bfde6edc 100644 --- a/runtime/org.argeo.slc.core/src/main/java/org/argeo/slc/core/execution/DefaultAgent.java +++ b/runtime/org.argeo.slc.core/src/main/java/org/argeo/slc/core/execution/DefaultAgent.java @@ -15,17 +15,23 @@ */ package org.argeo.slc.core.execution; +import java.io.UnsupportedEncodingException; import java.net.InetAddress; +import java.net.URI; +import java.net.URLDecoder; import java.net.UnknownHostException; import java.util.Collections; import java.util.HashMap; import java.util.Iterator; +import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import java.util.UUID; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; +import org.argeo.slc.BasicNameVersion; +import org.argeo.slc.SlcException; import org.argeo.slc.execution.ExecutionModuleDescriptor; import org.argeo.slc.execution.ExecutionModulesManager; import org.argeo.slc.execution.ExecutionProcess; @@ -35,6 +41,8 @@ import org.argeo.slc.execution.SlcAgentDescriptor; /** Implements the base methods of an SLC agent. */ public class DefaultAgent implements SlcAgent { private final static Log log = LogFactory.getLog(DefaultAgent.class); + /** UTF-8 charset for encoding. */ + private final static String UTF8 = "UTF-8"; private SlcAgentDescriptor agentDescriptor; private ExecutionModulesManager modulesManager; @@ -78,8 +86,8 @@ public class DefaultAgent implements SlcAgent { /** Clean up (needs to be called by overriding method) */ public void destroy() { -// modulesManager.unregisterProcessNotifier(this, -// new HashMap()); + // modulesManager.unregisterProcessNotifier(this, + // new HashMap()); } /** @@ -115,10 +123,51 @@ public class DefaultAgent implements SlcAgent { } } - public void kill(ExecutionProcess process) { - String processUuid = process.getUuid(); + public String process(List uris) { + DefaultProcess process = new DefaultProcess(); + for (URI uri : uris) { + String[] path = uri.getPath().split("/"); + if (path.length < 3) + throw new SlcException("Badly formatted URI: " + uri); + String module = path[1]; + StringBuilder flow = new StringBuilder(); + for (int i = 2; i < path.length; i++) + flow.append('/').append(path[i]); + + Map values = new HashMap(); + if (uri.getQuery() != null) + values = getQueryMap(uri.getQuery()); + + modulesManager.start(new BasicNameVersion(module, null)); + ExecutionModuleDescriptor emd = getExecutionModuleDescriptor( + module, null); + process.getRealizedFlows().add( + emd.asRealizedFlow(flow.toString(), values)); + } + process(process); + return process.getUuid(); + } + + public void kill(String processUuid) { if (runningProcesses.containsKey(processUuid)) { runningProcesses.get(processUuid).interrupt(); + } else { + // assume is finished + } + } + + public void waitFor(String processUuid, Long millis) { + if (runningProcesses.containsKey(processUuid)) { + try { + if (millis != null) + runningProcesses.get(processUuid).join(millis); + else + runningProcesses.get(processUuid).join(); + } catch (InterruptedException e) { + // silent + } + } else { + // assume is finished } } @@ -160,6 +209,25 @@ public class DefaultAgent implements SlcAgent { // { // } + /* + * UTILITIES + */ + private static Map getQueryMap(String query) { + String[] params = query.split("&"); + Map map = new LinkedHashMap(); + for (String param : params) { + String name = param.split("=")[0]; + String value = param.split("=")[1]; + try { + map.put(URLDecoder.decode(name, UTF8), + URLDecoder.decode(value, UTF8)); + } catch (UnsupportedEncodingException e) { + throw new SlcException("Cannot decode '" + param + "'", e); + } + } + return map; + } + /* * BEAN */ diff --git a/runtime/org.argeo.slc.core/src/main/java/org/argeo/slc/core/execution/DefaultAgentCli.java b/runtime/org.argeo.slc.core/src/main/java/org/argeo/slc/core/execution/DefaultAgentCli.java new file mode 100644 index 000000000..823207e87 --- /dev/null +++ b/runtime/org.argeo.slc.core/src/main/java/org/argeo/slc/core/execution/DefaultAgentCli.java @@ -0,0 +1,119 @@ +package org.argeo.slc.core.execution; + +import java.net.URI; +import java.net.URLEncoder; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Iterator; +import java.util.List; + +import org.argeo.security.OsAuthenticationToken; +import org.argeo.slc.SlcException; +import org.argeo.slc.execution.SlcAgent; +import org.argeo.slc.execution.SlcAgentCli; +import org.springframework.security.Authentication; +import org.springframework.security.AuthenticationManager; +import org.springframework.security.context.SecurityContextHolder; + +public class DefaultAgentCli implements SlcAgentCli { + private final static String UTF8 = "UTF-8"; + private SlcAgent agent; + private AuthenticationManager authenticationManager; + + private Long timeout = 24 * 60 * 60 * 1000l; + + public String process(String[] args) { + OsAuthenticationToken oat = new OsAuthenticationToken(); + Authentication authentication = authenticationManager.authenticate(oat); + SecurityContextHolder.getContext().setAuthentication(authentication); + + List uris = asURIs(args); + String processUuid = agent.process(uris); + agent.waitFor(processUuid, timeout); + return processUuid; + } + + public static List asURIs(String[] args) { + try { + List uris = new ArrayList(); + List leftOvers = new ArrayList(); + + Boolean hasArgs = false; + String currKey = null; + StringBuilder currUri = null; + Iterator argIt = Arrays.asList(args).iterator(); + while (argIt.hasNext()) { + String arg = argIt.next(); + if (!arg.startsWith("-")) { + if (currKey != null) {// value + currUri.append(URLEncoder.encode(arg, UTF8)); + currKey = null; + } else { // module + if (currUri != null) + uris.add(new URI(currUri.toString())); + currUri = new StringBuilder("flow:"); + + String currModule = arg; + currUri.append('/').append(currModule); + if (!arg.contains("/")) { + // flow path not in arg go to next arg + String currFlow = argIt.next(); + if (!currFlow.startsWith("/")) + currFlow = "/" + currFlow; + currUri.append(currFlow); + } + } + } else { + if (currUri == null) {// first args + leftOvers.add(arg); + } else { + if (!hasArgs) { + currUri.append('?'); + hasArgs = true; + } else { + currUri.append('&'); + } + + // deal with boolean keys + if (currKey != null) {// value + currUri.append(URLEncoder.encode("true", UTF8)); + currKey = null; + } + + String key; + if (arg.startsWith("--")) + key = arg.substring(2); + else if (arg.startsWith("-")) + key = arg.substring(1); + else + throw new SlcException("Cannot intepret key: " + + arg); + currKey = key; + currUri.append(URLEncoder.encode(key, UTF8)) + .append('='); + } + } + } + if (currUri != null) + uris.add(new URI(currUri.toString())); + return uris; + } catch (Exception e) { + throw new SlcException("Cannot convert " + Arrays.toString(args) + + " to flow URI", e); + } + } + + public void setAgent(SlcAgent agent) { + this.agent = agent; + } + + public void setAuthenticationManager( + AuthenticationManager authenticationManager) { + this.authenticationManager = authenticationManager; + } + + public void setTimeout(Long timeout) { + this.timeout = timeout; + } + +} diff --git a/runtime/org.argeo.slc.core/src/main/java/org/argeo/slc/core/execution/DefaultExecutionFlowDescriptorConverter.java b/runtime/org.argeo.slc.core/src/main/java/org/argeo/slc/core/execution/DefaultExecutionFlowDescriptorConverter.java index 0fcd073af..3c81ec192 100644 --- a/runtime/org.argeo.slc.core/src/main/java/org/argeo/slc/core/execution/DefaultExecutionFlowDescriptorConverter.java +++ b/runtime/org.argeo.slc.core/src/main/java/org/argeo/slc/core/execution/DefaultExecutionFlowDescriptorConverter.java @@ -210,8 +210,8 @@ public class DefaultExecutionFlowDescriptorConverter implements } - ExecutionFlowDescriptor efd = new ExecutionFlowDescriptor(name, values, - executionSpec); + ExecutionFlowDescriptor efd = new ExecutionFlowDescriptor(name, null, + values, executionSpec); if (executionFlow.getPath() != null) efd.setPath(executionFlow.getPath()); else diff --git a/runtime/org.argeo.slc.core/src/main/java/org/argeo/slc/core/execution/ExecutionThread.java b/runtime/org.argeo.slc.core/src/main/java/org/argeo/slc/core/execution/ExecutionThread.java index 71e2100e2..6a1c97284 100644 --- a/runtime/org.argeo.slc.core/src/main/java/org/argeo/slc/core/execution/ExecutionThread.java +++ b/runtime/org.argeo.slc.core/src/main/java/org/argeo/slc/core/execution/ExecutionThread.java @@ -74,6 +74,7 @@ public class ExecutionThread extends Thread { executionModulesManager.upgrade(realizedFlow .getModuleNameVersion()); + executionModulesManager.start(realizedFlow.getModuleNameVersion()); // START FLOW executionModulesManager.execute(realizedFlow); // END FLOW diff --git a/runtime/org.argeo.slc.core/src/test/java/org/argeo/slc/core/execution/DefaultAgentCliTest.java b/runtime/org.argeo.slc.core/src/test/java/org/argeo/slc/core/execution/DefaultAgentCliTest.java new file mode 100644 index 000000000..a7d9b8b78 --- /dev/null +++ b/runtime/org.argeo.slc.core/src/test/java/org/argeo/slc/core/execution/DefaultAgentCliTest.java @@ -0,0 +1,18 @@ +package org.argeo.slc.core.execution; + +import java.net.URI; +import java.util.List; + +import junit.framework.TestCase; + +public class DefaultAgentCliTest extends TestCase { + public void testArgsToUris() { + String[] args = { "org.argeo.slc.demo.minimal", "HelloWorld/WithVar", + "--testKey", "555" }; + List uris = DefaultAgentCli.asURIs(args); + assertEquals(1, uris.size()); + assertEquals( + "flow:/org.argeo.slc.demo.minimal/HelloWorld/WithVar?testKey=555", + uris.get(0).toString()); + } +} diff --git a/runtime/org.argeo.slc.launcher/jaas.config b/runtime/org.argeo.slc.launcher/jaas.config new file mode 100644 index 000000000..a63021f2b --- /dev/null +++ b/runtime/org.argeo.slc.launcher/jaas.config @@ -0,0 +1,3 @@ +NIX { + com.sun.security.auth.module.UnixLoginModule required debug=true; +}; \ No newline at end of file diff --git a/runtime/org.argeo.slc.launcher/pom.xml b/runtime/org.argeo.slc.launcher/pom.xml index 4bae3c3f3..64d5297cb 100644 --- a/runtime/org.argeo.slc.launcher/pom.xml +++ b/runtime/org.argeo.slc.launcher/pom.xml @@ -34,7 +34,6 @@ org.apache.felix maven-bundle-plugin - org.argeo.slc.cli.SlcMain @@ -64,47 +63,10 @@ - - - org.argeo.slc - org.argeo.slc.core - 1.1.12-SNAPSHOT - - - org.argeo.slc - org.argeo.slc.support.osgi - 1.1.12-SNAPSHOT - - - org.argeo.slc - org.argeo.slc.agent - 1.1.12-SNAPSHOT - - - org.argeo.commons.base org.argeo.osgi.boot ${version.argeo-commons} - - - - org.argeo.tp - org.springframework.osgi.extender - - - - org.argeo.tp - org.apache.commons.cli - - - - - org.argeo.commons.base - org.argeo.dep.log4j - ${version.argeo-commons} - pom - \ No newline at end of file diff --git a/runtime/org.argeo.slc.launcher/src/main/java/org/argeo/slc/cli/SlcMain.java b/runtime/org.argeo.slc.launcher/src/main/java/org/argeo/slc/cli/SlcMain.java index c7a726331..90ca7411f 100644 --- a/runtime/org.argeo.slc.launcher/src/main/java/org/argeo/slc/cli/SlcMain.java +++ b/runtime/org.argeo.slc.launcher/src/main/java/org/argeo/slc/cli/SlcMain.java @@ -16,41 +16,30 @@ package org.argeo.slc.cli; import java.io.File; -import java.io.FileInputStream; +import java.lang.reflect.Method; +import java.security.AccessController; +import java.security.PrivilegedAction; import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; import java.util.List; -import java.util.Properties; +import java.util.Map; +import java.util.ServiceLoader; import java.util.UUID; -import org.apache.commons.cli.CommandLine; -import org.apache.commons.cli.CommandLineParser; -import org.apache.commons.cli.GnuParser; -import org.apache.commons.cli.HelpFormatter; -import org.apache.commons.cli.Options; -import org.apache.commons.cli.ParseException; -import org.apache.commons.io.IOUtils; +import javax.security.auth.Subject; +import javax.security.auth.login.LoginContext; + import org.argeo.osgi.boot.OsgiBoot; -import org.argeo.slc.SlcException; -import org.eclipse.core.runtime.adaptor.EclipseStarter; -import org.osgi.framework.Bundle; import org.osgi.framework.BundleContext; +import org.osgi.framework.launch.Framework; +import org.osgi.framework.launch.FrameworkFactory; +import org.osgi.util.tracker.ServiceTracker; -@SuppressWarnings("restriction") +/** Configures an SLC runtime and runs a process. */ public class SlcMain implements Runnable { - /** Unique launch module */ - public final static String UNIQUE_LAUNCH_MODULE_PROPERTY = "slc.launch.module"; - - /** Unique launch flow */ - public final static String UNIQUE_LAUNCH_FLOW_PROPERTY = "slc.launch.flow"; - - /** Unique launch flow */ - public final static String UNIQUE_LAUNCH_ARGS_PROPERTY_BASE = "slc.launch.args"; - - private final Options options = new Options(); private final String[] args; - private final String commandName = "slc"; - // private static String bundlesToInstall = "/usr/share/osgi;in=*.jar"; private String bundlesToInstall = System.getProperty("user.home") + "/dev/src/slc/dep/org.argeo.slc.dep.minimal/target/dependency;in=*.jar," @@ -61,9 +50,6 @@ public class SlcMain implements Runnable { public SlcMain(String[] args) { this.args = args; - // bundlesToStart.add("org.springframework.osgi.extender"); - // bundlesToStart.add("org.argeo.slc.agent"); - bundlesToStart.add("org.springframework.osgi.extender"); bundlesToStart.add("org.argeo.node.repo.jackrabbit"); bundlesToStart.add("org.argeo.security.dao.os"); @@ -72,39 +58,14 @@ public class SlcMain implements Runnable { bundlesToStart.add("org.argeo.slc.agent.jcr"); } - @SuppressWarnings("unchecked") public void run() { - String module = null; - String moduleUrl = null; - String flow = null; - + final LoginContext lc; try { + // Authenticate + lc = new LoginContext("NIX"); + lc.login(); - CommandLineParser clParser = new GnuParser(); - CommandLine cl = clParser.parse(options, args); - - List arguments = cl.getArgList(); - if (arguments.size() == 0) { - // TODO default behaviour - } else { - module = arguments.get(0); - File moduleFile = new File(module); - if (moduleFile.exists()) { - if (moduleFile.isDirectory()) { - moduleUrl = "reference:file:" - + moduleFile.getCanonicalPath(); - } else { - moduleUrl = "file:" + moduleFile.getCanonicalPath(); - } - } - - if (arguments.size() == 1) { - // TODO module info - } else { - flow = arguments.get(1); - } - } - + // Prepare directories String executionDir = System.getProperty("user.dir"); File slcDir = new File(executionDir, "target/.slc"); File tempDir = new File(System.getProperty("java.io.tmpdir")); @@ -118,45 +79,75 @@ public class SlcMain implements Runnable { if (!confDir.exists()) confDir.mkdirs(); - BundleContext bundleContext = null; - try { - String[] osgiRuntimeArgs = { "-configuration", - confDir.getCanonicalPath(), "-data", - dataDir.getCanonicalPath(), "-console", "-clean" }; - bundleContext = EclipseStarter.startup(osgiRuntimeArgs, null); - } catch (Exception e) { - throw new RuntimeException("Cannot start Equinox.", e); - } + System.setProperty("log4j.configuration", "file:./log4j.properties"); + System.setProperty("argeo.node.repo.configuration", + "osgibundle:repository-memory.xml"); + + // Start Equinox + ServiceLoader ff = ServiceLoader + .load(FrameworkFactory.class); + FrameworkFactory frameworkFactory = ff.iterator().next(); + Map configuration = new HashMap(); + configuration.put("osgi.configuration.area", + confDir.getCanonicalPath()); + configuration.put("osgi.instance.area", dataDir.getCanonicalPath()); + configuration.put("osgi.clean", "true"); + + // Spring configs currently require System properties + System.getProperties().putAll(configuration); + + Framework framework = frameworkFactory.newFramework(configuration); + framework.start(); + BundleContext bundleContext = framework.getBundleContext(); + // String[] osgiRuntimeArgs = { "-configuration", + // confDir.getCanonicalPath(), "-data", + // dataDir.getCanonicalPath(), "-clean" }; + // BundleContext bundleContext = EclipseStarter.startup( + // osgiRuntimeArgs, null); // OSGi bootstrap OsgiBoot osgiBoot = new OsgiBoot(bundleContext); osgiBoot.installUrls(osgiBoot.getBundlesUrls(bundlesToInstall)); - if (moduleUrl != null) { - Bundle bundle = osgiBoot.installUrl(moduleUrl); - module = bundle.getSymbolicName(); - // TODO deal with version - } - - System.setProperty(UNIQUE_LAUNCH_MODULE_PROPERTY, module); - System.setProperty(UNIQUE_LAUNCH_FLOW_PROPERTY, flow); - System.setProperty("log4j.configuration", "file:./log4j.properties"); - System.setProperty("argeo.node.repo.configuration", - "osgibundle:repository-memory.xml"); - // start runtime + // Start runtime osgiBoot.startBundles(bundlesToStart); - } catch (ParseException e) { - System.err.println("Problem with command line arguments. " - + e.getMessage()); - badExit(); - } catch (SlcException e) { - System.err.println(e.getMessage()); - badExit(); + // Find SLC Agent + ServiceTracker agentTracker = new ServiceTracker(bundleContext, + "org.argeo.slc.execution.SlcAgentCli", null); + agentTracker.open(); + final Object agentCli = agentTracker.waitForService(30 * 1000); + + // Run as a privileged action + Subject.doAs(Subject.getSubject(AccessController.getContext()), + new PrivilegedAction() { + + public String run() { + try { + Class[] parameterTypes = { String[].class }; + Method method = agentCli.getClass().getMethod( + "process", parameterTypes); + Object[] methodArgs = { args }; + Object ret = method + .invoke(agentCli, methodArgs); + return ret.toString(); + } catch (Exception e) { + throw new RuntimeException("Cannot run " + + Arrays.toString(args) + " on " + + agentCli, e); + } + } + + }); + + // Shutdown OSGi runtime + framework.stop(); + framework.waitForStop(60 * 1000); + + System.exit(0); } catch (Exception e) { - System.err.println("Unexpected exception when bootstrapping."); e.printStackTrace(); - badExit(); + System.exit(1); } } @@ -164,44 +155,6 @@ public class SlcMain implements Runnable { new SlcMain(args).run(); } - public void printUsage() { - new HelpFormatter().printHelp(commandName, options, true); - } - - protected static void addProperty(Properties properties, String property) { - int eqIndex = property.indexOf('='); - if (eqIndex == 0) - throw new SlcException("Badly formatted property " + property); - - if (eqIndex > 0) { - String key = property.substring(0, eqIndex); - String value = property.substring(eqIndex + 1); - properties.setProperty(key, value); - - } else { - properties.setProperty(property, "true"); - } - } - - protected static void loadPropertyFile(Properties properties, - String propertyFile) { - FileInputStream in = null; - try { - in = new FileInputStream(propertyFile); - properties.load(in); - } catch (Exception e) { - throw new SlcException("Could not load proeprty file " - + propertyFile); - } finally { - IOUtils.closeQuietly(in); - } - } - - private void badExit() { - printUsage(); - System.exit(1); - } - protected static void info(Object msg) { System.out.println(msg); } @@ -209,4 +162,5 @@ public class SlcMain implements Runnable { protected static void debug(Object msg) { System.out.println(msg); } + } diff --git a/runtime/org.argeo.slc.specs/src/main/java/org/argeo/slc/execution/ExecutionFlowDescriptor.java b/runtime/org.argeo.slc.specs/src/main/java/org/argeo/slc/execution/ExecutionFlowDescriptor.java index 73b74a312..e3eea046f 100644 --- a/runtime/org.argeo.slc.specs/src/main/java/org/argeo/slc/execution/ExecutionFlowDescriptor.java +++ b/runtime/org.argeo.slc.specs/src/main/java/org/argeo/slc/execution/ExecutionFlowDescriptor.java @@ -16,6 +16,7 @@ package org.argeo.slc.execution; import java.io.Serializable; +import java.util.HashMap; import java.util.Map; /** @@ -39,7 +40,7 @@ import java.util.Map; * Generally, values object are either a PrimitiveAccessor or a * RefValue but can be other objects. */ -public class ExecutionFlowDescriptor implements Serializable { +public class ExecutionFlowDescriptor implements Serializable, Cloneable { private static final long serialVersionUID = 7101944857038041216L; private String name; private String description; @@ -50,13 +51,20 @@ public class ExecutionFlowDescriptor implements Serializable { public ExecutionFlowDescriptor() { } - public ExecutionFlowDescriptor(String name, Map values, - ExecutionSpec executionSpec) { + public ExecutionFlowDescriptor(String name, String description, + Map values, ExecutionSpec executionSpec) { this.name = name; this.values = values; this.executionSpec = executionSpec; } + /** The referenced {@link ExecutionSpec} is NOT cloned. */ + @Override + protected Object clone() throws CloneNotSupportedException { + return new ExecutionFlowDescriptor(name, description, + new HashMap(values), executionSpec); + } + public String getName() { return name; } diff --git a/runtime/org.argeo.slc.specs/src/main/java/org/argeo/slc/execution/ExecutionModuleDescriptor.java b/runtime/org.argeo.slc.specs/src/main/java/org/argeo/slc/execution/ExecutionModuleDescriptor.java index 24aa5629d..4de026822 100644 --- a/runtime/org.argeo.slc.specs/src/main/java/org/argeo/slc/execution/ExecutionModuleDescriptor.java +++ b/runtime/org.argeo.slc.specs/src/main/java/org/argeo/slc/execution/ExecutionModuleDescriptor.java @@ -17,7 +17,9 @@ package org.argeo.slc.execution; import java.util.ArrayList; import java.util.List; +import java.util.Map; +import org.argeo.slc.SlcException; import org.argeo.slc.deploy.ModuleDescriptor; /** Describes the information required to launch a flow */ @@ -37,6 +39,36 @@ public class ExecutionModuleDescriptor extends ModuleDescriptor { return executionFlows; } + /** + * Returns a new {@link ExecutionModuleDescriptor} that can be used to build + * a {@link RealizedFlow}. + */ + public ExecutionFlowDescriptor cloneFlowDescriptor(String name) { + ExecutionFlowDescriptor res = null; + for (ExecutionFlowDescriptor efd : executionFlows) { + if (efd.getName().equals(name) + || ("/" + efd.getName()).equals(name)) { + try { + res = (ExecutionFlowDescriptor) efd.clone(); + } catch (CloneNotSupportedException e) { + throw new SlcException("Cannot clone " + efd, e); + } + } + } + if (res == null) + throw new SlcException("Flow " + name + " not found."); + return res; + } + + public RealizedFlow asRealizedFlow(String flow, Map values) { + RealizedFlow realizedFlow = new RealizedFlow(); + realizedFlow.setFlowDescriptor(cloneFlowDescriptor(flow)); + realizedFlow.setModuleName(getName()); + realizedFlow.setModuleVersion(getVersion()); + realizedFlow.getFlowDescriptor().getValues().putAll(values); + return realizedFlow; + } + public void setExecutionSpecs(List executionSpecs) { this.executionSpecs = executionSpecs; } diff --git a/runtime/org.argeo.slc.specs/src/main/java/org/argeo/slc/execution/SlcAgent.java b/runtime/org.argeo.slc.specs/src/main/java/org/argeo/slc/execution/SlcAgent.java index 38fcb24a2..c96d4a884 100644 --- a/runtime/org.argeo.slc.specs/src/main/java/org/argeo/slc/execution/SlcAgent.java +++ b/runtime/org.argeo.slc.specs/src/main/java/org/argeo/slc/execution/SlcAgent.java @@ -15,6 +15,7 @@ */ package org.argeo.slc.execution; +import java.net.URI; import java.util.List; /** @@ -30,8 +31,25 @@ public interface SlcAgent { /** Execute / take part to this process */ public void process(ExecutionProcess process); + /** + * Asynchronously processes the flows defined as URIs, or interpret a single + * UUID URN as a scheduled or template process. + * + * @return the UUID of the process launched. + */ + public String process(List uris); + /** Kills this process */ - public void kill(ExecutionProcess process); + public void kill(String processUuid); + + /** + * Wait for this process to finish. returns immediately if it does not + * exist. + * + * @param millis + * can be null + */ + public void waitFor(String processUuid, Long millis); /** * Describe all the flows provided by this execution module. Typically diff --git a/runtime/org.argeo.slc.specs/src/main/java/org/argeo/slc/execution/SlcAgentCli.java b/runtime/org.argeo.slc.specs/src/main/java/org/argeo/slc/execution/SlcAgentCli.java new file mode 100644 index 000000000..497d1104d --- /dev/null +++ b/runtime/org.argeo.slc.specs/src/main/java/org/argeo/slc/execution/SlcAgentCli.java @@ -0,0 +1,14 @@ +package org.argeo.slc.execution; + +/** + * Interpret a command line and run it in the underlying agent, with the proper + * authentication. + */ +public interface SlcAgentCli { + /** + * Synchronously executes. + * + * @return the UUID of the process + */ + public String process(String[] args); +} diff --git a/runtime/org.argeo.slc.support.jcr/src/main/java/org/argeo/slc/jcr/execution/JcrAgent.java b/runtime/org.argeo.slc.support.jcr/src/main/java/org/argeo/slc/jcr/execution/JcrAgent.java index 273a6ced2..a7f5b7747 100644 --- a/runtime/org.argeo.slc.support.jcr/src/main/java/org/argeo/slc/jcr/execution/JcrAgent.java +++ b/runtime/org.argeo.slc.support.jcr/src/main/java/org/argeo/slc/jcr/execution/JcrAgent.java @@ -77,8 +77,12 @@ public class JcrAgent extends DefaultAgent implements SlcNames { protected ProcessThread createProcessThread( ThreadGroup processesThreadGroup, ExecutionModulesManager modulesManager, ExecutionProcess process) { - return new JcrProcessThread(processesThreadGroup, modulesManager, - (JcrExecutionProcess) process); + if (process instanceof JcrProcessThread) + return new JcrProcessThread(processesThreadGroup, modulesManager, + (JcrExecutionProcess) process); + else + return super.createProcessThread(processesThreadGroup, + modulesManager, process); } /* diff --git a/runtime/org.argeo.slc.support.jcr/src/main/java/org/argeo/slc/jcr/execution/JcrProcessThread.java b/runtime/org.argeo.slc.support.jcr/src/main/java/org/argeo/slc/jcr/execution/JcrProcessThread.java index 1ae15d419..8755829e7 100644 --- a/runtime/org.argeo.slc.support.jcr/src/main/java/org/argeo/slc/jcr/execution/JcrProcessThread.java +++ b/runtime/org.argeo.slc.support.jcr/src/main/java/org/argeo/slc/jcr/execution/JcrProcessThread.java @@ -39,162 +39,55 @@ public class JcrProcessThread extends ProcessThread implements SlcNames { super(processesThreadGroup, executionModulesManager, process); } + /** Overridden in order to set progress status on realized flow nodes. */ @Override protected void process() throws InterruptedException { Session session = null; - try { - session = getJcrExecutionProcess().getRepository().login(); + if (getProcess() instanceof JcrExecutionProcess) + try { + session = ((JcrExecutionProcess) getProcess()).getRepository() + .login(); - List realizedFlows = getProcess().getRealizedFlows(); - for (RealizedFlow realizedFlow : realizedFlows) { - Node realizedFlowNode = session - .getNode(((JcrRealizedFlow) realizedFlow).getPath()); + List realizedFlows = getProcess() + .getRealizedFlows(); + for (RealizedFlow realizedFlow : realizedFlows) { + Node realizedFlowNode = session + .getNode(((JcrRealizedFlow) realizedFlow).getPath()); + setFlowStatus(realizedFlowNode, ExecutionProcess.RUNNING); - // set status on realized flow - realizedFlowNode.setProperty(SLC_STATUS, - ExecutionProcess.RUNNING); - realizedFlowNode.getSession().save(); - try { - // - // EXECUTE THE FLOW - // - execute(realizedFlow, true); + try { + // + // EXECUTE THE FLOW + // + execute(realizedFlow, true); - // set status on realized flow - realizedFlowNode.setProperty(SLC_STATUS, - ExecutionProcess.COMPLETED); - realizedFlowNode.getSession().save(); - } catch (RepositoryException e) { - throw e; - } catch (InterruptedException e) { - // set status on realized flow - realizedFlowNode.setProperty(SLC_STATUS, - ExecutionProcess.KILLED); - realizedFlowNode.getSession().save(); - throw e; - } catch (RuntimeException e) { - // set status on realized flow - realizedFlowNode.setProperty(SLC_STATUS, - ExecutionProcess.ERROR); - realizedFlowNode.getSession().save(); - throw e; + setFlowStatus(realizedFlowNode, + ExecutionProcess.COMPLETED); + } catch (RepositoryException e) { + throw e; + } catch (InterruptedException e) { + setFlowStatus(realizedFlowNode, ExecutionProcess.KILLED); + throw e; + } catch (RuntimeException e) { + setFlowStatus(realizedFlowNode, ExecutionProcess.ERROR); + throw e; + } } + } catch (RepositoryException e) { + throw new ArgeoException("Cannot process " + + getJcrExecutionProcess().getNodePath(), e); + } finally { + JcrUtils.logoutQuietly(session); } - } catch (RepositoryException e) { - throw new ArgeoException("Cannot process " - + getJcrExecutionProcess().getNodePath(), e); - } finally { - JcrUtils.logoutQuietly(session); - } + else + super.process(); } - // - // /** CONFIGURE THE REALIZED FLOWS */ - // PROTECTED VOID EXECUTE(NODE REALIZEDFLOWNODE) THROWS REPOSITORYEXCEPTION, - // INTERRUPTEDEXCEPTION { - // IF (REALIZEDFLOWNODE.HASNODE(SLC_ADDRESS)) { - // STRING FLOWPATH = REALIZEDFLOWNODE.GETNODE(SLC_ADDRESS) - // .GETPROPERTY(PROPERTY.JCR_PATH).GETSTRING(); - // // TODO: CONVERT TO LOCAL PATH IF REMOTE - // - // NODE FLOWNODE = REALIZEDFLOWNODE.GETSESSION().GETNODE(FLOWPATH); - // STRING FLOWNAME = FLOWNODE.GETPROPERTY(SLC_NAME).GETSTRING(); - // - // NODE EXECUTIONMODULENODE = FLOWNODE.GETSESSION().GETNODE( - // SLCJCRUTILS.MODULEPATH(FLOWPATH)); - // STRING EXECUTIONMODULENAME = EXECUTIONMODULENODE.GETPROPERTY( - // SLC_NAME).GETSTRING(); - // STRING EXECUTIONMODULEVERSION = EXECUTIONMODULENODE.GETPROPERTY( - // SLC_VERSION).GETSTRING(); - // - // REALIZEDFLOW REALIZEDFLOW = NEW REALIZEDFLOW(); - // REALIZEDFLOW.SETMODULENAME(EXECUTIONMODULENAME); - // REALIZEDFLOW.SETMODULEVERSION(EXECUTIONMODULEVERSION); - // - // // RETRIEVE EXECUTION SPEC - // DEFAULTEXECUTIONSPEC EXECUTIONSPEC = NEW DEFAULTEXECUTIONSPEC(); - // MAP ATTRS = - // READEXECUTIONSPECATTRIBUTES(REALIZEDFLOWNODE); - // EXECUTIONSPEC.SETATTRIBUTES(ATTRS); - // - // // SET EXECUTION SPEC NAME - // IF (FLOWNODE.HASPROPERTY(SLCNAMES.SLC_SPEC)) { - // NODE EXECUTIONSPECNODE = FLOWNODE.GETPROPERTY(SLC_SPEC) - // .GETNODE(); - // EXECUTIONSPEC.SETBEANNAME(EXECUTIONSPECNODE.GETPROPERTY( - // SLC_NAME).GETSTRING()); - // } - // - // // EXPLICITLY RETRIEVE VALUES - // MAP VALUES = NEW HASHMAP(); - // FOR (STRING ATTRNAME : ATTRS.KEYSET()) { - // EXECUTIONSPECATTRIBUTE ATTR = ATTRS.GET(ATTRNAME); - // OBJECT VALUE = ATTR.GETVALUE(); - // VALUES.PUT(ATTRNAME, VALUE); - // } - // - // EXECUTIONFLOWDESCRIPTOR EFD = NEW EXECUTIONFLOWDESCRIPTOR(FLOWNAME, - // VALUES, EXECUTIONSPEC); - // REALIZEDFLOW.SETFLOWDESCRIPTOR(EFD); - // - // // - // // EXECUTE THE FLOW - // // - // EXECUTE(REALIZEDFLOW, TRUE); - // // - // } - // } - // - // PROTECTED MAP - // READEXECUTIONSPECATTRIBUTES( - // NODE NODE) { - // TRY { - // MAP ATTRS = NEW HASHMAP(); - // FOR (NODEITERATOR NIT = NODE.GETNODES(); NIT.HASNEXT();) { - // NODE SPECATTRNODE = NIT.NEXTNODE(); - // IF (SPECATTRNODE - // .ISNODETYPE(SLCTYPES.SLC_PRIMITIVE_SPEC_ATTRIBUTE)) { - // STRING TYPE = SPECATTRNODE.GETPROPERTY(SLC_TYPE) - // .GETSTRING(); - // OBJECT VALUE = NULL; - // IF (SPECATTRNODE.HASPROPERTY(SLC_VALUE)) { - // STRING VALUESTR = SPECATTRNODE.GETPROPERTY(SLC_VALUE) - // .GETSTRING(); - // VALUE = PRIMITIVEUTILS.CONVERT(TYPE, VALUESTR); - // } - // PRIMITIVESPECATTRIBUTE SPECATTR = NEW PRIMITIVESPECATTRIBUTE( - // TYPE, VALUE); - // ATTRS.PUT(SPECATTRNODE.GETNAME(), SPECATTR); - // } ELSE IF (SPECATTRNODE - // .ISNODETYPE(SLCTYPES.SLC_REF_SPEC_ATTRIBUTE)) { - // IF (!SPECATTRNODE.HASPROPERTY(SLC_VALUE)) { - // CONTINUE; - // } - // INTEGER VALUE = (INT) SPECATTRNODE.GETPROPERTY(SLC_VALUE) - // .GETLONG(); - // REFSPECATTRIBUTE SPECATTR = NEW REFSPECATTRIBUTE(); - // NODEITERATOR CHILDREN = SPECATTRNODE.GETNODES(); - // INT INDEX = 0; - // STRING ID = NULL; - // WHILE (CHILDREN.HASNEXT()) { - // NODE CHILD = CHILDREN.NEXTNODE(); - // IF (INDEX == VALUE) - // ID = CHILD.GETNAME(); - // INDEX++; - // } - // SPECATTR.SETVALUE(ID); - // ATTRS.PUT(SPECATTRNODE.GETNAME(), SPECATTR); - // } - // // THROW NEW SLCEXCEPTION("UNSUPPORTED SPEC ATTRIBUTE " - // // + SPECATTRNODE); - // } - // RETURN ATTRS; - // } CATCH (REPOSITORYEXCEPTION E) { - // THROW NEW SLCEXCEPTION("CANNOT READ SPEC ATTRIBUTES FROM " + NODE, - // E); - // } - // } + protected void setFlowStatus(Node realizedFlowNode, String status) + throws RepositoryException { + realizedFlowNode.setProperty(SLC_STATUS, status); + realizedFlowNode.getSession().save(); + } protected JcrExecutionProcess getJcrExecutionProcess() { return (JcrExecutionProcess) getProcess(); diff --git a/runtime/org.argeo.slc.support.jcr/src/main/java/org/argeo/slc/jcr/execution/JcrRealizedFlow.java b/runtime/org.argeo.slc.support.jcr/src/main/java/org/argeo/slc/jcr/execution/JcrRealizedFlow.java index 68aebd143..b382a9bee 100644 --- a/runtime/org.argeo.slc.support.jcr/src/main/java/org/argeo/slc/jcr/execution/JcrRealizedFlow.java +++ b/runtime/org.argeo.slc.support.jcr/src/main/java/org/argeo/slc/jcr/execution/JcrRealizedFlow.java @@ -42,6 +42,10 @@ public class JcrRealizedFlow extends RealizedFlow implements SlcNames { Node flowNode = realizedFlowNode.getSession().getNode(flowPath); String flowName = flowNode.getProperty(SLC_NAME).getString(); + String description = null; + if (flowNode.hasProperty(Property.JCR_DESCRIPTION)) + description = flowNode.getProperty(Property.JCR_DESCRIPTION) + .getString(); Node executionModuleNode = flowNode.getSession().getNode( SlcJcrUtils.modulePath(flowPath)); @@ -76,7 +80,7 @@ public class JcrRealizedFlow extends RealizedFlow implements SlcNames { } ExecutionFlowDescriptor efd = new ExecutionFlowDescriptor(flowName, - values, executionSpec); + description, values, executionSpec); realizedFlow.setFlowDescriptor(efd); } else { throw new SlcException("Unsupported realized flow " 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 3c3ed4067..ee3f151f2 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 @@ -320,6 +320,15 @@ public class BundlesManager implements BundleContextAware, FrameworkListener, return service; } + public OsgiBundle findRelatedBundle(String moduleName, String moduleVersion) { + OsgiBundle osgiBundle = new OsgiBundle(moduleName, moduleVersion); + if (osgiBundle.getVersion() == null) { + Bundle bundle = findRelatedBundle(osgiBundle); + osgiBundle = new OsgiBundle(bundle); + } + return osgiBundle; + } + /** * @param osgiBundle * cannot be null diff --git a/runtime/org.argeo.slc.support.osgi/src/main/java/org/argeo/slc/osgi/OsgiExecutionModulesManager.java b/runtime/org.argeo.slc.support.osgi/src/main/java/org/argeo/slc/osgi/OsgiExecutionModulesManager.java index d46ad48c5..8f1efe35d 100644 --- a/runtime/org.argeo.slc.support.osgi/src/main/java/org/argeo/slc/osgi/OsgiExecutionModulesManager.java +++ b/runtime/org.argeo.slc.support.osgi/src/main/java/org/argeo/slc/osgi/OsgiExecutionModulesManager.java @@ -140,9 +140,16 @@ public class OsgiExecutionModulesManager extends bundles: for (Iterator iterator = executionContexts .keySet().iterator(); iterator.hasNext();) { OsgiBundle ob = iterator.next(); - if (ob.equals(nameVersion)) { - osgiBundle = ob; - break bundles; + if (nameVersion.getVersion() != null) { + if (ob.equals(nameVersion)) { + osgiBundle = ob; + break bundles; + } + } else { + if (ob.getName().equals(nameVersion.getName())) { + osgiBundle = ob; + break bundles; + } } } if (osgiBundle == null) @@ -180,7 +187,8 @@ public class OsgiExecutionModulesManager extends String moduleName, String moduleVersion) { Map flows = new HashMap(); - OsgiBundle key = new OsgiBundle(moduleName, moduleVersion); + OsgiBundle key = bundlesManager.findRelatedBundle(moduleName, + moduleVersion); if (!executionFlows.containsKey(key)) return flows; Set flowsT = executionFlows.get(key); @@ -274,8 +282,9 @@ public class OsgiExecutionModulesManager extends protected synchronized ExecutionFlowDescriptorConverter getExecutionFlowDescriptorConverter( String moduleName, String moduleVersion) { - OsgiBundle osgiBundle = new OsgiBundle(moduleName, moduleVersion); - return getExecutionFlowDescriptorConverter(osgiBundle); + return findExecutionFlowDescriptorConverter(moduleName, moduleVersion); + // OsgiBundle osgiBundle = new OsgiBundle(moduleName, moduleVersion); + // return getExecutionFlowDescriptorConverter(osgiBundle); } protected synchronized ExecutionFlowDescriptorConverter getExecutionFlowDescriptorConverter( @@ -307,7 +316,7 @@ public class OsgiExecutionModulesManager extends Bundle bundle = bundlesManager.findRelatedBundle(new OsgiBundle( nameVersion)); if (bundle == null) - throw new SlcException("Counld not find bundle for " + throw new SlcException("Could not find bundle for " + nameVersion); bundlesManager.startSynchronous(bundle); -- 2.39.2