Support for ContainerFactory.listServices()
diff --git a/containers-api/src/main/java/org/apache/aries/containers/ContainerFactory.java b/containers-api/src/main/java/org/apache/aries/containers/ContainerFactory.java
index ec69264..d6d91d9 100644
--- a/containers-api/src/main/java/org/apache/aries/containers/ContainerFactory.java
+++ b/containers-api/src/main/java/org/apache/aries/containers/ContainerFactory.java
@@ -1,8 +1,12 @@
 package org.apache.aries.containers;
 
+import java.util.Set;
+
 import org.osgi.annotation.versioning.ProviderType;
 
 @ProviderType
 public interface ContainerFactory {
     Service getService(ServiceConfig config) throws Exception;
+
+    Set<String> listServices() throws Exception;
 }
diff --git a/containers-api/src/main/java/org/apache/aries/containers/Service.java b/containers-api/src/main/java/org/apache/aries/containers/Service.java
index 6b334d0..f440ceb 100644
--- a/containers-api/src/main/java/org/apache/aries/containers/Service.java
+++ b/containers-api/src/main/java/org/apache/aries/containers/Service.java
@@ -18,6 +18,8 @@
  */
 package org.apache.aries.containers;
 
+import java.util.List;
+
 import org.osgi.annotation.versioning.ProviderType;
 
 @ProviderType
@@ -33,5 +35,15 @@
      */
     int getActualInstanceCount();
 
+    ServiceConfig getConfiguration();
+
+    List<Container> listContainers();
+
     void setInstanceCount(int count);
+
+    /**
+     * Update the internal representation of the service with the actual runtime state
+     * which can be useful if it has been changed from the outside.
+     */
+    void refresh();
 }
\ No newline at end of file
diff --git a/containers-docker-local/src/main/java/org/apache/aries/containers/docker/local/impl/ContainerImpl.java b/containers-docker-local/src/main/java/org/apache/aries/containers/docker/local/impl/ContainerImpl.java
index 66f3f83..4895433 100644
--- a/containers-docker-local/src/main/java/org/apache/aries/containers/docker/local/impl/ContainerImpl.java
+++ b/containers-docker-local/src/main/java/org/apache/aries/containers/docker/local/impl/ContainerImpl.java
@@ -65,4 +65,49 @@
     void setService(ServiceImpl svc) {
         service = svc;
     }
+
+
+    @Override
+    public int hashCode() {
+        final int prime = 31;
+        int result = 1;
+        result = prime * result + ((id == null) ? 0 : id.hashCode());
+        result = prime * result + ((ip == null) ? 0 : ip.hashCode());
+        result = prime * result + ((ports == null) ? 0 : ports.hashCode());
+        return result;
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj)
+            return true;
+        if (obj == null)
+            return false;
+        if (getClass() != obj.getClass())
+            return false;
+
+        ContainerImpl other = (ContainerImpl) obj;
+        if (id == null) {
+            if (other.id != null)
+                return false;
+        } else if (!id.equals(other.id))
+            return false;
+        if (ip == null) {
+            if (other.ip != null)
+                return false;
+        } else if (!ip.equals(other.ip))
+            return false;
+        if (ports == null) {
+            if (other.ports != null)
+                return false;
+        } else if (!ports.equals(other.ports))
+            return false;
+        return true;
+    }
+
+    @Override
+    public String toString() {
+        return "ContainerImpl [id=" + id + ", ip=" + ip + ", ports=" + ports +
+                ", service=" + service.getConfiguration().getServiceName() + "]";
+    }
 }
diff --git a/containers-docker-local/src/main/java/org/apache/aries/containers/docker/local/impl/LocalDockerContainerFactory.java b/containers-docker-local/src/main/java/org/apache/aries/containers/docker/local/impl/LocalDockerContainerFactory.java
index 11ad192..307712e 100644
--- a/containers-docker-local/src/main/java/org/apache/aries/containers/docker/local/impl/LocalDockerContainerFactory.java
+++ b/containers-docker-local/src/main/java/org/apache/aries/containers/docker/local/impl/LocalDockerContainerFactory.java
@@ -27,15 +27,16 @@
 import java.util.Arrays;
 import java.util.Collections;
 import java.util.HashMap;
+import java.util.HashSet;
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
 import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.ConcurrentMap;
-import java.util.concurrent.atomic.AtomicBoolean;
 import java.util.regex.Pattern;
 import java.util.stream.Stream;
 
+import org.apache.aries.containers.Container;
 import org.apache.aries.containers.ContainerFactory;
 import org.apache.aries.containers.Service;
 import org.apache.aries.containers.ServiceConfig;
@@ -60,14 +61,10 @@
 
 
     private volatile LocalDockerController docker;
-    private final AtomicBoolean initialized = new AtomicBoolean(false);
     private final ConcurrentMap<String, Service> services =
             new ConcurrentHashMap<>();
 
