You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@karaf.apache.org by gn...@apache.org on 2014/04/10 16:15:49 UTC

[27/59] [abbrv] [KARAF-2852] Merge instance/core and instance/command

http://git-wip-us.apache.org/repos/asf/karaf/blob/7c2db062/instance/core/src/test/java/org/apache/karaf/instance/core/management/internal/InstanceToTableMapperTest.java
----------------------------------------------------------------------
diff --git a/instance/core/src/test/java/org/apache/karaf/instance/core/management/internal/InstanceToTableMapperTest.java b/instance/core/src/test/java/org/apache/karaf/instance/core/management/internal/InstanceToTableMapperTest.java
deleted file mode 100644
index c9541d3..0000000
--- a/instance/core/src/test/java/org/apache/karaf/instance/core/management/internal/InstanceToTableMapperTest.java
+++ /dev/null
@@ -1,90 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.karaf.instance.core.management.internal;
-
-import java.util.Collection;
-import java.util.Collections;
-
-import javax.management.openmbean.CompositeData;
-import javax.management.openmbean.TabularData;
-
-import junit.framework.TestCase;
-
-import org.apache.karaf.instance.core.Instance;
-import org.apache.karaf.instance.core.internal.InstanceToTableMapper;
-import org.easymock.EasyMock;
-import org.junit.Assert;
-
-public class InstanceToTableMapperTest extends TestCase {
-    public void testJMXInstance() throws Exception {
-        Instance instance = EasyMock.createMock(Instance.class);
-        EasyMock.expect(instance.getPid()).andReturn(1712);
-        EasyMock.expect(instance.getName()).andReturn("MyInstance");
-        EasyMock.expect(instance.isRoot()).andReturn(false);
-        EasyMock.expect(instance.getSshPort()).andReturn(0);
-        EasyMock.expect(instance.getRmiRegistryPort()).andReturn(0);
-        EasyMock.expect(instance.getRmiServerPort()).andReturn(0);
-        EasyMock.expect(instance.getState()).andThrow(new Exception("gotcha"));
-        EasyMock.expect(instance.getLocation()).andReturn("somewhere");
-        EasyMock.expect(instance.getJavaOpts()).andReturn("someopts");
-        EasyMock.replay(instance);
-        
-        TabularData td = InstanceToTableMapper.tableFrom(Collections.singletonList(instance));
-        Collection<?> keys = (Collection<?>) td.keySet().iterator().next();
-        Assert.assertEquals("MyInstance", keys.iterator().next());
-        
-        CompositeData cd = td.get(keys.toArray());
-        Assert.assertEquals(1712, cd.get("Pid"));
-        Assert.assertEquals("MyInstance", cd.get("Name"));
-        Assert.assertEquals(false, cd.get("Is Root"));
-        Assert.assertEquals(0, cd.get("SSH Port"));
-        Assert.assertEquals(0, cd.get("RMI Registry Port"));
-        Assert.assertEquals(0, cd.get("RMI Server Port"));
-        Assert.assertEquals("Error", cd.get("State"));
-        Assert.assertEquals("somewhere", cd.get("Location"));
-        Assert.assertEquals("someopts", cd.get("JavaOpts"));
-    }
-
-    public void testJMXInstance2() throws Exception {
-        Instance instance = EasyMock.createMock(Instance.class);
-        EasyMock.expect(instance.getPid()).andReturn(1712);
-        EasyMock.expect(instance.getName()).andReturn("MyInstance");
-        EasyMock.expect(instance.isRoot()).andReturn(true);
-        EasyMock.expect(instance.getSshPort()).andReturn(0);
-        EasyMock.expect(instance.getRmiRegistryPort()).andReturn(0);
-        EasyMock.expect(instance.getRmiServerPort()).andReturn(0);
-        EasyMock.expect(instance.getState()).andReturn("Started");
-        EasyMock.expect(instance.getLocation()).andReturn(null);
-        EasyMock.expect(instance.getJavaOpts()).andReturn(null);
-        EasyMock.replay(instance);
-        
-        TabularData td = InstanceToTableMapper.tableFrom(Collections.singletonList(instance));        
-        Collection<?> keys = (Collection<?>) td.keySet().iterator().next();
-        Assert.assertEquals("MyInstance", keys.iterator().next());
-        
-        CompositeData cd = td.get(keys.toArray());
-        Assert.assertEquals(1712, cd.get("Pid"));
-        Assert.assertEquals("MyInstance", cd.get("Name"));
-        Assert.assertEquals(true, cd.get("Is Root"));
-        Assert.assertEquals(0, cd.get("SSH Port"));
-        Assert.assertEquals(0, cd.get("RMI Registry Port"));
-        Assert.assertEquals(0, cd.get("RMI Server Port"));
-        Assert.assertEquals("Started", cd.get("State"));
-        Assert.assertNull(cd.get("Location"));
-        Assert.assertNull(cd.get("JavaOpts"));
-    }
-}

http://git-wip-us.apache.org/repos/asf/karaf/blob/7c2db062/instance/core/src/test/java/org/apache/karaf/jpm/MainTest.java
----------------------------------------------------------------------
diff --git a/instance/core/src/test/java/org/apache/karaf/jpm/MainTest.java b/instance/core/src/test/java/org/apache/karaf/jpm/MainTest.java
deleted file mode 100644
index e7f7c83..0000000
--- a/instance/core/src/test/java/org/apache/karaf/jpm/MainTest.java
+++ /dev/null
@@ -1,24 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.karaf.jpm;
-
-public class MainTest {
-
-    public static void main(String[] args) throws Exception {
-        Thread.sleep(Long.parseLong(args[0]));
-    }
-}

http://git-wip-us.apache.org/repos/asf/karaf/blob/7c2db062/instance/core/src/test/java/org/apache/karaf/jpm/ProcessTest.java
----------------------------------------------------------------------
diff --git a/instance/core/src/test/java/org/apache/karaf/jpm/ProcessTest.java b/instance/core/src/test/java/org/apache/karaf/jpm/ProcessTest.java
deleted file mode 100644
index 9cdc5ad..0000000
--- a/instance/core/src/test/java/org/apache/karaf/jpm/ProcessTest.java
+++ /dev/null
@@ -1,69 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.karaf.jpm;
-
-import java.io.File;
-
-import junit.framework.TestCase;
-
-import org.apache.karaf.jpm.impl.ProcessBuilderFactoryImpl;
-import org.apache.karaf.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("\"").append(javaPath).append("\"");
-        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 = new ProcessBuilderFactoryImpl().newBuilder();
-        org.apache.karaf.jpm.Process p = builder.command(command.toString()).start();
-        assertNotNull(p);
-        System.err.println("Process: " + p.getPid());
-        assertNotNull(p.getPid());
-        Thread.sleep(1000);
-        System.err.println("Running: " + p.isRunning());
-        assertTrue(p.isRunning());
-        System.err.println("Destroying");
-        p.destroy();
-        Thread.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");
-    }
-    */
-}

