X-Git-Url: http://git.argeo.org/?a=blobdiff_plain;f=runtime%2Forg.argeo.slc.launcher%2Fsrc%2Fmain%2Fjava%2Forg%2Fargeo%2Fslc%2Fcli%2FSlcMain.java;h=7bda5c84f7c7f6141deb44460c18f2d06a2908a1;hb=94ced3cb126cdc46436f84cad15ef4464e495071;hp=4aa0d095bdcc7b906fac601366a170560a6a579b;hpb=58e0e18d64a2080680a9f8397b0dfa2894519910;p=gpl%2Fargeo-slc.git 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 4aa0d095b..7bda5c84f 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,320 +16,329 @@ 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.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.eclipse.core.runtime.adaptor.EclipseStarter; -import org.osgi.framework.Bundle; import org.osgi.framework.BundleContext; +import org.osgi.framework.ServiceReference; +import org.osgi.framework.launch.Framework; +import org.osgi.framework.launch.FrameworkFactory; -@SuppressWarnings("restriction") -public class SlcMain { - /** Unique launch module */ - public static String UNIQUE_LAUNCH_MODULE_PROPERTY = "slc.launch.module"; - - /** Unique launch flow */ - public static String UNIQUE_LAUNCH_FLOW_PROPERTY = "slc.launch.flow"; - - // public enum Type { - // standalone, agent, server - // } - - // private static Boolean debug = true; - - // 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"; - - // private final static Option typeOpt = OptionBuilder.withLongOpt("mode") - // .withArgName("mode").hasArg() - // .withDescription("Execution type, one of: " + listTypeValues()) - // .create('t'); - // - // private final static Option propertyOpt = OptionBuilder - // .withLongOpt("property").withArgName("prop1=val1,prop2=val2") - // .hasArgs().withValueSeparator(',') - // .withDescription("use value for given property").create('p'); - // - // private final static Option propertiesOpt = OptionBuilder - // .withLongOpt("properties").withArgName("properties file").hasArgs() - // .withValueSeparator(',') - // .withDescription("load properties from file (-p has priority)") - // .create('P'); - // - // private final static Option moduleOpt = - // OptionBuilder.withLongOpt("module") - // .withArgName("module").hasArg().withDescription("Execution module") - // .create('m'); - // - // private final static Option flowsOpt = OptionBuilder.withLongOpt("flows") - // .withArgName("flows").hasArg().withDescription("Flows to execute") - // .create('f'); - // - // private final static Option runtimeOpt = OptionBuilder - // .withLongOpt("runtime").withArgName("runtime").hasArg() - // .withDescription("Runtime URL").create('r'); - - private final static Options options; - - private final static String commandName = "slc"; - - // private static String bundlesToInstall = "/usr/share/osgi;in=*.jar"; - private static String bundlesToInstall = System.getProperty("user.home") - + "/dev/src/slc/runtime/org.argeo.slc.launcher/target/dependency;in=*.jar"; - - // 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"; - private static String bundlesToStart = "org.springframework.osgi.extender," - + "org.argeo.slc.agent"; +/** Configures an SLC runtime and runs a process. */ +public class SlcMain implements PrivilegedAction { + public final static String NIX = "NIX"; + public final static String WINDOWS = "WINDOWS"; + public final static String SOLARIS = "SOLARIS"; + + public final static String os; + public final static String slcDirName = ".slc"; + final static File homeDir = new File(System.getProperty("user.home")); static { - options = new Options(); - // options.addOption(typeOpt); - // options.addOption(moduleOpt); - // options.addOption(flowsOpt); - // options.addOption(propertyOpt); - // options.addOption(propertiesOpt); - // options.addOption(runtimeOpt); + String osName = System.getProperty("os.name"); + if (osName.startsWith("Win")) + os = WINDOWS; + else if (osName.startsWith("Solaris")) + os = SOLARIS; + else + os = NIX; } - @SuppressWarnings({ "unchecked" }) - public static void main(String[] args) { - // Type type = null; - // Properties properties = new Properties(); - // String flows = null; - // String urlStr = null; + private Long timeout = 30 * 1000l; + private final String[] args; + private final File confDir; + private final File dataDir; + private final File modulesDir; + + private final List bundlesToStart = new ArrayList(); + + 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"); + } - String module = null; - String moduleUrl = null; - String flow = null; + public String run() { + long begin = System.currentTimeMillis(); + Framework framework = null; try { + info("## Date : " + new Date()); + info("## Data : " + dataDir.getCanonicalPath()); + + // 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()); + // FIXME must clean configuration area because jars are installed as + // file: by OSGi boot and not as reference:file: + configuration.put("osgi.clean", "true"); + if (args.length == 0) { + configuration.put("osgi.console", ""); + } - CommandLineParser clParser = new GnuParser(); - CommandLine cl = clParser.parse(options, args); + // Spring configs currently require System properties + System.getProperties().putAll(configuration); - 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(); - } + framework = frameworkFactory.newFramework(configuration); + framework.start(); + BundleContext bundleContext = framework.getBundleContext(); + + // OSGi bootstrap + OsgiBoot osgiBoot = new OsgiBoot(bundleContext); + + // working copy modules + if (modulesDir.exists()) + osgiBoot.installUrls(osgiBoot.getBundlesUrls(modulesDir + .getCanonicalPath() + ";in=*;ex=.gitignore")); + + // 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=**")); + + // Start runtime + osgiBoot.startBundles(bundlesToStart); + + // 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); + + // Initialization completed + long duration = System.currentTimeMillis() - begin; + info("[[ Initialized in " + (duration / 1000) + "s " + + (duration % 1000) + "ms ]]"); + + if (args.length == 0) + return null;// console mode + + // 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); + + // Shutdown OSGi runtime + framework.stop(); + framework.waitForStop(60 * 1000); + + 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 + " ..."); } } - String executionDir = System.getProperty("user.dir"); - File slcDir = new File(executionDir, "target/.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)); - - 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"); - - // start runtime - osgiBoot.startBundles(bundlesToStart); - - // Bundle bundle = (Bundle) osgiBoot.getBundlesBySymbolicName().get( - // "org.argeo.slc.specs"); - // bundle.loadClass(Execu) - // - // // retrieve modulesManager - // BundlesManager bundlesManager = new - // BundlesManager(bundleContext); - // ExecutionModulesManager modulesManager = bundlesManager - // .getSingleService(ExecutionModulesManager.class, null, true); - // - // RealizedFlow realizedFlow = RealizedFlow.create(module, null, - // flow, - // null); - // modulesManager.start(new BasicNameVersion(module, "0.0.0")); - // modulesManager.execute(realizedFlow); - - // 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(); + System.exit(1); } - - // 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(", "); - // } - // 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); + // covers the use case of running from the home directory + 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 { +// 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); +// } +// } +// +// } +