FELIX-1517 and FELIX-1528: use a defined location for the storage of the list of managed instances and avoid an exception if one instance has been deleted

git-svn-id: https://svn.apache.org/repos/asf/felix/trunk@808019 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/karaf/gshell/gshell-admin/src/main/java/org/apache/felix/karaf/gshell/admin/AdminServiceMBean.java b/karaf/gshell/gshell-admin/src/main/java/org/apache/felix/karaf/gshell/admin/AdminServiceMBean.java
index 8e3f8ae..8e18445 100644
--- a/karaf/gshell/gshell-admin/src/main/java/org/apache/felix/karaf/gshell/admin/AdminServiceMBean.java
+++ b/karaf/gshell/gshell-admin/src/main/java/org/apache/felix/karaf/gshell/admin/AdminServiceMBean.java
@@ -22,7 +22,7 @@
 
     String[] getInstances();
 
-    int getPort(String name) throws Exception;
+    int getPort(String name);
 
     void changePort(String name, int port) throws Exception;
 
diff --git a/karaf/gshell/gshell-admin/src/main/java/org/apache/felix/karaf/gshell/admin/Instance.java b/karaf/gshell/gshell-admin/src/main/java/org/apache/felix/karaf/gshell/admin/Instance.java
index e60485d..01bd510 100644
--- a/karaf/gshell/gshell-admin/src/main/java/org/apache/felix/karaf/gshell/admin/Instance.java
+++ b/karaf/gshell/gshell-admin/src/main/java/org/apache/felix/karaf/gshell/admin/Instance.java
@@ -21,6 +21,7 @@
     String STOPPED = "Stopped";
     String STARTING = "Starting";
     String STARTED = "Started";
+    String ERROR = "Error";
 
     String getName();
 
@@ -28,7 +29,7 @@
 
     int getPid();
 
-    int getPort() throws Exception;
+    int getPort();
 
     void changePort(int port) throws Exception;
 
diff --git a/karaf/gshell/gshell-admin/src/main/java/org/apache/felix/karaf/gshell/admin/internal/AdminServiceImpl.java b/karaf/gshell/gshell-admin/src/main/java/org/apache/felix/karaf/gshell/admin/internal/AdminServiceImpl.java
index 1b1190b..b072805 100644
--- a/karaf/gshell/gshell-admin/src/main/java/org/apache/felix/karaf/gshell/admin/internal/AdminServiceImpl.java
+++ b/karaf/gshell/gshell-admin/src/main/java/org/apache/felix/karaf/gshell/admin/internal/AdminServiceImpl.java
@@ -22,16 +22,15 @@
 import java.io.InputStream;
 import java.io.OutputStream;
 import java.io.PrintStream;
+import java.io.FileInputStream;
 import java.net.ServerSocket;
 import java.util.HashMap;
 import java.util.Map;
 import java.util.Scanner;
+import java.util.Properties;
 
 import org.apache.felix.karaf.gshell.admin.AdminService;
 import org.apache.felix.karaf.gshell.admin.Instance;
-import org.osgi.service.prefs.BackingStoreException;
-import org.osgi.service.prefs.Preferences;
-import org.osgi.service.prefs.PreferencesService;
 import org.slf4j.LoggerFactory;
 import org.slf4j.Logger;
 import org.fusesource.jansi.Ansi;
@@ -40,30 +39,56 @@
 
     private static final Logger LOGGER = LoggerFactory.getLogger(AdminServiceImpl.class);
 
-    private PreferencesService preferences;
-
     private Map<String, Instance> instances = new HashMap<String, Instance>();
 
     private int defaultPortStart = 8101;
 