http://git-wip-us.apache.org/repos/asf/karaf/blob/7c2db062/instance/core/src/test/resources/etc/startup.properties
----------------------------------------------------------------------
diff --git a/instance/core/src/test/resources/etc/startup.properties b/instance/core/src/test/resources/etc/startup.properties
deleted file mode 100644
index df7c9bc..0000000
--- a/instance/core/src/test/resources/etc/startup.properties
+++ /dev/null
@@ -1,20 +0,0 @@
-################################################################################
-#
-#    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.
-#
-################################################################################
-
-# Fake startup.properties for unit tests as the startup properties in generated by the karaf-maven-plugin
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/karaf/blob/7c2db062/instance/pom.xml
----------------------------------------------------------------------
diff --git a/instance/pom.xml b/instance/pom.xml
index c6c1930..baeb2f9 100644
--- a/instance/pom.xml
+++ b/instance/pom.xml
@@ -10,7 +10,7 @@
         (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
+            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,
@@ -29,13 +29,172 @@
     </parent>
 
     <groupId>org.apache.karaf.instance</groupId>
-    <artifactId>instance</artifactId>
-    <packaging>pom</packaging>
-    <name>Apache Karaf :: Instance</name>
+    <artifactId>org.apache.karaf.instance.core</artifactId>
+    <packaging>bundle</packaging>
+    <name>Apache Karaf :: Instance :: Core</name>
+    <description>Core implementation of the instance feature to manipulate Karaf child instances.</description>
 
-    <modules>
-        <module>core</module>
-        <module>command</module>
-    </modules>
+    <properties>
+        <appendedResourcesDirectory>${project.basedir}/../../etc/appended-resources</appendedResourcesDirectory>
+    </properties>
 
+    <dependencies>
+
+        <dependency>
+            <groupId>org.osgi</groupId>
+            <artifactId>org.osgi.core</artifactId>
+            <scope>provided</scope>
+        </dependency>
+
+        <dependency>
+            <groupId>org.slf4j</groupId>
+            <artifactId>slf4j-api</artifactId>
+            <scope>provided</scope>
+        </dependency>
+
+        <dependency>
+            <groupId>org.apache.felix</groupId>
+            <artifactId>org.apache.felix.utils</artifactId>
+            <scope>provided</scope>
+        </dependency>
+
+        <dependency>
+            <groupId>org.apache.karaf.shell</groupId>
+            <artifactId>org.apache.karaf.shell.core</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>org.apache.karaf</groupId>
+            <artifactId>org.apache.karaf.util</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>org.apache.karaf.features</groupId>
+            <artifactId>org.apache.karaf.features.core</artifactId>
+            <optional>true</optional>
+        </dependency>
+
+        <dependency>
+            <groupId>org.slf4j</groupId>
+            <artifactId>slf4j-jdk14</artifactId>
+            <scope>test</scope>
+        </dependency>
+    </dependencies>
+
+    <build>
+        <resources>
+            <resource>
+                <directory>${project.basedir}/src/main/resources</directory>
+                <includes>
+                    <include>**/*</include>
+                </includes>
+            </resource>
+            <resource>
+                <directory>${project.basedir}/src/main/resources</directory>
+                <filtering>true</filtering>
+                <includes>
+                    <include>**/*.info</include>
+                </includes>
+            </resource>
+            <resource>
+                <directory>${project.build.directory}/generated-resources</directory>
+                <includes>
+                    <include>**/*.*</include>
+                </includes>
+            </resource>
+        </resources>
+        <plugins>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-resources-plugin</artifactId>
+                <executions>
+                    <execution>
+                        <id>copy-resources</id>
+                        <phase>generate-resources</phase>
+                        <goals>
+                            <goal>copy-resources</goal>
+                        </goals>
+                        <configuration>
+                            <outputDirectory>${project.build.directory}/generated-resources/org/apache/karaf/instance/</outputDirectory>
+                            <resources>
+                                <resource>
+                                    <directory>${project.basedir}/../assemblies/features/framework/src/main/resources</directory>
+                                    <excludes>
+                                        <exclude>**/org.apache.karaf.management.cfg</exclude>
+                                        <exclude>**/org.apache.karaf.shell.cfg</exclude>
+                                        <exclude>**/system.properties</exclude>
+                                    </excludes>
+                                </resource>
+                                <resource>
+                                    <directory>${project.basedir}/../assemblies/features/framework/src/main/filtered-resources</directory>
+                                    <filtering>true</filtering>
+                                    <includes>
+                                        <include>**/*.properties</include>
+                                        <include>**/*.cfg</include>
+                                        <include>**/*.xml</include>
+                                        <include>**/*.info</include>
+                                    </includes>
+                                </resource>
+                                <resource>
+                                	<directory>${project.basedir}/../assemblies/features/framework/src/main/snapshot</directory>
+                                	<filtering>true</filtering>
+                                    <includes>
+                                        <include>**/*.cfg</include>
+                                    </includes>
+                                </resource>
+                            </resources>
+                        </configuration>
+                    </execution>
+                </executions>
+            </plugin>
+            <plugin>
+                <groupId>org.apache.felix</groupId>
+                <artifactId>maven-bundle-plugin</artifactId>
+                <configuration>
+                    <instructions>
+                        <Export-Package>
+                            org.apache.karaf.instance.core
+                        </Export-Package>
+                        <!-- We have to avoid importing instance.core.internal and jansi
+                             as Execute.java accesses the InstanceServiceImpl and jansi
+                             (but only outside OSGi) -->
+                        <Import-Package>
+                            !org.apache.karaf.shell.impl.action.command,
+                            !org.apache.karaf.instance.core.internal,
+                            *
+                        </Import-Package>
+                        <Provide-Capability>
+                            service-reference;effective:=active;objectClass=org.apache.karaf.instance.core.InstanceService
+                        </Provide-Capability>
+                        <Private-Package>
+                            org.apache.karaf.jpm,
+                            org.apache.karaf.jpm.impl,
+                            org.apache.karaf.instance.main,
+                            org.apache.karaf.instance.command,
+                            org.apache.karaf.instance.command.completers,
+                            org.apache.karaf.instance.core.internal,
+                            org.apache.karaf.instance.core.internal.osgi,
+                            org.apache.felix.utils.properties;-split-package:=merge-first,
+                            org.apache.karaf.util.locks,
+                            org.apache.karaf.util.tracker
+                        </Private-Package>
+                        <Bundle-Activator>
+                            org.apache.karaf.instance.core.internal.osgi.Activator
+                        </Bundle-Activator>
+                        <Karaf-Commands>org.apache.karaf.instance.command.*</Karaf-Commands>
+                    </instructions>
+                </configuration>
+            </plugin>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-surefire-plugin</artifactId>
+                <configuration>
+                  <excludes>
+                    <!-- this is not a unit test but an application used for testing -->
+                    <exclude>**/MainTest.java</exclude>
+                  </excludes>
+                </configuration>
+           </plugin>
+        </plugins>
+    </build>
 </project>

http://git-wip-us.apache.org/repos/asf/karaf/blob/7c2db062/instance/src/main/java/org/apache/karaf/instance/command/ChangeOptsCommand.java
----------------------------------------------------------------------
diff --git a/instance/src/main/java/org/apache/karaf/instance/command/ChangeOptsCommand.java b/instance/src/main/java/org/apache/karaf/instance/command/ChangeOptsCommand.java
new file mode 100644
index 0000000..c526c07
--- /dev/null
+++ b/instance/src/main/java/org/apache/karaf/instance/command/ChangeOptsCommand.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.karaf.instance.command;
+
+import org.apache.karaf.instance.command.completers.InstanceCompleter;
+import org.apache.karaf.shell.api.action.Argument;
+import org.apache.karaf.shell.api.action.Command;
+import org.apache.karaf.shell.api.action.Completion;
+import org.apache.karaf.shell.api.action.lifecycle.Service;
+
+@Command(scope = "instance", name = "opts-change", description = "Changes the Java options of an existing container instance.")
+@Service
+public class ChangeOptsCommand extends InstanceCommandSupport {
+
+    @Argument(index = 0, name = "name", description="The name of the container instance", required = true, multiValued = false)
+    @Completion(InstanceCompleter.class)
+    private String instance = null;
+
+    @Argument(index = 1, name = "javaOpts", description = "The new Java options to set", required = true, multiValued = false)
+    private String javaOpts;
+
+    protected Object doExecute() throws Exception {
+        getExistingInstance(instance).changeJavaOpts(javaOpts);
+        return null;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/karaf/blob/7c2db062/instance/src/main/java/org/apache/karaf/instance/command/ChangeRmiRegistryPortCommand.java
----------------------------------------------------------------------
diff --git a/instance/src/main/java/org/apache/karaf/instance/command/ChangeRmiRegistryPortCommand.java b/instance/src/main/java/org/apache/karaf/instance/command/ChangeRmiRegistryPortCommand.java
new file mode 100644
index 0000000..de5bfaf
--- /dev/null
+++ b/instance/src/main/java/org/apache/karaf/instance/command/ChangeRmiRegistryPortCommand.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.karaf.instance.command;
+
+import org.apache.karaf.instance.command.completers.InstanceCompleter;
+import org.apache.karaf.shell.api.action.Argument;
+import org.apache.karaf.shell.api.action.Command;
+import org.apache.karaf.shell.api.action.Completion;
+import org.apache.karaf.shell.api.action.lifecycle.Service;
+
+@Command(scope = "instance", name = "rmi-registry-port-change", description = "Changes the RMI registry port (used by management layer) of an existing container instance.")
+@Service
+public class ChangeRmiRegistryPortCommand extends InstanceCommandSupport {
+
+    @Argument(index = 0, name = "name", description = "The name of the container instance", required = true, multiValued = false)
+    @Completion(InstanceCompleter.class)
+    private String instance = null;
+
+    @Argument(index = 1, name = "port", description = "The new RMI registry port to set", required = true, multiValued = false)
+    private int port = 0;
+
+    protected Object doExecute() throws Exception {
+        getExistingInstance(instance).changeRmiRegistryPort(port);
+        return null;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/karaf/blob/7c2db062/instance/src/main/java/org/apache/karaf/instance/command/ChangeRmiServerPortCommand.java
----------------------------------------------------------------------
diff --git a/instance/src/main/java/org/apache/karaf/instance/command/ChangeRmiServerPortCommand.java b/instance/src/main/java/org/apache/karaf/instance/command/ChangeRmiServerPortCommand.java
new file mode 100644
index 0000000..0ac2cf7
--- /dev/null
+++ b/instance/src/main/java/org/apache/karaf/instance/command/ChangeRmiServerPortCommand.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.karaf.instance.command;
+
+import org.apache.karaf.instance.command.completers.InstanceCompleter;
+import org.apache.karaf.shell.api.action.Argument;
+import org.apache.karaf.shell.api.action.Command;
+import org.apache.karaf.shell.api.action.Completion;
+import org.apache.karaf.shell.api.action.lifecycle.Service;
+
+@Command(scope = "instance", name = "rmi-server-port-change", description = "Changes the RMI server port (used by management layer) of an existing instance.")
+@Service
+public class ChangeRmiServerPortCommand extends InstanceCommandSupport {
+
+    @Argument(index = 0, name = "name", description = "The name of the container instance", required = true, multiValued = false)
+    @Completion(InstanceCompleter.class)
+    private String instance = null;
+
+    @Argument(index = 1, name = "port", description = "The new RMI server port to set", required = true, multiValued = false)
+    private int port = 0;
+
+    protected Object doExecute() throws Exception {
+        getExistingInstance(instance).changeRmiServerPort(port);
+        return null;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/karaf/blob/7c2db062/instance/src/main/java/org/apache/karaf/instance/command/ChangeSshPortCommand.java
----------------------------------------------------------------------
diff --git a/instance/src/main/java/org/apache/karaf/instance/command/ChangeSshPortCommand.java b/instance/src/main/java/org/apache/karaf/instance/command/ChangeSshPortCommand.java
new file mode 100644
index 0000000..17ad26c
--- /dev/null
+++ b/instance/src/main/java/org/apache/karaf/instance/command/ChangeSshPortCommand.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.karaf.instance.command;
+
+import org.apache.karaf.instance.command.completers.InstanceCompleter;
+import org.apache.karaf.shell.api.action.Argument;
+import org.apache.karaf.shell.api.action.Command;
+import org.apache.karaf.shell.api.action.Completion;
+import org.apache.karaf.shell.api.action.lifecycle.Service;
+
+@Command(scope = "instance", name = "ssh-port-change", description = "Changes the secure shell port of an existing container instance.")
+@Service
+public class ChangeSshPortCommand extends InstanceCommandSupport {
+
+    @Argument(index = 0, name = "name", description="The name of the container instance", required = true, multiValued = false)
+    @Completion(InstanceCompleter.class)
+    private String instance = null;
+
+    @Argument(index = 1, name = "port", description = "The new secure shell port to set", required = true, multiValued = false)
+    private int port = 0;
+
+    protected Object doExecute() throws Exception {
+        getExistingInstance(instance).changeSshPort(port);
+        return null;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/karaf/blob/7c2db062/instance/src/main/java/org/apache/karaf/instance/command/CloneCommand.java
----------------------------------------------------------------------
diff --git a/instance/src/main/java/org/apache/karaf/instance/command/CloneCommand.java b/instance/src/main/java/org/apache/karaf/instance/command/CloneCommand.java
new file mode 100644
index 0000000..e4f28c5
--- /dev/null
+++ b/instance/src/main/java/org/apache/karaf/instance/command/CloneCommand.java
@@ -0,0 +1,66 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.karaf.instance.command;
+
+import org.apache.karaf.instance.command.completers.InstanceCompleter;
+import org.apache.karaf.instance.core.InstanceSettings;
+import org.apache.karaf.shell.api.action.Argument;
+import org.apache.karaf.shell.api.action.Command;
+import org.apache.karaf.shell.api.action.Completion;
+import org.apache.karaf.shell.api.action.Option;
+import org.apache.karaf.shell.api.action.lifecycle.Service;
+
+/**
+ * Clone an existing instance.
+ */
+@Command(scope = "instance", name = "clone", description = "Clones an existing container instance.")
+@Service
+public class CloneCommand extends InstanceCommandSupport {
+
+    @Option(name = "-s", aliases = {"--ssh-port"}, description = "Port number for remote secure shell connection", required = false, multiValued = false)
+    int sshPort = 0;
+
+    @Option(name = "-r", aliases = {"-rr", "--rmi-port", "--rmi-registry-port"}, description = "Port number for RMI registry connection", required = false, multiValued = false)
+    int rmiRegistryPort = 0;
+
+    @Option(name = "-rs", aliases = {"--rmi-server-port"}, description = "Port number for RMI server connection", required = false, multiValued = false)
+    int rmiServerPort = 0;
+
+    @Option(name = "-l", aliases = {"--location"}, description = "Location of the cloned container instance in the file system", required = false, multiValued = false)
+    String location;
+
+    @Option(name = "-o", aliases = {"--java-opts"}, description = "JVM options to use when launching the cloned instance", required = false, multiValued = false)
+    String javaOpts;
+
+    @Option(name = "-v", aliases = {"--verbose"}, description = "Display actions performed by the command (disabled by default)", required = false, multiValued = false)
+    boolean verbose = false;
+
+    @Argument(index = 0, name = "name", description = "The name of the source container instance", required = true, multiValued = false)
+    @Completion(InstanceCompleter.class)
+    String name;
+
+    @Argument(index = 1, name = "cloneName", description = "The name of the cloned container instance", required = true, multiValued = false)
+    String cloneName;
+
+
+    protected Object doExecute() throws Exception {
+        InstanceSettings settings = new InstanceSettings(sshPort, rmiRegistryPort, rmiServerPort, location, javaOpts, null, null);
+        getInstanceService().cloneInstance(name, cloneName, settings, verbose);
+        return null;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/karaf/blob/7c2db062/instance/src/main/java/org/apache/karaf/instance/command/ConnectCommand.java
----------------------------------------------------------------------
diff --git a/instance/src/main/java/org/apache/karaf/instance/command/ConnectCommand.java b/instance/src/main/java/org/apache/karaf/instance/command/ConnectCommand.java
new file mode 100644
index 0000000..c81a3eb
--- /dev/null
+++ b/instance/src/main/java/org/apache/karaf/instance/command/ConnectCommand.java
@@ -0,0 +1,78 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.karaf.instance.command;
+
+import java.util.List;
+
+import org.apache.karaf.instance.command.completers.InstanceCompleter;
+import org.apache.karaf.shell.api.action.Argument;
+import org.apache.karaf.shell.api.action.Command;
+import org.apache.karaf.shell.api.action.Completion;
+import org.apache.karaf.shell.api.action.Option;
+import org.apache.karaf.shell.api.action.lifecycle.Reference;
+import org.apache.karaf.shell.api.action.lifecycle.Service;
+import org.apache.karaf.shell.api.console.Session;
+
+@Command(scope = "instance", name = "connect", description = "Connects to an existing container instance.")
+@Service
+public class ConnectCommand extends InstanceCommandSupport {
+
+    @Option(name="-u", aliases={"--username"}, description="Remote user name", required = false, multiValued = false)
+    private String username;
+
+    @Option(name = "-p", aliases = {"--password"}, description = "Remote password", required = false, multiValued = false)
+    private String password;
+
+    @Argument(index = 0, name="name", description="The name of the container instance", required = true, multiValued = false)
+    @Completion(InstanceCompleter.class)
+    private String instance = null;
+
+    @Argument(index = 1, name = "command", description = "Optional command to execute", required = false, multiValued = true)
+    private List<String> command;
+
+    @Reference
+    Session session;
+
+    protected Object doExecute() throws Exception {
+        String cmdStr = "";
+        if (command != null) {
+            StringBuilder sb = new StringBuilder();
+            for (String cmd : command) {
+                if (sb.length() > 0) {
+                    sb.append(' ');
+                }
+                sb.append(cmd);
+            }
+            cmdStr = "'" + sb.toString().replaceAll("'", "\\'") + "'";
+        }
+
+        int port = getExistingInstance(instance).getSshPort();
+        if (username != null) {
+            if (password == null) {
+                session.execute("ssh:ssh -q -l " + username + " -p " + port + " localhost " + cmdStr);
+            } else {
+                session.execute("ssh:ssh -q -l " + username + " -P " + password + " -p " + port + " localhost " + cmdStr);
+            }
+        } else {
+            session.execute("ssh:ssh -q -p " + port + " localhost " + cmdStr);
+        }
+        return null;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/karaf/blob/7c2db062/instance/src/main/java/org/apache/karaf/instance/command/CreateCommand.java
----------------------------------------------------------------------
diff --git a/instance/src/main/java/org/apache/karaf/instance/command/CreateCommand.java b/instance/src/main/java/org/apache/karaf/instance/command/CreateCommand.java
new file mode 100644
index 0000000..0dcc3ac
--- /dev/null
+++ b/instance/src/main/java/org/apache/karaf/instance/command/CreateCommand.java
@@ -0,0 +1,74 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.karaf.instance.command;
+
+import java.util.List;
+
+import org.apache.karaf.features.command.completers.AllFeatureCompleter;
+import org.apache.karaf.features.command.completers.InstalledRepoUriCompleter;
+import org.apache.karaf.instance.core.InstanceSettings;
+import org.apache.karaf.shell.api.action.Argument;
+import org.apache.karaf.shell.api.action.Command;
+import org.apache.karaf.shell.api.action.Completion;
+import org.apache.karaf.shell.api.action.Option;
+import org.apache.karaf.shell.api.action.lifecycle.Service;
+
+/**
+ * Creates a new instance.
+ */
+@Command(scope = "instance", name = "create", description = "Creates a new container instance.")
+@Service
+public class CreateCommand extends InstanceCommandSupport
+{
+    @Option(name = "-s", aliases = {"--ssh-port"}, description = "Port number for remote secure shell connection", required = false, multiValued = false)
+    int sshPort = 0;
+
+    @Option(name = "-r", aliases = {"-rr", "--rmi-port", "--rmi-registry-port"}, description = "Port number for RMI registry connection", required = false, multiValued = false)
+    int rmiRegistryPort = 0;
+
+    @Option(name = "-rs", aliases = {"--rmi-server-port"}, description = "Port number for RMI server connection", required = false, multiValued = false)
+    int rmiServerPort = 0;
+
+    @Option(name = "-l", aliases = {"--location"}, description = "Location of the new container instance in the file system", required = false, multiValued = false)
+    String location;
+
+    @Option(name = "-o", aliases = {"--java-opts"}, description = "JVM options to use when launching the instance", required = false, multiValued = false)
+    String javaOpts;
+    
+    @Option(name = "-f", aliases = {"--feature"},
+            description = "Initial features. This option can be specified multiple times to enable multiple initial features", required = false, multiValued = true)
+    @Completion(AllFeatureCompleter.class)
+    List<String> features;
+    
+    @Option(name = "-furl", aliases = {"--featureURL"}, 
+            description = "Additional feature descriptor URLs. This option can be specified multiple times to add multiple URLs", required = false, multiValued = true)
+    @Completion(InstalledRepoUriCompleter.class)
+    List<String> featureURLs;
+
+    @Option(name = "-v", aliases = {"--verbose"}, description = "Display actions performed by the command (disabled by default)", required = false, multiValued = false)
+    boolean verbose = false;
+
+    @Argument(index = 0, name = "name", description="The name of the new container instance", required = true, multiValued = false)
+    String instance = null;
+
+    protected Object doExecute() throws Exception {
+        InstanceSettings settings = new InstanceSettings(sshPort, rmiRegistryPort, rmiServerPort, location, javaOpts, featureURLs, features);
+        getInstanceService().createInstance(instance, settings, verbose);
+        return null;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/karaf/blob/7c2db062/instance/src/main/java/org/apache/karaf/instance/command/DestroyCommand.java
----------------------------------------------------------------------
diff --git a/instance/src/main/java/org/apache/karaf/instance/command/DestroyCommand.java b/instance/src/main/java/org/apache/karaf/instance/command/DestroyCommand.java
new file mode 100644
index 0000000..fb2964f
--- /dev/null
+++ b/instance/src/main/java/org/apache/karaf/instance/command/DestroyCommand.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.karaf.instance.command;
+
+import org.apache.karaf.instance.command.completers.InstanceCompleter;
+import org.apache.karaf.shell.api.action.Argument;
+import org.apache.karaf.shell.api.action.Command;
+import org.apache.karaf.shell.api.action.Completion;
+import org.apache.karaf.shell.api.action.lifecycle.Service;
+
+/**
+ * Destroy an existing instance.
+ */
+@Command(scope = "instance", name = "destroy", description = "Destroys an existing container instance.")
+@Service
+public class DestroyCommand extends InstanceCommandSupport
+{
+    @Argument(index = 0, name = "name", description= "The name of the container instance to destroy", required = true, multiValued = false)
+    @Completion(InstanceCompleter.class)
+    private String instance = null;
+
+    protected Object doExecute() throws Exception {
+        getExistingInstance(instance).destroy();
+        return null;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/karaf/blob/7c2db062/instance/src/main/java/org/apache/karaf/instance/command/InstanceCommandSupport.java
----------------------------------------------------------------------
diff --git a/instance/src/main/java/org/apache/karaf/instance/command/InstanceCommandSupport.java b/instance/src/main/java/org/apache/karaf/instance/command/InstanceCommandSupport.java
new file mode 100644
index 0000000..3b0b535
--- /dev/null
+++ b/instance/src/main/java/org/apache/karaf/instance/command/InstanceCommandSupport.java
@@ -0,0 +1,51 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.karaf.instance.command;
+
+import org.apache.karaf.instance.core.Instance;
+import org.apache.karaf.instance.core.InstanceService;
+import org.apache.karaf.shell.api.action.Action;
+import org.apache.karaf.shell.api.action.lifecycle.Reference;
+
+public abstract class InstanceCommandSupport implements Action {
+
+    @Reference
+    private InstanceService instanceService;
+
+    public InstanceService getInstanceService() {
+        return instanceService;
+    }
+
+    public void setInstanceService(InstanceService instanceService) {
+        this.instanceService = instanceService;
+    }
+
+    protected Instance getExistingInstance(String name) {
+        Instance i = instanceService.getInstance(name);
+        if (i == null) {
+            throw new IllegalArgumentException("Instances '" + name + "' does not exist");
+        }
+        return i;
+    }
+
+    @Override
+    public Object execute() throws Exception {
+        return doExecute();
+    }
+
+    protected abstract Object doExecute() throws Exception;
+}

http://git-wip-us.apache.org/repos/asf/karaf/blob/7c2db062/instance/src/main/java/org/apache/karaf/instance/command/ListCommand.java
----------------------------------------------------------------------
diff --git a/instance/src/main/java/org/apache/karaf/instance/command/ListCommand.java b/instance/src/main/java/org/apache/karaf/instance/command/ListCommand.java
new file mode 100644
index 0000000..fe571a8
--- /dev/null
+++ b/instance/src/main/java/org/apache/karaf/instance/command/ListCommand.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.karaf.instance.command;
+
+import org.apache.karaf.instance.core.Instance;
+import org.apache.karaf.shell.api.action.Command;
+import org.apache.karaf.shell.api.action.Option;
+import org.apache.karaf.shell.api.action.lifecycle.Service;
+import org.apache.karaf.shell.support.table.ShellTable;
+
+@Command(scope = "instance", name = "list", description = "Lists all existing container instances.")
+@Service
+public class ListCommand extends InstanceCommandSupport {
+
+    @Option(name = "-l", aliases = { "--location" }, description = "Displays the location of the container instances", required = false, multiValued = false)
+    boolean location;
+
+    @Option(name = "-o", aliases = { "--java-opts" }, description = "Displays the Java options used to launch the JVM", required = false, multiValued = false)
+    boolean javaOpts;
+
+    @Option(name = "--no-color", description = "Disable table rendered output", required = false, multiValued = false)
+    boolean noFormat;
+
+    protected Object doExecute() throws Exception {
+        getInstanceService().refreshInstance();
+        Instance[] instances = getInstanceService().getInstances();
+        ShellTable table = new ShellTable();
+        table.column("SSH Port").alignRight();
+        table.column("RMI Registry").alignRight();
+        table.column("RMI Server").alignRight();
+        table.column("State");
+        table.column("PID");
+        table.column(getRightColumnHeader());
+        for (Instance instance : instances) {
+            table.addRow().addContent(
+                    instance.getSshPort(),
+                    instance.getRmiRegistryPort(),
+                    instance.getRmiServerPort(),
+                    instance.getState(),
+                    instance.getPid(),
+                    getRightColumnValue(instance));
+        }
+        table.print(System.out, !noFormat);
+        return null;
+    }
+
+    private String getRightColumnHeader() {
+        if (javaOpts) {
+            return "JavaOpts";
+        } else if (location) {
+            return "Location";
+        } else {
+            return "Name";
+        }
+    }
+
+    private String getRightColumnValue(Instance instance) {
+        if (javaOpts) {
+            return instance.getJavaOpts();
+        } else if (location) {
+            return instance.getLocation();
+        } else {
+            return instance.getName();
+        }
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/karaf/blob/7c2db062/instance/src/main/java/org/apache/karaf/instance/command/RenameCommand.java
----------------------------------------------------------------------
diff --git a/instance/src/main/java/org/apache/karaf/instance/command/RenameCommand.java b/instance/src/main/java/org/apache/karaf/instance/command/RenameCommand.java
new file mode 100644
index 0000000..ef68400
--- /dev/null
+++ b/instance/src/main/java/org/apache/karaf/instance/command/RenameCommand.java
@@ -0,0 +1,45 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.karaf.instance.command;
+
+import org.apache.karaf.instance.command.completers.InstanceCompleter;
+import org.apache.karaf.shell.api.action.Argument;
+import org.apache.karaf.shell.api.action.Command;
+import org.apache.karaf.shell.api.action.Completion;
+import org.apache.karaf.shell.api.action.Option;
+import org.apache.karaf.shell.api.action.lifecycle.Service;
+
+@Command(scope = "instance", name = "rename", description = "Rename an existing container instance.")
+@Service
+public class RenameCommand extends InstanceCommandSupport {
+
+    @Option(name = "-v", aliases = {"--verbose"}, description = "Display actions performed by the command (disabled by default)", required = false, multiValued = false)
+    boolean verbose = false;
+
+    @Argument(index = 0, name = "name", description = "The name of the container instance to rename", required = true, multiValued = false)
+    @Completion(InstanceCompleter.class)
+    String instance = null;
+
+    @Argument(index = 1, name = "new-name", description = "The new name of the container instance", required = true, multiValued = false)
+    String newName = null;
+
+    protected Object doExecute() throws Exception {
+        getInstanceService().renameInstance(instance, newName, verbose);
+        return null;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/karaf/blob/7c2db062/instance/src/main/java/org/apache/karaf/instance/command/StartCommand.java
----------------------------------------------------------------------
diff --git a/instance/src/main/java/org/apache/karaf/instance/command/StartCommand.java b/instance/src/main/java/org/apache/karaf/instance/command/StartCommand.java
new file mode 100644
index 0000000..8c52d5e
--- /dev/null
+++ b/instance/src/main/java/org/apache/karaf/instance/command/StartCommand.java
@@ -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.
+ */
+package org.apache.karaf.instance.command;
+
+import org.apache.karaf.instance.command.completers.InstanceCompleter;
+import org.apache.karaf.instance.core.Instance;
+import org.apache.karaf.shell.api.action.Argument;
+import org.apache.karaf.shell.api.action.Command;
+import org.apache.karaf.shell.api.action.Completion;
+import org.apache.karaf.shell.api.action.Option;
+import org.apache.karaf.shell.api.action.lifecycle.Service;
+
+@Command(scope = "instance", name = "start", description = "Start an existing container instance.")
+@Service
+public class StartCommand extends InstanceCommandSupport {
+                      
+    @Option(name = "-d", aliases = { "--debug"}, description = "Start the instance in debug mode", required = false, multiValued = false)
+    private boolean debug; 
+    
+    @Option(name = "-o", aliases = { "--java-opts"}, description = "Java options when launching the instance", required = false, multiValued = false)
+    private String javaOpts;
+
+    @Option(name = "-w", aliases = { "--wait"}, description = "Wait for the instance to be fully started", required = false, multiValued = false)
+    private boolean wait;
+
+    @Argument(index = 0, name = "name", description = "The name of the container instance", required = true, multiValued = false)
+    @Completion(InstanceCompleter.class)
+    private String instance = null;
+
+    static final String DEBUG_OPTS = " -Xdebug -Xnoagent -Djava.compiler=NONE -Xrunjdwp:transport=dt_socket,server=y,suspend=n,address=5005";
+    static final String DEFAULT_OPTS = "-server -Xmx512M -Dcom.sun.management.jmxremote";
+
+    protected Object doExecute() throws Exception {
+        Instance child = getExistingInstance(instance);
+        String opts = javaOpts;
+        if (opts == null) {
+            opts = child.getJavaOpts();
+        }
+        if (opts == null) {
+            opts = DEFAULT_OPTS;
+        }
+        if (debug) {
+            opts += DEBUG_OPTS;
+        }
+        if (wait) {
+            String state = child.getState();
+            if (Instance.STOPPED.equals(state)) {
+                child.start(opts);
+            }
+            if (!Instance.STARTED.equals(state)) {
+                do {
+                    Thread.sleep(500);
+                    state = child.getState();
+                } while (Instance.STARTING.equals(state));
+            }
+        } else {
+            child.start(opts);
+        }
+        return null;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/karaf/blob/7c2db062/instance/src/main/java/org/apache/karaf/instance/command/StatusCommand.java
----------------------------------------------------------------------
diff --git a/instance/src/main/java/org/apache/karaf/instance/command/StatusCommand.java b/instance/src/main/java/org/apache/karaf/instance/command/StatusCommand.java
new file mode 100644
index 0000000..82100e1
--- /dev/null
+++ b/instance/src/main/java/org/apache/karaf/instance/command/StatusCommand.java
@@ -0,0 +1,40 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.karaf.instance.command;
+
+import org.apache.karaf.instance.command.completers.InstanceCompleter;
+import org.apache.karaf.instance.core.Instance;
+import org.apache.karaf.shell.api.action.Argument;
+import org.apache.karaf.shell.api.action.Command;
+import org.apache.karaf.shell.api.action.Completion;
+import org.apache.karaf.shell.api.action.lifecycle.Service;
+
+@Command(scope = "instance", name = "status", description = "Check the current status of an instance.")
+@Service
+public class StatusCommand extends InstanceCommandSupport {
+
+    @Argument(index = 0, name = "name", description = "The name of the instance", required = true, multiValued = false)
+    @Completion(InstanceCompleter.class)
+    private String name;
+
+    protected Object doExecute() throws Exception {
+        Instance instance = getExistingInstance(name);
+        System.out.println(instance.getState());
+        return null;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/karaf/blob/7c2db062/instance/src/main/java/org/apache/karaf/instance/command/StopCommand.java
----------------------------------------------------------------------
diff --git a/instance/src/main/java/org/apache/karaf/instance/command/StopCommand.java b/instance/src/main/java/org/apache/karaf/instance/command/StopCommand.java
new file mode 100644
index 0000000..6c8de10
--- /dev/null
+++ b/instance/src/main/java/org/apache/karaf/instance/command/StopCommand.java
@@ -0,0 +1,38 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.karaf.instance.command;
+
+import org.apache.karaf.instance.command.completers.InstanceCompleter;
+import org.apache.karaf.shell.api.action.Argument;
+import org.apache.karaf.shell.api.action.Command;
+import org.apache.karaf.shell.api.action.Completion;
+import org.apache.karaf.shell.api.action.lifecycle.Service;
+
+@Command(scope = "instance", name = "stop", description = "Stop an existing container instance.")
+@Service
+public class StopCommand extends InstanceCommandSupport {
+
+    @Argument(index = 0, name = "name", description = "The name of the container instance", required = true, multiValued = false)
+    @Completion(InstanceCompleter.class)
+    private String instance = null;
+
+    protected Object doExecute() throws Exception {
+        getExistingInstance(instance).stop();
+        return null;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/karaf/blob/7c2db062/instance/src/main/java/org/apache/karaf/instance/command/completers/InstanceCompleter.java
----------------------------------------------------------------------
diff --git a/instance/src/main/java/org/apache/karaf/instance/command/completers/InstanceCompleter.java b/instance/src/main/java/org/apache/karaf/instance/command/completers/InstanceCompleter.java
new file mode 100644
index 0000000..4468374
--- /dev/null
+++ b/instance/src/main/java/org/apache/karaf/instance/command/completers/InstanceCompleter.java
@@ -0,0 +1,52 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.karaf.instance.command.completers;
+
+import java.util.List;
+
+import org.apache.karaf.instance.core.Instance;
+import org.apache.karaf.instance.core.InstanceService;
+import org.apache.karaf.shell.api.action.lifecycle.Reference;
+import org.apache.karaf.shell.api.action.lifecycle.Service;
+import org.apache.karaf.shell.api.console.CommandLine;
+import org.apache.karaf.shell.api.console.Completer;
+import org.apache.karaf.shell.api.console.Session;
+import org.apache.karaf.shell.support.completers.StringsCompleter;
+
+/**
+ * Displays a list of configured server instances for the instance commands.
+ *
+ */
+@Service
+public class InstanceCompleter implements Completer {
+
+    @Reference
+    private InstanceService instanceService;
+
+    public void setInstanceService(InstanceService instanceService) {
+        this.instanceService = instanceService;
+    }
+
+    public int complete(Session session, CommandLine commandLine, List<String> candidates) {
+        StringsCompleter delegate = new StringsCompleter();
+        for (Instance instance : instanceService.getInstances()) {
+            delegate.getStrings().add(instance.getName());
+        }
+        return delegate.complete(session, commandLine, candidates);
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/karaf/blob/7c2db062/instance/src/main/java/org/apache/karaf/instance/core/Instance.java
----------------------------------------------------------------------
diff --git a/instance/src/main/java/org/apache/karaf/instance/core/Instance.java b/instance/src/main/java/org/apache/karaf/instance/core/Instance.java
new file mode 100644
index 0000000..5e78bb2
--- /dev/null
+++ b/instance/src/main/java/org/apache/karaf/instance/core/Instance.java
@@ -0,0 +1,66 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.karaf.instance.core;
+
+public interface Instance {
+
+    String STOPPED = "Stopped";
+    String STARTING = "Starting";
+    String STARTED = "Started";
+    String ERROR = "Error";
+
+    String getName();
+
+    @Deprecated
+    void setName(String name);
+    
+    boolean isRoot();
+
+    String getLocation();
+
+    @Deprecated
+    void setLocation(String location);
+
+    int getPid();
+
+    int getSshPort();
+
+    void changeSshPort(int port) throws Exception;
+
+    int getRmiRegistryPort();
+
+    void changeRmiRegistryPort(int port) throws Exception;
+
+    int getRmiServerPort();
+
+    void changeRmiServerPort(int port) throws Exception;
+
+    String getJavaOpts();
+
+    void changeJavaOpts(String javaOpts) throws Exception;
+
+    void start(String javaOpts) throws Exception;
+
+    void stop() throws Exception;
+
+    void destroy() throws Exception;
+
+    String getState() throws Exception;
+
+    @Deprecated
+    boolean isAttached();
+}

http://git-wip-us.apache.org/repos/asf/karaf/blob/7c2db062/instance/src/main/java/org/apache/karaf/instance/core/InstanceService.java
----------------------------------------------------------------------
diff --git a/instance/src/main/java/org/apache/karaf/instance/core/InstanceService.java b/instance/src/main/java/org/apache/karaf/instance/core/InstanceService.java
new file mode 100644
index 0000000..cc6c10c
--- /dev/null
+++ b/instance/src/main/java/org/apache/karaf/instance/core/InstanceService.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.karaf.instance.core;
+
+public interface InstanceService {
+
+    Instance createInstance(String name, InstanceSettings settings, boolean printOutput) throws Exception;
+
+    void renameInstance(String name, String newName, boolean printOutput) throws Exception;
+
+    @Deprecated
+    void refreshInstance() throws Exception;
+
+    Instance cloneInstance(String name, String cloneName, InstanceSettings settings, boolean printOutput) throws Exception;
+
+    Instance[] getInstances();
+
+    Instance getInstance(String name);    
+}

http://git-wip-us.apache.org/repos/asf/karaf/blob/7c2db062/instance/src/main/java/org/apache/karaf/instance/core/InstanceSettings.java
----------------------------------------------------------------------
diff --git a/instance/src/main/java/org/apache/karaf/instance/core/InstanceSettings.java b/instance/src/main/java/org/apache/karaf/instance/core/InstanceSettings.java
new file mode 100644
index 0000000..0f9cf97
--- /dev/null
+++ b/instance/src/main/java/org/apache/karaf/instance/core/InstanceSettings.java
@@ -0,0 +1,97 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.karaf.instance.core;
+
+import java.util.List;
+
+public class InstanceSettings {
+
+    private final int sshPort;
+    private final int rmiRegistryPort;
+    private final int rmiServerPort;
+    private final String location;
+    private final String javaOpts;
+    private final List<String> featureURLs;
+    private final List<String> features;
+
+    public InstanceSettings(int sshPort, int rmiRegistryPort, int rmiServerPort, String location, String javaOpts, List<String> featureURLs, List<String> features) {
+        this.sshPort = sshPort;
+        this.rmiRegistryPort = rmiRegistryPort;
+        this.rmiServerPort = rmiServerPort;
+        this.location = location;
+        this.javaOpts = javaOpts;
+        this.featureURLs = featureURLs;
+        this.features = features;
+    }
+
+    public int getSshPort() {
+        return sshPort;
+    }
+
+    public int getRmiRegistryPort() {
+        return rmiRegistryPort;
+    }
+
+    public int getRmiServerPort() {
+        return rmiServerPort;
+    }
+
+    public String getLocation() {
+        return location;
+    }
+
+    public String getJavaOpts() {
+        return javaOpts;
+    }
+
+    public List<String> getFeatureURLs() {
+        return featureURLs;
+    }
+
+    public List<String> getFeatures() {
+        return features;
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (o == this) {
+            return true;
+        }
+        if (!(o instanceof InstanceSettings)) {
+            return false;
+        }
+        InstanceSettings is = (InstanceSettings) o;
+        return is.sshPort == sshPort &&
+               is.rmiRegistryPort == rmiRegistryPort &&
+               is.rmiServerPort == rmiServerPort &&
+               (location == null ? is.location == null : location.equals(is.location)) &&
+               (javaOpts == null ? is.javaOpts == null : javaOpts.equals(is.javaOpts)) &&
+               (featureURLs == null ? is.featureURLs == null : featureURLs.equals(is.featureURLs)) &&
+               (features == null ? is.features == null : features.equals(is.features));
+    }
+
+    @Override
+    public int hashCode() {
+        int result = sshPort + rmiRegistryPort + rmiServerPort;
+        result = 31 * result + (location != null ? location.hashCode() : 0);
+        result = 31 * result + (javaOpts != null ? javaOpts.hashCode() : 0);
+        result = 31 * result + (featureURLs != null ? featureURLs.hashCode() : 0);
+        result = 31 * result + (features != null ? features.hashCode() : 0);
+        return result;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/karaf/blob/7c2db062/instance/src/main/java/org/apache/karaf/instance/core/InstancesMBean.java
----------------------------------------------------------------------
diff --git a/instance/src/main/java/org/apache/karaf/instance/core/InstancesMBean.java b/instance/src/main/java/org/apache/karaf/instance/core/InstancesMBean.java
new file mode 100644
index 0000000..f75e099
--- /dev/null
+++ b/instance/src/main/java/org/apache/karaf/instance/core/InstancesMBean.java
@@ -0,0 +1,55 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.karaf.instance.core;
+
+import javax.management.MBeanException;
+import javax.management.openmbean.TabularData;
+
+public interface InstancesMBean {
+
+    String INSTANCE_PID = "Pid";
+    String INSTANCE_NAME = "Name";
+    String INSTANCE_IS_ROOT = "Is Root";
+    String INSTANCE_SSH_PORT = "SSH Port";
+    String INSTANCE_RMI_REGISTRY_PORT = "RMI Registry Port";
+    String INSTANCE_RMI_SERVER_PORT = "RMI Server Port";
+    String INSTANCE_STATE = "State";
+    String INSTANCE_LOCATION = "Location";
+    String INSTANCE_JAVAOPTS = "JavaOpts";
+
+    String[] INSTANCE = {INSTANCE_PID, INSTANCE_NAME, INSTANCE_IS_ROOT, INSTANCE_SSH_PORT, INSTANCE_RMI_REGISTRY_PORT,
+            INSTANCE_RMI_SERVER_PORT, INSTANCE_STATE, INSTANCE_LOCATION, INSTANCE_JAVAOPTS };
+
+    // Operations
+    int createInstance(String name, int sshPort, int rmiRegistryPort, int rmiServerPort, String location, String javaOpts, String features, String featureURLs) throws MBeanException;
+    void changeSshPort(String name, int port) throws MBeanException;
+    void changeRmiRegistryPort(String name, int port) throws MBeanException;
+    void changeRmiServerPort(String name, int port) throws MBeanException;
+    void changeJavaOpts(String name, String javaopts) throws MBeanException;
+    void destroyInstance(String name) throws MBeanException;
+    void startInstance(String name) throws MBeanException;
+    void startInstance(String name, String opts) throws MBeanException;
+    void startInstance(String name, String opts, boolean wait, boolean debug) throws MBeanException;
+    void stopInstance(String name) throws MBeanException;
+    void renameInstance(String originalName, String newName) throws MBeanException;
+    void renameInstance(String originalName, String newName, boolean verbose) throws MBeanException;
+    void cloneInstance(String name, String cloneName, int sshPort, int rmiRegistryPort, int rmiServerPort, String location, String javaOpts) throws MBeanException;
+
+    // Attributes
+    TabularData getInstances() throws MBeanException;
+
+}

http://git-wip-us.apache.org/repos/asf/karaf/blob/7c2db062/instance/src/main/java/org/apache/karaf/instance/core/internal/InstanceImpl.java
----------------------------------------------------------------------
diff --git a/instance/src/main/java/org/apache/karaf/instance/core/internal/InstanceImpl.java b/instance/src/main/java/org/apache/karaf/instance/core/internal/InstanceImpl.java
new file mode 100644
index 0000000..edc4ec5
--- /dev/null
+++ b/instance/src/main/java/org/apache/karaf/instance/core/internal/InstanceImpl.java
@@ -0,0 +1,110 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.karaf.instance.core.internal;
+
+import org.apache.karaf.instance.core.Instance;
+
+public class InstanceImpl implements Instance {
+
+    private final InstanceServiceImpl service;
+    private String name;
+
+    public InstanceImpl(InstanceServiceImpl service, String name) {
+        this.service = service;
+        this.name = name;
+    }
+
+    public String getName() {
+        return name;
+    }
+
+    public void setName(String name) {
+        throw new UnsupportedOperationException();
+    }
+
+    void doSetName(String name) {
+        this.name = name;
+    }
+
+    public boolean isRoot() {
+        return service.isInstanceRoot(name);
+    }
+
+    public String getLocation() {
+        return service.getInstanceLocation(name);
+    }
+
+    public void setLocation(String location) {
+        throw new UnsupportedOperationException();
+    }
+
+    public int getPid() {
+        return service.getInstancePid(name);
+    }
+
+    public int getSshPort() {
+        return service.getInstanceSshPort(name);
+    }
+
+    public void changeSshPort(int port) throws Exception {
+        service.changeInstanceSshPort(name, port);
+    }
+
+    public int getRmiRegistryPort() {
+        return service.getInstanceRmiRegistryPort(name);
+    }
+
+    public void changeRmiRegistryPort(int port) throws Exception {
+        service.changeInstanceRmiRegistryPort(name, port);
+    }
+
+    public int getRmiServerPort() {
+        return service.getInstanceRmiServerPort(name);
+    }
+
+    public void changeRmiServerPort(int port) throws Exception {
+        service.changeInstanceRmiServerPort(name, port);
+    }
+
+    public String getJavaOpts() {
+        return service.getInstanceJavaOpts(name);
+    }
+
+    public void changeJavaOpts(String javaOpts) throws Exception {
+        service.changeInstanceJavaOpts(name, javaOpts);
+    }
+
+    public void start(String javaOpts) throws Exception {
+        service.startInstance(name, javaOpts);
+    }
+
+    public void stop() throws Exception {
+        service.stopInstance(name);
+    }
+
+    public void destroy() throws Exception {
+        service.destroyInstance(name);
+    }
+
+    public String getState() throws Exception {
+        return service.getInstanceState(name);
+    }
+
+    public boolean isAttached() {
+        return getPid() != 0;
+    }
+}
\ No newline at end of file