-    private void init() {
-        if (!initialized.compareAndSet(false, true))
-            return;
-
+    public LocalDockerContainerFactory() {
         if (docker == null)
             docker = new LocalDockerController();
     }
@@ -78,8 +75,6 @@
 
     @Override
     public Service getService(ServiceConfig config) throws Exception {
-        init();
-
         Service existingService = services.get(config.getServiceName());
         if (existingService != null)
             return existingService;
@@ -163,7 +158,7 @@
         if (ids.size() == 0)
             return Collections.emptyList();
 
-        String infoJSON = docker.inspect(ids.toArray(new String [] {}));
+        String infoJSON = docker.inspect(ids);
         List<Object> data = new JSONParser(infoJSON).getParsedList();
         for (Object d : data) {
             if (!(d instanceof Map))
@@ -199,6 +194,7 @@
                     }
                 }
             }
+            // TODO check that the settings match!
             res.add(new ContainerImpl(m.get("Id").toString(), LocalDockerContainerFactory.getContainerHost(), ports));
         }
         return res;
@@ -213,4 +209,38 @@
     public static String getContainerHost() {
         return CONTAINER_HOST;
     }
+
+    @Override
+    public Set<String> listServices() throws Exception {
+        Set<String> res = new HashSet<>();
+        List<String> ids = docker.ps(SERVICE_NAME);
+
+        for (Service svc : services.values()) {
+            res.add(svc.getConfiguration().getServiceName());
+            for (Container c : svc.listContainers()) {
+                ids.remove(c.getID());
+            }
+        }
+
+        String json = docker.inspect(ids);
+        for (Object data : new JSONParser(json).getParsedList()) {
+            // These are services that have been launched previously and are not internally synced yet
+            if (!(data instanceof Map)) {
+                continue;
+            }
+
+            Object cd = ((Map) data).get("Config");
+            if (cd instanceof Map) {
+                Object ld = ((Map) cd).get("Labels");
+                if (ld instanceof Map) {
+                    Object serviceName = ((Map) ld).get(SERVICE_NAME);
+                    if (serviceName instanceof String) {
+                        res.add((String) serviceName);
+                    }
+                }
+            }
+        }
+
+        return res;
+    }
 }
diff --git a/containers-docker-local/src/main/java/org/apache/aries/containers/docker/local/impl/LocalDockerController.java b/containers-docker-local/src/main/java/org/apache/aries/containers/docker/local/impl/LocalDockerController.java
index bb36d07..94801b6 100644
--- a/containers-docker-local/src/main/java/org/apache/aries/containers/docker/local/impl/LocalDockerController.java
+++ b/containers-docker-local/src/main/java/org/apache/aries/containers/docker/local/impl/LocalDockerController.java
@@ -49,7 +49,7 @@
     }
 
     public List<String> ps(String labelFilter) {
-        String res = runCommand("docker", "ps", "-q", "-f", "label=" + labelFilter);
+        String res = runCommand("docker", "ps", "-q", "--no-trunc","-f", "label=" + labelFilter);
 
         String[] sa = res.trim().split("\\s+");
         List<String> sl = new ArrayList<>(sa.length);
@@ -61,12 +61,12 @@
         return sl;
     }
 
-    public String inspect(String... ids) {
-        String[] command = new String[ids.length+2];
-        command[0] = "docker";
-        command[1] = "inspect";
-        System.arraycopy(ids, 0, command, 2, ids.length);
-        return runCommand(command);
+    public String inspect(List<String> ids) {
+        List<String> cmd = new ArrayList<>();
+        cmd.add("docker");
+        cmd.add("inspect");
+        cmd.addAll(ids);
+        return runCommand(cmd.toArray(new String [] {}));
     }
 
     String runCommandExpectSingleID(String ... command) throws Exception {
diff --git a/containers-docker-local/src/main/java/org/apache/aries/containers/docker/local/impl/ServiceImpl.java b/containers-docker-local/src/main/java/org/apache/aries/containers/docker/local/impl/ServiceImpl.java
index 76484f0..895d809 100644
--- a/containers-docker-local/src/main/java/org/apache/aries/containers/docker/local/impl/ServiceImpl.java
+++ b/containers-docker-local/src/main/java/org/apache/aries/containers/docker/local/impl/ServiceImpl.java
@@ -18,9 +18,11 @@
  */
 package org.apache.aries.containers.docker.local.impl;
 
+import java.util.Collections;
 import java.util.List;
 import java.util.concurrent.CopyOnWriteArrayList;
 
+import org.apache.aries.containers.Container;
 import org.apache.aries.containers.Service;
 import org.apache.aries.containers.ServiceConfig;
 
@@ -49,6 +51,11 @@
     }
 
     @Override
+    public ServiceConfig getConfiguration() {
+        return config;
+    }
+
+    @Override
     public void setInstanceCount(int count) {
         try {
             int curSize = containers.size();
@@ -72,4 +79,14 @@
     public void killAndReplaceContainer(ContainerImpl containerImpl) {
         // TODO implement
     }
+
+    @Override
+    public List<Container> listContainers() {
+        return Collections.unmodifiableList(containers);
+    }
+
+    @Override
+    public void refresh() {
+        // TODO
+    }
 }