Move ServiceMix Kernel trunk into Felix

git-svn-id: https://svn.apache.org/repos/asf/felix/trunk@768912 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/karaf/gshell/gshell-admin/src/main/filtered-resources/org/apache/servicemix/kernel/gshell/admin/etc/org.apache.servicemix.features.cfg b/karaf/gshell/gshell-admin/src/main/filtered-resources/org/apache/servicemix/kernel/gshell/admin/etc/org.apache.servicemix.features.cfg
new file mode 100644
index 0000000..2e22aec
--- /dev/null
+++ b/karaf/gshell/gshell-admin/src/main/filtered-resources/org/apache/servicemix/kernel/gshell/admin/etc/org.apache.servicemix.features.cfg
@@ -0,0 +1,28 @@
+################################################################################

+#

+#    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.

+#

+################################################################################

+

+#

+# Comma separated list of features repositories to register by default

+#

+featuresRepositories=mvn:org.apache.servicemix.kernel/apache-servicemix-kernel/${version}/xml/features

+

+#

+# Comma separated list of features to install at startup

+#

+featuresBoot=

diff --git a/karaf/gshell/gshell-admin/src/main/filtered-resources/org/apache/servicemix/kernel/gshell/admin/etc/startup.properties b/karaf/gshell/gshell-admin/src/main/filtered-resources/org/apache/servicemix/kernel/gshell/admin/etc/startup.properties
new file mode 100644
index 0000000..f9689b1
--- /dev/null
+++ b/karaf/gshell/gshell-admin/src/main/filtered-resources/org/apache/servicemix/kernel/gshell/admin/etc/startup.properties
@@ -0,0 +1,76 @@
+################################################################################
+#
+#    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.
+#
+################################################################################
+
+# This file allows you to control the start level of each bundle.
+#
+
+#
+# Startup core services like logging
+#
+org/ops4j/pax/url/pax-url-mvn/${pax.url.version}/pax-url-mvn-${pax.url.version}.jar=5
+org/ops4j/pax/url/pax-url-wrap/${pax.url.version}/pax-url-wrap-${pax.url.version}.jar=5
+org/apache/geronimo/specs/geronimo-servlet_2.5_spec/${geronimo.servlet.version}/geronimo-servlet_2.5_spec-${geronimo.servlet.version}.jar=10
+org/apache/servicemix/specs/org.apache.servicemix.specs.jaxp-api-1.4/${servicemix.specs.version}/org.apache.servicemix.specs.jaxp-api-1.4-${servicemix.specs.version}.jar=10
+org/apache/servicemix/bundles/org.apache.servicemix.bundles.jaxp-ri/${jaxp.ri.version}/org.apache.servicemix.bundles.jaxp-ri-${jaxp.ri.version}.jar=10
+org/apache/felix/org.osgi.compendium/${felix.compendium.version}/org.osgi.compendium-${felix.compendium.version}.jar=10
+org/apache/felix/org.apache.felix.configadmin/${felix.configadmin.version}/org.apache.felix.configadmin-${felix.configadmin.version}.jar=10
+org/apache/geronimo/specs/geronimo-annotation_1.0_spec/${geronimo.annotation.version}/geronimo-annotation_1.0_spec-${geronimo.annotation.version}.jar=10
+org/apache/felix/org.apache.felix.prefs/${felix.prefs.version}/org.apache.felix.prefs-${felix.prefs.version}.jar=10
+org/apache/servicemix/kernel/org.apache.servicemix.kernel.filemonitor/${pom.version}/org.apache.servicemix.kernel.filemonitor-${pom.version}.jar=15
+org/ops4j/pax/logging/pax-logging-api/${pax.logging.version}/pax-logging-api-${pax.logging.version}.jar=20
+org/ops4j/pax/logging/pax-logging-service/${pax.logging.version}/pax-logging-service-${pax.logging.version}.jar=20
+
+#
+# The rest of the services..
+#
+org/apache/servicemix/bundles/org.apache.servicemix.bundles.jline/${jline.version}/org.apache.servicemix.bundles.jline-${jline.version}.jar=30
+org/apache/servicemix/bundles/org.apache.servicemix.bundles.aopalliance/${aopalliance.version}/org.apache.servicemix.bundles.aopalliance-${aopalliance.version}.jar=30
+org/apache/servicemix/bundles/org.apache.servicemix.bundles.cglib/${cglib.version}/org.apache.servicemix.bundles.cglib-${cglib.version}.jar=30
+org/apache/servicemix/bundles/org.apache.servicemix.bundles.mina/${mina.version}/org.apache.servicemix.bundles.mina-${mina.version}.jar=30
+org/apache/servicemix/bundles/org.apache.servicemix.bundles.oro/${oro.version}/org.apache.servicemix.bundles.oro-${oro.version}.jar=30
+org/apache/servicemix/bundles/org.apache.servicemix.bundles.commons-codec/${commons.codec.version}/org.apache.servicemix.bundles.commons-codec-${commons.codec.version}.jar=30
+org/apache/servicemix/bundles/org.apache.servicemix.bundles.commons-httpclient/${commons.httpclient.version}/org.apache.servicemix.bundles.commons-httpclient-${commons.httpclient.version}.jar=30
+org/apache/servicemix/bundles/org.apache.servicemix.bundles.commons-jexl/${commons.jexl.version}/org.apache.servicemix.bundles.commons-jexl-${commons.jexl.version}.jar=30
+org/apache/servicemix/bundles/org.apache.servicemix.bundles.commons-vfs/${commons.vfs.version}/org.apache.servicemix.bundles.commons-vfs-${commons.vfs.version}.jar=30
+org/springframework/spring-aop/${spring.version}/spring-aop-${spring.version}.jar=30
+org/springframework/spring-beans/${spring.version}/spring-beans-${spring.version}.jar=30
+org/springframework/spring-context/${spring.version}/spring-context-${spring.version}.jar=30
+org/springframework/spring-core/${spring.version}/spring-core-${spring.version}.jar=30
+org/springframework/osgi/spring-osgi-core/${spring.osgi.version}/spring-osgi-core-${spring.osgi.version}.jar=30
+org/springframework/osgi/spring-osgi-extender/${spring.osgi.version}/spring-osgi-extender-${spring.osgi.version}.jar=30
+org/springframework/osgi/spring-osgi-io/${spring.osgi.version}/spring-osgi-io-${spring.osgi.version}.jar=30
+org/apache/servicemix/kernel/org.apache.servicemix.kernel.spring/${pom.version}/org.apache.servicemix.kernel.spring-${pom.version}.jar=30
+org/apache/servicemix/kernel/org.apache.servicemix.kernel.management/${pom.version}/org.apache.servicemix.kernel.management-${pom.version}.jar=30
+org/apache/servicemix/kernel/gshell/org.apache.servicemix.kernel.gshell.admin/${pom.version}/org.apache.servicemix.kernel.gshell.admin-${pom.version}.jar=30
+org/apache/servicemix/kernel/gshell/org.apache.servicemix.kernel.gshell.osgi/${pom.version}/org.apache.servicemix.kernel.gshell.osgi-${pom.version}.jar=30
+org/apache/servicemix/kernel/gshell/org.apache.servicemix.kernel.gshell.features/${pom.version}/org.apache.servicemix.kernel.gshell.features-${pom.version}.jar=30
+org/apache/servicemix/kernel/gshell/org.apache.servicemix.kernel.gshell.log/${pom.version}/org.apache.servicemix.kernel.gshell.log-${pom.version}.jar=30
+org/apache/servicemix/kernel/gshell/org.apache.servicemix.kernel.gshell.config/${pom.version}/org.apache.servicemix.kernel.gshell.config-${pom.version}.jar=30
+org/apache/servicemix/kernel/gshell/org.apache.servicemix.kernel.gshell.packages/${pom.version}/org.apache.servicemix.kernel.gshell.packages-${pom.version}.jar=30
+org/apache/servicemix/kernel/jaas/org.apache.servicemix.kernel.jaas.config/${pom.version}/org.apache.servicemix.kernel.jaas.config-${pom.version}.jar=30
+org/apache/servicemix/kernel/jaas/org.apache.servicemix.kernel.jaas.modules/${pom.version}/org.apache.servicemix.kernel.jaas.modules-${pom.version}.jar=30
+com/google/code/sshd/sshd/${sshd.version}/sshd-${sshd.version}.jar=30
+org/osgi/jmx/${osgi.jmx.version}/jmx-${osgi.jmx.version}.jar=30
+com/oracle/osgi/jmx-impl/${osgi.jmx.version}/jmx-impl-${osgi.jmx.version}.jar=30
+
+#
+# Start console last
+#
+org/apache/servicemix/kernel/gshell/org.apache.servicemix.kernel.gshell.core/${pom.version}/org.apache.servicemix.kernel.gshell.core-${pom.version}.jar=40
+
diff --git a/karaf/gshell/gshell-admin/src/main/java/org/apache/servicemix/jpm/Process.java b/karaf/gshell/gshell-admin/src/main/java/org/apache/servicemix/jpm/Process.java
new file mode 100644
index 0000000..eedb31d
--- /dev/null
+++ b/karaf/gshell/gshell-admin/src/main/java/org/apache/servicemix/jpm/Process.java
@@ -0,0 +1,47 @@
+/*
+ * 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.servicemix.jpm;
+
+import java.io.IOException;
+import java.io.Serializable;
+
+/**
+ * Interface representing a process
+ */
+public interface Process extends Serializable {
+
+    /**
+     * Retrieves the PID of the process
+     * @return the pid
+     */
+    int getPid();
+
+    /**
+     * Check if this process is still running
+     * @return <code>true</code> if the process is running
+     * @throws IOException if an error occurs
+     */
+    boolean isRunning() throws IOException;
+
+    /**
+     * Destroy the process.
+     *
+     * @throws IOException
+     */
+    void destroy() throws IOException;
+
+}
diff --git a/karaf/gshell/gshell-admin/src/main/java/org/apache/servicemix/jpm/ProcessBuilder.java b/karaf/gshell/gshell-admin/src/main/java/org/apache/servicemix/jpm/ProcessBuilder.java
new file mode 100644
index 0000000..6862222
--- /dev/null
+++ b/karaf/gshell/gshell-admin/src/main/java/org/apache/servicemix/jpm/ProcessBuilder.java
@@ -0,0 +1,59 @@
+/*
+ * 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.servicemix.jpm;
+
+import java.io.File;
+import java.io.IOException;
+
+/**
+ * Interface used to create new processes.
+ */
+public interface ProcessBuilder {
+
+    /**
+     * Specified the current directory to run the command from
+     *
+     * @param dir the directory to run the command from
+     * @return the ProcessBuilder instance
+     */
+    ProcessBuilder directory(File dir);
+
+    /**
+     * Set the command to execute
+     *
+     * @param command the command to execute
+     * @return the ProcessBuilder instance
+     */
+    ProcessBuilder command(String command);
+
+    /**
+     * Create and start the process
+     *
+     * @return the process that has been started
+     * @throws IOException if the process can not be created
+     */
+    Process start() throws IOException;
+
+    /**
+     * Attach to an existing process
+     *
+     * @return the process that has been attached
+     * @throws IOException if the process can not be attached to
+     */
+    Process attach(int pid) throws IOException;
+
+}
diff --git a/karaf/gshell/gshell-admin/src/main/java/org/apache/servicemix/jpm/ProcessBuilderFactory.java b/karaf/gshell/gshell-admin/src/main/java/org/apache/servicemix/jpm/ProcessBuilderFactory.java
new file mode 100644
index 0000000..433b615
--- /dev/null
+++ b/karaf/gshell/gshell-admin/src/main/java/org/apache/servicemix/jpm/ProcessBuilderFactory.java
@@ -0,0 +1,30 @@
+/*
+ * 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.servicemix.jpm;
+
+/**
+ * Factory for process builders.
+ */
+public abstract class ProcessBuilderFactory {
+
+    public static ProcessBuilderFactory newInstance() {
+        return new org.apache.servicemix.jpm.impl.ProcessBuilderFactoryImpl();
+    }
+
+    public abstract ProcessBuilder newBuilder();
+
+}
diff --git a/karaf/gshell/gshell-admin/src/main/java/org/apache/servicemix/jpm/impl/ProcessBuilderFactoryImpl.java b/karaf/gshell/gshell-admin/src/main/java/org/apache/servicemix/jpm/impl/ProcessBuilderFactoryImpl.java
new file mode 100644
index 0000000..4db4657
--- /dev/null
+++ b/karaf/gshell/gshell-admin/src/main/java/org/apache/servicemix/jpm/impl/ProcessBuilderFactoryImpl.java
@@ -0,0 +1,27 @@
+/*
+ * 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.servicemix.jpm.impl;
+
+import org.apache.servicemix.jpm.ProcessBuilder;
+import org.apache.servicemix.jpm.ProcessBuilderFactory;
+
+public class ProcessBuilderFactoryImpl extends ProcessBuilderFactory {
+
+    public ProcessBuilder newBuilder() {
+        return new ProcessBuilderImpl();
+    }
+}
diff --git a/karaf/gshell/gshell-admin/src/main/java/org/apache/servicemix/jpm/impl/ProcessBuilderImpl.java b/karaf/gshell/gshell-admin/src/main/java/org/apache/servicemix/jpm/impl/ProcessBuilderImpl.java
new file mode 100644
index 0000000..649da6b
--- /dev/null
+++ b/karaf/gshell/gshell-admin/src/main/java/org/apache/servicemix/jpm/impl/ProcessBuilderImpl.java
@@ -0,0 +1,48 @@
+/*
+ * 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.servicemix.jpm.impl;
+
+import java.io.File;
+import java.io.IOException;
+
+import org.apache.servicemix.jpm.Process;
+import org.apache.servicemix.jpm.ProcessBuilder;
+
+
+public class ProcessBuilderImpl implements ProcessBuilder {
+
+    private File dir;
+    private String command;
+
+    public ProcessBuilder directory(File dir) {
+        this.dir = dir;
+        return this;
+    }
+
+    public ProcessBuilder command(String command) {
+        this.command = command;
+        return this;
+    }
+
+    public Process start() throws IOException {
+        return ProcessImpl.create(dir, command);
+    }
+
+    public Process attach(int pid) throws IOException {
+        return ProcessImpl.attach(pid);
+    }
+}
diff --git a/karaf/gshell/gshell-admin/src/main/java/org/apache/servicemix/jpm/impl/ProcessImpl.java b/karaf/gshell/gshell-admin/src/main/java/org/apache/servicemix/jpm/impl/ProcessImpl.java
new file mode 100644
index 0000000..71146fa
--- /dev/null
+++ b/karaf/gshell/gshell-admin/src/main/java/org/apache/servicemix/jpm/impl/ProcessImpl.java
@@ -0,0 +1,150 @@
+/*
+ * 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.servicemix.jpm.impl;
+
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.InterruptedIOException;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.apache.servicemix.jpm.Process;
+
+public class ProcessImpl implements Process {
+
+    private int pid;
+    //private File input;
+    //private File output;
+    //private File error;
+
+    public ProcessImpl(int pid/*, File input, File output, File error*/) {
+        this.pid = pid;
+        //this.input = input;
+        //this.output = output;
+        //this.error = error;
+    }
+
+    public int getPid() {
+        return pid;
+    }
+
+    public boolean isRunning() throws IOException {
+        if (ScriptUtils.isWindows()) {
+            Map<String, String> props = new HashMap<String, String>();
+            props.put("${pid}", Integer.toString(pid));
+            int ret = ScriptUtils.execute("running", props);
+            return ret == 0;
+        } else {
+            try {
+                java.lang.Process process = new java.lang.ProcessBuilder("ps", "-p", Integer.toString(pid)).start();
+                BufferedReader r = new BufferedReader(new InputStreamReader(process.getInputStream()));
+                r.readLine(); // skip headers
+                String s = r.readLine();
+                boolean running = s != null && s.length() > 0;
+                int ret = process.waitFor();
+                return running;
+            } catch (InterruptedException e) {
+                throw new InterruptedIOException();
+            }
+        }
+    }
+
+    public void destroy() throws IOException {
+        int ret;
+        if (ScriptUtils.isWindows()) {
+            Map<String, String> props = new HashMap<String, String>();
+            props.put("${pid}", Integer.toString(pid));
+            ret = ScriptUtils.execute("destroy", props);
+        } else {
+            ret = ScriptUtils.executeProcess(new java.lang.ProcessBuilder("kill", "-9", Integer.toString(pid)));
+        }
+        if (ret != 0) {
+            throw new IOException("Unable to destroy proces, it may be already terminated");
+        }
+    }
+
+    /*
+    public OutputStream getInputStream() throws FileNotFoundException {
+        return new FileOutputStream(input);
+    }
+
+    public InputStream getOutputStream() throws FileNotFoundException {
+        return new FileInputStream(output);
+    }
+
+    public InputStream getErrorStream() throws FileNotFoundException {
+        return new FileInputStream(error);
+    }
+    */
+
+    public int waitFor() throws InterruptedException {
+        return 0;
+    }
+
+    public int exitValue() {
+        return 0;
+    }
+
+    public static Process create(File dir, String command) throws IOException {
+        //File input = File.createTempFile("jpm.", ".input");
+        //File output = File.createTempFile("jpm.", ".output");
+        //File error = File.createTempFile("jpm.", ".error");
+        File pidFile = File.createTempFile("jpm.", ".pid");
+        try {
+            Map<String, String> props = new HashMap<String, String>();
+            //props.put("${in.file}", input.getCanonicalPath());
+            //props.put("${out.file}", output.getCanonicalPath());
+            //props.put("${err.file}", error.getCanonicalPath());
+            props.put("${pid.file}", pidFile.getCanonicalPath());
+            props.put("${dir}", dir != null ? dir.getCanonicalPath() : "");
+            if (ScriptUtils.isWindows()) {
+                command = command.replaceAll("\"", "\"\"");
+            }
+            props.put("${command}", command);
+            int ret = ScriptUtils.execute("start", props);
+            if (ret != 0) {
+                throw new IOException("Unable to create process (error code: " + ret + ")");
+            }
+            int pid = readPid(pidFile);
+            return new ProcessImpl(pid/*, input, output, error*/);
+        } finally {
+            pidFile.delete();
+        }
+    }
+
+    public static Process attach(int pid) throws IOException {
+        return new ProcessImpl(pid);
+    }
+
+    private static int readPid(File pidFile) throws IOException {
+        InputStream is = new FileInputStream(pidFile);
+        try {
+            BufferedReader r = new BufferedReader(new InputStreamReader(is));
+            String pidString = r.readLine();
+            return Integer.valueOf(pidString);
+        } finally {
+            try {
+                is.close();
+            } catch (IOException e) {}
+        }
+    }
+
+}
diff --git a/karaf/gshell/gshell-admin/src/main/java/org/apache/servicemix/jpm/impl/ScriptUtils.java b/karaf/gshell/gshell-admin/src/main/java/org/apache/servicemix/jpm/impl/ScriptUtils.java
new file mode 100644
index 0000000..869c958
--- /dev/null
+++ b/karaf/gshell/gshell-admin/src/main/java/org/apache/servicemix/jpm/impl/ScriptUtils.java
@@ -0,0 +1,124 @@
+/*
+ * 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.servicemix.jpm.impl;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InterruptedIOException;
+import java.io.OutputStream;
+import java.io.PrintStream;
+import java.util.Map;
+import java.util.Scanner;
+
+public class ScriptUtils {
+
+    public static int execute(String name, Map<String, String> props) throws IOException {
+        File script = File.createTempFile("jpm.", ".script");
+        try {
+            if (isWindows()) {
+                String res = "windows/" + name + ".vbs";
+                ScriptUtils.copyFilteredResource(res, script, props);
+                return executeProcess(new java.lang.ProcessBuilder("cscript",
+                                                                   "/NOLOGO",
+                                                                   "//E:vbs",
+                                                                   script.getCanonicalPath()));
+            } else {
+                String res = "unix/" + name + ".sh";
+                ScriptUtils.copyFilteredResource(res, script, props);
+                return executeProcess(new java.lang.ProcessBuilder("/bin/sh",
+                                                                   script.getCanonicalPath()));
+            }
+        } finally {
+            script.delete();
+        }
+    }
+
+    public static int executeProcess(java.lang.ProcessBuilder builder) throws IOException {
+        try {
+            java.lang.Process process = builder.start();
+            return process.waitFor();
+        } catch (InterruptedException e) {
+            throw new InterruptedIOException();
+        }
+    }
+
+    public static void copyFilteredResource(String resource, File outFile, Map<String, String> props) throws IOException {
+        InputStream is = null;
+        try {
+            is = ScriptUtils.class.getResourceAsStream(resource);
+            // 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();
+                    line = filter(line, props);
+                    out.println(line);
+                }
+            } finally {
+                safeClose(out);
+            }
+        } finally {
+            safeClose(is);
+        }
+    }
+
+    private static void safeClose(InputStream is) throws IOException {
+        if (is == null) {
+            return;
+        }
+        try {
+            is.close();
+        } catch (Throwable ignore) {
+        }
+    }
+
+    private static void safeClose(OutputStream is) throws IOException {
+        if (is == null) {
+            return;
+        }
+        try {
+            is.close();
+        } catch (Throwable ignore) {
+        }
+    }
+
+    private static String filter(String line, Map<String, String> props) {
+        for (Map.Entry<String, String> i : props.entrySet()) {
+            int p1 = line.indexOf(i.getKey());
+            if( p1 >= 0 ) {
+                String l1 = line.substring(0, p1);
+                String l2 = line.substring(p1+i.getKey().length());
+                line = l1+i.getValue()+l2;
+            }
+        }
+        return line;
+    }
+
+    private static final boolean windows;
+
+    static {
+        windows = System.getProperty("os.name").toLowerCase().indexOf("windows") != -1;
+    }
+
+    public static boolean isWindows() {
+        return windows;
+    }
+
+}
diff --git a/karaf/gshell/gshell-admin/src/main/java/org/apache/servicemix/kernel/gshell/admin/AdminService.java b/karaf/gshell/gshell-admin/src/main/java/org/apache/servicemix/kernel/gshell/admin/AdminService.java
new file mode 100644
index 0000000..cbf7181
--- /dev/null
+++ b/karaf/gshell/gshell-admin/src/main/java/org/apache/servicemix/kernel/gshell/admin/AdminService.java
@@ -0,0 +1,27 @@
+/*
+ * 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.servicemix.kernel.gshell.admin;
+
+public interface AdminService {
+
+    Instance createInstance(String name, int port, String location) throws Exception;
+
+    Instance[] getInstances();
+
+    Instance getInstance(String name);
+
+}
diff --git a/karaf/gshell/gshell-admin/src/main/java/org/apache/servicemix/kernel/gshell/admin/AdminServiceMBean.java b/karaf/gshell/gshell-admin/src/main/java/org/apache/servicemix/kernel/gshell/admin/AdminServiceMBean.java
new file mode 100644
index 0000000..8a68d2d
--- /dev/null
+++ b/karaf/gshell/gshell-admin/src/main/java/org/apache/servicemix/kernel/gshell/admin/AdminServiceMBean.java
@@ -0,0 +1,37 @@
+/*
+ * 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.servicemix.kernel.gshell.admin;
+
+public interface AdminServiceMBean {
+
+    void createInstance(String name, int port, String location) throws Exception;
+
+    String[] getInstances();
+
+    int getPort(String name) throws Exception;
+
+    void changePort(String name, int port) throws Exception;
+
+    String getState(String name) throws Exception;
+
+    void start(String name, String javaOpts) throws Exception;
+
+    void stop(String name) throws Exception;
+
+    void destroy(String name) throws Exception;
+
+}
diff --git a/karaf/gshell/gshell-admin/src/main/java/org/apache/servicemix/kernel/gshell/admin/Instance.java b/karaf/gshell/gshell-admin/src/main/java/org/apache/servicemix/kernel/gshell/admin/Instance.java
new file mode 100644
index 0000000..07612aa
--- /dev/null
+++ b/karaf/gshell/gshell-admin/src/main/java/org/apache/servicemix/kernel/gshell/admin/Instance.java
@@ -0,0 +1,43 @@
+/*
+ * 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.servicemix.kernel.gshell.admin;
+
+public interface Instance {
+
+    String STOPPED = "Stopped";
+    String STARTING = "Starting";
+    String STARTED = "Started";
+
+    String getName();
+
+    String getLocation();
+
+    int getPid();
+
+    int getPort() throws Exception;
+
+    void changePort(int port) throws Exception;
+
+    void start(String javaOpts) throws Exception;
+
+    void stop() throws Exception;
+
+    void destroy() throws Exception;
+
+    String getState() throws Exception;
+
+}
diff --git a/karaf/gshell/gshell-admin/src/main/java/org/apache/servicemix/kernel/gshell/admin/internal/AdminServiceImpl.java b/karaf/gshell/gshell-admin/src/main/java/org/apache/servicemix/kernel/gshell/admin/internal/AdminServiceImpl.java
new file mode 100644
index 0000000..54283a8
--- /dev/null
+++ b/karaf/gshell/gshell-admin/src/main/java/org/apache/servicemix/kernel/gshell/admin/internal/AdminServiceImpl.java
@@ -0,0 +1,299 @@
+/*
+ * 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.servicemix.kernel.gshell.admin.internal;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.io.PrintStream;
+import java.net.ServerSocket;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Scanner;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.apache.geronimo.gshell.shell.ShellContext;
+import org.apache.geronimo.gshell.shell.ShellContextHolder;
+import org.apache.servicemix.kernel.gshell.admin.AdminService;
+import org.apache.servicemix.kernel.gshell.admin.Instance;
+import org.osgi.service.prefs.BackingStoreException;
+import org.osgi.service.prefs.Preferences;
+import org.osgi.service.prefs.PreferencesService;
+import org.springframework.beans.factory.InitializingBean;
+
+public class AdminServiceImpl implements AdminService, InitializingBean {
+
+    private static final Log LOGGER = LogFactory.getLog(AdminServiceImpl.class);
+
+    private PreferencesService preferences;
+
+    private Map<String, Instance> instances = new HashMap<String, Instance>();
+
+    private int defaultPortStart = 8101;
+
+    public PreferencesService getPreferences() {
+        return preferences;
+    }
+
+    public void setPreferences(PreferencesService preferences) {
+        this.preferences = preferences;
+    }
+
+    public synchronized void afterPropertiesSet() throws Exception {
+        try {
+            Preferences prefs = preferences.getUserPreferences("AdminServiceState");
+            Preferences child = prefs.node("Instances");
+            int count = child.getInt("count", 0);
+            Map<String, Instance> newInstances = new HashMap<String, Instance>();
+            for (int i = 0; i < count; i++) {
+                String name = child.get("item." + i + ".name", null);
+                String loc = child.get("item." + i + ".loc", null);
+                int pid = child.getInt("item." + i + ".pid", 0);
+                if (name != null) {
+                    InstanceImpl instance = new InstanceImpl(this, name, loc);
+                    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 ServiceMix instance list", e);
+        }
+    }
+
+    public synchronized Instance createInstance(String name, int port, String location) throws Exception {
+        if (instances.get(name) != null) {
+            throw new IllegalArgumentException("Instance '" + name + "' already exists");
+        }
+        File serviceMixBase = new File(location != null ? location : ("instances/" + name)).getCanonicalFile();
+        int sshPort = port;
+        if (sshPort <= 0) {
+            try {
+                Preferences prefs = preferences.getUserPreferences("AdminServiceState");
+                sshPort = prefs.getInt("port", defaultPortStart + 1);
+                prefs.putInt("port", sshPort + 1);
+                prefs.flush();
+                prefs.sync();
+            } catch (Exception e) {
+                try {
+                    ServerSocket ss = new ServerSocket(0);
+                    sshPort = ss.getLocalPort();
+                    ss.close();
+                } catch (Exception t) {
+                }
+            }
+            if (sshPort <= 0) {
+                sshPort = defaultPortStart;
+            }
+        }
+        println("Creating new instance on port " + sshPort + " at: @|bold " + serviceMixBase + "|");
+
+        mkdir(serviceMixBase, "bin");
+        mkdir(serviceMixBase, "etc");
+        mkdir(serviceMixBase, "system");
+        mkdir(serviceMixBase, "deploy");
+        mkdir(serviceMixBase, "data");
+
+        copyResourceToDir(serviceMixBase, "etc/config.properties", true);
+        copyResourceToDir(serviceMixBase, "etc/org.apache.servicemix.features.cfg", true);
+        copyResourceToDir(serviceMixBase, "etc/users.properties", true);
+        copyResourceToDir(serviceMixBase, "etc/org.ops4j.pax.logging.cfg", true);
+        copyResourceToDir(serviceMixBase, "etc/org.ops4j.pax.url.mvn.cfg", true);
+        copyResourceToDir(serviceMixBase, "etc/startup.properties", true);
+
+        HashMap<String, String> props = new HashMap<String, String>();
+        props.put("${servicemix.name}", name);
+        props.put("${servicemix.home}", System.getProperty("servicemix.home"));
+        props.put("${servicemix.base}", serviceMixBase.getPath());
+        props.put("${servicemix.sshPort}", Integer.toString(sshPort));
+        copyFilteredResourceToDir(serviceMixBase, "etc/system.properties", props);
+        copyFilteredResourceToDir(serviceMixBase, "etc/org.apache.servicemix.shell.cfg", props);
+        if( System.getProperty("os.name").startsWith("Win") ) {
+            copyFilteredResourceToDir(serviceMixBase, "bin/servicemix.bat", props);
+        } else {
+            copyFilteredResourceToDir(serviceMixBase, "bin/servicemix", props);
+            chmod(new File(serviceMixBase, "bin/servicemix"), "a+x");
+        }
+        Instance instance = new InstanceImpl(this, name, serviceMixBase.toString());
+        instances.put(name, instance);
+        saveState();
+        return instance;
+    }
+
+    public synchronized Instance[] getInstances() {
+        return instances.values().toArray(new Instance[0]);
+    }
+
+    public synchronized Instance getInstance(String name) {
+        return instances.get(name);
+    }
+
+    synchronized void forget(String name) {
+        instances.remove(name);
+    }
+
+    synchronized void saveState() throws IOException, BackingStoreException {
+        Preferences prefs = preferences.getUserPreferences("AdminServiceState");
+        Preferences child = prefs.node("Instances");
+        child.clear();
+        Instance[] data = getInstances();
+        child.putInt("count", data.length);
+        for (int i = 0; i < data.length; i++) {
+            child.put("item." + i + ".name", data[i].getName());
+            child.put("item." + i + ".loc", data[i].getLocation());
+            child.putInt("item." + i + ".pid", data[i].getPid());
+        }
+        prefs.flush();
+        prefs.sync();
+    }
+
+    private void copyResourceToDir(File target, String resource, boolean text) throws Exception {
+        File outFile = new File(target, resource);
+        if( !outFile.exists() ) {
+            println("Creating file: @|bold " + outFile.getPath() + "|");
+            InputStream is = getClass().getClassLoader().getResourceAsStream("/org/apache/servicemix/kernel/gshell/admin/" + resource);
+            try {
+                if( text ) {
+                    // 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);
+                    }
+                } else {
+                    // Binary so just write it out the way it came in.
+                    FileOutputStream out = new FileOutputStream(new File(target, resource));
+                    try {
+                        int c=0;
+                        while((c=is.read())>=0) {
+                            out.write(c);
+                        }
+                    } finally {
+                        safeClose(out);
+                    }
+                }
+            } finally {
+                safeClose(is);
+            }
+        }
+    }
+
+    private void println(String st) {
+        ShellContext ctx = ShellContextHolder.get(true);
+        if (ctx != null) {
+            ctx.getIo().out.println(st);
+        } else {
+            System.out.println(st);
+        }
+    }
+
+    private void copyFilteredResourceToDir(File target, String resource, HashMap<String, String> props) throws Exception {
+        File outFile = new File(target, resource);
+        if( !outFile.exists() ) {
+            println("Creating file: @|bold "+outFile.getPath()+"|");
+            InputStream is = getClass().getClassLoader().getResourceAsStream("/org/apache/servicemix/kernel/gshell/admin/" + resource);
+            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));
+                try {
+                    Scanner scanner = new Scanner(is);
+                    while (scanner.hasNextLine() ) {
+                        String line = scanner.nextLine();
+                        line = filter(line, props);
+                        out.println(line);
+                    }
+                } finally {
+                    safeClose(out);
+                }
+            } finally {
+                safeClose(is);
+            }
+        }
+    }
+
+    private void safeClose(InputStream is) throws IOException {
+        if (is == null) {
+            return;
+        }
+        try {
+            is.close();
+        } catch (Throwable ignore) {
+        }
+    }
+
+    private void safeClose(OutputStream is) throws IOException {
+        if (is == null) {
+            return;
+        }
+        try {
+            is.close();
+        } catch (Throwable ignore) {
+        }
+    }
+
+    private String filter(String line, HashMap<String, String> props) {
+        for (Map.Entry<String, String> i : props.entrySet()) {
+            int p1 = line.indexOf(i.getKey());
+            if( p1 >= 0 ) {
+                String l1 = line.substring(0, p1);
+                String l2 = line.substring(p1+i.getKey().length());
+                line = l1+i.getValue()+l2;
+            }
+        }
+        return line;
+    }
+
+    private void mkdir(File serviceMixBase, String path) {
+        File file = new File(serviceMixBase, path);
+        if( !file.exists() ) {
+            println("Creating dir:  @|bold "+file.getPath()+"|");
+            file.mkdirs();
+        }
+    }
+
+    private int chmod(File serviceFile, String mode) throws Exception {
+        ProcessBuilder builder = new ProcessBuilder();
+        builder.command("chmod", mode, serviceFile.getCanonicalPath());
+        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();
+        int status = p.waitFor();
+        //handler.stop();
+        return status;
+    }
+
+}
diff --git a/karaf/gshell/gshell-admin/src/main/java/org/apache/servicemix/kernel/gshell/admin/internal/AdminServiceMBeanImpl.java b/karaf/gshell/gshell-admin/src/main/java/org/apache/servicemix/kernel/gshell/admin/internal/AdminServiceMBeanImpl.java
new file mode 100644
index 0000000..a53b663
--- /dev/null
+++ b/karaf/gshell/gshell-admin/src/main/java/org/apache/servicemix/kernel/gshell/admin/internal/AdminServiceMBeanImpl.java
@@ -0,0 +1,81 @@
+/*
+ * 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.servicemix.kernel.gshell.admin.internal;
+
+import org.apache.servicemix.kernel.gshell.admin.AdminService;
+import org.apache.servicemix.kernel.gshell.admin.AdminServiceMBean;
+import org.apache.servicemix.kernel.gshell.admin.Instance;
+
+public class AdminServiceMBeanImpl implements AdminServiceMBean {
+
+    private AdminService adminService;
+
+    public AdminService getAdminService() {
+        return adminService;
+    }
+
+    public void setAdminService(AdminService adminService) {
+        this.adminService = adminService;
+    }
+
+    public void createInstance(String name, int port, String location) throws Exception {
+        adminService.createInstance(name, port, location);
+    }
+
+    public String[] getInstances() {
+        Instance[] instances = adminService.getInstances();
+        String[] names = new String[instances.length];
+        for (int i = 0; i < instances.length; i++) {
+            names[i] = instances[i].getName();
+        }
+        return names;
+    }
+
+    public int getPort(String name) throws Exception {
+        return getExistingInstance(name).getPort();
+    }
+
+    public void changePort(String name, int port) throws Exception {
+        getExistingInstance(name).changePort(port);
+    }
+
+    public String getState(String name) throws Exception {
+        return getExistingInstance(name).getState();
+    }
+
+    public void start(String name, String javaOpts) throws Exception {
+        getExistingInstance(name).start(javaOpts);
+    }
+
+    public void stop(String name) throws Exception {
+        getExistingInstance(name).stop();
+    }
+
+    public void destroy(String name) throws Exception {
+        getExistingInstance(name).destroy();
+    }
+
+
+    private Instance getExistingInstance(String name) {
+        Instance i = adminService.getInstance(name);
+        if (i == null) {
+            throw new IllegalArgumentException("Instance '" + name + "' does not exist");
+        }
+        return i;
+    }
+
+}
diff --git a/karaf/gshell/gshell-admin/src/main/java/org/apache/servicemix/kernel/gshell/admin/internal/InstanceImpl.java b/karaf/gshell/gshell-admin/src/main/java/org/apache/servicemix/kernel/gshell/admin/internal/InstanceImpl.java
new file mode 100644
index 0000000..3815ca5
--- /dev/null
+++ b/karaf/gshell/gshell-admin/src/main/java/org/apache/servicemix/kernel/gshell/admin/internal/InstanceImpl.java
@@ -0,0 +1,220 @@
+/*
+ * 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.servicemix.kernel.gshell.admin.internal;
+
+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.OutputStream;
+import java.net.Socket;
+import java.util.Properties;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.apache.servicemix.jpm.Process;
+import org.apache.servicemix.jpm.ProcessBuilderFactory;
+import org.apache.servicemix.jpm.impl.ScriptUtils;
+import org.apache.servicemix.kernel.gshell.admin.Instance;
+
+public class InstanceImpl implements Instance {
+
+    private static final Log LOG = LogFactory.getLog(InstanceImpl.class);
+
+    private AdminServiceImpl service;
+    private String name;
+    private String location;
+    private Process process;
+
+    public InstanceImpl(AdminServiceImpl service, String name, String location) {
+        this.service = service;
+        this.name = name;
+        this.location = location;
+    }
+
+    public void attach(int pid) throws IOException {
+        checkProcess();
+        if (this.process != null) {
+            throw new IllegalStateException("Instance already started");
+        }
+        this.process = ProcessBuilderFactory.newInstance().newBuilder().attach(pid);
+    }
+
+    public String getName() {
+        return this.name;
+    }
+
+    public String getLocation() {
+        return location;
+    }
+
+    public int getPid() {
+        checkProcess();
+        return this.process != null ? this.process.getPid() : 0;
+    }
+
+    public int getPort() throws Exception {
+        InputStream is = null;
+        try {
+            File f = new File(location, "etc/org.apache.servicemix.shell.cfg");
+            is = new FileInputStream(f);
+            Properties props = new Properties();
+            props.load(is);
+            String loc = props.getProperty("sshPort");
+            return Integer.parseInt(loc);
+        } finally {
+            if (is != null) {
+                is.close();
+            }
+        }
+    }
+
+    public void changePort(int port) throws Exception {
+        checkProcess();
+        if (this.process != null) {
+            throw new IllegalStateException("Instance not stopped");
+        }
+        Properties props = new Properties();
+        File f = new File(location, "etc/org.apache.servicemix.shell.cfg");
+        InputStream is = new FileInputStream(f);
+        try {
+            props.load(is);
+        } finally {
+            is.close();
+        }
+        props.setProperty("sshPort", Integer.toString(port));
+        OutputStream os = new FileOutputStream(f);
+        try {
+            props.store(os, null);
+        } finally {
+            os.close();
+        }
+    }
+
+    public synchronized void start(String javaOpts) throws Exception {
+        checkProcess();
+        if (this.process != null) {
+            throw new IllegalStateException("Instance already started");
+        }
+        if (javaOpts == null) {
+            javaOpts = "-server -Xmx512M -Dcom.sun.management.jmxremote";
+        }
+        File libDir = new File(System.getProperty("servicemix.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 command = new File(System.getProperty("java.home"), ScriptUtils.isWindows() ? "bin\\java.exe" : "bin/java").getCanonicalPath()
+                + " " + javaOpts
+                + " -Dservicemix.home=\"" + System.getProperty("servicemix.home") + "\""
+                + " -Dservicemix.base=\"" + new File(location).getCanonicalPath() + "\""
+                + " -Dservicemix.startLocalConsole=false"
+                + " -Dservicemix.startRemoteShell=true"
+                + " -classpath " + classpath.toString()
+                + " org.apache.servicemix.kernel.main.Main";
+        LOG.debug("Starting instance with command: " + command);
+        this.process = ProcessBuilderFactory.newInstance().newBuilder()
+                        .directory(new File(location))
+                        .command(command)
+                        .start();
+        this.service.saveState();
+    }
+
+    public synchronized void stop() throws Exception {
+        checkProcess();
+        if (this.process == null) {
+            throw new IllegalStateException("Instance not started");
+        }
+        this.process.destroy();
+    }
+
+    public synchronized void destroy() throws Exception {
+        checkProcess();
+        if (this.process != null) {
+            throw new IllegalStateException("Instance not stopped");
+        }
+        deleteFile(new File(location));
+        this.service.forget(name);
+        this.service.saveState();
+    }
+
+
+    public synchronized String getState() {
+        checkProcess();
+        if (this.process == null) {
+            return STOPPED;
+        } else {
+            try {
+                int port = getPort();
+                Socket s = new Socket("localhost", port);
+                s.close();
+                return STARTED;
+            } catch (Exception e) {
+                // ignore
+            }
+            return STARTING;
+        }
+    }
+
+    protected void checkProcess() {
+        if (this.process != null) {
+            try {
+                if (!this.process.isRunning()) {
+                    this.process = null;
+                }
+            } catch (IOException e) {
+            }
+        }
+    }
+
+    protected static 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();
+                    }
+                }
+            }
+        }
+        result &= fileToDelete.delete();
+        return result;
+    }
+}
diff --git a/karaf/gshell/gshell-admin/src/main/java/org/apache/servicemix/kernel/gshell/admin/internal/commands/AdminCommandSupport.java b/karaf/gshell/gshell-admin/src/main/java/org/apache/servicemix/kernel/gshell/admin/internal/commands/AdminCommandSupport.java
new file mode 100644
index 0000000..9da97b4
--- /dev/null
+++ b/karaf/gshell/gshell-admin/src/main/java/org/apache/servicemix/kernel/gshell/admin/internal/commands/AdminCommandSupport.java
@@ -0,0 +1,42 @@
+/*
+ * 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.servicemix.kernel.gshell.admin.internal.commands;
+
+import org.apache.servicemix.kernel.gshell.admin.AdminService;
+import org.apache.servicemix.kernel.gshell.admin.Instance;
+import org.apache.servicemix.kernel.gshell.core.OsgiCommandSupport;
+
+public abstract class AdminCommandSupport extends OsgiCommandSupport {
+
+    private AdminService adminService;
+
+    public AdminService getAdminService() {
+        return adminService;
+    }
+
+    public void setAdminService(AdminService adminService) {
+        this.adminService = adminService;
+    }
+
+    protected Instance getExistingInstance(String name) {
+        Instance i = adminService.getInstance(name);
+        if (i == null) {
+            throw new IllegalArgumentException("Instance '" + name + "' does not exist");
+        }
+        return i;
+    }
+}
diff --git a/karaf/gshell/gshell-admin/src/main/java/org/apache/servicemix/kernel/gshell/admin/internal/commands/ChangePortCommand.java b/karaf/gshell/gshell-admin/src/main/java/org/apache/servicemix/kernel/gshell/admin/internal/commands/ChangePortCommand.java
new file mode 100644
index 0000000..adbf2f6
--- /dev/null
+++ b/karaf/gshell/gshell-admin/src/main/java/org/apache/servicemix/kernel/gshell/admin/internal/commands/ChangePortCommand.java
@@ -0,0 +1,33 @@
+/*
+ * 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.servicemix.kernel.gshell.admin.internal.commands;
+
+import org.apache.geronimo.gshell.clp.Argument;
+
+public class ChangePortCommand extends AdminCommandSupport {
+
+    @Argument(index=0, required=true, description="The instance name")
+    private String instance = null;
+
+    @Argument(index=1, required=true, description="The new port")
+    private int port = 0;
+
+    protected Object doExecute() throws Exception {
+        getExistingInstance(instance).changePort(port);
+        return Result.SUCCESS;
+    }
+}
\ No newline at end of file
diff --git a/karaf/gshell/gshell-admin/src/main/java/org/apache/servicemix/kernel/gshell/admin/internal/commands/ConnectCommand.java b/karaf/gshell/gshell-admin/src/main/java/org/apache/servicemix/kernel/gshell/admin/internal/commands/ConnectCommand.java
new file mode 100644
index 0000000..244b9f8
--- /dev/null
+++ b/karaf/gshell/gshell-admin/src/main/java/org/apache/servicemix/kernel/gshell/admin/internal/commands/ConnectCommand.java
@@ -0,0 +1,41 @@
+/*
+ * 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.servicemix.kernel.gshell.admin.internal.commands;
+
+import org.apache.geronimo.gshell.clp.Argument;
+import org.apache.geronimo.gshell.clp.Option;
+import org.apache.geronimo.gshell.shell.ShellContextHolder;
+
+public class ConnectCommand extends AdminCommandSupport {
+
+    @Argument(index=0, required=true, description="The instance name")
+    private String instance = null;
+
+    @Option(name="-u", aliases={"--username"}, token="USERNAME", description="Remote user name")
+    private String username = "smx";
+
+    @Option(name="-p", aliases={"--password"}, token="PASSWORD", description="Remote user password")
+    private String password = "smx";
+
+    protected Object doExecute() throws Exception {
+        int port = getExistingInstance(instance).getPort();
+        ShellContextHolder.get().getShell().execute("ssh -l " + username + " -P " + password + " -p " + port + " localhost");
+        return Result.SUCCESS;
+    }
+}
diff --git a/karaf/gshell/gshell-admin/src/main/java/org/apache/servicemix/kernel/gshell/admin/internal/commands/CreateCommand.java b/karaf/gshell/gshell-admin/src/main/java/org/apache/servicemix/kernel/gshell/admin/internal/commands/CreateCommand.java
new file mode 100644
index 0000000..d13c381
--- /dev/null
+++ b/karaf/gshell/gshell-admin/src/main/java/org/apache/servicemix/kernel/gshell/admin/internal/commands/CreateCommand.java
@@ -0,0 +1,43 @@
+/*
+ * 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.servicemix.kernel.gshell.admin.internal.commands;
+
+import org.apache.geronimo.gshell.clp.Argument;
+import org.apache.geronimo.gshell.clp.Option;
+
+/**
+ * Creates a new servicemix instance 
+ *
+ * @version $Rev: 679826 $ $Date: 2008-07-25 17:00:12 +0200 (Fri, 25 Jul 2008) $
+ */
+public class CreateCommand extends AdminCommandSupport
+{
+    @Option(name = "-p", aliases = { "--port"}, description = "Port number for remote shell connection")
+    private int port = 0;
+
+    @Option(name = "-l", aliases = { "--location"}, description = "Location of the new instance on the file system")
+    private String location;
+
+    @Argument(index=0, required=true, description="Name of the new ServiceMix instance")
+    private String instance = null;
+
+    protected Object doExecute() throws Exception {
+        getAdminService().createInstance(instance, port, location);
+        return Result.SUCCESS;
+    }
+
+}
diff --git a/karaf/gshell/gshell-admin/src/main/java/org/apache/servicemix/kernel/gshell/admin/internal/commands/DestroyCommand.java b/karaf/gshell/gshell-admin/src/main/java/org/apache/servicemix/kernel/gshell/admin/internal/commands/DestroyCommand.java
new file mode 100644
index 0000000..6084caa
--- /dev/null
+++ b/karaf/gshell/gshell-admin/src/main/java/org/apache/servicemix/kernel/gshell/admin/internal/commands/DestroyCommand.java
@@ -0,0 +1,36 @@
+/*
+ * 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.servicemix.kernel.gshell.admin.internal.commands;
+
+import org.apache.geronimo.gshell.clp.Argument;
+
+/**
+ * Creates a new servicemix instance
+ *
+ * @version $Rev: 679826 $ $Date: 2008-07-25 17:00:12 +0200 (Fri, 25 Jul 2008) $
+ */
+public class DestroyCommand extends AdminCommandSupport
+{
+    @Argument(index=0, required=true, description="The name of the ServiceMix instance to destroy")
+    private String instance = null;
+
+    protected Object doExecute() throws Exception {
+        getExistingInstance(instance).destroy();
+        return Result.SUCCESS;
+    }
+
+}
diff --git a/karaf/gshell/gshell-admin/src/main/java/org/apache/servicemix/kernel/gshell/admin/internal/commands/ListCommand.java b/karaf/gshell/gshell-admin/src/main/java/org/apache/servicemix/kernel/gshell/admin/internal/commands/ListCommand.java
new file mode 100644
index 0000000..61f3afb
--- /dev/null
+++ b/karaf/gshell/gshell-admin/src/main/java/org/apache/servicemix/kernel/gshell/admin/internal/commands/ListCommand.java
@@ -0,0 +1,68 @@
+/*
+ * 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.servicemix.kernel.gshell.admin.internal.commands;
+
+import org.apache.geronimo.gshell.clp.Option;
+import org.apache.servicemix.kernel.gshell.admin.Instance;
+
+/**
+ * List available instances
+ */
+public class ListCommand extends AdminCommandSupport {
+
+    @Option(name = "-l", aliases = { "--location" }, description = "Display instances location")
+    boolean location;
+
+    protected Object doExecute() throws Exception {
+        Instance[] instances = getAdminService().getInstances();
+        if (location) {
+            io.out.println("  Port   State       Pid  Location");
+        } else {
+            io.out.println("  Port   State       Pid  Name");
+        }
+        for (Instance instance : instances) {
+            StringBuilder sb = new StringBuilder();
+            sb.append('[');
+            String s = Integer.toString(instance.getPort());
+            for (int i = s.length(); i < 5; i++) {
+                sb.append(' ');
+            }
+            sb.append(s);
+            sb.append("] [");
+            String state = instance.getState();
+            while (state.length() < "starting".length()) {
+                state += " ";
+            }
+            sb.append(state);
+            sb.append("] [");
+            s = Integer.toString(instance.getPid());
+            for (int i = s.length(); i < 5; i++) {
+                sb.append(' ');
+            }
+            sb.append(s);
+            sb.append("] ");
+            if (location) {
+                sb.append(instance.getLocation());
+            } else {
+                sb.append(instance.getName());
+            }
+            io.out.println(sb.toString());
+        }
+        return Result.SUCCESS;
+    }
+
+}
diff --git a/karaf/gshell/gshell-admin/src/main/java/org/apache/servicemix/kernel/gshell/admin/internal/commands/StartCommand.java b/karaf/gshell/gshell-admin/src/main/java/org/apache/servicemix/kernel/gshell/admin/internal/commands/StartCommand.java
new file mode 100644
index 0000000..77afa91
--- /dev/null
+++ b/karaf/gshell/gshell-admin/src/main/java/org/apache/servicemix/kernel/gshell/admin/internal/commands/StartCommand.java
@@ -0,0 +1,34 @@
+/*
+ * 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.servicemix.kernel.gshell.admin.internal.commands;
+
+import org.apache.geronimo.gshell.clp.Argument;
+import org.apache.geronimo.gshell.clp.Option;
+
+public class StartCommand extends AdminCommandSupport {
+
+    @Option(name = "-o", aliases = { "--java-opts"}, description = "Java options when launching the instance")
+    private String javaOpts;
+
+    @Argument(index=0, required=true, description="The instance name")
+    private String instance = null;
+
+    protected Object doExecute() throws Exception {
+        getExistingInstance(instance).start(javaOpts);
+        return Result.SUCCESS;
+    }
+}
diff --git a/karaf/gshell/gshell-admin/src/main/java/org/apache/servicemix/kernel/gshell/admin/internal/commands/StopCommand.java b/karaf/gshell/gshell-admin/src/main/java/org/apache/servicemix/kernel/gshell/admin/internal/commands/StopCommand.java
new file mode 100644
index 0000000..c449387
--- /dev/null
+++ b/karaf/gshell/gshell-admin/src/main/java/org/apache/servicemix/kernel/gshell/admin/internal/commands/StopCommand.java
@@ -0,0 +1,30 @@
+/*
+ * 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.servicemix.kernel.gshell.admin.internal.commands;
+
+import org.apache.geronimo.gshell.clp.Argument;
+
+public class StopCommand extends AdminCommandSupport {
+
+    @Argument(index=0, required=true, description="The instance name")
+    private String instance = null;
+
+    protected Object doExecute() throws Exception {
+        getExistingInstance(instance).stop();
+        return Result.SUCCESS;
+    }
+}
\ No newline at end of file
diff --git a/karaf/gshell/gshell-admin/src/main/java/org/apache/servicemix/kernel/gshell/admin/internal/completers/InstanceCompleter.java b/karaf/gshell/gshell-admin/src/main/java/org/apache/servicemix/kernel/gshell/admin/internal/completers/InstanceCompleter.java
new file mode 100644
index 0000000..cfcb95a
--- /dev/null
+++ b/karaf/gshell/gshell-admin/src/main/java/org/apache/servicemix/kernel/gshell/admin/internal/completers/InstanceCompleter.java
@@ -0,0 +1,46 @@
+/*
+ * 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.servicemix.kernel.gshell.admin.internal.completers;
+
+import java.util.List;
+
+import org.apache.servicemix.kernel.gshell.admin.AdminService;
+import org.apache.servicemix.kernel.gshell.admin.Instance;
+import org.apache.geronimo.gshell.console.completer.StringsCompleter;
+import jline.Completor;
+
+/**
+ * {@link jline.Completor} for server instance names.
+ *
+ * Displays a list of configured server instances for the Admin commands.
+ *
+ */
+public class InstanceCompleter implements Completor {
+    private AdminService adminService;
+
+    public void setAdminService(AdminService adminService) {
+        this.adminService = adminService;
+    }
+
+    public int complete(String buffer, int cursor, List candidates) {
+        StringsCompleter delegate = new StringsCompleter();
+        for (Instance instance : adminService.getInstances()) {
+            delegate.getStrings().add(instance.getName());
+        }
+        return delegate.complete(buffer, cursor, candidates);
+    }
+}
diff --git a/karaf/gshell/gshell-admin/src/main/resources/META-INF/spring/gshell-admin.xml b/karaf/gshell/gshell-admin/src/main/resources/META-INF/spring/gshell-admin.xml
new file mode 100644
index 0000000..5f05513
--- /dev/null
+++ b/karaf/gshell/gshell-admin/src/main/resources/META-INF/spring/gshell-admin.xml
@@ -0,0 +1,106 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+
+    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.
+
+-->
+<beans xmlns="http://www.springframework.org/schema/beans"
+       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+       xmlns:osgi="http://www.springframework.org/schema/osgi"
+       xmlns:osgix="http://www.springframework.org/schema/osgi-compendium"
+       xmlns:util="http://www.springframework.org/schema/util"
+       xmlns:gshell="http://servicemix.apache.org/schema/servicemix-gshell"
+       xsi:schemaLocation="
+  http://www.springframework.org/schema/beans
+  http://www.springframework.org/schema/beans/spring-beans.xsd
+  http://www.springframework.org/schema/osgi
+  http://www.springframework.org/schema/osgi/spring-osgi.xsd
+  http://www.springframework.org/schema/osgi-compendium
+  http://www.springframework.org/schema/osgi-compendium/spring-osgi-compendium.xsd
+  http://www.springframework.org/schema/util
+  http://www.springframework.org/schema/util/spring-util.xsd
+  http://servicemix.apache.org/schema/servicemix-gshell
+  http://servicemix.apache.org/schema/servicemix-gshell/servicemix-gshell.xsd">
+
+    <import resource="classpath:org/apache/servicemix/kernel/gshell/core/commands.xml" />
+
+    <bean id="adminCommandBundleSupport" scope="prototype">
+        <property name="adminService" ref="adminService" />
+    </bean>
+
+    <gshell:command-bundle>
+        <gshell:command name="admin/create">
+            <gshell:action class="org.apache.servicemix.kernel.gshell.admin.internal.commands.CreateCommand"
+                           parent="adminCommandBundleSupport" />
+        </gshell:command>
+        <gshell:command name="admin/connect">
+            <gshell:action class="org.apache.servicemix.kernel.gshell.admin.internal.commands.ConnectCommand"
+                           parent="adminCommandBundleSupport" />
+            <gshell:completers>
+                <ref bean="instanceCompleter" />
+                <null/>
+            </gshell:completers>
+        </gshell:command>
+        <gshell:command name="admin/list">
+            <gshell:action class="org.apache.servicemix.kernel.gshell.admin.internal.commands.ListCommand"
+                           parent="adminCommandBundleSupport" />
+        </gshell:command>
+        <gshell:command name="admin/start">
+            <gshell:action class="org.apache.servicemix.kernel.gshell.admin.internal.commands.StartCommand"
+                           parent="adminCommandBundleSupport" />
+            <gshell:completers>
+                <ref bean="instanceCompleter" />
+                <null/>
+            </gshell:completers>
+        </gshell:command>
+        <gshell:command name="admin/stop">
+            <gshell:action class="org.apache.servicemix.kernel.gshell.admin.internal.commands.StopCommand"
+                           parent="adminCommandBundleSupport" />
+            <gshell:completers>
+                <ref bean="instanceCompleter" />
+                <null/>
+            </gshell:completers>
+        </gshell:command>
+        <gshell:command name="admin/destroy">
+            <gshell:action class="org.apache.servicemix.kernel.gshell.admin.internal.commands.DestroyCommand"
+                           parent="adminCommandBundleSupport" />
+            <gshell:completers>
+                <ref bean="instanceCompleter" />
+                <null/>
+            </gshell:completers>
+        </gshell:command>
+        <gshell:command name="admin/change-port">
+            <gshell:action class="org.apache.servicemix.kernel.gshell.admin.internal.commands.ChangePortCommand"
+                           parent="adminCommandBundleSupport" />
+            <gshell:completers>
+                <ref bean="instanceCompleter" />
+                <null/>
+            </gshell:completers>
+        </gshell:command>
+    </gshell:command-bundle>
+
+    <osgi:reference id="preferences" interface="org.osgi.service.prefs.PreferencesService" cardinality="0..1" />
+
+    <bean id="adminService" class="org.apache.servicemix.kernel.gshell.admin.internal.AdminServiceImpl">
+        <property name="preferences" ref="preferences" />
+    </bean>
+
+    <bean id="instanceCompleter" class="org.apache.servicemix.kernel.gshell.admin.internal.completers.InstanceCompleter">
+        <property name="adminService" ref="adminService" />
+    </bean>
+
+
+</beans>
\ No newline at end of file
diff --git a/karaf/gshell/gshell-admin/src/main/resources/org/apache/servicemix/jpm/impl/unix/start.sh b/karaf/gshell/gshell-admin/src/main/resources/org/apache/servicemix/jpm/impl/unix/start.sh
new file mode 100644
index 0000000..1d1d720
--- /dev/null
+++ b/karaf/gshell/gshell-admin/src/main/resources/org/apache/servicemix/jpm/impl/unix/start.sh
@@ -0,0 +1,29 @@
+#!/bin/sh
+################################################################################
+#
+#    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.
+#
+################################################################################
+
+#exec 1>${out.file}
+#exec 2>${err.file}
+exec 1>/dev/null
+exec 2>/dev/null
+if [ "x${dir}" != "x" ]; then
+    cd ${dir}
+fi
+nohup ${command} &
+echo $! > ${pid.file}
diff --git a/karaf/gshell/gshell-admin/src/main/resources/org/apache/servicemix/jpm/impl/windows/destroy.vbs b/karaf/gshell/gshell-admin/src/main/resources/org/apache/servicemix/jpm/impl/windows/destroy.vbs
new file mode 100644
index 0000000..abd60eb
--- /dev/null
+++ b/karaf/gshell/gshell-admin/src/main/resources/org/apache/servicemix/jpm/impl/windows/destroy.vbs
@@ -0,0 +1,27 @@
+'===============================================================================
+'
+'    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.
+'
+'===============================================================================
+
+Set objWMIService = GetObject("winmgmts:\\.\root\cimv2")
+Set colProcessList = objWMIService.ExecQuery("Select * from Win32_Process Where ProcessId = ${pid}")
+intRetVal = 1
+For Each objProcess in colProcessList
+    objProcess.Terminate()
+    intRetVal = 0
+Next
+WScript.Quit(intRetVal)
diff --git a/karaf/gshell/gshell-admin/src/main/resources/org/apache/servicemix/jpm/impl/windows/running.vbs b/karaf/gshell/gshell-admin/src/main/resources/org/apache/servicemix/jpm/impl/windows/running.vbs
new file mode 100644
index 0000000..32c65c5
--- /dev/null
+++ b/karaf/gshell/gshell-admin/src/main/resources/org/apache/servicemix/jpm/impl/windows/running.vbs
@@ -0,0 +1,26 @@
+'===============================================================================
+'
+'    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.
+'
+'===============================================================================
+
+Set objWMIService = GetObject("winmgmts:\\.\root\cimv2")
+Set colProcessList = objWMIService.ExecQuery("Select * from Win32_Process Where ProcessId = ${pid}")
+intRetVal = 1
+For Each objProcess in colProcessList
+    intRetVal = 0
+Next
+WScript.Quit(intRetVal)
diff --git a/karaf/gshell/gshell-admin/src/main/resources/org/apache/servicemix/jpm/impl/windows/start.vbs b/karaf/gshell/gshell-admin/src/main/resources/org/apache/servicemix/jpm/impl/windows/start.vbs
new file mode 100644
index 0000000..6004c86
--- /dev/null
+++ b/karaf/gshell/gshell-admin/src/main/resources/org/apache/servicemix/jpm/impl/windows/start.vbs
@@ -0,0 +1,34 @@
+'===============================================================================
+'
+'    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.
+'
+'===============================================================================
+
+Set objWMIService = GetObject("winmgmts:\\.\root\cimv2")
+Set objConfig = objWMIService.Get("Win32_ProcessStartup").SpawnInstance_
+objConfig.ShowWindow = SW_HIDE
+objConfig.CreateFlags = 8
+If Len("${dir}") > 0 Then
+    intReturn = objWMIService.Get("Win32_Process").Create("${command}", "${dir}", objConfig, intProcessID)
+Else
+    intReturn = objWMIService.Get("Win32_Process").Create("${command}", Null, objConfig, intProcessID)
+End If
+If intReturn = 0 Then
+    Set objOutputFile = CreateObject("Scripting.fileSystemObject").CreateTextFile("${pid.file}", TRUE)
+    objOutputFile.WriteLine(intProcessID)
+    objOutputFile.Close
+End If
+WScript.Quit(intReturn)
diff --git a/karaf/gshell/gshell-admin/src/main/resources/org/apache/servicemix/kernel/gshell/admin/bin/servicemix b/karaf/gshell/gshell-admin/src/main/resources/org/apache/servicemix/kernel/gshell/admin/bin/servicemix
new file mode 100644
index 0000000..20a33e6
--- /dev/null
+++ b/karaf/gshell/gshell-admin/src/main/resources/org/apache/servicemix/kernel/gshell/admin/bin/servicemix
@@ -0,0 +1,25 @@
+#!/bin/sh
+################################################################################
+#
+#    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.
+#
+################################################################################
+
+SERVICEMIX_HOME=${servicemix.home}
+SERVICEMIX_BASE=${servicemix.base}
+
+export SERVICEMIX_BASE
+${SERVICEMIX_HOME}/bin/servicemix "$*"
\ No newline at end of file
diff --git a/karaf/gshell/gshell-admin/src/main/resources/org/apache/servicemix/kernel/gshell/admin/bin/servicemix.bat b/karaf/gshell/gshell-admin/src/main/resources/org/apache/servicemix/kernel/gshell/admin/bin/servicemix.bat
new file mode 100644
index 0000000..13c155a
--- /dev/null
+++ b/karaf/gshell/gshell-admin/src/main/resources/org/apache/servicemix/kernel/gshell/admin/bin/servicemix.bat
@@ -0,0 +1,25 @@
+@ECHO OFF
+REM =========================================================================
+REM 
+REM Licensed to the Apache Software Foundation (ASF) under one or more
+REM contributor license agreements.  See the NOTICE file distributed with
+REM this work for additional information regarding copyright ownership.
+REM The ASF licenses this file to You under the Apache License, Version 2.0
+REM (the "License"); you may not use this file except in compliance with
+REM the License.  You may obtain a copy of the License at
+REM 
+REM    http://www.apache.org/licenses/LICENSE-2.0
+REM 
+REM Unless required by applicable law or agreed to in writing, software
+REM distributed under the License is distributed on an "AS IS" BASIS,
+REM WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+REM See the License for the specific language governing permissions and
+REM limitations under the License.
+REM 
+REM =========================================================================
+
+SET SERVICEMIX_BASE=${servicemix.base}
+SETLOCAL
+SET SERVICEMIX_HOME=${servicemix.home}
+
+%SERVICEMIX_HOME%\bin\servicemix.bat %*
diff --git a/karaf/gshell/gshell-admin/src/main/resources/org/apache/servicemix/kernel/gshell/admin/etc/org.apache.servicemix.shell.cfg b/karaf/gshell/gshell-admin/src/main/resources/org/apache/servicemix/kernel/gshell/admin/etc/org.apache.servicemix.shell.cfg
new file mode 100644
index 0000000..e6a8fd2
--- /dev/null
+++ b/karaf/gshell/gshell-admin/src/main/resources/org/apache/servicemix/kernel/gshell/admin/etc/org.apache.servicemix.shell.cfg
@@ -0,0 +1,23 @@
+################################################################################
+#
+#    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.
+#
+################################################################################
+
+#
+startLocalConsole=${servicemix.startLocalConsole}
+startRemoteShell=${servicemix.startRemoteShell}
+sshPort=${servicemix.sshPort}
diff --git a/karaf/gshell/gshell-admin/src/main/resources/org/apache/servicemix/kernel/gshell/admin/etc/org.ops4j.pax.logging.cfg b/karaf/gshell/gshell-admin/src/main/resources/org/apache/servicemix/kernel/gshell/admin/etc/org.ops4j.pax.logging.cfg
new file mode 100644
index 0000000..24ddea5
--- /dev/null
+++ b/karaf/gshell/gshell-admin/src/main/resources/org/apache/servicemix/kernel/gshell/admin/etc/org.ops4j.pax.logging.cfg
@@ -0,0 +1,36 @@
+################################################################################
+#
+#    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.
+#
+################################################################################
+
+# Root logger
+log4j.rootLogger=INFO, out, osgi:VmLogAppender
+
+# Logger infos
+log4j.logger.org.apache.geronimo.gshell.remote=WARN
+
+# CONSOLE appender not used by default
+log4j.appender.stdout=org.apache.log4j.ConsoleAppender
+log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
+log4j.appender.stdout.layout.ConversionPattern=%d{ABSOLUTE} | %-5.5p | %-16.16t | %-32.32c{1} | %-32.32C %4L | %m%n
+
+# File appender
+log4j.appender.out=org.apache.log4j.FileAppender
+log4j.appender.out.layout=org.apache.log4j.PatternLayout
+log4j.appender.out.layout.ConversionPattern=%d{ABSOLUTE} | %-5.5p | %-16.16t | %-32.32c{1} | %-32.32C %4L | %m%n
+log4j.appender.out.file=${servicemix.base}/data/log/servicemix.log
+log4j.appender.out.append=true
diff --git a/karaf/gshell/gshell-admin/src/main/resources/org/apache/servicemix/kernel/gshell/admin/etc/org.ops4j.pax.url.mvn.cfg b/karaf/gshell/gshell-admin/src/main/resources/org/apache/servicemix/kernel/gshell/admin/etc/org.ops4j.pax.url.mvn.cfg
new file mode 100644
index 0000000..d0317cd
--- /dev/null
+++ b/karaf/gshell/gshell-admin/src/main/resources/org/apache/servicemix/kernel/gshell/admin/etc/org.ops4j.pax.url.mvn.cfg
@@ -0,0 +1,73 @@
+################################################################################
+#
+#    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.
+#
+################################################################################
+
+#
+# If set to true, the following property will not allow any certificate to be used
+# when accessing maven repositories through SSL
+#
+#org.ops4j.pax.url.mvn.certificateCheck=
+
+#
+# Path to the local maven settings file.
+# The repositories defined in this file will be automatically added to the list
+# of default repositories if the 'org.ops4j.pax.url.mvn.repositories' property
+# below is not set.
+# The following locations are checked for the existence of the settings.xml file
+#   * 1. looks for the specified url
+#   * 2. if not found looks for ${user.home}/.m2/settings.xml
+#   * 3. if not found looks for ${maven.home}/conf/settings.xml
+#   * 4. if not found looks for ${M2_HOME}/conf/settings.xml
+#
+#org.ops4j.pax.url.mvn.settings=
+
+#
+# Path to the local maven repository which is used to avoid downloading
+# artifacts when they already exist locally.
+# The value of this property will be extracted from the settings.xml file
+# above, or defaulted to:
+#     System.getProperty( "user.home" ) + "/.m2/repository"
+#
+#org.ops4j.pax.url.mvn.localRepository=
+
+#
+# Comma separated list of repositories scanned when resolving an artifact.
+# Those repositories will be checked before iterating through the
+     below list of repositories and even before the local repository
+# A repository url can be appended with zero or more of the following flags:
+#    @snapshots  : the repository contains snaphots
+#    @noreleases : the repository does not contain any released artifacts
+#
+# The following property value will add the system folder as a repo.
+#
+org.ops4j.pax.url.mvn.defaultRepositories=file:${servicemix.home}/system@snapshots,file:${servicemix.base}/system@snapshots
+
+#
+# Comma separated list of repositories scanned when resolving an artifact.
+# The default list includes the following repositories:
+#    http://repo1.maven.org/maven2
+#    http://repository.ops4j.org/maven2
+# To add repositories to the default ones, prepend '+' to the list of repositories
+# to add.
+# A repository url can be appended with zero or more of the following flags:
+#    @snapshots  : the repository contains snaphots
+#    @noreleases : the repository does not contain any released artifacts
+#
+# The following property value will add the system folders as a repo.
+#
+org.ops4j.pax.url.mvn.repositories=file:${servicemix.base}/system@snapshots,file:${user.home}/.m2/repository@snapshots,http://repo1.maven.org/maven2,http://people.apache.org/repo/m2-snapshot-repository@snapshots@noreleases,http://svn.apache.org/repos/asf/servicemix/m2-repo
diff --git a/karaf/gshell/gshell-admin/src/main/resources/org/apache/servicemix/kernel/gshell/admin/etc/system.properties b/karaf/gshell/gshell-admin/src/main/resources/org/apache/servicemix/kernel/gshell/admin/etc/system.properties
new file mode 100644
index 0000000..255295e
--- /dev/null
+++ b/karaf/gshell/gshell-admin/src/main/resources/org/apache/servicemix/kernel/gshell/admin/etc/system.properties
@@ -0,0 +1,21 @@
+################################################################################
+#
+#    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.
+#
+################################################################################
+
+org.ops4j.pax.logging.DefaultServiceLog.level=ERROR
+servicemix.name=${servicemix.name}
\ No newline at end of file
diff --git a/karaf/gshell/gshell-admin/src/main/resources/org/apache/servicemix/kernel/gshell/admin/etc/users.properties b/karaf/gshell/gshell-admin/src/main/resources/org/apache/servicemix/kernel/gshell/admin/etc/users.properties
new file mode 100644
index 0000000..0348fae
--- /dev/null
+++ b/karaf/gshell/gshell-admin/src/main/resources/org/apache/servicemix/kernel/gshell/admin/etc/users.properties
@@ -0,0 +1,21 @@
+################################################################################
+#
+#    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.
+#
+################################################################################
+
+#
+smx=smx,admin
diff --git a/karaf/gshell/gshell-admin/src/main/resources/org/apache/servicemix/kernel/gshell/admin/internal/commands/ChangePortCommand.properties b/karaf/gshell/gshell-admin/src/main/resources/org/apache/servicemix/kernel/gshell/admin/internal/commands/ChangePortCommand.properties
new file mode 100644
index 0000000..6a7edbf
--- /dev/null
+++ b/karaf/gshell/gshell-admin/src/main/resources/org/apache/servicemix/kernel/gshell/admin/internal/commands/ChangePortCommand.properties
@@ -0,0 +1,27 @@
+##
+## 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.
+##
+
+##
+## $Rev: 703511 $ $Date: 2008-10-10 18:07:36 +0200 (Fri, 10 Oct 2008) $
+##
+
+command.description=Change the port of an existing instance.
+
+command.manual=\
+  TODO: date manual
\ No newline at end of file
diff --git a/karaf/gshell/gshell-admin/src/main/resources/org/apache/servicemix/kernel/gshell/admin/internal/commands/ConnectCommand.properties b/karaf/gshell/gshell-admin/src/main/resources/org/apache/servicemix/kernel/gshell/admin/internal/commands/ConnectCommand.properties
new file mode 100644
index 0000000..1c78a34
--- /dev/null
+++ b/karaf/gshell/gshell-admin/src/main/resources/org/apache/servicemix/kernel/gshell/admin/internal/commands/ConnectCommand.properties
@@ -0,0 +1,27 @@
+##
+## 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.
+##
+
+##
+## $Rev: 703511 $ $Date: 2008-10-10 18:07:36 +0200 (Fri, 10 Oct 2008) $
+##
+
+command.description=Connect to an existing instance.
+
+command.manual=\
+  TODO: date manual
\ No newline at end of file
diff --git a/karaf/gshell/gshell-admin/src/main/resources/org/apache/servicemix/kernel/gshell/admin/internal/commands/CreateCommand.properties b/karaf/gshell/gshell-admin/src/main/resources/org/apache/servicemix/kernel/gshell/admin/internal/commands/CreateCommand.properties
new file mode 100644
index 0000000..532ada2
--- /dev/null
+++ b/karaf/gshell/gshell-admin/src/main/resources/org/apache/servicemix/kernel/gshell/admin/internal/commands/CreateCommand.properties
@@ -0,0 +1,27 @@
+##
+## 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.
+##
+
+##
+## $Rev: 703511 $ $Date: 2008-10-10 18:07:36 +0200 (Fri, 10 Oct 2008) $
+##
+
+command.description=Create a new instance.
+
+command.manual=\
+  TODO: date manual
\ No newline at end of file
diff --git a/karaf/gshell/gshell-admin/src/main/resources/org/apache/servicemix/kernel/gshell/admin/internal/commands/DestroyCommand.properties b/karaf/gshell/gshell-admin/src/main/resources/org/apache/servicemix/kernel/gshell/admin/internal/commands/DestroyCommand.properties
new file mode 100644
index 0000000..cb0581c
--- /dev/null
+++ b/karaf/gshell/gshell-admin/src/main/resources/org/apache/servicemix/kernel/gshell/admin/internal/commands/DestroyCommand.properties
@@ -0,0 +1,27 @@
+##
+## 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.
+##
+
+##
+## $Rev: 703511 $ $Date: 2008-10-10 18:07:36 +0200 (Fri, 10 Oct 2008) $
+##
+
+command.description=Destroy an existing instance.
+
+command.manual=\
+  TODO: date manual
\ No newline at end of file
diff --git a/karaf/gshell/gshell-admin/src/main/resources/org/apache/servicemix/kernel/gshell/admin/internal/commands/ListCommand.properties b/karaf/gshell/gshell-admin/src/main/resources/org/apache/servicemix/kernel/gshell/admin/internal/commands/ListCommand.properties
new file mode 100644
index 0000000..c473471
--- /dev/null
+++ b/karaf/gshell/gshell-admin/src/main/resources/org/apache/servicemix/kernel/gshell/admin/internal/commands/ListCommand.properties
@@ -0,0 +1,27 @@
+##
+## 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.
+##
+
+##
+## $Rev: 703511 $ $Date: 2008-10-10 18:07:36 +0200 (Fri, 10 Oct 2008) $
+##
+
+command.description=List existing instances.
+
+command.manual=\
+  TODO: date manual
\ No newline at end of file
diff --git a/karaf/gshell/gshell-admin/src/main/resources/org/apache/servicemix/kernel/gshell/admin/internal/commands/StartCommand.properties b/karaf/gshell/gshell-admin/src/main/resources/org/apache/servicemix/kernel/gshell/admin/internal/commands/StartCommand.properties
new file mode 100644
index 0000000..dfb4046
--- /dev/null
+++ b/karaf/gshell/gshell-admin/src/main/resources/org/apache/servicemix/kernel/gshell/admin/internal/commands/StartCommand.properties
@@ -0,0 +1,27 @@
+##
+## 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.
+##
+
+##
+## $Rev: 703511 $ $Date: 2008-10-10 18:07:36 +0200 (Fri, 10 Oct 2008) $
+##
+
+command.description=Start an existing instance.
+
+command.manual=\
+  TODO: date manual
\ No newline at end of file
diff --git a/karaf/gshell/gshell-admin/src/main/resources/org/apache/servicemix/kernel/gshell/admin/internal/commands/StopCommand.properties b/karaf/gshell/gshell-admin/src/main/resources/org/apache/servicemix/kernel/gshell/admin/internal/commands/StopCommand.properties
new file mode 100644
index 0000000..0cd3acd
--- /dev/null
+++ b/karaf/gshell/gshell-admin/src/main/resources/org/apache/servicemix/kernel/gshell/admin/internal/commands/StopCommand.properties
@@ -0,0 +1,27 @@
+##
+## 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.
+##
+
+##
+## $Rev: 703511 $ $Date: 2008-10-10 18:07:36 +0200 (Fri, 10 Oct 2008) $
+##
+
+command.description=Stop an existing instance.
+
+command.manual=\
+  TODO: date manual
\ No newline at end of file
diff --git a/karaf/gshell/gshell-admin/src/test/java/org/apache/servicemix/jpm/MainTest.java b/karaf/gshell/gshell-admin/src/test/java/org/apache/servicemix/jpm/MainTest.java
new file mode 100644
index 0000000..1833584
--- /dev/null
+++ b/karaf/gshell/gshell-admin/src/test/java/org/apache/servicemix/jpm/MainTest.java
@@ -0,0 +1,24 @@
+/*
+ * 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.servicemix.jpm;
+
+public class MainTest {
+
+    public static void main(String[] args) throws Exception {
+        Thread.sleep(Long.parseLong(args[0]));
+    }
+}
diff --git a/karaf/gshell/gshell-admin/src/test/java/org/apache/servicemix/jpm/ProcessTest.java b/karaf/gshell/gshell-admin/src/test/java/org/apache/servicemix/jpm/ProcessTest.java
new file mode 100644
index 0000000..8328813
--- /dev/null
+++ b/karaf/gshell/gshell-admin/src/test/java/org/apache/servicemix/jpm/ProcessTest.java
@@ -0,0 +1,67 @@
+/*
+ * 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.servicemix.jpm;
+
+import java.io.File;
+
+import junit.framework.TestCase;
+import org.apache.servicemix.jpm.impl.ScriptUtils;
+
+public class ProcessTest extends TestCase {
+
+    public void testCreate() throws Exception {
+        String javaPath = new File(System.getProperty("java.home"), ScriptUtils.isWindows() ? "bin\\java.exe" : "bin/java").getCanonicalPath();
+        System.err.println(javaPath);
+        StringBuilder command = new StringBuilder();
+        command.append(javaPath);
+        command.append(" -Dprop=\"key\"");
+        command.append(" -classpath ");
+        String clRes = getClass().getName().replace('.', '/') + ".class";
+        String str = getClass().getClassLoader().getResource(clRes).toString();
+        str = str.substring("file:".length(), str.indexOf(clRes));
+        command.append(str);
+        command.append(" ");
+        command.append(MainTest.class.getName());
+        command.append(" ");
+        command.append(60000);
+        System.err.println("Executing: " + command.toString());
+
+        ProcessBuilder builder = ProcessBuilderFactory.newInstance().newBuilder();
+        Process p = builder.command(command.toString()).start();
+        assertNotNull(p);
+        System.err.println("Process: " + p.getPid());
+        assertNotNull(p.getPid());
+        Thread.currentThread().sleep(1000);
+        System.err.println("Running: " + p.isRunning());
+        assertTrue(p.isRunning());
+        System.err.println("Destroying");
+        p.destroy();
+        Thread.currentThread().sleep(1000);
+        System.err.println("Running: " + p.isRunning());
+        assertFalse(p.isRunning());
+    }
+
+    /*
+     * When the process creation fails, no error is reported by the script
+     * 
+    public void testFailure() throws Exception {
+        ProcessBuilder builder = ProcessBuilderFactory.newInstance().newBuilder();
+        Process p = builder.command("ec").start();
+        fail("An exception should have been thrown");
+    }
+    */
+}