+/*
+ * 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.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
package org.argeo.slc.cli;
-import java.io.FileInputStream;
-import java.io.IOException;
-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 org.apache.commons.logging.Log;
-import org.apache.commons.logging.LogFactory;
-import org.argeo.slc.SlcException;
-import org.argeo.slc.logging.Log4jUtils;
-import org.argeo.slc.runtime.SlcExecutionContext;
-import org.argeo.slc.runtime.SlcRuntime;
-import org.springframework.context.ConfigurableApplicationContext;
-import org.springframework.context.support.ClassPathXmlApplicationContext;
-import org.springframework.context.support.FileSystemXmlApplicationContext;
-
-public class SlcMain {
- public enum Mode {
- single, agent, osgi
+import java.io.File;
+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.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.osgi.framework.BundleContext;
+import org.osgi.framework.ServiceReference;
+import org.osgi.framework.launch.Framework;
+import org.osgi.framework.launch.FrameworkFactory;
+
+/** Configures an SLC runtime and runs a process. */
+public class SlcMain implements Runnable {
+ public final static String NIX = "NIX";
+ public final static String WINDOWS = "WINDOWS";
+ public final static String SOLARIS = "SOLARIS";
+
+ public final static String os;
+ static {
+ String osName = System.getProperty("os.name");
+ if (osName.startsWith("Win"))
+ os = WINDOWS;
+ else if (osName.startsWith("Solaris"))
+ os = SOLARIS;
+ else
+ os = NIX;
}
- private static Log log = null;
-
- 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 modeOpt = OptionBuilder.withLongOpt("mode")
- .withArgName("mode").hasArg().withDescription(
- "SLC execution mode, one of: " + listModeValues()).create(
- 'm');
-
- 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 scriptOpt = OptionBuilder.withLongOpt("script")
- .withArgName("script").hasArg().withDescription(
- "SLC script to execute").create('s');
-
- private final static Option targetsOpt = OptionBuilder.withLongOpt(
- "targets").withArgName("targets").hasArg().withDescription(
- "Targets to execute").create('t');
-
- private final static Option runtimeOpt = OptionBuilder.withLongOpt(
- "runtime").withArgName("runtime").hasArg().withDescription(
- "Runtime to use, either a full path or relative to slc app conf dir: "
- + "<conf dir>/runtime/<runtime>/.xml").create('r');
-
- private final static Options options;
-
- private final static String commandName = "slc";
-
- static {
- options = new Options();
- options.addOption(modeOpt);
- options.addOption(scriptOpt);
- options.addOption(targetsOpt);
- options.addOption(propertyOpt);
- options.addOption(propertiesOpt);
- options.addOption(runtimeOpt);
+ // private final DateFormat dateFormat = new
+ // SimpleDateFormat("HH:mm:ss,SSS");
+ private Long timeout = 30 * 1000l;
+ private final String[] args;
+
+ // 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,"
+ + System.getProperty("user.home")
+ + "/dev/src/slc/demo/modules;in=*;ex=pom.xml;ex=.svn";
+
+ private final List<String> bundlesToStart = new ArrayList<String>();
+
+ public SlcMain(String[] args) {
+ this.args = args;
+ 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");
+ // bundlesToStart.add("org.argeo.slc.agent.cli");
}
- public static void main(String[] args) {
- Mode mode = null;
- Properties properties = new Properties();
- String script = null;
- String targets = null;
- String runtimeStr = null;
+ public void run() {
+ long begin = System.currentTimeMillis();
+ // System.out.println(dateFormat.format(new Date()));
+ Boolean isTransient = false;
+ File dataDir = null;
+ final LoginContext lc;
try {
-
- CommandLineParser clParser = new GnuParser();
- CommandLine cl = clParser.parse(options, args);
-
- // Mode
- String modeStr = cl.getOptionValue(modeOpt.getOpt());
- if (modeStr == null) {
- mode = Mode.single;
- } else {
- try {
- mode = Mode.valueOf(modeStr);
- } catch (IllegalArgumentException e) {
- throw new SlcException("Unrecognized mode '" + modeStr
- + "'", e);
- }
- }
-
- // Script
- if (mode.equals(Mode.single)) {
- if (!cl.hasOption(scriptOpt.getOpt()))
- throw new SlcException("Mode " + Mode.single
- + " requires option '" + scriptOpt.getLongOpt()
- + "'");
- script = cl.getOptionValue(scriptOpt.getOpt());
-
- // Targets
- if (cl.hasOption(targetsOpt.getOpt()))
- targets = cl.getOptionValue(targetsOpt.getOpt());
- }
-
- // Properties
- if (cl.hasOption(propertiesOpt.getOpt())) {
- for (String propertyFile : cl.getOptionValues(propertiesOpt
- .getOpt())) {
- loadPropertyFile(properties, propertyFile);
- }
+ // Authenticate
+ lc = new LoginContext(os);
+ lc.login();
+
+ // Prepare directories
+ String executionDir = System.getProperty("user.dir");
+ File slcDir = new File(executionDir, ".slc");
+ File tempDir = new File(System.getProperty("java.io.tmpdir"));
+
+ if (isTransient)
+ dataDir = new File(tempDir, "slc-data-"
+ + UUID.randomUUID().toString());
+ else
+ dataDir = new File(slcDir, "data");
+ if (!dataDir.exists())
+ dataDir.mkdirs();
+
+ File confDir = new File(slcDir, "conf");
+ if (!confDir.exists())
+ confDir.mkdirs();
+
+ System.setProperty("log4j.configuration", "file:./log4j.properties");
+ if (isTransient)
+ System.setProperty("argeo.node.repo.configuration",
+ "osgibundle:repository-memory.xml");
+
+ // 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());
+ // configuration.put("osgi.clean", "true");
+ // configuration.put("osgi.console", "");
+
+ // 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));
+
+ // 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);
}
- if (cl.hasOption(propertyOpt.getOpt())) {
- for (String property : cl.getOptionValues(propertyOpt.getOpt())) {
- addProperty(properties, property);
- }
- }
-
- // Runtime
- if (cl.hasOption(runtimeOpt.getOpt())) {
- runtimeStr = 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();
+ final Object agentCli = bundleContext.getService(sr);
+
+ // 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");
+
+ long duration = System.currentTimeMillis() - begin;
+ System.out.println("Initialized in " + (duration / 1000) + "s "
+ + (duration % 1000) + "ms");
+ // Run as a privileged action
+ Subject.doAs(Subject.getSubject(AccessController.getContext()),
+ new PrivilegedAction<String>() {
+
+ 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();
- }
-
- // Initializes logging and log arguments
- initLogging(properties);
- if (log.isDebugEnabled()) {
- log.debug("Mode: " + mode);
- if (runtimeStr != null)
- log.debug("Runtime: " + runtimeStr);
- log.debug("User properties: " + properties);
- if (script != null)
- log.debug("Script: " + script);
- if (targets != null)
- log.debug("Targets: " + targets);
- }
-
- // Execution
- if (mode.equals(Mode.single)) {
- try {
- // DefaultSlcRuntime runtime = new DefaultSlcRuntime();
- // FIXME: inject this more cleanly
- ClassLoader cl = Thread.currentThread().getContextClassLoader();
- Class clss = cl.loadClass("org.argeo.slc.ant.AntSlcRuntime");
- SlcRuntime<? extends SlcExecutionContext> runtime = (SlcRuntime<? extends SlcExecutionContext>) clss
- .newInstance();
- runtime.executeScript(runtimeStr, script, targets, properties,
- null, null);
- // System.exit(0);
- } catch (Exception e) {
- log.error("SLC client terminated with an error: ", e);
- System.exit(1);
- }
- }
- // Agent
- else if (mode.equals(Mode.agent)) {
- final ConfigurableApplicationContext applicationContext;
- if (runtimeStr == null) {
- applicationContext = new ClassPathXmlApplicationContext(
- DEFAULT_AGENT_CONTEXT);
- } else {
- applicationContext = new FileSystemXmlApplicationContext(
- runtimeStr);
- }
- applicationContext.registerShutdownHook();
- applicationContext.start();
- log.info("SLC Agent context started.");
- }
- // OSGi
- else if (mode.equals(Mode.osgi)) {
- final ConfigurableApplicationContext applicationContext;
- if (runtimeStr == null) {
- applicationContext = new ClassPathXmlApplicationContext(
- DEFAULT_AGENT_CONTEXT);
- } else {
- applicationContext = new FileSystemXmlApplicationContext(
- runtimeStr);
+ System.exit(1);
+ } finally {
+ if (isTransient && dataDir != null && dataDir.exists()) {
+ // TODO clean up transient data dir
}
- applicationContext.registerShutdownHook();
- applicationContext.start();
- log.info("SLC Agent context started.");
- }
- }
-
- public static void printUsage() {
- new HelpFormatter().printHelp(commandName, options, true);
- }
- private static String listModeValues() {
- StringBuffer buf = new StringBuffer("");
- for (Mode mode : Mode.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");
- }
+ public static void main(String[] args) {
+ new SlcMain(args).run();
}
- 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);
- }
+ protected static void info(Object msg) {
+ System.out.println(msg);
}
- private static void initLogging(Properties userProperties) {
- System.setProperty("log4j.defaultInitOverride", "true");
-
- // Add log4j user properties to System properties
- for (Object obj : userProperties.keySet()) {
- String key = obj.toString();
- if (key.startsWith("log4j.")) {
- System.setProperty(key, userProperties.getProperty(key));
- }
- }
- Log4jUtils.initLog4j(System.getProperty("log4j.configuration",
- "classpath:" + BOOTSTRAP_LOG4J_CONFIG));
- log = LogFactory.getLog(SlcMain.class);
-
+ protected static void debug(Object msg) {
+ System.out.println(msg);
}
- private static void badExit() {
- printUsage();
- System.exit(1);
- }
}