/*
- * Copyright (C) 2007-2012 Mathieu Baudier
+ * Copyright (C) 2007-2012 Argeo GmbH
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
package org.argeo.slc.cli;
import java.io.File;
-import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.lang.reflect.Method;
+import java.security.AccessController;
+import java.security.PrivilegedAction;
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.HashMap;
import java.util.List;
-import java.util.Properties;
-
-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.Option;
-import org.apache.commons.cli.OptionBuilder;
-import org.apache.commons.cli.Options;
-import org.apache.commons.cli.ParseException;
-import org.apache.commons.io.IOUtils;
+import java.util.Map;
+import java.util.ServiceLoader;
+import java.util.UUID;
+
+import javax.security.auth.Subject;
+import javax.security.auth.login.LoginContext;
+
import org.argeo.osgi.boot.OsgiBoot;
-import org.argeo.slc.SlcException;
-import org.argeo.slc.execution.ExecutionModulesManager;
-import org.eclipse.core.runtime.adaptor.EclipseStarter;
-import org.osgi.framework.Bundle;
import org.osgi.framework.BundleContext;
+import org.osgi.framework.BundleException;
import org.osgi.framework.ServiceReference;
+import org.osgi.framework.launch.Framework;
+import org.osgi.framework.launch.FrameworkFactory;
-@SuppressWarnings("static-access")
-public class SlcMain {
- public enum Type {
- standalone, agent, server
- }
+/** Configures an SLC runtime and runs a process. */
+public class SlcMain implements PrivilegedAction<String> {
+ public final static String NIX = "NIX";
+ public final static String WINDOWS = "WINDOWS";
+ public final static String SOLARIS = "SOLARIS";
- private static Boolean debug = true;
+ public final static String os;
+ public final static String slcDirName = ".slc";
+ final static File homeDir = new File(System.getProperty("user.home"));
- // private final static String BOOTSTRAP_LOG4J_CONFIG =
- // "org/argeo/slc/cli/bootstrapLog4j.properties";
- // private final static String DEFAULT_AGENT_CONTEXT =
- // "classpath:org/argeo/slc/cli/spring-agent-default.xml";
+ static {
+ String osName = System.getProperty("os.name");
+ if (osName.startsWith("Win"))
+ os = WINDOWS;
+ else if (osName.startsWith("Solaris"))
+ os = SOLARIS;
+ else
+ os = NIX;
+ }
- private final static Option typeOpt = OptionBuilder.withLongOpt("mode")
- .withArgName("mode").hasArg()
- .withDescription("Execution type, one of: " + listTypeValues())
- .create('t');
+ private Long timeout = 30 * 1000l;
+ private final String[] args;
+ private final File confDir;
+ private final File dataDir;
+ private final File modulesDir;
+
+ private final List<String> bundlesToStart = new ArrayList<String>();
+
+ public SlcMain(String[] args, File confDir, File dataDir, File modulesDir) {
+ this.args = args;
+ this.confDir = confDir;
+ this.dataDir = dataDir;
+ this.modulesDir = modulesDir;
+ bundlesToStart.add("org.springframework.osgi.extender");
+ bundlesToStart.add("org.argeo.node.repo.jackrabbit");
+ bundlesToStart.add("org.argeo.security.dao.os");
+ bundlesToStart.add("org.argeo.slc.node.jackrabbit");
+ bundlesToStart.add("org.argeo.slc.agent");
+ bundlesToStart.add("org.argeo.slc.agent.jcr");
+ if (args.length == 0)
+ bundlesToStart.add("org.argeo.slc.support.equinox");
+ // bundlesToStart.add("org.argeo.slc.agent.cli");
+ }
- private final static Option propertyOpt = OptionBuilder
- .withLongOpt("property").withArgName("prop1=val1,prop2=val2")
- .hasArgs().withValueSeparator(',')
- .withDescription("use value for given property").create('p');
+ public String run() {
+ long begin = System.currentTimeMillis();
- private final static Option propertiesOpt = OptionBuilder
- .withLongOpt("properties").withArgName("properties file").hasArgs()
- .withValueSeparator(',')
- .withDescription("load properties from file (-p has priority)")
- .create('P');
+ Framework framework = null;
+ try {
+ info("## Date : " + new Date());
+ info("## Data : " + dataDir.getCanonicalPath());
+
+ // Start Equinox
+ ServiceLoader<FrameworkFactory> ff = ServiceLoader
+ .load(FrameworkFactory.class);
+ FrameworkFactory frameworkFactory = ff.iterator().next();
+ Map<String, String> configuration = new HashMap<String, String>();
+ configuration.put("osgi.configuration.area",
+ confDir.getCanonicalPath());
+ configuration.put("osgi.instance.area", dataDir.getCanonicalPath());
+ if (args.length == 0) {
+ // configuration.put("osgi.clean", "true");
+ configuration.put("osgi.console", "");
+ }
- private final static Option moduleOpt = OptionBuilder.withLongOpt("module")
- .withArgName("module").hasArg().withDescription("Execution module")
- .create('m');
+ // Spring configs currently require System properties
+ System.getProperties().putAll(configuration);
- private final static Option flowsOpt = OptionBuilder.withLongOpt("flows")
- .withArgName("flows").hasArg().withDescription("Flows to execute")
- .create('f');
+ framework = frameworkFactory.newFramework(configuration);
+ framework.start();
+ BundleContext bundleContext = framework.getBundleContext();
- private final static Option runtimeOpt = OptionBuilder
- .withLongOpt("runtime").withArgName("runtime").hasArg()
- .withDescription("Runtime URL").create('r');
+ // OSGi bootstrap
+ OsgiBoot osgiBoot = new OsgiBoot(bundleContext);
- private final static Options options;
+ // working copy modules
+ if (modulesDir.exists())
+ osgiBoot.installUrls(osgiBoot.getBundlesUrls(modulesDir
+ .getCanonicalPath() + ";in=*;ex=.gitignore"));
- private final static String commandName = "slc";
+ // system modules
+ if (System.getProperty(OsgiBoot.PROP_ARGEO_OSGI_BUNDLES) != null)
+ osgiBoot.installUrls(osgiBoot.getBundlesUrls(System
+ .getProperty(OsgiBoot.PROP_ARGEO_OSGI_BUNDLES)));
+ else
+ osgiBoot.installUrls(osgiBoot.getBundlesUrls(System
+ .getProperty("user.home") + "/.slc/modules/;in=**"));
- private static String bundlesToInstall = "/usr/share/osgi;in=*.jar";
+ // Start runtime
+ osgiBoot.startBundles(bundlesToStart);
- private static String bundlesToStart = "org.springframework.osgi.extender,"
- + "org.argeo.node.repofactory.jackrabbit,"
- + "org.argeo.node.repo.jackrabbit," + "org.argeo.security.dao.os,"
- + "org.argeo.slc.node.jackrabbit," + "org.argeo.slc.agent,"
- + "org.argeo.slc.agent.jcr";
+ // Find SLC Agent
+ ServiceReference sr = null;
+ while (sr == null) {
+ sr = bundleContext
+ .getServiceReference("org.argeo.slc.execution.SlcAgentCli");
+ if (System.currentTimeMillis() - begin > timeout)
+ throw new RuntimeException("Cannot find SLC agent CLI");
+ Thread.sleep(100);
+ }
+ Object agentCli = bundleContext.getService(sr);
- static {
- options = new Options();
- // options.addOption(typeOpt);
- // options.addOption(moduleOpt);
- // options.addOption(flowsOpt);
- // options.addOption(propertyOpt);
- // options.addOption(propertiesOpt);
- // options.addOption(runtimeOpt);
- }
+ // Initialization completed
+ long duration = System.currentTimeMillis() - begin;
+ info("[[ Initialized in " + (duration / 1000) + "s "
+ + (duration % 1000) + "ms ]]");
- public static void main(String[] args) {
- // Type type = null;
- // Properties properties = new Properties();
- // String flows = null;
- // String urlStr = null;
+ if (args.length == 0)
+ return null;// console mode
- String module = null;
- String moduleUrl = null;
- String flow = null;
+ // Subject.doAs(Subject.getSubject(AccessController.getContext()),
+ // new AgentCliCall(agentCli));
+ Class<?>[] parameterTypes = { String[].class };
+ Method method = agentCli.getClass().getMethod("process",
+ parameterTypes);
+ Object[] methodArgs = { args };
+ Object ret = method.invoke(agentCli, methodArgs);
- try {
-
- CommandLineParser clParser = new GnuParser();
- CommandLine cl = clParser.parse(options, args);
+ // Shutdown OSGi runtime
+ framework.stop();
+ framework.waitForStop(60 * 1000);
- List<String> 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();
- }
+ return ret.toString();
+ } catch (Exception e) {
+ // Shutdown OSGi runtime
+ if (framework != null)
+ try {
+ framework.stop();
+ framework.waitForStop(15 * 1000);
+ } catch (Exception silent) {
}
+ throw new RuntimeException("Cannot run SLC command line", e);
+ } finally {
+
+ }
+ }
- if (arguments.size() == 1) {
- // TODO module info
- } else {
- flow = arguments.get(1);
+ public static void main(String[] args) {
+ try {
+ // Prepare directories
+ File executionDir = new File(System.getProperty("user.dir"));
+ File slcDir;
+ Boolean isTransient = false;
+ if (isTransient) {
+ File tempDir = new File(System.getProperty("java.io.tmpdir")
+ + "/" + System.getProperty("user.name"));
+ slcDir = new File(tempDir, "slc-"
+ + UUID.randomUUID().toString());
+ slcDir.mkdirs();
+ System.setProperty("argeo.node.repo.configuration",
+ "osgibundle:repository-memory.xml");
+ } else {
+ slcDir = findSlcDir(executionDir);
+ if (slcDir == null) {
+ slcDir = new File(executionDir, slcDirName);
+ slcDir.mkdirs();
+ info("## Creating an SLC node at " + slcDir + " ...");
}
}
- // System.setProperty(
- // ExecutionModulesManager.UNIQUE_LAUNCH_MODULE_PROPERTY,
- // module);
- // System.setProperty(
- // ExecutionModulesManager.UNIQUE_LAUNCH_FLOW_PROPERTY, flow);
-
- String executionDir = System.getProperty("user.dir");
- File slcDir = new File(executionDir, ".slc");
File dataDir = new File(slcDir, "data");
if (!dataDir.exists())
dataDir.mkdirs();
+
File confDir = new File(slcDir, "conf");
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);
- }
-
- // OSGi bootstrap
- OsgiBoot osgiBoot = new OsgiBoot(bundleContext);
- osgiBoot.installUrls(osgiBoot.getBundlesUrls(bundlesToInstall));
- osgiBoot.startBundles(bundlesToStart);
-
- if (moduleUrl != null) {
- Bundle bundle = osgiBoot.installUrl(moduleUrl);
- module = bundle.getSymbolicName();
- // TODO deal with version
- }
-
- // retrieve modulesManager
- ServiceReference sr = bundleContext
- .getServiceReference(ExecutionModulesManager.class
- .getName());
- ExecutionModulesManager modulesManager = (ExecutionModulesManager) bundleContext
- .getService(sr);
-
-
- modulesManager.execute(null);
-
- // osgiBoot.bootstrap();
- // osgiBoot.bootstrap();
-
- // Mode
- // String typeStr = cl.getOptionValue(typeOpt.getOpt());
- // if (typeStr == null) {
- // type = Type.standalone;
- // } else {
- // try {
- // type = Type.valueOf(typeStr);
- // } catch (IllegalArgumentException e) {
- // throw new SlcException("Unrecognized mode '" + typeStr
- // + "'", e);
- // }
- // }
- //
- // // Script
- // if (type.equals(Type.standalone)) {
- // if (!cl.hasOption(moduleOpt.getOpt()))
- // throw new SlcException("Type " + Type.standalone
- // + " requires option '" + moduleOpt.getLongOpt()
- // + "'");
- // module = cl.getOptionValue(moduleOpt.getOpt());
- //
- // // Targets
- // if (cl.hasOption(flowsOpt.getOpt()))
- // flows = cl.getOptionValue(flowsOpt.getOpt());
- // }
- //
- // // Properties
- // if (cl.hasOption(propertiesOpt.getOpt())) {
- // for (String propertyFile : cl.getOptionValues(propertiesOpt
- // .getOpt())) {
- // loadPropertyFile(properties, propertyFile);
- // }
- // }
- // if (cl.hasOption(propertyOpt.getOpt())) {
- // for (String property : cl.getOptionValues(propertyOpt.getOpt()))
- // {
- // addProperty(properties, property);
- // }
- // }
- //
- // // Runtime
- // if (cl.hasOption(runtimeOpt.getOpt())) {
- // urlStr = cl.getOptionValue(runtimeOpt.getOpt());
- // }
- } catch (ParseException e) {
- System.err.println("Problem with command line arguments. "
- + e.getMessage());
- badExit();
- } catch (SlcException e) {
- System.err.println(e.getMessage());
- badExit();
+ File modulesDir = new File(slcDir, "modules");
+
+ // JAAS
+ File jaasFile = new File(confDir, "jaas.config");
+ if (!jaasFile.exists())
+ copyResource("/org/argeo/slc/cli/jaas.config", jaasFile);
+ System.setProperty("java.security.auth.login.config",
+ jaasFile.getCanonicalPath());
+
+ // log4j
+ File log4jFile = new File(confDir, "log4j.properties");
+ if (!log4jFile.exists())
+ copyResource("/org/argeo/slc/cli/log4j.properties", log4jFile);
+ System.setProperty("log4j.configuration",
+ "file://" + log4jFile.getCanonicalPath());
+ // Run as a privileged action
+ LoginContext lc = new LoginContext(os);
+ lc.login();
+
+ Subject subject = Subject.getSubject(AccessController.getContext());
+ Subject.doAs(subject, new SlcMain(args, confDir, dataDir,
+ modulesDir));
+
+ if (args.length != 0)
+ System.exit(0);
} catch (Exception e) {
- System.err.println("Unexpected exception when bootstrapping.");
e.printStackTrace();
- badExit();
- }
-
- // if (debug) {
- // debug("Mode: " + type);
- // if (urlStr != null)
- // debug("Runtime: " + urlStr);
- // debug("User properties: " + properties);
- // if (module != null)
- // debug("Module: " + module);
- // if (flows != null)
- // debug("Flows: " + flows);
- // }
- //
- // // Standalone
- // if (type.equals(Type.standalone)) {
- // }
- // // Agent
- // else if (type.equals(Type.agent)) {
- // }
- }
-
- public static void printUsage() {
- new HelpFormatter().printHelp(commandName, options, true);
- }
-
- private static String listTypeValues() {
- StringBuffer buf = new StringBuffer("");
- for (Type mode : Type.values()) {
- buf.append(mode).append(", ");
+ System.exit(1);
}
- String str = buf.toString();
- // unsafe, but there will be at least one value in the enum
- return str.substring(0, str.length() - 2);
}
- 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");
+ /**
+ * Recursively look in parent directories for a directory named
+ * {@link #slcDirName}
+ */
+ protected static File findSlcDir(File currentDir) {
+ File slcDir = new File(currentDir, slcDirName);
+ if (slcDir.exists() && slcDir.isDirectory())
+ return slcDir;
+ File parentDir = currentDir.getParentFile();
+ if (parentDir == null)
+ return null;
+ try {
+ // ~/.slc reserved for agent
+ if (parentDir.getCanonicalPath().equals(homeDir.getCanonicalPath()))
+ return null;
+ } catch (IOException e) {
+ throw new RuntimeException("Cannot check home directory", e);
}
+ return findSlcDir(parentDir);
}
- protected static void loadPropertyFile(Properties properties,
- String propertyFile) {
- FileInputStream in = null;
+ protected static void copyResource(String resource, File targetFile) {
+ InputStream input = null;
+ FileOutputStream output = null;
try {
- in = new FileInputStream(propertyFile);
- properties.load(in);
+ input = SlcMain.class.getResourceAsStream(resource);
+ output = new FileOutputStream(targetFile);
+ byte[] buf = new byte[8192];
+ while (true) {
+ int length = input.read(buf);
+ if (length < 0)
+ break;
+ output.write(buf, 0, length);
+ }
} catch (Exception e) {
- throw new SlcException("Could not load proeprty file "
- + propertyFile);
+ throw new RuntimeException("Cannot write " + resource + " file to "
+ + targetFile, e);
} finally {
- IOUtils.closeQuietly(in);
+ try {
+ input.close();
+ } catch (Exception ignore) {
+ }
+ try {
+ output.close();
+ } catch (Exception ignore) {
+ }
}
- }
- private static void badExit() {
- printUsage();
- System.exit(1);
}
protected static void info(Object msg) {
System.out.println(msg);
}
+ protected static void err(Object msg) {
+ System.err.println(msg);
+ }
+
protected static void debug(Object msg) {
System.out.println(msg);
}
+
}
+
+// private String bundlesToInstall = System.getProperty("user.home")
+// +
+// "/dev/src/slc/dep/org.argeo.slc.dep.minimal/target/dependency;in=*.jar,"
+// + System.getProperty("user.home")
+// + "/dev/src/slc/demo/modules;in=*;ex=pom.xml;ex=.svn";
+
+// ServiceTracker agentTracker = new ServiceTracker(bundleContext,
+// "org.argeo.slc.execution.SlcAgentCli", null);
+// agentTracker.open();
+// final Object agentCli = agentTracker.waitForService(30 * 1000);
+// if (agentCli == null)
+// throw new RuntimeException("Cannot find SLC agent CLI");
+
+// protected class AgentCliCall implements PrivilegedAction<String> {
+// private final Object agentCli;
+//
+// public AgentCliCall(Object agentCli) {
+// super();
+// this.agentCli = agentCli;
+// }
+//
+// 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);
+// }
+// }
+//
+// }
+