You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@karaf.apache.org by gn...@apache.org on 2013/03/13 13:21:07 UTC
svn commit: r1455901 [2/2] - in /karaf/trunk: ./
instance/command/src/main/java/org/apache/karaf/instance/main/
instance/command/src/test/java/org/apache/karaf/instance/main/
instance/core/ instance/core/src/main/java/org/apache/karaf/instance/core/
in...
Modified: karaf/trunk/instance/core/src/main/java/org/apache/karaf/instance/core/internal/InstanceServiceImpl.java
URL: http://svn.apache.org/viewvc/karaf/trunk/instance/core/src/main/java/org/apache/karaf/instance/core/internal/InstanceServiceImpl.java?rev=1455901&r1=1455900&r2=1455901&view=diff
==============================================================================
--- karaf/trunk/instance/core/src/main/java/org/apache/karaf/instance/core/internal/InstanceServiceImpl.java (original)
+++ karaf/trunk/instance/core/src/main/java/org/apache/karaf/instance/core/internal/InstanceServiceImpl.java Wed Mar 13 12:21:07 2013
@@ -16,26 +16,40 @@
*/
package org.apache.karaf.instance.core.internal;
+import org.apache.karaf.instance.core.Instance;
+import org.apache.karaf.instance.core.InstanceService;
+import org.apache.karaf.instance.core.InstanceSettings;
+import org.apache.karaf.jpm.Process;
+import org.apache.karaf.jpm.impl.ProcessBuilderFactoryImpl;
+import org.apache.karaf.jpm.impl.ScriptUtils;
+import org.apache.karaf.util.properties.FileLockUtils;
+import org.fusesource.jansi.Ansi;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
+import java.io.FilenameFilter;
import java.io.IOException;
import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.InterruptedIOException;
import java.io.OutputStream;
import java.io.PrintStream;
+import java.net.Socket;
+import java.net.URL;
+import java.util.ArrayList;
import java.util.Collections;
+import java.util.Enumeration;
import java.util.HashMap;
+import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.Scanner;
-import org.apache.karaf.instance.core.Instance;
-import org.apache.karaf.instance.core.InstanceService;
-import org.apache.karaf.instance.core.InstanceSettings;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
public class InstanceServiceImpl implements InstanceService {
public static final String STORAGE_FILE = "instance.properties";
@@ -44,18 +58,41 @@ public class InstanceServiceImpl impleme
private static final Logger LOGGER = LoggerFactory.getLogger(InstanceServiceImpl.class);
- private Map<String, Instance> instances = new HashMap<String, Instance>();
+ private static final String CONFIG_PROPERTIES_FILE_NAME = "config.properties";
+
+ private static final String KARAF_SHUTDOWN_PORT = "karaf.shutdown.port";
+
+ private static final String KARAF_SHUTDOWN_HOST = "karaf.shutdown.host";
+
+ private static final String KARAF_SHUTDOWN_PORT_FILE = "karaf.shutdown.port.file";
- private int defaultSshPortStart = 8101;
+ private static final String KARAF_SHUTDOWN_COMMAND = "karaf.shutdown.command";
- private int defaultRmiRegistryPortStart = 1099;
+ private static final String KARAF_SHUTDOWN_PID_FILE = "karaf.shutdown.pid.file";
- private int defaultRmiServerPortStart = 44444;
+ private static final String DEFAULT_SHUTDOWN_COMMAND = "SHUTDOWN";
+
+ private LinkedHashMap<String, InstanceImpl> proxies = new LinkedHashMap<String, InstanceImpl>();
private File storageLocation;
private long stopTimeout = 30000;
+ static class InstanceState {
+ String name;
+ String loc;
+ String opts;
+ int pid;
+ boolean root;
+ }
+
+ static class State {
+ int defaultSshPortStart = 8101;
+ int defaultRmiRegistryPortStart = 1099;
+ int defaultRmiServerPortStart = 44444;
+ Map<String, InstanceState> instances;
+ }
+
public File getStorageLocation() {
return storageLocation;
}
@@ -72,103 +109,123 @@ public class InstanceServiceImpl impleme
this.stopTimeout = stopTimeout;
}
- private Properties loadStorage(File location) throws IOException {
- InputStream is = null;
- try {
- is = new FileInputStream(location);
- Properties props = new Properties();
- props.load(is);
- return props;
- } finally {
- if (is != null) {
- is.close();
+ private State loadData(org.apache.felix.utils.properties.Properties storage) {
+ State state = new State();
+ int count = getInt(storage, "count", 0);
+ state.defaultSshPortStart = getInt(storage, "ssh.port", state.defaultSshPortStart);
+ state.defaultRmiRegistryPortStart = getInt(storage, "rmi.registry.port", state.defaultRmiRegistryPortStart);
+ state.defaultRmiServerPortStart = getInt(storage, "rmi.server.port", state.defaultRmiServerPortStart);
+ state.instances = new LinkedHashMap<String, InstanceState>();
+
+ for (int i = 0; i < count; i++) {
+ InstanceState instance = new InstanceState();
+ instance.name = getString(storage, "item." + i + ".name", null);
+ instance.loc = getString(storage, "item." + i + ".loc", null);
+ instance.opts = getString(storage, "item." + i + ".opts", null);
+ instance.pid = getInt(storage, "item." + i + ".pid", 0);
+ instance.root = getBool(storage, "item." + i + ".root", false);
+ state.instances.put(instance.name, instance);
+ }
+ // Update proxies list
+ for (InstanceState instance : state.instances.values()) {
+ if (!this.proxies.containsKey(instance.name)) {
+ proxies.put(instance.name, new InstanceImpl(this, instance.name));
+ }
+ }
+ List<String> names = new ArrayList<String>(this.proxies.keySet());
+ for (String name : names) {
+ if (!state.instances.containsKey(name)) {
+ this.proxies.remove(name);
}
}
+ return state;
}
- private void saveStorage(Properties props, File location, String comment) throws IOException {
- OutputStream os = null;
- try {
- os = new FileOutputStream(location);
- props.store(os, comment);
- } finally {
- if (os != null) {
- os.close();
- }
+ private void saveData(State state, org.apache.felix.utils.properties.Properties storage) {
+ storage.put("ssh.port", Integer.toString(state.defaultSshPortStart));
+ storage.put("rmi.registry.port", Integer.toString(state.defaultRmiRegistryPortStart));
+ storage.put("rmi.server.port", Integer.toString(state.defaultRmiServerPortStart));
+ storage.put("count", Integer.toString(state.instances.size()));
+ int i = 0;
+ for (InstanceState instance : state.instances.values()) {
+ storage.put("item." + i + ".name", instance.name);
+ storage.put("item." + i + ".root", Boolean.toString(instance.root));
+ storage.put("item." + i + ".loc", instance.loc);
+ storage.put("item." + i + ".pid", Integer.toString(instance.pid));
+ storage.put("item." + i + ".opts", instance.opts != null ? instance.opts : "");
+ i++;
+ }
+ while (storage.containsKey("item." + i + ".name")) {
+ storage.remove("item." + i + ".name");
+ storage.remove("item." + i + ".root");
+ storage.remove("item." + i + ".loc");
+ storage.remove("item." + i + ".pid");
+ storage.remove("item." + i + ".opts");
+ i++;
}
}
- public synchronized void init() throws Exception {
- try {
- File storageFile = new File(storageLocation, STORAGE_FILE);
- if (!storageFile.isFile()) {
- if (storageFile.exists()) {
- LOGGER.error("Instances storage location should be a file: " + storageFile);
- }
- return;
- }
- Properties storage = loadStorage(storageFile);
- int count = Integer.parseInt(storage.getProperty("count", "0"));
- defaultSshPortStart = Integer.parseInt(storage.getProperty("ssh.port", Integer.toString(defaultSshPortStart)));
- defaultRmiRegistryPortStart = Integer.parseInt(storage.getProperty("rmi.registry.port", Integer.toString(defaultRmiRegistryPortStart)));
- defaultRmiServerPortStart = Integer.parseInt(storage.getProperty("rmi.server.port", Integer.toString(defaultRmiServerPortStart)));
- Map<String, Instance> newInstances = new HashMap<String, Instance>();
- for (int i = 0; i < count; i++) {
- String name = storage.getProperty("item." + i + ".name", null);
- String loc = storage.getProperty("item." + i + ".loc", null);
- String opts = storage.getProperty("item." + i + ".opts", null);
- int pid = Integer.parseInt(storage.getProperty("item." + i + ".pid", "0"));
- boolean root = Boolean.parseBoolean(storage.getProperty("item." + i + ".root", "false"));
- if (name != null) {
- InstanceImpl instance = new InstanceImpl(this, name, loc, opts, root);
- if (pid > 0) {
- try {
- instance.attach(pid);
- } catch (IOException e) {
- // Ignore
- }
- }
- newInstances.put(name, instance);
- }
- }
- instances = newInstances;
- } catch (Exception e) {
- LOGGER.warn("Unable to reload Karaf instance list", e);
+ private boolean getBool(org.apache.felix.utils.properties.Properties storage, String name, boolean def) {
+ Object value = storage.get(name);
+ if (value != null) {
+ return Boolean.parseBoolean(value.toString());
+ } else {
+ return def;
}
}
-
- public synchronized void refreshInstance() throws Exception {
- try {
- init();
- File storageFile = new File(storageLocation, STORAGE_FILE);
+
+ private int getInt(org.apache.felix.utils.properties.Properties storage, String name, int def) {
+ Object value = storage.get(name);
+ if (value != null) {
+ return Integer.parseInt(value.toString());
+ } else {
+ return def;
+ }
+ }
+
+ private String getString(org.apache.felix.utils.properties.Properties storage, String name, String def) {
+ Object value = storage.get(name);
+ return value != null ? value.toString() : def;
+ }
+
+ interface Task<T> {
+ T call(State state) throws IOException;
+ }
+
+ <T> T execute(final Task<T> callback) {
+ final File storageFile = new File(storageLocation, STORAGE_FILE);
+ if (!storageFile.exists()) {
+ storageFile.getParentFile().mkdirs();
+ try {
+ storageFile.createNewFile();
+ } catch (IOException e) {
+ // Ignore
+ }
+ }
+ if (storageFile.exists()) {
if (!storageFile.isFile()) {
- if (storageFile.exists()) {
- LOGGER.error("Instances storage location should be a file: " + storageFile);
- }
- return;
+ throw new IllegalStateException("Instance storage location should be a file: " + storageFile);
}
- Properties storage = loadStorage(storageFile);
- int count = Integer.parseInt(storage.getProperty("count", "0"));
- for (int i = 0; i < count; i++) {
- String name = storage.getProperty("item." + i + ".name", null);
- int pid = Integer.parseInt(storage.getProperty("item." + i + ".pid", "0"));
- if (name != null) {
- InstanceImpl instance = (InstanceImpl)instances.get(name);
- if (pid > 0 && instance != null && !instance.isAttached()) {
- try {
- instance.attach(pid);
- } catch (IOException e) {
- // Ignore
- }
+ try {
+ return FileLockUtils.execute(storageFile, new FileLockUtils.CallableWithProperties<T>() {
+ public T call(org.apache.felix.utils.properties.Properties properties) throws IOException {
+ State state = loadData(properties);
+ T t = callback.call(state);
+ saveData(state, properties);
+ return t;
}
- }
+ });
+ } catch (IOException e) {
+ throw new RuntimeException(e);
}
- } catch (Exception e) {
- LOGGER.warn("Unable to reload Karaf instance list", e);
+ } else {
+ throw new IllegalStateException("Instance storage location does not exist: " + storageFile);
}
}
-
-
+
+ public synchronized void refreshInstance() throws Exception {
+ }
+
private void logInfo(String message, boolean printOutput, Object... args) {
if (LOGGER.isInfoEnabled() || printOutput) {
String formatted = String.format(message, args);
@@ -179,295 +236,618 @@ public class InstanceServiceImpl impleme
}
}
- public synchronized Instance createInstance(String name, InstanceSettings settings, boolean printOutput) throws Exception {
- try {
- init();
- } catch (Exception e) {
- LOGGER.warn("Unable to reload Karaf instance list", e);
- }
- if (instances.get(name) != null) {
- throw new IllegalArgumentException("Instance '" + name + "' already exists");
- }
- String loc = settings.getLocation() != null ? settings.getLocation() : name;
- File karafBase = new File(loc);
- if (!karafBase.isAbsolute()) {
- karafBase = new File(storageLocation, loc);
- }
- int sshPort = settings.getSshPort();
- if (sshPort <= 0) {
- sshPort = ++defaultSshPortStart;
- }
- int rmiRegistryPort = settings.getRmiRegistryPort();
- if (rmiRegistryPort <= 0) {
- rmiRegistryPort = ++defaultRmiRegistryPortStart;
- }
- int rmiServerPort = settings.getRmiServerPort();
- if (rmiServerPort <= 0) {
- rmiServerPort = ++defaultRmiServerPortStart;
- }
-
- logInfo("Creating new instance on SSH port %d and registry port %d / RMI server port %d at: %s",
- printOutput, sshPort, rmiRegistryPort, rmiServerPort, karafBase);
-
- mkdir(karafBase, "bin", printOutput);
- mkdir(karafBase, "etc", printOutput);
- mkdir(karafBase, "system", printOutput);
- mkdir(karafBase, "deploy", printOutput);
- mkdir(karafBase, "data", printOutput);
-
- copyResourceToDir(karafBase, "etc/config.properties", printOutput);
- copyResourceToDir(karafBase, "etc/jre.properties", printOutput);
- copyResourceToDir(karafBase, "etc/custom.properties", printOutput);
- copyResourceToDir(karafBase, "etc/java.util.logging.properties", printOutput);
- copyResourceToDir(karafBase, "etc/org.apache.felix.fileinstall-deploy.cfg", printOutput);
- copyResourceToDir(karafBase, "etc/org.apache.karaf.log.cfg", printOutput);
- copyResourceToDir(karafBase, "etc/org.ops4j.pax.logging.cfg", printOutput);
- copyResourceToDir(karafBase, "etc/org.ops4j.pax.url.mvn.cfg", printOutput);
- // copyResourceToDir(karafBase, "etc/startup.properties", printOutput);
- copyResourceToDir(karafBase, "etc/users.properties", printOutput);
- copyResourceToDir(karafBase, "etc/keys.properties", printOutput);
-
- copyResourceToDir(karafBase, FEATURES_CFG, printOutput);
- addFeaturesFromSettings(new File(karafBase, FEATURES_CFG), settings);
-
- // The startup.properties is now generated by the karaf maven plugin, so
- // we use the one from the root instance instead of embedding it
- File curbase = new File(System.getProperty("karaf.base"));
- copy(new File(curbase, "etc/startup.properties"), new File(karafBase, "etc/startup.properties"));
-
- HashMap<String, String> props = new HashMap<String, String>();
- props.put("${SUBST-KARAF-NAME}", name);
- props.put("${SUBST-KARAF-HOME}", System.getProperty("karaf.home"));
- props.put("${SUBST-KARAF-BASE}", karafBase.getPath());
- props.put("${SUBST-SSH-PORT}", Integer.toString(sshPort));
- props.put("${SUBST-RMI-REGISTRY-PORT}", Integer.toString(rmiRegistryPort));
- props.put("${SUBST-RMI-SERVER-PORT}", Integer.toString(rmiServerPort));
- copyFilteredResourceToDir(karafBase, "etc/system.properties", props, printOutput);
- copyFilteredResourceToDir(karafBase, "etc/org.apache.karaf.shell.cfg", props, printOutput);
- copyFilteredResourceToDir(karafBase, "etc/org.apache.karaf.management.cfg", props, printOutput);
- // If we use batch files, use batch files, else use bash scripts (even on cygwin)
- boolean windows = System.getProperty("os.name").startsWith("Win");
- copyFilteredResourceToDir(karafBase, "bin/karaf.bat", props, printOutput);
- copyFilteredResourceToDir(karafBase, "bin/start.bat", props, printOutput);
- copyFilteredResourceToDir(karafBase, "bin/stop.bat", props, printOutput);
- copyFilteredResourceToDir(karafBase, "bin/karaf", props, printOutput);
- copyFilteredResourceToDir(karafBase, "bin/start", props, printOutput);
- copyFilteredResourceToDir(karafBase, "bin/stop", props, printOutput);
- if ( !windows ) {
- chmod(new File(karafBase, "bin/karaf"), "a+x");
- chmod(new File(karafBase, "bin/start"), "a+x");
- chmod(new File(karafBase, "bin/stop"), "a+x");
- }
-
-
- String javaOpts = settings.getJavaOpts();
- if (javaOpts == null || javaOpts.length() == 0) {
- javaOpts = "-server -Xmx512M -Dcom.sun.management.jmxremote";
- }
- Instance instance = new InstanceImpl(this, name, karafBase.toString(), settings.getJavaOpts());
- instances.put(name, instance);
- saveState();
- return instance;
- }
-
- void addFeaturesFromSettings(File featuresCfg, InstanceSettings settings) throws IOException {
- Properties p = loadStorage(featuresCfg);
- appendToPropList(p, "featuresBoot", Collections.singletonList("ssh"));
- appendToPropList(p, "featuresBoot", settings.getFeatures());
- appendToPropList(p, "featuresRepositories", settings.getFeatureURLs());
- saveStorage(p, featuresCfg, "Features Configuration");
+ public synchronized Instance createInstance(final String name, final InstanceSettings settings, final boolean printOutput) throws Exception {
+ return execute(new Task<Instance>() {
+ public Instance call(State state) throws IOException {
+ if (state.instances.get(name) != null) {
+ throw new IllegalArgumentException("Instance '" + name + "' already exists");
+ }
+ String loc = settings.getLocation() != null ? settings.getLocation() : name;
+ File karafBase = new File(loc);
+ if (!karafBase.isAbsolute()) {
+ karafBase = new File(storageLocation, loc);
+ }
+ int sshPort = settings.getSshPort();
+ if (sshPort <= 0) {
+ sshPort = ++state.defaultSshPortStart;
+ }
+ int rmiRegistryPort = settings.getRmiRegistryPort();
+ if (rmiRegistryPort <= 0) {
+ rmiRegistryPort = ++state.defaultRmiRegistryPortStart;
+ }
+ int rmiServerPort = settings.getRmiServerPort();
+ if (rmiServerPort <= 0) {
+ rmiServerPort = ++state.defaultRmiServerPortStart;
+ }
+ logInfo("Creating new instance on SSH port %d and registry port %d / RMI server port %d at: %s",
+ printOutput, sshPort, rmiRegistryPort, rmiServerPort, karafBase);
+
+ mkdir(karafBase, "bin", printOutput);
+ mkdir(karafBase, "etc", printOutput);
+ mkdir(karafBase, "system", printOutput);
+ mkdir(karafBase, "deploy", printOutput);
+ mkdir(karafBase, "data", printOutput);
+
+ copyResourceToDir(karafBase, "etc/config.properties", printOutput);
+ copyResourceToDir(karafBase, "etc/jre.properties", printOutput);
+ copyResourceToDir(karafBase, "etc/custom.properties", printOutput);
+ copyResourceToDir(karafBase, "etc/java.util.logging.properties", printOutput);
+ copyResourceToDir(karafBase, "etc/org.apache.felix.fileinstall-deploy.cfg", printOutput);
+ copyResourceToDir(karafBase, "etc/org.apache.karaf.log.cfg", printOutput);
+ copyResourceToDir(karafBase, "etc/org.ops4j.pax.logging.cfg", printOutput);
+ copyResourceToDir(karafBase, "etc/org.ops4j.pax.url.mvn.cfg", printOutput);
+// copyResourceToDir(karafBase, "etc/startup.properties", printOutput);
+ copyResourceToDir(karafBase, "etc/users.properties", printOutput);
+ copyResourceToDir(karafBase, "etc/keys.properties", printOutput);
+
+ copyResourceToDir(karafBase, FEATURES_CFG, printOutput);
+ addFeaturesFromSettings(new File(karafBase, FEATURES_CFG), settings);
+
+ // The startup.properties is now generated by the karaf maven plugin, so
+ // we use the one from the root instance instead of embedding it
+ File curbase = new File(System.getProperty("karaf.base"));
+ copy(new File(curbase, "etc/startup.properties"), new File(karafBase, "etc/startup.properties"));
+
+ HashMap<String, String> props = new HashMap<String, String>();
+ props.put("${SUBST-KARAF-NAME}", name);
+ props.put("${SUBST-KARAF-HOME}", System.getProperty("karaf.home"));
+ props.put("${SUBST-KARAF-BASE}", karafBase.getPath());
+ props.put("${SUBST-SSH-PORT}", Integer.toString(sshPort));
+ props.put("${SUBST-RMI-REGISTRY-PORT}", Integer.toString(rmiRegistryPort));
+ props.put("${SUBST-RMI-SERVER-PORT}", Integer.toString(rmiServerPort));
+ copyFilteredResourceToDir(karafBase, "etc/system.properties", props, printOutput);
+ copyFilteredResourceToDir(karafBase, "etc/org.apache.karaf.shell.cfg", props, printOutput);
+ copyFilteredResourceToDir(karafBase, "etc/org.apache.karaf.management.cfg", props, printOutput);
+ // If we use batch files, use batch files, else use bash scripts (even on cygwin)
+ boolean windows = System.getProperty("os.name").startsWith("Win");
+ boolean cygwin = windows && new File(System.getProperty("karaf.home"), "bin/admin").exists();
+ if (windows && !cygwin) {
+ copyFilteredResourceToDir(karafBase, "bin/karaf.bat", props, printOutput);
+ copyFilteredResourceToDir(karafBase, "bin/start.bat", props, printOutput);
+ copyFilteredResourceToDir(karafBase, "bin/stop.bat", props, printOutput);
+ } else {
+ copyFilteredResourceToDir(karafBase, "bin/karaf", props, printOutput);
+ copyFilteredResourceToDir(karafBase, "bin/start", props, printOutput);
+ copyFilteredResourceToDir(karafBase, "bin/stop", props, printOutput);
+ if (!cygwin) {
+ chmod(new File(karafBase, "bin/karaf"), "a+x");
+ chmod(new File(karafBase, "bin/start"), "a+x");
+ chmod(new File(karafBase, "bin/stop"), "a+x");
+ }
+ }
+
+ String javaOpts = settings.getJavaOpts();
+ if (javaOpts == null || javaOpts.length() == 0) {
+ javaOpts = "-server -Xmx512M -Dcom.sun.management.jmxremote";
+ }
+ InstanceState is = new InstanceState();
+ is.name = name;
+ is.loc = karafBase.toString();
+ is.opts = javaOpts;
+ state.instances.put(name, is);
+ InstanceImpl instance = new InstanceImpl(InstanceServiceImpl.this, name);
+ InstanceServiceImpl.this.proxies.put(name, instance);
+ return instance;
+ }
+ });
+ }
+
+ void addFeaturesFromSettings(File featuresCfg, final InstanceSettings settings) throws IOException {
+ FileLockUtils.execute(featuresCfg, new FileLockUtils.RunnableWithProperties() {
+ public void run(org.apache.felix.utils.properties.Properties properties) throws IOException {
+ appendToPropList(properties, "featuresBoot", Collections.singletonList("ssh"));
+ appendToPropList(properties, "featuresBoot", settings.getFeatures());
+ appendToPropList(properties, "featuresRepositories", settings.getFeatureURLs());
+ }
+ });
}
- private void appendToPropList(Properties p, String key, List<String> elements) {
+ private void appendToPropList(org.apache.felix.utils.properties.Properties p, String key, List<String> elements) {
if (elements == null) {
return;
}
- StringBuilder sb = new StringBuilder(p.getProperty(key).trim());
+ StringBuilder sb = new StringBuilder(p.get(key).toString().trim());
for (String f : elements) {
if (sb.length() > 0) {
sb.append(',');
}
sb.append(f);
}
- p.setProperty(key, sb.toString());
+ p.put(key, sb.toString());
}
-
- public synchronized Instance[] getInstances() {
- return instances.values().toArray(new Instance[0]);
+
+ public Instance[] getInstances() {
+ return execute(new Task<Instance[]>() {
+ public Instance[] call(State state) throws IOException {
+ return proxies.values().toArray(new Instance[proxies.size()]);
+ }
+ });
}
- public synchronized Instance getInstance(String name) {
- try {
- init();
- } catch (Exception e) {
- LOGGER.warn("Unable to reload Karaf instance list", e);
- }
- return instances.get(name);
+ public Instance getInstance(final String name) {
+ return execute(new Task<Instance>() {
+ public Instance call(State state) throws IOException {
+ return proxies.get(name);
+ }
+ });
+ }
+
+ public void startInstance(final String name, final String javaOpts) {
+ execute(new Task<Object>() {
+ public Object call(State state) throws IOException {
+ InstanceState instance = state.instances.get(name);
+ if (instance == null) {
+ throw new IllegalArgumentException("Instance " + name + " not found");
+ }
+ checkPid(instance);
+ if (instance.pid != 0) {
+ throw new IllegalStateException("Instance already started");
+ }
+ String opts = javaOpts;
+ if (opts == null || opts.length() == 0) {
+ opts = instance.opts;
+ }
+ if (opts == null || opts.length() == 0) {
+ opts = "-server -Xmx512M -Dcom.sun.management.jmxremote";
+ }
+ String karafOpts = System.getProperty("karaf.opts", "");
+
+ File libDir = new File(System.getProperty("karaf.home"), "lib");
+ File[] jars = libDir.listFiles(new FilenameFilter() {
+ public boolean accept(File dir, String name) {
+ return name.endsWith(".jar");
+ }
+ });
+ StringBuilder classpath = new StringBuilder();
+ for (File jar : jars) {
+ if (classpath.length() > 0) {
+ classpath.append(System.getProperty("path.separator"));
+ }
+ classpath.append(jar.getCanonicalPath());
+ }
+ String location = instance.loc;
+ String command = "\""
+ + new File(System.getProperty("java.home"), ScriptUtils.isWindows() ? "bin\\java.exe" : "bin/java").getCanonicalPath()
+ + "\" " + opts
+ + " " + karafOpts
+ + " -Djava.util.logging.config.file=\"" + new File(location, "etc/java.util.logging.properties").getCanonicalPath() + "\""
+ + " -Djava.endorsed.dirs=\"" + new File(new File(new File(System.getProperty("java.home"), "jre"), "lib"), "endorsed") + System.getProperty("path.separator") + new File(new File(System.getProperty("java.home"), "lib"), "endorsed") + System.getProperty("path.separator") + new File(libDir, "endorsed").getCanonicalPath() + "\""
+ + " -Djava.ext.dirs=\"" + new File(new File(new File(System.getProperty("java.home"), "jre"), "lib"), "ext") + System.getProperty("path.separator") + new File(new File(System.getProperty("java.home"), "lib"), "ext") + System.getProperty("path.separator") + new File(libDir, "ext").getCanonicalPath() + "\""
+ + " -Dkaraf.home=\"" + System.getProperty("karaf.home") + "\""
+ + " -Dkaraf.base=\"" + new File(location).getCanonicalPath() + "\""
+ + " -Dkaraf.startLocalConsole=false"
+ + " -Dkaraf.startRemoteShell=true"
+ + " -classpath " + classpath.toString()
+ + " org.apache.karaf.main.Main";
+ LOGGER.debug("Starting instance " + name + " with command: " + command);
+ org.apache.karaf.jpm.Process process = new ProcessBuilderFactoryImpl().newBuilder()
+ .directory(new File(location))
+ .command(command)
+ .start();
+ instance.pid = process.getPid();
+ return null;
+ }
+ });
+ }
+
+ public void stopInstance(final String name) {
+ execute(new Task<Object>() {
+ public Object call(State state) throws IOException {
+ InstanceState instance = state.instances.get(name);
+ if (instance == null) {
+ throw new IllegalArgumentException("Instance " + name + " not found");
+ }
+ checkPid(instance);
+ if (instance.pid == 0) {
+ throw new IllegalStateException("Instance already stopped");
+ }
+ cleanShutdown(instance);
+ if (instance.pid > 0) {
+ Process process = new ProcessBuilderFactoryImpl().newBuilder().attach(instance.pid);
+ process.destroy();
+ }
+ return null;
+ }
+ });
}
- synchronized void forget(String name) {
- instances.remove(name);
+ public void destroyInstance(final String name) {
+ execute(new Task<Object>() {
+ public Object call(State state) throws IOException {
+ InstanceState instance = state.instances.get(name);
+ if (instance == null) {
+ throw new IllegalArgumentException("Instance " + name + " not found");
+ }
+ checkPid(instance);
+ if (instance.pid != 0) {
+ throw new IllegalStateException("Instance not stopped");
+ }
+ deleteFile(new File(instance.loc));
+ state.instances.remove(name);
+ InstanceServiceImpl.this.proxies.remove(name);
+ return null;
+ }
+ });
}
- public synchronized void renameInstance(String oldName, String newName, boolean printOutput) throws Exception {
- try {
- init();
- } catch (Exception e) {
- LOGGER.warn("Unable to reload Karaf instance list", e);
- }
- if (instances.get(newName) != null) {
- throw new IllegalArgumentException("Instance " + newName + " already exists");
- }
- Instance instance = instances.get(oldName);
- if (instance == null) {
- throw new IllegalArgumentException("Instance " + oldName + " not found");
- }
- if (instance.isRoot()) {
- throw new IllegalArgumentException("Root instance cannot be renamed");
- }
- if (instance.getPid() != 0) {
- throw new IllegalStateException("Instance not stopped");
- }
+ public void renameInstance(final String oldName, final String newName, final boolean printOutput) throws Exception {
+ execute(new Task<Object>() {
+ public Object call(State state) throws IOException {
+ if (state.instances.get(newName) != null) {
+ throw new IllegalArgumentException("Instance " + newName + " already exists");
+ }
+ InstanceState instance = state.instances.get(oldName);
+ if (instance == null) {
+ throw new IllegalArgumentException("Instance " + oldName + " not found");
+ }
+ if (instance.root) {
+ throw new IllegalArgumentException("Root instance cannot be renamed");
+ }
+ checkPid(instance);
+ if (instance.pid != 0) {
+ throw new IllegalStateException("Instance not stopped");
+ }
- logInfo("Renaming instance %s to %s", printOutput, oldName, newName);
-
- // remove the old instance
- instances.remove(oldName);
- // update instance
- instance.setName(newName);
- // rename directory
- String oldLocationPath = instance.getLocation();
- File oldLocation = new File(oldLocationPath);
- String basedir = oldLocation.getParent();
- File newLocation = new File(basedir, newName);
- oldLocation.renameTo(newLocation);
- // update the instance location
- instance.setLocation(newLocation.getPath());
- // create the properties map including the instance name and instance location
- HashMap<String, String> props = new HashMap<String, String>();
- props.put(oldName, newName);
- props.put(oldLocationPath, newLocation.getPath());
- // replace all references to the "old" name by the new one in etc/system.properties
- // NB: it's replacement to avoid to override the user's changes
- filterResource(newLocation, "etc/system.properties", props);
- // replace all references to the "old" name by the new one in bin/karaf
- filterResource(newLocation, "bin/karaf", props);
- filterResource(newLocation, "bin/start", props);
- filterResource(newLocation, "bin/stop", props);
- filterResource(newLocation, "bin/karaf.bat", props);
- filterResource(newLocation, "bin/start.bat", props);
- filterResource(newLocation, "bin/stop.bat", props);
- // add the renamed instances
- instances.put(newName, instance);
- // save instance definition in the instances.properties
- saveState();
+ println(Ansi.ansi().a("Renaming instance ")
+ .a(Ansi.Attribute.INTENSITY_BOLD).a(oldName).a(Ansi.Attribute.RESET)
+ .a(" to ")
+ .a(Ansi.Attribute.INTENSITY_BOLD).a(newName).a(Ansi.Attribute.RESET).toString());
+ // rename directory
+ String oldLocationPath = instance.loc;
+ File oldLocation = new File(oldLocationPath);
+ String basedir = oldLocation.getParent();
+ File newLocation = new File(basedir, newName);
+ oldLocation.renameTo(newLocation);
+ // create the properties map including the instance name and instance location
+ // TODO: replacing is bad, we should re-extract the needed files
+ HashMap<String, String> props = new HashMap<String, String>();
+ props.put(oldName, newName);
+ props.put(oldLocationPath, newLocation.getPath());
+ // replace all references to the "old" name by the new one in etc/system.properties
+ // NB: it's replacement to avoid to override the user's changes
+ filterResource(newLocation, "etc/system.properties", props);
+ // replace all references to the "old" name by the new one in bin/karaf
+ filterResource(newLocation, "bin/karaf", props);
+ filterResource(newLocation, "bin/start", props);
+ filterResource(newLocation, "bin/stop", props);
+ filterResource(newLocation, "bin/karaf.bat", props);
+ filterResource(newLocation, "bin/start.bat", props);
+ filterResource(newLocation, "bin/stop.bat", props);
+ // update instance
+ instance.name = newName;
+ instance.loc = newLocation.getPath();
+ state.instances.put(newName, instance);
+ state.instances.remove(oldName);
+ InstanceImpl proxy = InstanceServiceImpl.this.proxies.remove(oldName);
+ if (proxy == null) {
+ proxy = new InstanceImpl(InstanceServiceImpl.this, newName);
+ } else {
+ proxy.doSetName(newName);
+ }
+ InstanceServiceImpl.this.proxies.put(newName, proxy);
+ return null;
+ }
+ });
}
- public synchronized Instance cloneInstance(String name, String cloneName, InstanceSettings settings, boolean printOutput) throws Exception {
+ public synchronized Instance cloneInstance(final String name, final String cloneName, final InstanceSettings settings, final boolean printOutput) throws Exception {
+ return execute(new Task<Instance>() {
+ public Instance call(State state) throws IOException {
+ if (state.instances.get(cloneName) != null) {
+ throw new IllegalArgumentException("Instance " + cloneName + " already exists");
+ }
+ InstanceState instance = state.instances.get(name);
+ if (instance == null) {
+ throw new IllegalArgumentException("Instance " + name + " not found");
+ }
+
+ // define the clone instance location
+ String cloneLocationPath = settings.getLocation() != null ? settings.getLocation() : cloneName;
+ File cloneLocation = new File(cloneLocationPath);
+ if (!cloneLocation.isAbsolute()) {
+ cloneLocation = new File(storageLocation, cloneLocationPath);
+ }
+ // copy instance directory
+ String locationPath = instance.loc;
+ File location = new File(locationPath);
+ copy(location, cloneLocation);
+ // create the properties map including the instance name, location, ssh and rmi port numbers
+ // TODO: replacing stuff anywhere is not really good, we might end up replacing unwanted stuff
+ // TODO: if no ports are overriden, shouldn't we choose new ports ?
+ HashMap<String, String> props = new HashMap<String, String>();
+ props.put(name, cloneName);
+ props.put(locationPath, cloneLocationPath);
+ if (settings.getSshPort() > 0)
+ props.put(Integer.toString(getInstanceSshPort(instance.name)), Integer.toString(settings.getSshPort()));
+ if (settings.getRmiRegistryPort() > 0)
+ props.put(Integer.toString(getInstanceRmiRegistryPort(instance.name)), Integer.toString(settings.getRmiRegistryPort()));
+ if (settings.getRmiServerPort() > 0)
+ props.put(Integer.toString(getInstanceRmiServerPort(instance.name)), Integer.toString(settings.getRmiServerPort()));
+ // filtering clone files
+ filterResource(cloneLocation, "etc/custom.properties", props);
+ filterResource(cloneLocation, "etc/org.apache.karaf.management.cfg", props);
+ filterResource(cloneLocation, "etc/org.apache.karaf.shell.cfg", props);
+ filterResource(cloneLocation, "etc/org.ops4j.pax.logging.cfg", props);
+ filterResource(cloneLocation, "etc/system.properties", props);
+ filterResource(cloneLocation, "bin/karaf", props);
+ filterResource(cloneLocation, "bin/start", props);
+ filterResource(cloneLocation, "bin/stop", props);
+ filterResource(cloneLocation, "bin/karaf.bat", props);
+ filterResource(cloneLocation, "bin/start.bat", props);
+ filterResource(cloneLocation, "bin/stop.bat", props);
+ // create and add the clone instance in the registry
+ String javaOpts = settings.getJavaOpts();
+ if (javaOpts == null || javaOpts.length() == 0) {
+ javaOpts = "-server -Xmx512M -Dcom.sun.management.jmxremote";
+ }
+ InstanceState is = new InstanceState();
+ is.name = cloneName;
+ is.loc = cloneLocation.toString();
+ is.opts = javaOpts;
+ state.instances.put(cloneName, is);
+ InstanceImpl cloneInstance = new InstanceImpl(InstanceServiceImpl.this, cloneName);
+ InstanceServiceImpl.this.proxies.put(cloneName, cloneInstance);
+ return cloneInstance;
+ }
+ });
+ }
+
+ private void checkPid(InstanceState instance) throws IOException {
+ if (instance.pid != 0) {
+ Process process = new ProcessBuilderFactoryImpl().newBuilder().attach(instance.pid);
+ if (!process.isRunning()) {
+ instance.pid = 0;
+ }
+ }
+ }
+
+ protected void cleanShutdown(InstanceState instance) {
try {
- init();
+ File file = new File(new File(instance.loc, "etc"), CONFIG_PROPERTIES_FILE_NAME);
+ URL configPropURL = file.toURI().toURL();
+ Properties props = loadPropertiesFile(configPropURL);
+ props.put("karaf.base", new File(instance.loc).getCanonicalPath());
+ props.put("karaf.home", System.getProperty("karaf.home"));
+ props.put("karaf.data", new File(new File(instance.loc), "data").getCanonicalPath());
+ for (Enumeration e = props.propertyNames(); e.hasMoreElements();) {
+ String key = (String) e.nextElement();
+ props.setProperty(key,
+ substVars(props.getProperty(key), key, null, props));
+ }
+ int port = Integer.parseInt(props.getProperty(KARAF_SHUTDOWN_PORT, "0"));
+ String host = props.getProperty(KARAF_SHUTDOWN_HOST, "localhost");
+ String portFile = props.getProperty(KARAF_SHUTDOWN_PORT_FILE);
+ String shutdown = props.getProperty(KARAF_SHUTDOWN_COMMAND, DEFAULT_SHUTDOWN_COMMAND);
+ if (port == 0 && portFile != null) {
+ BufferedReader r = new BufferedReader(new InputStreamReader(new FileInputStream(portFile)));
+ String portStr = r.readLine();
+ port = Integer.parseInt(portStr);
+ r.close();
+ }
+ // We found the port, try to send the command
+ if (port > 0) {
+ Socket s = new Socket(host, port);
+ s.getOutputStream().write(shutdown.getBytes());
+ s.close();
+ long t = System.currentTimeMillis() + getStopTimeout();
+ do {
+ Thread.sleep(100);
+ checkPid(instance);
+ } while (System.currentTimeMillis() < t && instance.pid > 0);
+ }
} catch (Exception e) {
- LOGGER.warn("Unable to reload Karaf instance list", e);
- }
- if (instances.get(cloneName) != null) {
- throw new IllegalArgumentException("Instance " + cloneName + " already exists");
+ LOGGER.debug("Unable to cleanly shutdown instance " + instance.name, e);
}
- Instance instance = instances.get(name);
+ }
+
+ int getInstanceSshPort(String name) {
+ return getKarafPort(name, "etc/org.apache.karaf.shell.cfg", "sshPort");
+ }
+
+ void changeInstanceSshPort(String name, final int port) throws Exception {
+ setKarafPort(name, "etc/org.apache.karaf.shell.cfg", "sshPort", port);
+ }
+
+ int getInstanceRmiRegistryPort(String name) {
+ return getKarafPort(name, "etc/org.apache.karaf.management.cfg", "rmiRegistryPort");
+ }
+
+ void changeInstanceRmiRegistryPort(String name, final int port) throws Exception {
+ setKarafPort(name, "etc/org.apache.karaf.management.cfg", "rmiRegistryPort", port);
+ }
+
+ int getInstanceRmiServerPort(String name) {
+ return getKarafPort(name, "etc/org.apache.karaf.management.cfg", "rmiServerPort");
+ }
+
+ void changeInstanceRmiServerPort(String name, int port) throws Exception {
+ setKarafPort(name, "etc/org.apache.karaf.management.cfg", "rmiServerPort", port);
+ }
+
+ private int getKarafPort(final String name, final String path, final String key) {
+ return execute(new Task<Integer>() {
+ public Integer call(State state) throws IOException {
+ return InstanceServiceImpl.this.getKarafPort(state, name, path, key);
+ }
+ });
+ }
+
+ private Integer getKarafPort(State state, String name, String path, final String key) {
+ InstanceState instance = state.instances.get(name);
if (instance == null) {
throw new IllegalArgumentException("Instance " + name + " not found");
}
-
- logInfo("Cloning instance %s into %s", printOutput, name, cloneName);
-
- // define the clone instance location
- String cloneLocationPath = settings.getLocation() != null ? settings.getLocation() : cloneName;
- File cloneLocation = new File(cloneLocationPath);
- if (!cloneLocation.isAbsolute()) {
- cloneLocation = new File(storageLocation, cloneLocationPath);
- }
- // copy instance directory
- String locationPath = instance.getLocation();
- File location = new File(locationPath);
- copy(location, cloneLocation);
- // create the properties map including the instance name, location, ssh and rmi port numbers
- HashMap<String, String> props = new HashMap<String, String>();
- props.put(name, cloneName);
- props.put(locationPath, cloneLocationPath);
- if (settings.getSshPort() > 0)
- props.put(new Integer(instance.getSshPort()).toString(), new Integer(settings.getSshPort()).toString());
- if (settings.getRmiRegistryPort() > 0)
- props.put(new Integer(instance.getRmiRegistryPort()).toString(), new Integer(settings.getRmiRegistryPort()).toString());
- if (settings.getRmiServerPort() > 0)
- props.put(new Integer(instance.getRmiServerPort()).toString(), new Integer(settings.getRmiServerPort()).toString());
- // filtering clone files
- filterResource(cloneLocation, "etc/custom.properties", props);
- filterResource(cloneLocation, "etc/org.apache.karaf.management.cfg", props);
- filterResource(cloneLocation, "etc/org.apache.karaf.shell.cfg", props);
- filterResource(cloneLocation, "etc/org.ops4j.pax.logging.cfg", props);
- filterResource(cloneLocation, "etc/system.properties", props);
- filterResource(cloneLocation, "bin/karaf", props);
- filterResource(cloneLocation, "bin/start", props);
- filterResource(cloneLocation, "bin/stop", props);
- filterResource(cloneLocation, "bin/karaf.bat", props);
- filterResource(cloneLocation, "bin/start.bat", props);
- filterResource(cloneLocation, "bin/stop.bat", props);
- // create and add the clone instance in the registry
- String javaOpts = settings.getJavaOpts();
- if (javaOpts == null || javaOpts.length() == 0) {
- javaOpts = "-server -Xmx512M -Dcom.sun.management.jmxremote";
- }
- Instance cloneInstance = new InstanceImpl(this, cloneName, cloneLocation.toString(), settings.getJavaOpts());
- instances.put(cloneName, cloneInstance);
- saveState();
- return cloneInstance;
- }
-
- synchronized void saveState() throws IOException {
- Properties storage = new Properties();
- Instance[] data = getInstances();
- storage.setProperty("ssh.port", Integer.toString(defaultSshPortStart));
- storage.setProperty("rmi.registry.port", Integer.toString(defaultRmiRegistryPortStart));
- storage.setProperty("rmi.server.port", Integer.toString(defaultRmiServerPortStart));
- storage.setProperty("count", Integer.toString(data.length));
- for (int i = 0; i < data.length; i++) {
- storage.setProperty("item." + i + ".name", data[i].getName());
- storage.setProperty("item." + i + ".root", data[i].isRoot() + "");
- storage.setProperty("item." + i + ".loc", data[i].getLocation());
- storage.setProperty("item." + i + ".pid", Integer.toString(data[i].getPid()));
- storage.setProperty("item." + i + ".opts", data[i].getJavaOpts() != null ? data[i].getJavaOpts() : "");
+ File f = new File(instance.loc, path);
+ try {
+ return FileLockUtils.execute(f, new FileLockUtils.CallableWithProperties<Integer>() {
+ public Integer call(org.apache.felix.utils.properties.Properties properties) throws IOException {
+ return Integer.parseInt(properties.get(key).toString());
+ }
+ });
+ } catch (IOException e) {
+ return 0;
}
- saveStorage(storage, new File(storageLocation, STORAGE_FILE), "Instances Service storage");
}
-
- private void copyResourceToDir(File target, String resource, boolean printOutput) throws Exception {
- File outFile = new File(target, resource);
- if (outFile.exists()) {
- return;
- }
-
- logInfo("Creating file: %s", printOutput, outFile.getPath());
+ private void setKarafPort(final String name, final String path, final String key, final int port) throws IOException {
+ execute(new Task<Object>() {
+ public Object call(State state) throws IOException {
+ InstanceState instance = state.instances.get(name);
+ if (instance == null) {
+ throw new IllegalArgumentException("Instance " + name + " not found");
+ }
+ checkPid(instance);
+ if (instance.pid != 0) {
+ throw new IllegalStateException("Instance is not stopped");
+ }
+ File f = new File(instance.loc, path);
+ FileLockUtils.execute(f, new FileLockUtils.RunnableWithProperties() {
+ public void run(org.apache.felix.utils.properties.Properties properties) throws IOException {
+ properties.put(key, Integer.toString(port));
+ }
+ });
+ return null;
+ }
+ });
+ }
- String sourcePath = "org/apache/karaf/instance/resources/" + resource;
- InputStream is = getClass().getClassLoader().getResourceAsStream(sourcePath);
- if (is == null) {
- throw new IOException("Unable to find resource " + sourcePath + " on classpath");
+ boolean isInstanceRoot(final String name) {
+ return execute(new Task<Boolean>() {
+ public Boolean call(State state) throws IOException {
+ InstanceState instance = state.instances.get(name);
+ if (instance == null) {
+ throw new IllegalArgumentException("Instance " + name + " not found");
+ }
+ return instance.root;
+ }
+ });
+ }
+
+ String getInstanceLocation(final String name) {
+ return execute(new Task<String>() {
+ public String call(State state) throws IOException {
+ InstanceState instance = state.instances.get(name);
+ if (instance == null) {
+ throw new IllegalArgumentException("Instance " + name + " not found");
+ }
+ return instance.loc;
+ }
+ });
+ }
+
+ int getInstancePid(final String name) {
+ return execute(new Task<Integer>() {
+ public Integer call(State state) throws IOException {
+ InstanceState instance = state.instances.get(name);
+ if (instance == null) {
+ throw new IllegalArgumentException("Instance " + name + " not found");
+ }
+ checkPid(instance);
+ return instance.pid;
+ }
+ });
+ }
+
+ String getInstanceJavaOpts(final String name) {
+ return execute(new Task<String>() {
+ public String call(State state) throws IOException {
+ InstanceState instance = state.instances.get(name);
+ if (instance == null) {
+ throw new IllegalArgumentException("Instance " + name + " not found");
+ }
+ return instance.opts;
+ }
+ });
+ }
+
+ void changeInstanceJavaOpts(final String name, final String opts) {
+ execute(new Task<String>() {
+ public String call(State state) throws IOException {
+ InstanceState instance = state.instances.get(name);
+ if (instance == null) {
+ throw new IllegalArgumentException("Instance " + name + " not found");
+ }
+ instance.opts = opts;
+ return null;
+ }
+ });
+ }
+
+ String getInstanceState(final String name) {
+ return execute(new Task<String>() {
+ public String call(State state) throws IOException {
+ InstanceState instance = state.instances.get(name);
+ if (instance == null) {
+ throw new IllegalArgumentException("Instance " + name + " not found");
+ }
+ int port = getKarafPort(state, name, "etc/org.apache.karaf.shell.cfg", "sshPort");
+ if (!new File(instance.loc).isDirectory() || port <= 0) {
+ return Instance.ERROR;
+ }
+ checkPid(instance);
+ if (instance.pid == 0) {
+ return Instance.STOPPED;
+ } else {
+ try {
+ Socket s = new Socket("localhost", port);
+ s.close();
+ return Instance.STARTED;
+ } catch (Exception e) {
+ // ignore
+ }
+ return Instance.STARTING;
+ }
+ }
+ });
+ }
+
+ private boolean deleteFile(File fileToDelete) {
+ if (fileToDelete == null || !fileToDelete.exists()) {
+ return true;
+ }
+ boolean result = true;
+ if (fileToDelete.isDirectory()) {
+ File[] files = fileToDelete.listFiles();
+ if (files == null) {
+ result = false;
+ } else {
+ for (int i = 0; i < files.length; i++) {
+ File file = files[i];
+ if (file.getName().equals(".") || file.getName().equals("..")) {
+ continue;
+ }
+ if (file.isDirectory()) {
+ result &= deleteFile(file);
+ } else {
+ result &= file.delete();
+ }
+ }
+ }
}
- try {
- // Read it line at a time so that we can use the platform line
- // ending when we write it out.
- PrintStream out = new PrintStream(new FileOutputStream(outFile));
+ result &= fileToDelete.delete();
+ return result;
+ }
+
+ private void copyResourceToDir(File target, String resource, boolean printOutput) throws IOException {
+ File outFile = new File(target, resource);
+ if( !outFile.exists() ) {
+ logInfo("Creating file: %s", printOutput, outFile.getPath());
+ InputStream is = getClass().getClassLoader().getResourceAsStream("org/apache/karaf/instance/resources/" + resource);
try {
- Scanner scanner = new Scanner(is);
- while (scanner.hasNextLine()) {
- String line = scanner.nextLine();
- out.println(line);
+ // Read it line at a time so that we can use the platform line ending when we write it out.
+ PrintStream out = new PrintStream(new FileOutputStream(outFile));
+ try {
+ Scanner scanner = new Scanner(is);
+ while (scanner.hasNextLine() ) {
+ String line = scanner.nextLine();
+ out.println(line);
+ }
+ } finally {
+ safeClose(out);
}
} finally {
- safeClose(out);
+ safeClose(is);
}
- } finally {
- safeClose(is);
}
}
@@ -475,7 +855,31 @@ public class InstanceServiceImpl impleme
System.out.println(st);
}
- private void filterResource(File basedir, String path, HashMap<String, String> props) throws Exception {
+ protected static Properties loadPropertiesFile(URL configPropURL) throws Exception {
+ // Read the properties file.
+ Properties configProps = new Properties();
+ InputStream is = null;
+ try {
+ is = configPropURL.openConnection().getInputStream();
+ configProps.load(is);
+ is.close();
+ }
+ catch (Exception ex) {
+ System.err.println(
+ "Error loading config properties from " + configPropURL);
+ System.err.println("Main: " + ex);
+ try {
+ if (is != null) is.close();
+ }
+ catch (IOException ex2) {
+ // Nothing we can do.
+ }
+ return null;
+ }
+ return configProps;
+ }
+
+ private void filterResource(File basedir, String path, HashMap<String, String> props) throws IOException {
File file = new File(basedir, path);
File bak = new File(basedir, path + BACKUP_EXTENSION);
if (!file.exists()) {
@@ -489,7 +893,7 @@ public class InstanceServiceImpl impleme
bak.delete();
}
- private void copyFilteredResourceToDir(File target, String resource, HashMap<String, String> props, boolean printOutput) throws Exception {
+ private void copyFilteredResourceToDir(File target, String resource, HashMap<String, String> props, boolean printOutput) throws IOException {
File outFile = new File(target, resource);
if( !outFile.exists() ) {
logInfo("Creating file: %s", printOutput, outFile.getPath());
@@ -498,7 +902,7 @@ public class InstanceServiceImpl impleme
}
}
- private void copyAndFilterResource(InputStream source, OutputStream target, HashMap<String, String> props) throws Exception {
+ private void copyAndFilterResource(InputStream source, OutputStream target, HashMap<String, String> props) throws IOException {
try {
// read it line at a time so that we can use the platform line ending when we write it out.
PrintStream out = new PrintStream(target);
@@ -557,15 +961,27 @@ public class InstanceServiceImpl impleme
}
}
- private int chmod(File serviceFile, String mode) throws Exception {
- ProcessBuilder builder = new ProcessBuilder();
+ private int chmod(File serviceFile, String mode) throws IOException {
+ java.lang.ProcessBuilder builder = new java.lang.ProcessBuilder();
builder.command("chmod", mode, serviceFile.getCanonicalPath());
- Process p = builder.start();
- int status = p.waitFor();
- return status;
+ java.lang.Process p = builder.start();
+
+ // gnodet: Fix SMX4KNL-46: cpu goes to 100% after running the 'admin create' command
+ // Not sure exactly what happens, but commenting the process io redirection seems
+ // to work around the problem.
+ //
+ //PumpStreamHandler handler = new PumpStreamHandler(io.inputStream, io.outputStream, io.errorStream);
+ //handler.attach(p);
+ //handler.start();
+ try {
+ return p.waitFor();
+ } catch (InterruptedException e) {
+ throw (IOException) new InterruptedIOException().initCause(e);
+ }
+ //handler.stop();
}
- private void copy(File source, File destination) throws Exception {
+ private void copy(File source, File destination) throws IOException {
if (source.getName().equals("cache.lock")) {
// ignore cache.lock file
return;
@@ -594,7 +1010,99 @@ public class InstanceServiceImpl impleme
in.close();
out.close();
}
+ }
+
+ private static final String DELIM_START = "${";
+ private static final String DELIM_STOP = "}";
+
+ protected static String substVars(String val, String currentKey,
+ Map<String, String> cycleMap, Properties configProps)
+ throws IllegalArgumentException {
+ // If there is currently no cycle map, then create
+ // one for detecting cycles for this invocation.
+ if (cycleMap == null) {
+ cycleMap = new HashMap<String, String>();
+ }
+
+ // Put the current key in the cycle map.
+ cycleMap.put(currentKey, currentKey);
+
+ // Assume we have a value that is something like:
+ // "leading ${foo.${bar}} middle ${baz} trailing"
+
+ // Find the first ending '}' variable delimiter, which
+ // will correspond to the first deepest nested variable
+ // placeholder.
+ int stopDelim = val.indexOf(DELIM_STOP);
+
+ // Find the matching starting "${" variable delimiter
+ // by looping until we find a start delimiter that is
+ // greater than the stop delimiter we have found.
+ int startDelim = val.indexOf(DELIM_START);
+ while (stopDelim >= 0) {
+ int idx = val.indexOf(DELIM_START, startDelim + DELIM_START.length());
+ if ((idx < 0) || (idx > stopDelim)) {
+ break;
+ } else if (idx < stopDelim) {
+ startDelim = idx;
+ }
+ }
+
+ // If we do not have a start or stop delimiter, then just
+ // return the existing value.
+ if ((startDelim < 0) && (stopDelim < 0)) {
+ return val;
+ }
+ // At this point, we found a stop delimiter without a start,
+ // so throw an exception.
+ else if (((startDelim < 0) || (startDelim > stopDelim))
+ && (stopDelim >= 0)) {
+ throw new IllegalArgumentException(
+ "stop delimiter with no start delimiter: "
+ + val);
+ }
+
+ // At this point, we have found a variable placeholder so
+ // we must perform a variable substitution on it.
+ // Using the start and stop delimiter indices, extract
+ // the first, deepest nested variable placeholder.
+ String variable =
+ val.substring(startDelim + DELIM_START.length(), stopDelim);
+
+ // Verify that this is not a recursive variable reference.
+ if (cycleMap.get(variable) != null) {
+ throw new IllegalArgumentException(
+ "recursive variable reference: " + variable);
+ }
+
+ // Get the value of the deepest nested variable placeholder.
+ // Try to configuration properties first.
+ String substValue = (configProps != null)
+ ? configProps.getProperty(variable, null)
+ : null;
+ if (substValue == null) {
+ // Ignore unknown property values.
+ substValue = System.getProperty(variable, "");
+ }
+
+ // Remove the found variable from the cycle map, since
+ // it may appear more than once in the value and we don't
+ // want such situations to appear as a recursive reference.
+ cycleMap.remove(variable);
+
+ // Append the leading characters, the substituted value of
+ // the variable, and the trailing characters to get the new
+ // value.
+ val = val.substring(0, startDelim)
+ + substValue
+ + val.substring(stopDelim + DELIM_STOP.length(), val.length());
+
+ // Now perform substitution again, since there could still
+ // be substitutions to make.
+ val = substVars(val, currentKey, cycleMap, configProps);
+ // Return the value.
+ return val;
}
-}
+}
\ No newline at end of file
Modified: karaf/trunk/instance/core/src/main/resources/OSGI-INF/blueprint/instance-core.xml
URL: http://svn.apache.org/viewvc/karaf/trunk/instance/core/src/main/resources/OSGI-INF/blueprint/instance-core.xml?rev=1455901&r1=1455900&r2=1455901&view=diff
==============================================================================
--- karaf/trunk/instance/core/src/main/resources/OSGI-INF/blueprint/instance-core.xml (original)
+++ karaf/trunk/instance/core/src/main/resources/OSGI-INF/blueprint/instance-core.xml Wed Mar 13 12:21:07 2013
@@ -22,7 +22,7 @@
<ext:property-placeholder />
- <bean id="instanceService" class="org.apache.karaf.instance.core.internal.InstanceServiceImpl" init-method="init">
+ <bean id="instanceService" class="org.apache.karaf.instance.core.internal.InstanceServiceImpl">
<property name="storageLocation" value="${karaf.instances}" />
</bean>
Modified: karaf/trunk/main/pom.xml
URL: http://svn.apache.org/viewvc/karaf/trunk/main/pom.xml?rev=1455901&r1=1455900&r2=1455901&view=diff
==============================================================================
--- karaf/trunk/main/pom.xml (original)
+++ karaf/trunk/main/pom.xml Wed Mar 13 12:21:07 2013
@@ -61,6 +61,10 @@
<version>1.1.1</version>
<scope>test</scope>
</dependency>
+ <dependency>
+ <groupId>org.apache.karaf</groupId>
+ <artifactId>org.apache.karaf.util</artifactId>
+ </dependency>
</dependencies>
<build>
@@ -99,8 +103,14 @@
org.apache.karaf.info
</Export-Package>
<Private-Package>
- org.apache.karaf.main*
+ org.apache.karaf.main*,
+ org.apache.felix.*;-split-package:=merge-first,
+ org.apache.karaf.util.*;-split-package:=merge-first,
+ org.eclipse.*;-split-package:=merge-first,
+ org.osgi.*;-split-package:=merge-first,
+ META-INF;-split-package:=merge-first
</Private-Package>
+ <Import-Package>!*</Import-Package>
</instructions>
<unpackBundle>true</unpackBundle>
</configuration>
Modified: karaf/trunk/main/src/main/java/org/apache/karaf/main/InstanceHelper.java
URL: http://svn.apache.org/viewvc/karaf/trunk/main/src/main/java/org/apache/karaf/main/InstanceHelper.java?rev=1455901&r1=1455900&r2=1455901&view=diff
==============================================================================
--- karaf/trunk/main/src/main/java/org/apache/karaf/main/InstanceHelper.java (original)
+++ karaf/trunk/main/src/main/java/org/apache/karaf/main/InstanceHelper.java Wed Mar 13 12:21:07 2013
@@ -21,6 +21,7 @@ package org.apache.karaf.main;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
+import java.io.IOException;
import java.io.OutputStreamWriter;
import java.io.Writer;
import java.lang.management.ManagementFactory;
@@ -31,19 +32,17 @@ import java.util.Properties;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
+import org.apache.karaf.util.properties.FileLockUtils;
import org.osgi.framework.launch.Framework;
public class InstanceHelper {
- static void updateInstancePid(File karafHome, File karafBase) {
+ static void updateInstancePid(final File karafHome, File karafBase) {
try {
- String instanceName = System.getProperty("karaf.name");
- String pid = ManagementFactory.getRuntimeMXBean().getName();
- if (pid.indexOf('@') > 0) {
- pid = pid.substring(0, pid.indexOf('@'));
- }
-
- boolean isRoot = karafHome.equals(karafBase);
+ final String instanceName = System.getProperty("karaf.name");
+ final String pid = getPid();
+
+ final boolean isRoot = karafHome.equals(karafBase);
if (instanceName != null) {
String storage = System.getProperty("karaf.instances");
@@ -52,63 +51,69 @@ public class InstanceHelper {
"This property needs to be set to the full path of the instance.properties file.");
}
File storageFile = new File(storage);
- File propertiesFile = new File(storageFile, "instance.properties");
- Properties props = new Properties();
- if (propertiesFile.exists()) {
- FileInputStream fis = new FileInputStream(propertiesFile);
- props.load(fis);
- int count = Integer.parseInt(props.getProperty("count"));
-
- // update root name if karaf.name got updated since the last container start
- if (isRoot) {
- for (int i = 0; i < count; i++) {
- //looking for root instance entry
- String name = props.getProperty("item." + i + ".name");
- boolean root = Boolean.parseBoolean(props.getProperty("item." + i + ".root", "false"));
- if (name != null && root && !name.equals(instanceName)) {
- props.setProperty("item." + i + ".name", instanceName);
- }
+ final File propertiesFile = new File(storageFile, "instance.properties");
+ if (!propertiesFile.getParentFile().exists()) {
+ try {
+ if (!propertiesFile.getParentFile().mkdirs()) {
+ throw new Exception("Unable to create directory " + propertiesFile.getParentFile());
}
+ } catch (SecurityException se) {
+ throw new Exception(se.getMessage());
}
-
- for (int i = 0; i < count; i++) {
- String name = props.getProperty("item." + i + ".name");
- if (name.equals(instanceName)) {
- props.setProperty("item." + i + ".pid", pid);
- FileOutputStream fos = new FileOutputStream(propertiesFile);
- props.store(fos, null);
- fis.close();
- fos.close();
- return;
- }
- }
- fis.close();
- if (!isRoot) {
- throw new Exception("Instance " + instanceName + " not found");
- }
- } else if (isRoot) {
- if (!propertiesFile.getParentFile().exists()) {
- try {
- propertiesFile.getParentFile().mkdirs();
- } catch (SecurityException se) {
- throw new Exception(se.getMessage());
+ }
+ FileLockUtils.execute(propertiesFile, new FileLockUtils.RunnableWithProperties() {
+ public void run(org.apache.felix.utils.properties.Properties props) throws IOException {
+ if (props.isEmpty()) {
+ if (isRoot) {
+ props.setProperty("count", "1");
+ props.setProperty("item.0.name", instanceName);
+ props.setProperty("item.0.loc", karafHome.getAbsolutePath());
+ props.setProperty("item.0.pid", pid);
+ props.setProperty("item.0.root", "true");
+ } else {
+ throw new IllegalStateException("Child instance started but no root registered in " + propertiesFile);
+ }
+ } else {
+ int count = Integer.parseInt(props.getProperty("count"));
+ // update root name if karaf.name got updated since the last container start
+ if (isRoot) {
+ for (int i = 0; i < count; i++) {
+ //looking for root instance entry
+ boolean root = Boolean.parseBoolean(props.getProperty("item." + i + ".root", "false"));
+ if (root) {
+ props.setProperty("item." + i + ".name", instanceName);
+ props.setProperty("item." + i + ".pid", pid);
+ return;
+ }
+ }
+ throw new IllegalStateException("Unable to find root instance in " + propertiesFile);
+ } else {
+ for (int i = 0; i < count; i++) {
+ String name = props.getProperty("item." + i + ".name");
+ if (name.equals(instanceName)) {
+ props.setProperty("item." + i + ".pid", pid);
+ return;
+ }
+ }
+ throw new IllegalStateException("Unable to find instance '" + instanceName + "'in " + propertiesFile);
+ }
}
}
- props.setProperty("count", "1");
- props.setProperty("item.0.name", instanceName);
- props.setProperty("item.0.loc", karafHome.getAbsolutePath());
- props.setProperty("item.0.pid", pid);
- props.setProperty("item.0.root", "true");
- FileOutputStream fos = new FileOutputStream(propertiesFile);
- props.store(fos, null);
- fos.close();
- }
- }
+ });
+ }
} catch (Exception e) {
System.err.println("Unable to update instance pid: " + e.getMessage());
}
}
+ private static String getPid() {
+ String pid = ManagementFactory.getRuntimeMXBean().getName();
+ if (pid.indexOf('@') > 0) {
+ pid = pid.substring(0, pid.indexOf('@'));
+ }
+ return pid;
+ }
+
private static void writePid(String pidFile) {
try {
if (pidFile != null) {
Modified: karaf/trunk/pom.xml
URL: http://svn.apache.org/viewvc/karaf/trunk/pom.xml?rev=1455901&r1=1455900&r2=1455901&view=diff
==============================================================================
--- karaf/trunk/pom.xml (original)
+++ karaf/trunk/pom.xml Wed Mar 13 12:21:07 2013
@@ -814,6 +814,7 @@
<groupId>org.apache.felix</groupId>
<artifactId>org.apache.felix.shell</artifactId>
</exclusion>
+
<exclusion>
<groupId>net.sf.kxml</groupId>
<artifactId>kxml2</artifactId>
Modified: karaf/trunk/util/pom.xml
URL: http://svn.apache.org/viewvc/karaf/trunk/util/pom.xml?rev=1455901&r1=1455900&r2=1455901&view=diff
==============================================================================
--- karaf/trunk/util/pom.xml (original)
+++ karaf/trunk/util/pom.xml Wed Mar 13 12:21:07 2013
@@ -44,6 +44,10 @@
<artifactId>slf4j-api</artifactId>
<scope>provided</scope>
</dependency>
+ <dependency>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>org.apache.felix.utils</artifactId>
+ </dependency>
</dependencies>
<properties>
Added: karaf/trunk/util/src/main/java/org/apache/karaf/util/properties/FileLockUtils.java
URL: http://svn.apache.org/viewvc/karaf/trunk/util/src/main/java/org/apache/karaf/util/properties/FileLockUtils.java?rev=1455901&view=auto
==============================================================================
--- karaf/trunk/util/src/main/java/org/apache/karaf/util/properties/FileLockUtils.java (added)
+++ karaf/trunk/util/src/main/java/org/apache/karaf/util/properties/FileLockUtils.java Wed Mar 13 12:21:07 2013
@@ -0,0 +1,110 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.apache.karaf.util.properties;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.io.IOException;
+import java.io.RandomAccessFile;
+import java.nio.channels.FileLock;
+import org.apache.felix.utils.properties.Properties;
+
+public final class FileLockUtils {
+
+ private FileLockUtils() { }
+
+ public static interface Runnable {
+ void run(RandomAccessFile file) throws IOException;
+ }
+
+ public static interface Callable<T> {
+ T call(RandomAccessFile file) throws IOException;
+ }
+
+ public static interface RunnableWithProperties {
+ void run(Properties properties) throws IOException;
+ }
+
+ public static interface CallableWithProperties<T> {
+ T call(Properties properties) throws IOException;
+ }
+
+ public static void execute(File file, Runnable callback) throws IOException {
+ RandomAccessFile raf = new RandomAccessFile(file, "rw");
+ try {
+ FileLock lock = raf.getChannel().lock();
+ try {
+ callback.run(raf);
+ } finally {
+ lock.release();
+ }
+ } finally {
+ raf.close();
+ }
+ }
+
+ public static <T> T execute(File file, Callable<T> callback) throws IOException {
+ RandomAccessFile raf = new RandomAccessFile(file, "rw");
+ try {
+ FileLock lock = raf.getChannel().lock();
+ try {
+ return callback.call(raf);
+ } finally {
+ lock.release();
+ }
+ } finally {
+ raf.close();
+ }
+ }
+
+ public static void execute(File file, final RunnableWithProperties callback) throws IOException {
+ execute(file, new Runnable() {
+ public void run(RandomAccessFile file) throws IOException {
+ byte[] buffer = new byte[(int) file.length()];
+ file.readFully(buffer);
+ Properties props = new Properties();
+ props.load(new ByteArrayInputStream(buffer));
+ callback.run(props);
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ props.store(baos, null);
+ file.setLength(0);
+ file.write(baos.toByteArray());
+ }
+ });
+ }
+
+ public static <T> T execute(File file, final CallableWithProperties<T> callback) throws IOException {
+ return execute(file, new Callable<T>() {
+ public T call(RandomAccessFile file) throws IOException {
+ byte[] buffer = new byte[(int) file.length()];
+ file.readFully(buffer);
+ Properties props = new Properties();
+ props.load(new ByteArrayInputStream(buffer));
+ T result = callback.call(props);
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ props.store(baos, null);
+ file.setLength(0);
+ file.write(baos.toByteArray());
+ return result;
+ }
+ });
+ }
+
+}