-    public PreferencesService getPreferences() {
-        return preferences;
+    private File storageLocation;
+
+    public File getStorageLocation() {
+        return storageLocation;
     }
 
-    public void setPreferences(PreferencesService preferences) {
-        this.preferences = preferences;
+    public void setStorageLocation(File storage) {
+        this.storageLocation = storage;
+    }
+
+    private Properties loadStorage(File location) throws IOException {
+        InputStream is = null;
+        try {
+            is = new FileInputStream(location);
+            Properties props = new Properties();
+            props.load(is);
+            return props;
+        } finally {
+            if (is != null) {
+                is.close();
+            }
+        }
+    }
+
+    private void saveStorage(Properties props, File location) throws IOException {
+        OutputStream os = null;
+        try {
+            os = new FileOutputStream(location);
+            props.store(os, "Admin Service storage");
+        } finally {
+            if (os != null) {
+                os.close();
+            }
+        }
     }
 
     public synchronized void init() throws Exception {
         try {
-            Preferences prefs = preferences.getUserPreferences("AdminServiceState");
-            Preferences child = prefs.node("Instances");
-            int count = child.getInt("count", 0);
+            Properties storage = loadStorage(storageLocation);
+            int count = Integer.parseInt(storage.getProperty("count", "0"));
+            defaultPortStart = Integer.parseInt(storage.getProperty("port", Integer.toString(defaultPortStart)));
             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);
+                String name = storage.getProperty("item." + i + ".name", null);
+                String loc = storage.getProperty("item." + i + ".loc", null);
+                int pid = Integer.parseInt(storage.getProperty("item." + i + ".pid", "0"));
                 if (name != null) {
                     InstanceImpl instance = new InstanceImpl(this, name, loc);
                     if (pid > 0) {
@@ -89,23 +114,7 @@
         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;
-            }
+            sshPort = ++defaultPortStart;
         }
         println("Creating new instance on port " + sshPort + " at: @|bold " + serviceMixBase + "|");
 
@@ -156,19 +165,17 @@
         instances.remove(name);
     }
 
-    synchronized void saveState() throws IOException, BackingStoreException {
-        Preferences prefs = preferences.getUserPreferences("AdminServiceState");
-        Preferences child = prefs.node("Instances");
-        child.clear();
+    synchronized void saveState() throws IOException {
+        Properties storage = new Properties();
         Instance[] data = getInstances();
-        child.putInt("count", data.length);
+        storage.setProperty("port", Integer.toString(defaultPortStart));
+        storage.setProperty("count", Integer.toString(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());
+            storage.setProperty("item." + i + ".name", data[i].getName());
+            storage.setProperty("item." + i + ".loc", data[i].getLocation());
+            storage.setProperty("item." + i + ".pid", Integer.toString(data[i].getPid()));
         }
-        prefs.flush();
-        prefs.sync();
+        saveStorage(storage, storageLocation);
     }
 
     private void copyResourceToDir(File target, String resource, boolean text) throws Exception {
diff --git a/karaf/gshell/gshell-admin/src/main/java/org/apache/felix/karaf/gshell/admin/internal/AdminServiceMBeanImpl.java b/karaf/gshell/gshell-admin/src/main/java/org/apache/felix/karaf/gshell/admin/internal/AdminServiceMBeanImpl.java
index afa3d83..b83cb83 100644
--- a/karaf/gshell/gshell-admin/src/main/java/org/apache/felix/karaf/gshell/admin/internal/AdminServiceMBeanImpl.java
+++ b/karaf/gshell/gshell-admin/src/main/java/org/apache/felix/karaf/gshell/admin/internal/AdminServiceMBeanImpl.java
@@ -45,7 +45,7 @@
         return names;
     }
 
-    public int getPort(String name) throws Exception {
+    public int getPort(String name) {
         return getExistingInstance(name).getPort();
     }
 
diff --git a/karaf/gshell/gshell-admin/src/main/java/org/apache/felix/karaf/gshell/admin/internal/InstanceImpl.java b/karaf/gshell/gshell-admin/src/main/java/org/apache/felix/karaf/gshell/admin/internal/InstanceImpl.java
index e851e1e..0d22a08 100644
--- a/karaf/gshell/gshell-admin/src/main/java/org/apache/felix/karaf/gshell/admin/internal/InstanceImpl.java
+++ b/karaf/gshell/gshell-admin/src/main/java/org/apache/felix/karaf/gshell/admin/internal/InstanceImpl.java
@@ -64,12 +64,16 @@
         return location;
     }
 
+    public boolean exists() {
+        return new File(location).isDirectory();
+    }
+
     public int getPid() {
         checkProcess();
         return this.process != null ? this.process.getPid() : 0;
     }
 
-    public int getPort() throws Exception {
+    public int getPort() {
         InputStream is = null;
         try {
             File f = new File(location, "etc/org.apache.felix.karaf.shell.cfg");
@@ -78,9 +82,15 @@
             props.load(is);
             String loc = props.getProperty("sshPort");
             return Integer.parseInt(loc);
+        } catch (Exception e) {
+            return 0;
         } finally {
             if (is != null) {
-                is.close();
+                try {
+                    is.close();
+                } catch (IOException e) {
+                    // Ignore
+                }
             }
         }
     }
@@ -165,12 +175,15 @@
 
 
     public synchronized String getState() {
+        int port = getPort();
+        if (!exists() || port <= 0) {
+            return ERROR;
+        }
         checkProcess();
         if (this.process == null) {
             return STOPPED;
         } else {
             try {
-                int port = getPort();
                 Socket s = new Socket("localhost", port);
                 s.close();
                 return STARTED;
diff --git a/karaf/gshell/gshell-admin/src/main/resources/OSGI-INF/blueprint/gshell-admin.xml b/karaf/gshell/gshell-admin/src/main/resources/OSGI-INF/blueprint/gshell-admin.xml
index d92260a..361fa9f 100644
--- a/karaf/gshell/gshell-admin/src/main/resources/OSGI-INF/blueprint/gshell-admin.xml
+++ b/karaf/gshell/gshell-admin/src/main/resources/OSGI-INF/blueprint/gshell-admin.xml
@@ -18,6 +18,7 @@
 
 -->
 <blueprint xmlns="http://www.osgi.org/xmlns/blueprint/v1.0.0"
+           xmlns:ext="http://geronimo.apache.org/blueprint/xmlns/blueprint-ext/v1.0.0"
            default-activation="lazy">
 
     <command-bundle xmlns="http://felix.apache.org/karaf/xmlns/gshell/v1.0.0">
@@ -78,10 +79,8 @@
         </command>
     </command-bundle>
 
-    <reference id="preferences" interface="org.osgi.service.prefs.PreferencesService" availability="optional"/>
-
     <bean id="adminService" class="org.apache.felix.karaf.gshell.admin.internal.AdminServiceImpl" init-method="init">
-        <property name="preferences" ref="preferences" />
+        <property name="storageLocation" value="${karaf.home}/etc/instances.properties" />
     </bean>
 
     <bean id="instanceCompleter" class="org.apache.felix.karaf.gshell.admin.internal.completers.InstanceCompleter">
@@ -90,4 +89,7 @@
     
     <service ref="adminService" interface="org.apache.felix.karaf.gshell.admin.AdminService" />
 
+    <!-- Allow the use of system properties -->
+    <ext:property-placeholder />
+
 </blueprint>