You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@aries.apache.org by cs...@apache.org on 2016/03/14 17:49:35 UTC

[1/5] aries-rsa git commit: Adding roundtrip test

Repository: aries-rsa
Updated Branches:
  refs/heads/master bd0352f56 -> 69bb901e9


http://git-wip-us.apache.org/repos/asf/aries-rsa/blob/69bb901e/itests/testbundle-service-tcp/src/main/java/org/apache/aries/rsa/itests/tcp/service/Activator.java
----------------------------------------------------------------------
diff --git a/itests/testbundle-service-tcp/src/main/java/org/apache/aries/rsa/itests/tcp/service/Activator.java b/itests/testbundle-service-tcp/src/main/java/org/apache/aries/rsa/itests/tcp/service/Activator.java
deleted file mode 100644
index 184dd2b..0000000
--- a/itests/testbundle-service-tcp/src/main/java/org/apache/aries/rsa/itests/tcp/service/Activator.java
+++ /dev/null
@@ -1,25 +0,0 @@
-package org.apache.aries.rsa.itests.tcp.service;
-
-import java.util.Dictionary;
-import java.util.Hashtable;
-
-import org.apache.aries.rsa.itests.tcp.api.EchoService;
-import org.osgi.framework.BundleActivator;
-import org.osgi.framework.BundleContext;
-import org.osgi.service.remoteserviceadmin.RemoteConstants;
-
-public class Activator implements BundleActivator {
-
-    @Override
-    public void start(BundleContext context) throws Exception {
-        EchoService echoService = new EchoServiceImpl();
-        Dictionary<String, String> props = new Hashtable<String, String>();
-        props.put(RemoteConstants.SERVICE_EXPORTED_INTERFACES, "*");
-        context.registerService(EchoService.class, echoService, props);
-    }
-
-    @Override
-    public void stop(BundleContext context) throws Exception {
-   }
-
-}

http://git-wip-us.apache.org/repos/asf/aries-rsa/blob/69bb901e/itests/testbundle-service-tcp/src/main/java/org/apache/aries/rsa/itests/tcp/service/EchoServiceImpl.java
----------------------------------------------------------------------
diff --git a/itests/testbundle-service-tcp/src/main/java/org/apache/aries/rsa/itests/tcp/service/EchoServiceImpl.java b/itests/testbundle-service-tcp/src/main/java/org/apache/aries/rsa/itests/tcp/service/EchoServiceImpl.java
deleted file mode 100644
index a79abb2..0000000
--- a/itests/testbundle-service-tcp/src/main/java/org/apache/aries/rsa/itests/tcp/service/EchoServiceImpl.java
+++ /dev/null
@@ -1,12 +0,0 @@
-package org.apache.aries.rsa.itests.tcp.service;
-
-import org.apache.aries.rsa.itests.tcp.api.EchoService;
-
-public class EchoServiceImpl implements EchoService {
-
-    @Override
-    public String echo(String msg) {
-        return msg;
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/aries-rsa/blob/69bb901e/pom.xml
----------------------------------------------------------------------
diff --git a/pom.xml b/pom.xml
index c104d12..eb898cb 100644
--- a/pom.xml
+++ b/pom.xml
@@ -77,6 +77,7 @@
         <module>topology-manager</module>
         <module>provider</module>
         <module>discovery</module>
+        <module>examples</module>
         <module>features</module>
         <module>itests</module>
     </modules>

http://git-wip-us.apache.org/repos/asf/aries-rsa/blob/69bb901e/rsa/src/main/java/org/apache/aries/rsa/core/ClientServiceFactory.java
----------------------------------------------------------------------
diff --git a/rsa/src/main/java/org/apache/aries/rsa/core/ClientServiceFactory.java b/rsa/src/main/java/org/apache/aries/rsa/core/ClientServiceFactory.java
index 54bbc54..b9aec0c 100644
--- a/rsa/src/main/java/org/apache/aries/rsa/core/ClientServiceFactory.java
+++ b/rsa/src/main/java/org/apache/aries/rsa/core/ClientServiceFactory.java
@@ -21,7 +21,6 @@ package org.apache.aries.rsa.core;
 import java.security.AccessController;
 import java.security.PrivilegedAction;
 import java.util.ArrayList;
-import java.util.Arrays;
 import java.util.List;
 
 import org.apache.aries.rsa.spi.DistributionProvider;
@@ -85,9 +84,6 @@ public class ClientServiceFactory implements ServiceFactory {
     }
 
     public void ungetService(Bundle requestingBundle, ServiceRegistration sreg, Object serviceObject) {
-        String[] interfaces = (String[])sreg.getReference().getProperty(org.osgi.framework.Constants.OBJECTCLASS);
-        LOG.info("Releasing a client object, interfaces: {}", Arrays.toString(interfaces));
-
         synchronized (this) {
             serviceCounter--;
             LOG.debug("Services still provided by this ServiceFactory: {}", serviceCounter);

http://git-wip-us.apache.org/repos/asf/aries-rsa/blob/69bb901e/spi/pom.xml
----------------------------------------------------------------------
diff --git a/spi/pom.xml b/spi/pom.xml
index da2a348..3f3b8a7 100644
--- a/spi/pom.xml
+++ b/spi/pom.xml
@@ -1,3 +1,22 @@
+<?xml version='1.0' encoding='UTF-8' ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements. See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership. The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License. You may obtain a copy of the License at
+
+  http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied. See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
 <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
     xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
     <modelVersion>4.0.0</modelVersion>


[5/5] aries-rsa git commit: Adding roundtrip test

Posted by cs...@apache.org.
Adding roundtrip test


Project: http://git-wip-us.apache.org/repos/asf/aries-rsa/repo
Commit: http://git-wip-us.apache.org/repos/asf/aries-rsa/commit/69bb901e
Tree: http://git-wip-us.apache.org/repos/asf/aries-rsa/tree/69bb901e
Diff: http://git-wip-us.apache.org/repos/asf/aries-rsa/diff/69bb901e

Branch: refs/heads/master
Commit: 69bb901e935452f25ae1ed8ba86484b33deb1bd5
Parents: bd0352f
Author: Christian Schneider <ch...@die-schneider.net>
Authored: Mon Mar 14 17:49:19 2016 +0100
Committer: Christian Schneider <ch...@die-schneider.net>
Committed: Mon Mar 14 17:49:19 2016 +0100

----------------------------------------------------------------------
 discovery/pom.xml                               |   2 -
 discovery/zookeeper-server-config/bnd.bnd       |   1 -
 discovery/zookeeper-server-config/pom.xml       |  40 ---
 .../zookeeper/server/config/Activator.java      | 110 -------
 discovery/zookeeper-server/bnd.bnd              |   1 -
 discovery/zookeeper-server/pom.xml              |  50 ---
 .../discovery/zookeeper/server/Activator.java   |  44 ---
 .../dosgi/discovery/zookeeper/server/Utils.java | 108 -------
 .../zookeeper/server/ZookeeperStarter.java      | 164 ----------
 .../resources/OSGI-INF/metatype/zookeeper.xml   |  34 ---
 .../zookeeper/server/ZookeeperStarterTest.java  |  81 -----
 discovery/zookeeper/bnd.bnd                     |   3 +-
 .../rsa/discovery/zookeeper/Activator.java      |  58 ++++
 .../discovery/zookeeper/ZooKeeperDiscovery.java | 186 ++++++++++++
 .../zookeeper/publish/DiscoveryPlugin.java      |  54 ++++
 .../publish/PublishingEndpointListener.java     | 210 +++++++++++++
 .../PublishingEndpointListenerFactory.java      | 105 +++++++
 .../rsa/discovery/zookeeper/server/Utils.java   | 108 +++++++
 .../zookeeper/server/ZookeeperStarter.java      | 164 ++++++++++
 .../subscribe/EndpointListenerTracker.java      |  56 ++++
 .../zookeeper/subscribe/InterfaceMonitor.java   | 262 ++++++++++++++++
 .../subscribe/InterfaceMonitorManager.java      | 261 ++++++++++++++++
 .../rsa/discovery/zookeeper/util/Utils.java     |  54 ++++
 .../dosgi/discovery/zookeeper/Activator.java    |  43 ---
 .../discovery/zookeeper/ZooKeeperDiscovery.java | 186 ------------
 .../zookeeper/publish/DiscoveryPlugin.java      |  54 ----
 .../publish/PublishingEndpointListener.java     | 210 -------------
 .../PublishingEndpointListenerFactory.java      | 105 -------
 .../subscribe/EndpointListenerTracker.java      |  56 ----
 .../zookeeper/subscribe/InterfaceMonitor.java   | 262 ----------------
 .../subscribe/InterfaceMonitorManager.java      | 261 ----------------
 .../dosgi/discovery/zookeeper/util/Utils.java   |  54 ----
 .../resources/OSGI-INF/metatype/zookeeper.xml   |  34 +++
 .../zookeeper/DiscoveryDriverTest.java          | 135 +++++++++
 .../FindInZooKeeperCustomizerTest.java          | 301 +++++++++++++++++++
 .../InterfaceDataMonitorListenerImplTest.java   | 183 +++++++++++
 .../zookeeper/ZookeeperDiscoveryTest.java       |  56 ++++
 .../PublishingEndpointListenerFactoryTest.java  | 102 +++++++
 .../publish/PublishingEndpointListenerTest.java | 209 +++++++++++++
 .../zookeeper/server/ZookeeperStarterTest.java  |  82 +++++
 .../subscribe/InterfaceMonitorManagerTest.java  | 113 +++++++
 .../subscribe/InterfaceMonitorTest.java         |  68 +++++
 .../rsa/discovery/zookeeper/util/UtilsTest.java |  37 +++
 .../zookeeper/DiscoveryDriverTest.java          | 135 ---------
 .../FindInZooKeeperCustomizerTest.java          | 301 -------------------
 .../InterfaceDataMonitorListenerImplTest.java   | 183 -----------
 .../zookeeper/ZookeeperDiscoveryTest.java       |  55 ----
 .../PublishingEndpointListenerFactoryTest.java  | 100 ------
 .../publish/PublishingEndpointListenerTest.java | 207 -------------
 .../subscribe/InterfaceMonitorManagerTest.java  | 112 -------
 .../subscribe/InterfaceMonitorTest.java         |  67 -----
 .../discovery/zookeeper/util/UtilsTest.java     |  35 ---
 examples/echotcp/Readme.md                      |  44 +++
 examples/echotcp/api/bnd.bnd                    |   1 +
 examples/echotcp/api/pom.xml                    |  11 +
 .../rsa/examples/echotcp/api/EchoService.java   |   5 +
 .../aries/rsa/examples/echotcp/api/packageinfo  |  19 ++
 examples/echotcp/consumer/bnd.bnd               |   1 +
 examples/echotcp/consumer/pom.xml               |  39 +++
 .../examples/echotcp/consumer/EchoConsumer.java |  41 +++
 examples/echotcp/pom.xml                        |  76 +++++
 examples/echotcp/service/bnd.bnd                |   1 +
 examples/echotcp/service/pom.xml                |  39 +++
 .../echotcp/service/EchoServiceImpl.java        |  14 +
 examples/pom.xml                                |  43 +++
 features/src/main/resources/features.xml        |   4 -
 itests/felix/pom.xml                            |  35 ++-
 .../aries/rsa/itests/felix/RsaTestBase.java     | 120 ++++++++
 .../rsa/itests/felix/TestDiscoveryExport.java   |  90 +-----
 .../aries/rsa/itests/felix/TestRoundTrip.java   |  88 ++++++
 .../felix/ZookeeperDiscoveryConfigurer.java     |  28 ++
 .../itests/felix/ZookeeperServerConfigurer.java |  32 ++
 itests/pom.xml                                  |   1 -
 itests/testbundle-service-tcp/bnd.bnd           |   3 -
 itests/testbundle-service-tcp/pom.xml           |  40 ---
 .../aries/rsa/itests/tcp/api/EchoService.java   |   5 -
 .../aries/rsa/itests/tcp/service/Activator.java |  25 --
 .../rsa/itests/tcp/service/EchoServiceImpl.java |  12 -
 pom.xml                                         |   1 +
 .../aries/rsa/core/ClientServiceFactory.java    |   4 -
 spi/pom.xml                                     |  19 ++
 81 files changed, 3503 insertions(+), 3240 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/aries-rsa/blob/69bb901e/discovery/pom.xml
----------------------------------------------------------------------
diff --git a/discovery/pom.xml b/discovery/pom.xml
index 40b5f80..9fc449b 100644
--- a/discovery/pom.xml
+++ b/discovery/pom.xml
@@ -34,7 +34,5 @@
     <modules>
       <module>local</module>
       <module>zookeeper</module>
-      <module>zookeeper-server</module>
-      <module>zookeeper-server-config</module>
     </modules>
 </project>

http://git-wip-us.apache.org/repos/asf/aries-rsa/blob/69bb901e/discovery/zookeeper-server-config/bnd.bnd
----------------------------------------------------------------------
diff --git a/discovery/zookeeper-server-config/bnd.bnd b/discovery/zookeeper-server-config/bnd.bnd
deleted file mode 100644
index 769558e..0000000
--- a/discovery/zookeeper-server-config/bnd.bnd
+++ /dev/null
@@ -1 +0,0 @@
-Bundle-Activator: org.apache.cxf.dosgi.discovery.zookeeper.server.config.Activator

http://git-wip-us.apache.org/repos/asf/aries-rsa/blob/69bb901e/discovery/zookeeper-server-config/pom.xml
----------------------------------------------------------------------
diff --git a/discovery/zookeeper-server-config/pom.xml b/discovery/zookeeper-server-config/pom.xml
deleted file mode 100644
index 4f7ac7a..0000000
--- a/discovery/zookeeper-server-config/pom.xml
+++ /dev/null
@@ -1,40 +0,0 @@
-<?xml version='1.0' encoding='UTF-8' ?>
-<!--
-  Licensed to the Apache Software Foundation (ASF) under one
-  or more contributor license agreements. See the NOTICE file
-  distributed with this work for additional information
-  regarding copyright ownership. The ASF licenses this file
-  to you under the Apache License, Version 2.0 (the
-  "License"); you may not use this file except in compliance
-  with the License. You may obtain a copy of the License at
-
-  http://www.apache.org/licenses/LICENSE-2.0
-
-  Unless required by applicable law or agreed to in writing,
-  software distributed under the License is distributed on an
-  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
-  KIND, either express or implied. See the License for the
-  specific language governing permissions and limitations
-  under the License.
--->
-<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
-
-    <modelVersion>4.0.0</modelVersion>
-
-    <parent>
-      <groupId>org.apache.aries.rsa</groupId>
-      <artifactId>parent</artifactId>
-      <version>1.8-SNAPSHOT</version>
-      <relativePath>../../parent/pom.xml</relativePath>
-    </parent>
-    
-    <groupId>org.apache.aries.rsa.discovery</groupId>
-    <artifactId>zookeeper-server-config</artifactId>
-    <packaging>bundle</packaging>
-    <name>Aries Remote Service Admin Discovery Zookeeper Config</name>
-
-    <properties>
-        <topDirectoryLocation>../..</topDirectoryLocation>
-    </properties>
-
-</project>

http://git-wip-us.apache.org/repos/asf/aries-rsa/blob/69bb901e/discovery/zookeeper-server-config/src/main/java/org/apache/cxf/dosgi/discovery/zookeeper/server/config/Activator.java
----------------------------------------------------------------------
diff --git a/discovery/zookeeper-server-config/src/main/java/org/apache/cxf/dosgi/discovery/zookeeper/server/config/Activator.java b/discovery/zookeeper-server-config/src/main/java/org/apache/cxf/dosgi/discovery/zookeeper/server/config/Activator.java
deleted file mode 100644
index e92fe0b..0000000
--- a/discovery/zookeeper-server-config/src/main/java/org/apache/cxf/dosgi/discovery/zookeeper/server/config/Activator.java
+++ /dev/null
@@ -1,110 +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.cxf.dosgi.discovery.zookeeper.server.config;
-
-import java.io.IOException;
-import java.net.ServerSocket;
-import java.util.Dictionary;
-import java.util.Hashtable;
-
-import org.osgi.framework.BundleActivator;
-import org.osgi.framework.BundleContext;
-import org.osgi.framework.ServiceReference;
-import org.osgi.service.cm.Configuration;
-import org.osgi.service.cm.ConfigurationAdmin;
-import org.osgi.service.cm.ManagedService;
-import org.osgi.util.tracker.ServiceTracker;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-public class Activator implements BundleActivator {
-
-    private static final Logger LOG = LoggerFactory.getLogger(Activator.class);
-    private static final String ZOOKEEPER_PORT = "org.apache.aries.rsa.discovery.zookeeper.port";
-    private static final String PID = "org.apache.aries.rsa.discovery.zookeeper.server";
-    private ServiceTracker<ConfigurationAdmin, ConfigurationAdmin> st;
-
-    public void start(BundleContext context) throws Exception {
-        synchronized (Activator.class) {
-            // Only one thread gets to set the port number
-            if (System.getProperty(ZOOKEEPER_PORT) == null) {
-                String port = getFreePort();
-                System.setProperty(ZOOKEEPER_PORT, port);
-                LOG.info("Global ZooKeeper port: {}", port);
-            }
-        }
-
-        st = new ServiceTracker<ConfigurationAdmin, ConfigurationAdmin>(context, ConfigurationAdmin.class, null) {
-            @Override
-            public ConfigurationAdmin addingService(ServiceReference<ConfigurationAdmin> reference) {
-                ConfigurationAdmin service = super.addingService(reference);
-                try {
-                    Configuration cfg = service.getConfiguration(PID, null);
-                    Dictionary<String, Object> props = new Hashtable<String, Object>();
-                    String zp = System.getProperty(ZOOKEEPER_PORT);
-                    props.put("clientPort", zp);
-                    cfg.update(props);
-                    LOG.debug("Set ZooKeeper client port to {}", zp);
-                } catch (IOException e) {
-                    LOG.error("Failed to configure ZooKeeper server!", e);
-                }
-                return service;
-            }
-        };
-        st.open();
-
-        // The following section is done synchronously otherwise it doesn't happen in time for the CT
-        ServiceReference<?>[] refs = context.getServiceReferences(ManagedService.class.getName(),
-                "(service.pid=org.apache.cxf.dosgi.discovery.zookeeper)");
-        if (refs == null || refs.length == 0) {
-            throw new RuntimeException("This bundle must be started after the bundle with the ZooKeeper "
-                                       + "Discovery Managed Service was started.");
-        }
-
-        Dictionary<String, Object> props = new Hashtable<String, Object>();
-        props.put("zookeeper.host", "127.0.0.1");
-        props.put("zookeeper.port", System.getProperty(ZOOKEEPER_PORT));
-
-        ManagedService ms = (ManagedService) context.getService(refs[0]);
-        try {
-            ms.updated(props);
-        } finally {
-            if (ms != null) {
-                context.ungetService(refs[0]);
-            }
-        }
-        LOG.debug("Passed the zookeeper.host property to the ZooKeeper Client managed service.");
-    }
-
-    private String getFreePort() {
-        try {
-            ServerSocket ss = new ServerSocket(0);
-            String port = "" + ss.getLocalPort();
-            ss.close();
-            return port;
-        } catch (IOException e) {
-            LOG.error("Failed to find a free port!", e);
-            return null;
-        }
-    }
-
-    public void stop(BundleContext context) throws Exception {
-        st.close();
-    }
-}

http://git-wip-us.apache.org/repos/asf/aries-rsa/blob/69bb901e/discovery/zookeeper-server/bnd.bnd
----------------------------------------------------------------------
diff --git a/discovery/zookeeper-server/bnd.bnd b/discovery/zookeeper-server/bnd.bnd
deleted file mode 100644
index cef642b..0000000
--- a/discovery/zookeeper-server/bnd.bnd
+++ /dev/null
@@ -1 +0,0 @@
-Bundle-Activator: org.apache.cxf.dosgi.discovery.zookeeper.server.Activator

http://git-wip-us.apache.org/repos/asf/aries-rsa/blob/69bb901e/discovery/zookeeper-server/pom.xml
----------------------------------------------------------------------
diff --git a/discovery/zookeeper-server/pom.xml b/discovery/zookeeper-server/pom.xml
deleted file mode 100644
index e6bcdba..0000000
--- a/discovery/zookeeper-server/pom.xml
+++ /dev/null
@@ -1,50 +0,0 @@
-<?xml version='1.0' encoding='UTF-8' ?>
-<!--
-  Licensed to the Apache Software Foundation (ASF) under one
-  or more contributor license agreements. See the NOTICE file
-  distributed with this work for additional information
-  regarding copyright ownership. The ASF licenses this file
-  to you under the Apache License, Version 2.0 (the
-  "License"); you may not use this file except in compliance
-  with the License. You may obtain a copy of the License at
-
-  http://www.apache.org/licenses/LICENSE-2.0
-
-  Unless required by applicable law or agreed to in writing,
-  software distributed under the License is distributed on an
-  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
-  KIND, either express or implied. See the License for the
-  specific language governing permissions and limitations
-  under the License.
--->
-<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
-
-    <modelVersion>4.0.0</modelVersion>
-
-    <parent>
-      <groupId>org.apache.aries.rsa</groupId>
-      <artifactId>parent</artifactId>
-      <version>1.8-SNAPSHOT</version>
-      <relativePath>../../parent/pom.xml</relativePath>
-    </parent>
-    
-    <groupId>org.apache.aries.rsa.discovery</groupId>
-    <artifactId>zookeeper-server</artifactId>
-    <packaging>bundle</packaging>
-    <name>Aries Remote Service Admin Discovery Zookeeper Server</name>
-    
-
-    <properties>
-        <topDirectoryLocation>../..</topDirectoryLocation>
-    </properties>
-
-    <dependencies>
-        <dependency>
-            <groupId>org.apache.zookeeper</groupId>
-            <artifactId>zookeeper</artifactId>
-            <scope>provided</scope>
-        </dependency>
-
-    </dependencies>
-
-</project>

http://git-wip-us.apache.org/repos/asf/aries-rsa/blob/69bb901e/discovery/zookeeper-server/src/main/java/org/apache/cxf/dosgi/discovery/zookeeper/server/Activator.java
----------------------------------------------------------------------
diff --git a/discovery/zookeeper-server/src/main/java/org/apache/cxf/dosgi/discovery/zookeeper/server/Activator.java b/discovery/zookeeper-server/src/main/java/org/apache/cxf/dosgi/discovery/zookeeper/server/Activator.java
deleted file mode 100644
index 17c5568..0000000
--- a/discovery/zookeeper-server/src/main/java/org/apache/cxf/dosgi/discovery/zookeeper/server/Activator.java
+++ /dev/null
@@ -1,44 +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.cxf.dosgi.discovery.zookeeper.server;
-
-import java.util.Dictionary;
-import java.util.Hashtable;
-
-import org.osgi.framework.BundleActivator;
-import org.osgi.framework.BundleContext;
-import org.osgi.framework.Constants;
-
-public class Activator implements BundleActivator {
-
-    ZookeeperStarter zkStarter;
-
-    public void start(BundleContext context) throws Exception {
-        zkStarter = new ZookeeperStarter(context);
-        Dictionary<String, Object> props = new Hashtable<String, Object>();
-        props.put(Constants.SERVICE_PID, "org.apache.aries.rsa.discovery.zookeeper.server");
-        context.registerService(org.osgi.service.cm.ManagedService.class.getName(), zkStarter, props);
-    }
-
-    public void stop(BundleContext context) throws Exception {
-        if (zkStarter != null) {
-            zkStarter.shutdown();
-        }
-    }
-}

http://git-wip-us.apache.org/repos/asf/aries-rsa/blob/69bb901e/discovery/zookeeper-server/src/main/java/org/apache/cxf/dosgi/discovery/zookeeper/server/Utils.java
----------------------------------------------------------------------
diff --git a/discovery/zookeeper-server/src/main/java/org/apache/cxf/dosgi/discovery/zookeeper/server/Utils.java b/discovery/zookeeper-server/src/main/java/org/apache/cxf/dosgi/discovery/zookeeper/server/Utils.java
deleted file mode 100644
index fe3c663..0000000
--- a/discovery/zookeeper-server/src/main/java/org/apache/cxf/dosgi/discovery/zookeeper/server/Utils.java
+++ /dev/null
@@ -1,108 +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.cxf.dosgi.discovery.zookeeper.server;
-
-import java.util.ArrayList;
-import java.util.Dictionary;
-import java.util.Enumeration;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.Properties;
-
-/**
- * General purpose utility methods.
- */
-public final class Utils {
-
-    private Utils() {
-        // prevent instantiation
-    }
-
-    /**
-     * Remove entries whose values are empty from the given dictionary.
-     *
-     * @param dict a dictionary
-     */
-    public static void removeEmptyValues(Dictionary<String, ?> dict) {
-        List<String> keysToRemove = new ArrayList<String>();
-        Enumeration<String> keys = dict.keys();
-        while (keys.hasMoreElements()) {
-            String key = keys.nextElement();
-            Object value = dict.get(key);
-            if (value instanceof String && "".equals(value)) {
-                keysToRemove.add(key);
-            }
-        }
-        for (String key : keysToRemove) {
-            dict.remove(key);
-        }
-    }
-
-    /**
-     * Puts the given key-value pair in the given dictionary if the key does not
-     * already exist in it or if its existing value is null.
-     *
-     * @param dict a dictionary
-     * @param key the key
-     * @param value the default value to set
-     */
-    public static void setDefault(Dictionary<String, String> dict, String key, String value) {
-        if (dict.get(key) == null) {
-            dict.put(key, value);
-        }
-    }
-
-    /**
-     * Converts the given Dictionary to a Map.
-     *
-     * @param dict a dictionary
-     * @param <K> the key type
-     * @param <V> the value type
-     * @return the converted map, or an empty map if the given dictionary is null
-     */
-    public static <K, V> Map<K, V> toMap(Dictionary<K, V> dict) {
-        Map<K, V> map = new HashMap<K, V>();
-        if (dict != null) {
-            Enumeration<K> keys = dict.keys();
-            while (keys.hasMoreElements()) {
-                K key = keys.nextElement();
-                map.put(key, dict.get(key));
-            }
-        }
-        return map;
-    }
-
-    /**
-     * Converts a Dictionary into a Properties instance.
-     *
-     * @param dict a dictionary
-     * @param <K> the key type
-     * @param <V> the value type
-     * @return the properties
-     */
-    public static <K, V> Properties toProperties(Dictionary<K, V> dict) {
-        Properties props = new Properties();
-        for (Enumeration<K> e = dict.keys(); e.hasMoreElements();) {
-            K key = e.nextElement();
-            props.put(key, dict.get(key));
-        }
-        return props;
-    }
-}

http://git-wip-us.apache.org/repos/asf/aries-rsa/blob/69bb901e/discovery/zookeeper-server/src/main/java/org/apache/cxf/dosgi/discovery/zookeeper/server/ZookeeperStarter.java
----------------------------------------------------------------------
diff --git a/discovery/zookeeper-server/src/main/java/org/apache/cxf/dosgi/discovery/zookeeper/server/ZookeeperStarter.java b/discovery/zookeeper-server/src/main/java/org/apache/cxf/dosgi/discovery/zookeeper/server/ZookeeperStarter.java
deleted file mode 100644
index bd5618f..0000000
--- a/discovery/zookeeper-server/src/main/java/org/apache/cxf/dosgi/discovery/zookeeper/server/ZookeeperStarter.java
+++ /dev/null
@@ -1,164 +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.cxf.dosgi.discovery.zookeeper.server;
-
-import java.io.File;
-import java.io.IOException;
-import java.util.Dictionary;
-import java.util.Map;
-
-import org.apache.zookeeper.server.ServerConfig;
-import org.apache.zookeeper.server.ZooKeeperServerMain;
-import org.apache.zookeeper.server.quorum.QuorumPeerConfig;
-import org.apache.zookeeper.server.quorum.QuorumPeerConfig.ConfigException;
-import org.apache.zookeeper.server.quorum.QuorumPeerMain;
-import org.osgi.framework.BundleContext;
-import org.osgi.service.cm.ConfigurationException;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-public class ZookeeperStarter implements org.osgi.service.cm.ManagedService {
-
-    private static final Logger LOG = LoggerFactory.getLogger(ZookeeperStarter.class); //NOPMD - using log4j here
-
-    protected ZookeeperServer main;
-    private final BundleContext bundleContext;
-    private Thread zkMainThread;
-    private Map<String, ?> curConfiguration;
-
-    public ZookeeperStarter(BundleContext ctx) {
-        bundleContext = ctx;
-    }
-
-    synchronized void shutdown() {
-        if (main != null) {
-            LOG.info("Shutting down ZooKeeper server");
-            try {
-                main.shutdown();
-                if (zkMainThread != null) {
-                    zkMainThread.join();
-                }
-            } catch (Throwable e) {
-                LOG.error(e.getMessage(), e);
-            }
-            main = null;
-            zkMainThread = null;
-        }
-    }
-
-    private void setDefaults(Dictionary<String, String> dict) throws IOException {
-        Utils.removeEmptyValues(dict); // to avoid NumberFormatExceptions
-        Utils.setDefault(dict, "tickTime", "2000");
-        Utils.setDefault(dict, "initLimit", "10");
-        Utils.setDefault(dict, "syncLimit", "5");
-        Utils.setDefault(dict, "clientPort", "2181");
-        Utils.setDefault(dict, "dataDir", new File(bundleContext.getDataFile(""), "zkdata").getCanonicalPath());
-    }
-
-    @SuppressWarnings("unchecked")
-    public synchronized void updated(Dictionary<String, ?> dict) throws ConfigurationException {
-        LOG.debug("Received configuration update for Zookeeper Server: " + dict);
-        try {
-            if (dict != null) {
-                setDefaults((Dictionary<String, String>)dict);
-            }
-            Map<String, ?> configMap = Utils.toMap(dict);
-            if (!configMap.equals(curConfiguration)) { // only if something actually changed
-                shutdown();
-                curConfiguration = configMap;
-                // config is null if it doesn't exist, is being deleted or has not yet been loaded
-                // in which case we just stop running
-                if (dict != null) {
-                    startFromConfig(parseConfig(dict));
-                    LOG.info("Applied configuration update: " + dict);
-                }
-            }
-        } catch (Exception th) {
-            LOG.error("Problem applying configuration update: " + dict, th);
-        }
-    }
-
-    private QuorumPeerConfig parseConfig(Dictionary<String, ?> dict) throws IOException, ConfigException {
-        QuorumPeerConfig config = new QuorumPeerConfig();
-        config.parseProperties(Utils.toProperties(dict));
-        return config;
-    }
-
-    protected void startFromConfig(final QuorumPeerConfig config) {
-        int numServers = config.getServers().size();
-        main = numServers > 1 ? new MyQuorumPeerMain(config) : new MyZooKeeperServerMain(config);
-        zkMainThread = new Thread(new Runnable() {
-            public void run() {
-                try {
-                    main.startup();
-                } catch (Throwable e) {
-                    LOG.error("Problem running ZooKeeper server.", e);
-                }
-            }
-        });
-        zkMainThread.start();
-    }
-
-    interface ZookeeperServer {
-        void startup() throws IOException;
-        void shutdown();
-    }
-
-    static class MyQuorumPeerMain extends QuorumPeerMain implements ZookeeperServer {
-
-        private QuorumPeerConfig config;
-
-        MyQuorumPeerMain(QuorumPeerConfig config) {
-            this.config = config;
-        }
-
-        public void startup() throws IOException {
-            runFromConfig(config);
-        }
-
-        public void shutdown() {
-            if (null != quorumPeer) {
-                quorumPeer.shutdown();
-            }
-        }
-    }
-
-    static class MyZooKeeperServerMain extends ZooKeeperServerMain implements ZookeeperServer {
-
-        private QuorumPeerConfig config;
-
-        MyZooKeeperServerMain(QuorumPeerConfig config) {
-            this.config = config;
-        }
-
-        public void startup() throws IOException {
-            ServerConfig serverConfig = new ServerConfig();
-            serverConfig.readFrom(config);
-            runFromConfig(serverConfig);
-        }
-
-        public void shutdown() {
-            try {
-                super.shutdown();
-            } catch (Exception e) {
-                LOG.error("Error shutting down ZooKeeper", e);
-            }
-        }
-    }
-}

http://git-wip-us.apache.org/repos/asf/aries-rsa/blob/69bb901e/discovery/zookeeper-server/src/main/resources/OSGI-INF/metatype/zookeeper.xml
----------------------------------------------------------------------
diff --git a/discovery/zookeeper-server/src/main/resources/OSGI-INF/metatype/zookeeper.xml b/discovery/zookeeper-server/src/main/resources/OSGI-INF/metatype/zookeeper.xml
deleted file mode 100644
index efd9403..0000000
--- a/discovery/zookeeper-server/src/main/resources/OSGI-INF/metatype/zookeeper.xml
+++ /dev/null
@@ -1,34 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
-  Licensed to the Apache Software Foundation (ASF) under one
-  or more contributor license agreements. See the NOTICE file
-  distributed with this work for additional information
-  regarding copyright ownership. The ASF licenses this file
-  to you under the Apache License, Version 2.0 (the
-  "License"); you may not use this file except in compliance
-  with the License. You may obtain a copy of the License at
-
-  http://www.apache.org/licenses/LICENSE-2.0
-
-  Unless required by applicable law or agreed to in writing,
-  software distributed under the License is distributed on an
-  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
-  KIND, either express or implied. See the License for the
-  specific language governing permissions and limitations
-  under the License.
--->
-<MetaData xmlns="http://www.osgi.org/xmlns/metadata/v1.0.0"
-	 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
-	 xsi:schemaLocation="
-		 http://www.osgi.org/xmlns/metadata/v1.0.0 http://www.osgi.org/xmlns/metatype/v1.1.0/metatype.xsd
-	 ">
-	 <OCD description="" name="Zookeeper server config" id="org.apache.cxf.dosgi.discovery.zookeeper.server">
-        <AD id="clientPort" required="false" type="String" default="2181" description=""/>
-	 	<AD id="tickTime" required="false" type="String" default="2000" description=""/>
-        <AD id="initLimit" required="false" type="String" default="10" description=""/>
-        <AD id="syncLimit" required="false" type="String" default="5" description=""/>
-	 </OCD>
-	 <Designate pid="org.apache.cxf.dosgi.discovery.zookeeper.server">
-	 	<Object ocdref="org.apache.cxf.dosgi.discovery.zookeeper.server"/>
-	 </Designate>
-</MetaData>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/aries-rsa/blob/69bb901e/discovery/zookeeper-server/src/test/java/org/apache/cxf/dosgi/discovery/zookeeper/server/ZookeeperStarterTest.java
----------------------------------------------------------------------
diff --git a/discovery/zookeeper-server/src/test/java/org/apache/cxf/dosgi/discovery/zookeeper/server/ZookeeperStarterTest.java b/discovery/zookeeper-server/src/test/java/org/apache/cxf/dosgi/discovery/zookeeper/server/ZookeeperStarterTest.java
deleted file mode 100644
index 17ca117..0000000
--- a/discovery/zookeeper-server/src/test/java/org/apache/cxf/dosgi/discovery/zookeeper/server/ZookeeperStarterTest.java
+++ /dev/null
@@ -1,81 +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.cxf.dosgi.discovery.zookeeper.server;
-
-import java.io.File;
-import java.util.Dictionary;
-import java.util.Hashtable;
-
-import junit.framework.TestCase;
-
-import org.apache.cxf.dosgi.discovery.zookeeper.server.ZookeeperStarter.MyZooKeeperServerMain;
-import org.apache.zookeeper.server.quorum.QuorumPeerConfig;
-import org.easymock.classextension.EasyMock;
-import org.easymock.classextension.IMocksControl;
-import org.osgi.framework.BundleContext;
-
-import static org.easymock.EasyMock.expect;
-import static org.easymock.classextension.EasyMock.replay;
-import static org.easymock.classextension.EasyMock.verify;
-
-public class ZookeeperStarterTest extends TestCase {
-
-    public void testUpdateConfig() throws Exception {
-        final File tempDir = new File("target");
-        IMocksControl control = EasyMock.createControl();
-        BundleContext bc = control.createMock(BundleContext.class);
-        expect(bc.getDataFile("")).andReturn(tempDir);
-        final MyZooKeeperServerMain mockServer = control.createMock(MyZooKeeperServerMain.class);
-        control.replay();
-
-        ZookeeperStarter starter = new ZookeeperStarter(bc) {
-            @Override
-            protected void startFromConfig(QuorumPeerConfig config) {
-                assertEquals(1234, config.getClientPortAddress().getPort());
-                assertTrue(config.getDataDir().contains(tempDir + File.separator + "zkdata"));
-                assertEquals(2000, config.getTickTime());
-                assertEquals(10, config.getInitLimit());
-                assertEquals(5, config.getSyncLimit());
-                this.main = mockServer;
-            }
-        };
-        Dictionary<String, Object> props = new Hashtable<String, Object>();
-        props.put("clientPort", "1234");
-        starter.updated(props);
-        assertNotNull(starter.main);
-
-        control.verify();
-    }
-
-    public void testRemoveConfiguration() throws Exception {
-        BundleContext bc = EasyMock.createMock(BundleContext.class);
-        MyZooKeeperServerMain zkServer = EasyMock.createMock(MyZooKeeperServerMain.class);
-        zkServer.shutdown();
-        EasyMock.expectLastCall();
-
-        replay(zkServer);
-
-        ZookeeperStarter starter = new ZookeeperStarter(bc);
-        starter.main = zkServer;
-        starter.updated(null);
-
-        verify(zkServer);
-        assertNull("main should be null", starter.main);
-    }
-}

http://git-wip-us.apache.org/repos/asf/aries-rsa/blob/69bb901e/discovery/zookeeper/bnd.bnd
----------------------------------------------------------------------
diff --git a/discovery/zookeeper/bnd.bnd b/discovery/zookeeper/bnd.bnd
index 5c1f23d..3e572c6 100644
--- a/discovery/zookeeper/bnd.bnd
+++ b/discovery/zookeeper/bnd.bnd
@@ -1 +1,2 @@
-Bundle-Activator:  org.apache.cxf.dosgi.discovery.zookeeper.Activator
+Bundle-Activator: org.apache.aries.rsa.discovery.zookeeper.Activator
+

http://git-wip-us.apache.org/repos/asf/aries-rsa/blob/69bb901e/discovery/zookeeper/src/main/java/org/apache/aries/rsa/discovery/zookeeper/Activator.java
----------------------------------------------------------------------
diff --git a/discovery/zookeeper/src/main/java/org/apache/aries/rsa/discovery/zookeeper/Activator.java b/discovery/zookeeper/src/main/java/org/apache/aries/rsa/discovery/zookeeper/Activator.java
new file mode 100644
index 0000000..3b17f35
--- /dev/null
+++ b/discovery/zookeeper/src/main/java/org/apache/aries/rsa/discovery/zookeeper/Activator.java
@@ -0,0 +1,58 @@
+/**
+ * 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.aries.rsa.discovery.zookeeper;
+
+import java.util.Dictionary;
+import java.util.Hashtable;
+
+import org.apache.aries.rsa.discovery.zookeeper.server.ZookeeperStarter;
+import org.osgi.framework.BundleActivator;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.Constants;
+import org.osgi.service.cm.ManagedService;
+
+public class Activator implements BundleActivator {
+
+    private static final String PID_DISCOVERY_ZOOKEEPER = "org.apache.aries.rsa.discovery.zookeeper";
+    private static final String PID_ZOOKEEPER_SERVER    = "org.apache.aries.rsa.discovery.zookeeper.server";
+    private ZooKeeperDiscovery zkd;
+    private ZookeeperStarter zkStarter;
+
+    public synchronized void start(BundleContext bc) throws Exception {
+        zkd = new ZooKeeperDiscovery(bc);
+        bc.registerService(ManagedService.class, zkd, configProperties(PID_DISCOVERY_ZOOKEEPER));
+        
+        zkStarter = new ZookeeperStarter(bc);
+        bc.registerService(ManagedService.class, zkStarter, configProperties(PID_ZOOKEEPER_SERVER));
+    }
+
+    public synchronized void stop(BundleContext bc) throws Exception {
+        zkd.stop(true);
+        
+        if (zkStarter != null) {
+            zkStarter.shutdown();
+        }
+    }
+    
+    private Dictionary<String, String> configProperties(String pid) {
+        Dictionary<String, String> props = new Hashtable<String, String>();
+        props.put(Constants.SERVICE_PID, pid);
+        return props;
+    }
+}

http://git-wip-us.apache.org/repos/asf/aries-rsa/blob/69bb901e/discovery/zookeeper/src/main/java/org/apache/aries/rsa/discovery/zookeeper/ZooKeeperDiscovery.java
----------------------------------------------------------------------
diff --git a/discovery/zookeeper/src/main/java/org/apache/aries/rsa/discovery/zookeeper/ZooKeeperDiscovery.java b/discovery/zookeeper/src/main/java/org/apache/aries/rsa/discovery/zookeeper/ZooKeeperDiscovery.java
new file mode 100644
index 0000000..085c074
--- /dev/null
+++ b/discovery/zookeeper/src/main/java/org/apache/aries/rsa/discovery/zookeeper/ZooKeeperDiscovery.java
@@ -0,0 +1,186 @@
+/**
+ * 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.aries.rsa.discovery.zookeeper;
+
+import java.io.IOException;
+import java.util.Dictionary;
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.apache.aries.rsa.discovery.zookeeper.publish.PublishingEndpointListenerFactory;
+import org.apache.aries.rsa.discovery.zookeeper.subscribe.EndpointListenerTracker;
+import org.apache.aries.rsa.discovery.zookeeper.subscribe.InterfaceMonitorManager;
+import org.apache.zookeeper.WatchedEvent;
+import org.apache.zookeeper.Watcher;
+import org.apache.zookeeper.ZooKeeper;
+import org.osgi.framework.BundleContext;
+import org.osgi.service.cm.ConfigurationException;
+import org.osgi.service.cm.ManagedService;
+import org.osgi.service.remoteserviceadmin.EndpointListener;
+import org.osgi.util.tracker.ServiceTracker;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class ZooKeeperDiscovery implements Watcher, ManagedService {
+
+    public static final String DISCOVERY_ZOOKEEPER_ID = "org.apache.cxf.dosgi.discovery.zookeeper";
+
+    private static final Logger LOG = LoggerFactory.getLogger(ZooKeeperDiscovery.class);
+
+    private final BundleContext bctx;
+
+    private PublishingEndpointListenerFactory endpointListenerFactory;
+    private ServiceTracker<EndpointListener, EndpointListener> endpointListenerTracker;
+    private InterfaceMonitorManager imManager;
+    private ZooKeeper zkClient;
+    private boolean closed;
+    private boolean started;
+
+    private Dictionary<String, ?> curConfiguration;
+
+    public ZooKeeperDiscovery(BundleContext bctx) {
+        this.bctx = bctx;
+    }
+
+    public synchronized void updated(Dictionary<String, ?> configuration) throws ConfigurationException {
+        LOG.debug("Received configuration update for Zookeeper Discovery: {}", configuration);
+        // make changes only if config actually changed, to prevent unnecessary ZooKeeper reconnections
+        if (!ZooKeeperDiscovery.toMap(configuration).equals(ZooKeeperDiscovery.toMap(curConfiguration))) {
+            stop(false);
+            curConfiguration = configuration;
+            // config is null if it doesn't exist, is being deleted or has not yet been loaded
+            // in which case we just stop running
+            if (!closed && configuration != null) {
+                try {
+                    createZookeeper(configuration);
+                } catch (IOException e) {
+                    throw new ConfigurationException(null, "Error starting zookeeper client", e);
+                }
+            }
+        }
+    }
+
+    private synchronized void start() {
+        if (closed) {
+            return;
+        }
+        if (started) {
+            // we must be re-entrant, i.e. can be called when already started
+            LOG.debug("ZookeeperDiscovery already started");
+            return;
+        }
+        LOG.debug("starting ZookeeperDiscovery");
+        endpointListenerFactory = new PublishingEndpointListenerFactory(zkClient, bctx);
+        endpointListenerFactory.start();
+        imManager = new InterfaceMonitorManager(bctx, zkClient);
+        endpointListenerTracker = new EndpointListenerTracker(bctx, imManager);
+        endpointListenerTracker.open();
+        started = true;
+    }
+
+    public synchronized void stop(boolean close) {
+        if (started) {
+            LOG.debug("stopping ZookeeperDiscovery");
+        }
+        started = false;
+        closed |= close;
+        if (endpointListenerFactory != null) {
+            endpointListenerFactory.stop();
+        }
+        if (endpointListenerTracker != null) {
+            endpointListenerTracker.close();
+        }
+        if (imManager != null) {
+            imManager.close();
+        }
+        if (zkClient != null) {
+            try {
+                zkClient.close();
+            } catch (InterruptedException e) {
+                LOG.error("Error closing ZooKeeper", e);
+            }
+        }
+    }
+
+    protected ZooKeeper createZooKeeper(String host, String port, int timeout) throws IOException {
+        LOG.info("ZooKeeper discovery connecting to {}:{} with timeout {}",
+                new Object[]{host, port, timeout});
+        return new ZooKeeper(host + ":" + port, timeout, this);
+    }
+
+    /* Callback for ZooKeeper */
+    public void process(WatchedEvent event) {
+        LOG.debug("got ZooKeeper event " + event);
+        switch (event.getState()) {
+        case SyncConnected:
+            LOG.info("Connection to ZooKeeper established");
+            // this event can be triggered more than once in a row (e.g. after Disconnected event),
+            // so we must be re-entrant here
+            start();
+            break;
+
+        case Expired:
+            LOG.info("Connection to ZooKeeper expired. Trying to create a new connection");
+            stop(false);
+            try {
+                createZookeeper(curConfiguration);
+            } catch (IOException e) {
+                LOG.error("Error starting zookeeper client", e);
+            }
+            break;
+
+        default:
+            // ignore other events
+            break;
+        }
+    }
+
+    private void createZookeeper(Dictionary<String, ?> config) throws IOException {
+        String host = (String)getWithDefault(config, "zookeeper.host", "localhost");
+        String port = (String)getWithDefault(config, "zookeeper.port", "2181");
+        int timeout = Integer.parseInt((String)getWithDefault(config, "zookeeper.timeout", "3000"));
+        zkClient = createZooKeeper(host, port, timeout);
+    }
+    
+    public Object getWithDefault(Dictionary<String, ?> config, String key, Object defaultValue) {
+        Object value = config.get(key);
+        return value != null ? value : defaultValue;
+    }
+    
+    /**
+     * Converts the given Dictionary to a Map.
+     *
+     * @param dict a dictionary
+     * @param <K> the key type
+     * @param <V> the value type
+     * @return the converted map, or an empty map if the given dictionary is null
+     */
+    public static <K, V> Map<K, V> toMap(Dictionary<K, V> dict) {
+        Map<K, V> map = new HashMap<K, V>();
+        if (dict != null) {
+            Enumeration<K> keys = dict.keys();
+            while (keys.hasMoreElements()) {
+                K key = keys.nextElement();
+                map.put(key, dict.get(key));
+            }
+        }
+        return map;
+    }
+}

http://git-wip-us.apache.org/repos/asf/aries-rsa/blob/69bb901e/discovery/zookeeper/src/main/java/org/apache/aries/rsa/discovery/zookeeper/publish/DiscoveryPlugin.java
----------------------------------------------------------------------
diff --git a/discovery/zookeeper/src/main/java/org/apache/aries/rsa/discovery/zookeeper/publish/DiscoveryPlugin.java b/discovery/zookeeper/src/main/java/org/apache/aries/rsa/discovery/zookeeper/publish/DiscoveryPlugin.java
new file mode 100644
index 0000000..033bee2
--- /dev/null
+++ b/discovery/zookeeper/src/main/java/org/apache/aries/rsa/discovery/zookeeper/publish/DiscoveryPlugin.java
@@ -0,0 +1,54 @@
+/**
+ * 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.aries.rsa.discovery.zookeeper.publish;
+
+import java.util.Map;
+
+/**
+ * This interface allows transformation of service registration information before it is pushed into the ZooKeeper
+ * discovery system.
+ * It can be useful for situations where a host name or port number needs to be changed in cases where the host running
+ * the service is known differently from the outside to what the local Java process thinks it is.
+ * Extra service properties can also be added to the registration which can be useful to refine the remote service
+ * lookup process. <p/>
+ *
+ * DiscoveryPlugins use the OSGi WhiteBoard pattern. To add one to the system, register an instance under this interface
+ * with the OSGi Service Registry. All registered DiscoveryPlugin instances are visited and given a chance to
+ * process the information before it is pushed into ZooKeeper. <p/>
+ *
+ * Note that the changes made using this plugin do not modify the local service registration.
+ *
+ */
+public interface DiscoveryPlugin {
+
+    /**
+     * Process service registration information. Plugins can change this information before it is published into the
+     * ZooKeeper discovery system.
+     *
+     * @param mutableProperties A map of service registration properties. The map is mutable and any changes to the map
+     * will be reflected in the ZooKeeper registration.
+     * @param endpointKey The key under which the service is registered in ZooKeeper. This key typically has the
+     * following format: hostname#port##context. While the actual value of this key is not actually used by the
+     * system (people can use it as a hint to understand where the service is located), the value <i>must</i> be
+     * unique for all services of a given type.
+     * @return The <tt>endpointKey</tt> value to be used. If there is no need to change this simply return the value
+     * of the <tt>endpointKey</tt> parameter.
+     */
+    String process(Map<String, Object> mutableProperties, String endpointKey);
+}

http://git-wip-us.apache.org/repos/asf/aries-rsa/blob/69bb901e/discovery/zookeeper/src/main/java/org/apache/aries/rsa/discovery/zookeeper/publish/PublishingEndpointListener.java
----------------------------------------------------------------------
diff --git a/discovery/zookeeper/src/main/java/org/apache/aries/rsa/discovery/zookeeper/publish/PublishingEndpointListener.java b/discovery/zookeeper/src/main/java/org/apache/aries/rsa/discovery/zookeeper/publish/PublishingEndpointListener.java
new file mode 100644
index 0000000..75efbd3
--- /dev/null
+++ b/discovery/zookeeper/src/main/java/org/apache/aries/rsa/discovery/zookeeper/publish/PublishingEndpointListener.java
@@ -0,0 +1,210 @@
+/**
+ * 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.aries.rsa.discovery.zookeeper.publish;
+
+import java.io.IOException;
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.net.UnknownHostException;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.aries.rsa.discovery.endpoint.EndpointDescriptionParser;
+import org.apache.aries.rsa.discovery.endpoint.PropertiesMapper;
+import org.apache.aries.rsa.discovery.zookeeper.util.Utils;
+import org.apache.zookeeper.CreateMode;
+import org.apache.zookeeper.KeeperException;
+import org.apache.zookeeper.KeeperException.NoNodeException;
+import org.apache.zookeeper.KeeperException.NodeExistsException;
+import org.apache.zookeeper.ZooDefs.Ids;
+import org.apache.zookeeper.ZooKeeper;
+import org.osgi.framework.BundleContext;
+import org.osgi.service.remoteserviceadmin.EndpointDescription;
+import org.osgi.service.remoteserviceadmin.EndpointListener;
+import org.osgi.util.tracker.ServiceTracker;
+import org.osgi.xmlns.rsa.v1_0.EndpointDescriptionType;
+import org.osgi.xmlns.rsa.v1_0.PropertyType;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Listens for local Endpoints and publishes them to ZooKeeper.
+ */
+public class PublishingEndpointListener implements EndpointListener {
+
+    private static final Logger LOG = LoggerFactory.getLogger(PublishingEndpointListener.class);
+
+    private final ZooKeeper zk;
+    private final ServiceTracker<DiscoveryPlugin, DiscoveryPlugin> discoveryPluginTracker;
+    private final List<EndpointDescription> endpoints = new ArrayList<EndpointDescription>();
+    private boolean closed;
+
+    private final EndpointDescriptionParser endpointDescriptionParser;
+
+    public PublishingEndpointListener(ZooKeeper zk, BundleContext bctx) {
+        this.zk = zk;
+        discoveryPluginTracker = new ServiceTracker<DiscoveryPlugin, DiscoveryPlugin>(bctx, 
+            DiscoveryPlugin.class, null);
+        discoveryPluginTracker.open();
+        endpointDescriptionParser = new EndpointDescriptionParser();
+    }
+
+    public void endpointAdded(EndpointDescription endpoint, String matchedFilter) {
+        LOG.info("Local EndpointDescription added: {}", endpoint);
+
+        synchronized (endpoints) {
+            if (closed) {
+                return;
+            }
+            if (endpoints.contains(endpoint)) {
+                // TODO -> Should the published endpoint be updated here?
+                return;
+            }
+
+            try {
+                addEndpoint(endpoint);
+                endpoints.add(endpoint);
+            } catch (Exception ex) {
+                LOG.error("Exception while processing the addition of an endpoint.", ex);
+            }
+        }
+    }
+
+    private void addEndpoint(EndpointDescription endpoint) throws URISyntaxException, KeeperException,
+                                                                  InterruptedException, IOException {
+        Collection<String> interfaces = endpoint.getInterfaces();
+        String endpointKey = getKey(endpoint);
+        Map<String, Object> props = new HashMap<String, Object>(endpoint.getProperties());
+
+        // process plugins
+        Object[] plugins = discoveryPluginTracker.getServices();
+        if (plugins != null) {
+            for (Object plugin : plugins) {
+                if (plugin instanceof DiscoveryPlugin) {
+                    endpointKey = ((DiscoveryPlugin)plugin).process(props, endpointKey);
+                }
+            }
+        }
+
+        for (String name : interfaces) {
+            String path = Utils.getZooKeeperPath(name);
+            String fullPath = path + '/' + endpointKey;
+            LOG.info("Creating ZooKeeper node for service with path {}", fullPath);
+            createPath(path, zk);
+            List<PropertyType> propsOut = new PropertiesMapper().fromProps(props);
+            EndpointDescriptionType epd = new EndpointDescriptionType();
+            epd.getProperty().addAll(propsOut);
+            byte[] epData = endpointDescriptionParser.getData(epd);
+            createEphemeralNode(fullPath, epData);
+        }
+    }
+
+    private void createEphemeralNode(String fullPath, byte[] data) throws KeeperException, InterruptedException {
+        try {
+            zk.create(fullPath, data, Ids.OPEN_ACL_UNSAFE, CreateMode.EPHEMERAL);
+        } catch (NodeExistsException nee) {
+            // this sometimes happens after a ZooKeeper node dies and the ephemeral node
+            // that belonged to the old session was not yet deleted. We need to make our
+            // session the owner of the node so it won't get deleted automatically -
+            // we do this by deleting and recreating it ourselves.
+            LOG.info("node for endpoint already exists, recreating: {}", fullPath);
+            try {
+                zk.delete(fullPath, -1);
+            } catch (NoNodeException nne) {
+                // it's a race condition, but as long as it got deleted - it's ok
+            }
+            zk.create(fullPath, data, Ids.OPEN_ACL_UNSAFE, CreateMode.EPHEMERAL);
+        }
+    }
+
+    public void endpointRemoved(EndpointDescription endpoint, String matchedFilter) {
+        LOG.info("Local EndpointDescription removed: {}", endpoint);
+
+        synchronized (endpoints) {
+            if (closed) {
+                return;
+            }
+            if (!endpoints.contains(endpoint)) {
+                return;
+            }
+
+            try {
+                removeEndpoint(endpoint);
+                endpoints.remove(endpoint);
+            } catch (Exception ex) {
+                LOG.error("Exception while processing the removal of an endpoint", ex);
+            }
+        }
+    }
+
+    private void removeEndpoint(EndpointDescription endpoint) throws UnknownHostException, URISyntaxException {
+        Collection<String> interfaces = endpoint.getInterfaces();
+        String endpointKey = getKey(endpoint);
+        for (String name : interfaces) {
+            String path = Utils.getZooKeeperPath(name);
+            String fullPath = path + '/' + endpointKey;
+            LOG.debug("Removing ZooKeeper node: {}", fullPath);
+            try {
+                zk.delete(fullPath, -1);
+            } catch (Exception ex) {
+                LOG.debug("Error while removing endpoint: {}", ex); // e.g. session expired
+            }
+        }
+    }
+
+    private static void createPath(String path, ZooKeeper zk) throws KeeperException, InterruptedException {
+        StringBuilder current = new StringBuilder();
+        List<String> parts = Utils.removeEmpty(Arrays.asList(path.split("/")));
+        for (String part : parts) {
+            current.append('/');
+            current.append(part);
+            try {
+                zk.create(current.toString(), new byte[0], Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);
+            } catch (NodeExistsException nee) {
+                // it's not the first node with this path to ever exist - that's normal
+            }
+        }
+    }
+
+    private static String getKey(EndpointDescription endpoint) throws URISyntaxException {
+        URI uri = new URI(endpoint.getId());
+        return new StringBuilder().append(uri.getHost()).append("#").append(uri.getPort())
+            .append("#").append(uri.getPath().replace('/', '#')).toString();
+    }
+
+    public void close() {
+        LOG.debug("closing - removing all endpoints");
+        synchronized (endpoints) {
+            closed = true;
+            for (EndpointDescription endpoint : endpoints) {
+                try {
+                    removeEndpoint(endpoint);
+                } catch (Exception ex) {
+                    LOG.error("Exception while removing endpoint during close", ex);
+                }
+            }
+            endpoints.clear();
+        }
+        discoveryPluginTracker.close();
+    }
+}

http://git-wip-us.apache.org/repos/asf/aries-rsa/blob/69bb901e/discovery/zookeeper/src/main/java/org/apache/aries/rsa/discovery/zookeeper/publish/PublishingEndpointListenerFactory.java
----------------------------------------------------------------------
diff --git a/discovery/zookeeper/src/main/java/org/apache/aries/rsa/discovery/zookeeper/publish/PublishingEndpointListenerFactory.java b/discovery/zookeeper/src/main/java/org/apache/aries/rsa/discovery/zookeeper/publish/PublishingEndpointListenerFactory.java
new file mode 100644
index 0000000..1eabec3
--- /dev/null
+++ b/discovery/zookeeper/src/main/java/org/apache/aries/rsa/discovery/zookeeper/publish/PublishingEndpointListenerFactory.java
@@ -0,0 +1,105 @@
+/**
+ * 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.aries.rsa.discovery.zookeeper.publish;
+
+import java.util.ArrayList;
+import java.util.Dictionary;
+import java.util.Hashtable;
+import java.util.List;
+
+import org.apache.aries.rsa.discovery.zookeeper.ZooKeeperDiscovery;
+import org.apache.zookeeper.ZooKeeper;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.Constants;
+import org.osgi.framework.ServiceFactory;
+import org.osgi.framework.ServiceRegistration;
+import org.osgi.service.remoteserviceadmin.EndpointListener;
+import org.osgi.service.remoteserviceadmin.RemoteConstants;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Creates local EndpointListeners that publish to ZooKeeper.
+ */
+public class PublishingEndpointListenerFactory implements ServiceFactory<PublishingEndpointListener> {
+
+    private static final Logger LOG = LoggerFactory.getLogger(PublishingEndpointListenerFactory.class);
+
+    private final BundleContext bctx;
+    private final ZooKeeper zk;
+    private final List<PublishingEndpointListener> listeners = new ArrayList<PublishingEndpointListener>();
+    private ServiceRegistration<?> serviceRegistration;
+
+    public PublishingEndpointListenerFactory(ZooKeeper zk, BundleContext bctx) {
+        this.bctx = bctx;
+        this.zk = zk;
+    }
+
+    public PublishingEndpointListener getService(Bundle b, ServiceRegistration<PublishingEndpointListener> sr) {
+        LOG.debug("new EndpointListener from factory");
+        synchronized (listeners) {
+            PublishingEndpointListener pel = new PublishingEndpointListener(zk, bctx);
+            listeners.add(pel);
+            return pel;
+        }
+    }
+
+    public void ungetService(Bundle b, ServiceRegistration<PublishingEndpointListener> sr, 
+                             PublishingEndpointListener pel) {
+        LOG.debug("remove EndpointListener");
+        synchronized (listeners) {
+            if (listeners.remove(pel)) {
+                pel.close();
+            }
+        }
+    }
+
+    public synchronized void start() {
+        Dictionary<String, String> props = new Hashtable<String, String>();
+        String uuid = bctx.getProperty(Constants.FRAMEWORK_UUID);
+        props.put(EndpointListener.ENDPOINT_LISTENER_SCOPE, 
+                  String.format("(&(%s=*)(%s=%s))", Constants.OBJECTCLASS, 
+                                RemoteConstants.ENDPOINT_FRAMEWORK_UUID, uuid));
+        props.put(ZooKeeperDiscovery.DISCOVERY_ZOOKEEPER_ID, "true");
+        serviceRegistration = bctx.registerService(EndpointListener.class.getName(), this, props);
+    }
+    
+    public synchronized void stop() {
+        if (serviceRegistration != null) {
+            serviceRegistration.unregister();
+            serviceRegistration = null;
+        }
+        synchronized (listeners) {
+            for (PublishingEndpointListener pel : listeners) {
+                pel.close();
+            }
+            listeners.clear();
+        }
+    }
+
+    /**
+     * Only for the test case!
+     */
+    protected List<PublishingEndpointListener> getListeners() {
+        synchronized (listeners) {
+            return listeners;
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/aries-rsa/blob/69bb901e/discovery/zookeeper/src/main/java/org/apache/aries/rsa/discovery/zookeeper/server/Utils.java
----------------------------------------------------------------------
diff --git a/discovery/zookeeper/src/main/java/org/apache/aries/rsa/discovery/zookeeper/server/Utils.java b/discovery/zookeeper/src/main/java/org/apache/aries/rsa/discovery/zookeeper/server/Utils.java
new file mode 100644
index 0000000..67ea3a4
--- /dev/null
+++ b/discovery/zookeeper/src/main/java/org/apache/aries/rsa/discovery/zookeeper/server/Utils.java
@@ -0,0 +1,108 @@
+/**
+ * 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.aries.rsa.discovery.zookeeper.server;
+
+import java.util.ArrayList;
+import java.util.Dictionary;
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Properties;
+
+/**
+ * General purpose utility methods.
+ */
+public final class Utils {
+
+    private Utils() {
+        // prevent instantiation
+    }
+
+    /**
+     * Remove entries whose values are empty from the given dictionary.
+     *
+     * @param dict a dictionary
+     */
+    public static void removeEmptyValues(Dictionary<String, ?> dict) {
+        List<String> keysToRemove = new ArrayList<String>();
+        Enumeration<String> keys = dict.keys();
+        while (keys.hasMoreElements()) {
+            String key = keys.nextElement();
+            Object value = dict.get(key);
+            if (value instanceof String && "".equals(value)) {
+                keysToRemove.add(key);
+            }
+        }
+        for (String key : keysToRemove) {
+            dict.remove(key);
+        }
+    }
+
+    /**
+     * Puts the given key-value pair in the given dictionary if the key does not
+     * already exist in it or if its existing value is null.
+     *
+     * @param dict a dictionary
+     * @param key the key
+     * @param value the default value to set
+     */
+    public static void setDefault(Dictionary<String, String> dict, String key, String value) {
+        if (dict.get(key) == null) {
+            dict.put(key, value);
+        }
+    }
+
+    /**
+     * Converts the given Dictionary to a Map.
+     *
+     * @param dict a dictionary
+     * @param <K> the key type
+     * @param <V> the value type
+     * @return the converted map, or an empty map if the given dictionary is null
+     */
+    public static <K, V> Map<K, V> toMap(Dictionary<K, V> dict) {
+        Map<K, V> map = new HashMap<K, V>();
+        if (dict != null) {
+            Enumeration<K> keys = dict.keys();
+            while (keys.hasMoreElements()) {
+                K key = keys.nextElement();
+                map.put(key, dict.get(key));
+            }
+        }
+        return map;
+    }
+
+    /**
+     * Converts a Dictionary into a Properties instance.
+     *
+     * @param dict a dictionary
+     * @param <K> the key type
+     * @param <V> the value type
+     * @return the properties
+     */
+    public static <K, V> Properties toProperties(Dictionary<K, V> dict) {
+        Properties props = new Properties();
+        for (Enumeration<K> e = dict.keys(); e.hasMoreElements();) {
+            K key = e.nextElement();
+            props.put(key, dict.get(key));
+        }
+        return props;
+    }
+}

http://git-wip-us.apache.org/repos/asf/aries-rsa/blob/69bb901e/discovery/zookeeper/src/main/java/org/apache/aries/rsa/discovery/zookeeper/server/ZookeeperStarter.java
----------------------------------------------------------------------
diff --git a/discovery/zookeeper/src/main/java/org/apache/aries/rsa/discovery/zookeeper/server/ZookeeperStarter.java b/discovery/zookeeper/src/main/java/org/apache/aries/rsa/discovery/zookeeper/server/ZookeeperStarter.java
new file mode 100644
index 0000000..520aa99
--- /dev/null
+++ b/discovery/zookeeper/src/main/java/org/apache/aries/rsa/discovery/zookeeper/server/ZookeeperStarter.java
@@ -0,0 +1,164 @@
+/**
+ * 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.aries.rsa.discovery.zookeeper.server;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.Dictionary;
+import java.util.Map;
+
+import org.apache.zookeeper.server.ServerConfig;
+import org.apache.zookeeper.server.ZooKeeperServerMain;
+import org.apache.zookeeper.server.quorum.QuorumPeerConfig;
+import org.apache.zookeeper.server.quorum.QuorumPeerConfig.ConfigException;
+import org.apache.zookeeper.server.quorum.QuorumPeerMain;
+import org.osgi.framework.BundleContext;
+import org.osgi.service.cm.ConfigurationException;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class ZookeeperStarter implements org.osgi.service.cm.ManagedService {
+
+    private static final Logger LOG = LoggerFactory.getLogger(ZookeeperStarter.class);
+
+    protected ZookeeperServer main;
+    private final BundleContext bundleContext;
+    private Thread zkMainThread;
+    private Map<String, ?> curConfiguration;
+
+    public ZookeeperStarter(BundleContext ctx) {
+        bundleContext = ctx;
+    }
+
+    public synchronized void shutdown() {
+        if (main != null) {
+            LOG.info("Shutting down ZooKeeper server");
+            try {
+                main.shutdown();
+                if (zkMainThread != null) {
+                    zkMainThread.join();
+                }
+            } catch (Throwable e) {
+                LOG.error(e.getMessage(), e);
+            }
+            main = null;
+            zkMainThread = null;
+        }
+    }
+
+    private void setDefaults(Dictionary<String, String> dict) throws IOException {
+        Utils.removeEmptyValues(dict); // to avoid NumberFormatExceptions
+        Utils.setDefault(dict, "tickTime", "2000");
+        Utils.setDefault(dict, "initLimit", "10");
+        Utils.setDefault(dict, "syncLimit", "5");
+        Utils.setDefault(dict, "clientPort", "2181");
+        Utils.setDefault(dict, "dataDir", new File(bundleContext.getDataFile(""), "zkdata").getCanonicalPath());
+    }
+
+    @SuppressWarnings("unchecked")
+    public synchronized void updated(Dictionary<String, ?> dict) throws ConfigurationException {
+        LOG.debug("Received configuration update for Zookeeper Server: " + dict);
+        try {
+            if (dict != null) {
+                setDefaults((Dictionary<String, String>)dict);
+            }
+            Map<String, ?> configMap = Utils.toMap(dict);
+            if (!configMap.equals(curConfiguration)) { // only if something actually changed
+                shutdown();
+                curConfiguration = configMap;
+                // config is null if it doesn't exist, is being deleted or has not yet been loaded
+                // in which case we just stop running
+                if (dict != null) {
+                    startFromConfig(parseConfig(dict));
+                    LOG.info("Applied configuration update: " + dict);
+                }
+            }
+        } catch (Exception th) {
+            LOG.error("Problem applying configuration update: " + dict, th);
+        }
+    }
+
+    private QuorumPeerConfig parseConfig(Dictionary<String, ?> dict) throws IOException, ConfigException {
+        QuorumPeerConfig config = new QuorumPeerConfig();
+        config.parseProperties(Utils.toProperties(dict));
+        return config;
+    }
+
+    protected void startFromConfig(final QuorumPeerConfig config) {
+        int numServers = config.getServers().size();
+        main = numServers > 1 ? new MyQuorumPeerMain(config) : new MyZooKeeperServerMain(config);
+        zkMainThread = new Thread(new Runnable() {
+            public void run() {
+                try {
+                    main.startup();
+                } catch (Throwable e) {
+                    LOG.error("Problem running ZooKeeper server.", e);
+                }
+            }
+        });
+        zkMainThread.start();
+    }
+
+    interface ZookeeperServer {
+        void startup() throws IOException;
+        void shutdown();
+    }
+
+    static class MyQuorumPeerMain extends QuorumPeerMain implements ZookeeperServer {
+
+        private QuorumPeerConfig config;
+
+        MyQuorumPeerMain(QuorumPeerConfig config) {
+            this.config = config;
+        }
+
+        public void startup() throws IOException {
+            runFromConfig(config);
+        }
+
+        public void shutdown() {
+            if (null != quorumPeer) {
+                quorumPeer.shutdown();
+            }
+        }
+    }
+
+    static class MyZooKeeperServerMain extends ZooKeeperServerMain implements ZookeeperServer {
+
+        private QuorumPeerConfig config;
+
+        MyZooKeeperServerMain(QuorumPeerConfig config) {
+            this.config = config;
+        }
+
+        public void startup() throws IOException {
+            ServerConfig serverConfig = new ServerConfig();
+            serverConfig.readFrom(config);
+            runFromConfig(serverConfig);
+        }
+
+        public void shutdown() {
+            try {
+                super.shutdown();
+            } catch (Exception e) {
+                LOG.error("Error shutting down ZooKeeper", e);
+            }
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/aries-rsa/blob/69bb901e/discovery/zookeeper/src/main/java/org/apache/aries/rsa/discovery/zookeeper/subscribe/EndpointListenerTracker.java
----------------------------------------------------------------------
diff --git a/discovery/zookeeper/src/main/java/org/apache/aries/rsa/discovery/zookeeper/subscribe/EndpointListenerTracker.java b/discovery/zookeeper/src/main/java/org/apache/aries/rsa/discovery/zookeeper/subscribe/EndpointListenerTracker.java
new file mode 100644
index 0000000..5909ee0
--- /dev/null
+++ b/discovery/zookeeper/src/main/java/org/apache/aries/rsa/discovery/zookeeper/subscribe/EndpointListenerTracker.java
@@ -0,0 +1,56 @@
+/**
+ * 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.aries.rsa.discovery.zookeeper.subscribe;
+
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.ServiceReference;
+import org.osgi.service.remoteserviceadmin.EndpointListener;
+import org.osgi.util.tracker.ServiceTracker;
+
+/**
+ * Tracks interest in EndpointListeners. Delegates to InterfaceMonitorManager to manage
+ * interest in the scopes of each EndpointListener.
+ */
+public class EndpointListenerTracker extends ServiceTracker<EndpointListener, EndpointListener> {
+    private final InterfaceMonitorManager imManager;
+
+    public EndpointListenerTracker(BundleContext bctx, InterfaceMonitorManager imManager) {
+        super(bctx, EndpointListener.class, null);
+        this.imManager = imManager;
+    }
+
+    @Override
+    public EndpointListener addingService(ServiceReference<EndpointListener> endpointListener) {
+        imManager.addInterest(endpointListener);
+        return null;
+    }
+
+    @Override
+    public void modifiedService(ServiceReference<EndpointListener> endpointListener, EndpointListener service) {
+        // called when an EndpointListener updates its service properties,
+        // e.g. when its interest scope is expanded/reduced
+        imManager.addInterest(endpointListener);
+    }
+
+    @Override
+    public void removedService(ServiceReference<EndpointListener> endpointListener, EndpointListener service) {
+        imManager.removeInterest(endpointListener);
+    }
+
+}


[2/5] aries-rsa git commit: Adding roundtrip test

Posted by cs...@apache.org.
http://git-wip-us.apache.org/repos/asf/aries-rsa/blob/69bb901e/discovery/zookeeper/src/test/java/org/apache/cxf/dosgi/discovery/zookeeper/InterfaceDataMonitorListenerImplTest.java
----------------------------------------------------------------------
diff --git a/discovery/zookeeper/src/test/java/org/apache/cxf/dosgi/discovery/zookeeper/InterfaceDataMonitorListenerImplTest.java b/discovery/zookeeper/src/test/java/org/apache/cxf/dosgi/discovery/zookeeper/InterfaceDataMonitorListenerImplTest.java
deleted file mode 100644
index 53b6139..0000000
--- a/discovery/zookeeper/src/test/java/org/apache/cxf/dosgi/discovery/zookeeper/InterfaceDataMonitorListenerImplTest.java
+++ /dev/null
@@ -1,183 +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.cxf.dosgi.discovery.zookeeper;
-
-import junit.framework.TestCase;
-
-public class InterfaceDataMonitorListenerImplTest extends TestCase {
-
-    public void testDUMMY() {
-        assertTrue(true);
-    }
-
-//    public void testChange() throws Exception {
-//        final List<DiscoveredServiceNotification> dsnCallbacks = new ArrayList<DiscoveredServiceNotification>();
-//        DiscoveredServiceTracker dst = new DiscoveredServiceTracker() {
-//            public void serviceChanged(DiscoveredServiceNotification dsn) {
-//                dsnCallbacks.add(dsn);
-//            }
-//        };
-//
-//        //----------------------------------------------------------------
-//        // Test DiscoveredServiceNotification.AVAILABLE
-//        //----------------------------------------------------------------
-//        Properties initial = new Properties();
-//        initial.put("a", "b");
-//        initial.put(ServicePublication.ENDPOINT_LOCATION, "http://somehost:12345/some/context");
-//        ByteArrayOutputStream propBytes = new ByteArrayOutputStream();
-//        initial.store(propBytes, "");
-//
-//        ZooKeeper zk = EasyMock.createMock(ZooKeeper.class);
-//        EasyMock.expect(zk.getChildren(Utils.getZooKeeperPath(String.class.getName()), false))
-//            .andReturn(Arrays.asList("x#y#z"));
-//        EasyMock.expect(zk.getData(Utils.getZooKeeperPath(String.class.getName()) + "/x#y#z", false, null))
-//            .andReturn(propBytes.toByteArray());
-//        EasyMock.replay(zk);
-//
-//        InterfaceDataMonitorListenerImpl dml = new InterfaceDataMonitorListenerImpl(zk, String.class.getName(), dst);
-//
-//        assertEquals("Precondition failed", 0, dsnCallbacks.size());
-//        dml.change();
-//        assertEquals(1, dsnCallbacks.size());
-//        DiscoveredServiceNotification dsn = dsnCallbacks.iterator().next();
-//        assertEquals(Collections.singleton(String.class.getName()), dsn.getInterfaces());
-//        assertEquals(DiscoveredServiceNotification.AVAILABLE, dsn.getType());
-//        assertEquals(0, dsn.getFilters().size());
-//        ServiceEndpointDescription sed = dsn.getServiceEndpointDescription();
-//        assertEquals(Collections.singleton(String.class.getName()), sed.getProvidedInterfaces());
-//
-//        Properties expected = new Properties();
-//        expected.load(new ByteArrayInputStream(propBytes.toByteArray()));
-//        expected.put("service.exported.configs", "org.apache.cxf.ws");
-//        expected.put("org.apache.cxf.ws.address", "http://somehost:12345/some/context");
-//
-//        assertEquals(expected, sed.getProperties());
-//        EasyMock.verify(zk);
-//
-//        // Again with the same data
-//        EasyMock.reset(zk);
-//        EasyMock.expect(zk.getChildren(Utils.getZooKeeperPath(String.class.getName()), false))
-//            .andReturn(Arrays.asList("x#y#z"));
-//        EasyMock.expect(zk.getData(Utils.getZooKeeperPath(String.class.getName()) + "/x#y#z", false, null))
-//            .andReturn(propBytes.toByteArray());
-//        EasyMock.replay(zk);
-//
-//        dsnCallbacks.clear();
-//        assertEquals("Precondition failed", 0, dsnCallbacks.size());
-//        dml.change();
-//        assertEquals(0, dsnCallbacks.size());
-//
-//        EasyMock.verify(zk);
-//        //----------------------------------------------------------------
-//        // Test DiscoveredServiceNotification.MODIFIED
-//        //----------------------------------------------------------------
-//        Properties modified = new Properties();
-//        modified.put("c", "d");
-//        modified.put(ServicePublication.ENDPOINT_LOCATION, "http://somehost:999/some/context");
-//        modified.put("service.exported.configs", "org.apache.cxf.rs");
-//        ByteArrayOutputStream modBytes = new ByteArrayOutputStream();
-//        modified.store(modBytes, "");
-//
-//        EasyMock.reset(zk);
-//        EasyMock.expect(zk.getChildren(Utils.getZooKeeperPath(String.class.getName()), false))
-//            .andReturn(Arrays.asList("x#y#z"));
-//        EasyMock.expect(zk.getData(Utils.getZooKeeperPath(String.class.getName()) + "/x#y#z", false, null))
-//            .andReturn(modBytes.toByteArray());
-//        EasyMock.replay(zk);
-//
-//        dsnCallbacks.clear();
-//        assertEquals("Precondition failed", 0, dsnCallbacks.size());
-//        dml.change();
-//        assertEquals(1, dsnCallbacks.size());
-//        DiscoveredServiceNotification dsn2 = dsnCallbacks.iterator().next();
-//        assertEquals(Collections.singleton(String.class.getName()), dsn2.getInterfaces());
-//        assertEquals(DiscoveredServiceNotification.MODIFIED, dsn2.getType());
-//        assertEquals(0, dsn2.getFilters().size());
-//        ServiceEndpointDescription sed2 = dsn2.getServiceEndpointDescription();
-//        assertEquals(Collections.singleton(String.class.getName()), sed2.getProvidedInterfaces());
-//        assertEquals(modified, sed2.getProperties());
-//
-//        EasyMock.verify(zk);
-//
-//        //----------------------------------------------------------------
-//        // Test DiscoveredServiceNotification.MODIFIED2
-//        //----------------------------------------------------------------
-//        Properties modified2 = new Properties();
-//        modified2.put("c", "d2");
-//        modified2.put(ServicePublication.ENDPOINT_LOCATION, "http://somehost:112/some/context");
-//        modified2.put("service.exported.configs", "org.apache.cxf.ws");
-//        modified2.put("org.apache.cxf.ws.address", "http://somewhereelse/123");
-//        ByteArrayOutputStream modBytes2 = new ByteArrayOutputStream();
-//        modified2.store(modBytes2, "");
-//
-//        EasyMock.reset(zk);
-//        EasyMock.expect(zk.getChildren(Utils.getZooKeeperPath(String.class.getName()), false))
-//            .andReturn(Arrays.asList("x#y#z"));
-//        EasyMock.expect(zk.getData(Utils.getZooKeeperPath(String.class.getName()) + "/x#y#z", false, null))
-//            .andReturn(modBytes2.toByteArray());
-//        EasyMock.replay(zk);
-//
-//        dsnCallbacks.clear();
-//        assertEquals("Precondition failed", 0, dsnCallbacks.size());
-//        dml.change();
-//        assertEquals(1, dsnCallbacks.size());
-//        DiscoveredServiceNotification dsn3 = dsnCallbacks.iterator().next();
-//        assertEquals(Collections.singleton(String.class.getName()), dsn3.getInterfaces());
-//        assertEquals(DiscoveredServiceNotification.MODIFIED, dsn3.getType());
-//        assertEquals(0, dsn3.getFilters().size());
-//        ServiceEndpointDescription sed3 = dsn3.getServiceEndpointDescription();
-//        assertEquals(Collections.singleton(String.class.getName()), sed3.getProvidedInterfaces());
-//        assertEquals(modified2, sed3.getProperties());
-//
-//        EasyMock.verify(zk);
-//        //----------------------------------------------------------------
-//        // Test DiscoveredServiceNotification.UNAVAILABLE
-//        //----------------------------------------------------------------
-//        EasyMock.reset(zk);
-//        EasyMock.expect(zk.getChildren(Utils.getZooKeeperPath(String.class.getName()), false))
-//            .andReturn(Collections.<String>emptyList());
-//        EasyMock.replay(zk);
-//
-//        dsnCallbacks.clear();
-//        assertEquals("Precondition failed", 0, dsnCallbacks.size());
-//        dml.change();
-//        assertEquals(1, dsnCallbacks.size());
-//        DiscoveredServiceNotification dsn4 = dsnCallbacks.iterator().next();
-//        assertEquals(Collections.singleton(String.class.getName()), dsn4.getInterfaces());
-//        assertEquals(DiscoveredServiceNotification.UNAVAILABLE, dsn4.getType());
-//        assertEquals(0, dsn4.getFilters().size());
-//        ServiceEndpointDescription sed4 = dsn4.getServiceEndpointDescription();
-//        assertEquals(Collections.singleton(String.class.getName()), sed4.getProvidedInterfaces());
-//        assertEquals(modified2, sed4.getProperties());
-//
-//        EasyMock.verify(zk);
-//
-//        // Try the same again...
-//        EasyMock.reset(zk);
-//        EasyMock.expect(zk.getChildren(Utils.getZooKeeperPath(String.class.getName()), false))
-//            .andReturn(Collections.<String>emptyList());
-//        EasyMock.replay(zk);
-//
-//        dsnCallbacks.clear();
-//        assertEquals("Precondition failed", 0, dsnCallbacks.size());
-//        dml.change();
-//        assertEquals("Should not receive a callback again...", 0, dsnCallbacks.size());
-//        EasyMock.verify(zk);
-//    }
-}

http://git-wip-us.apache.org/repos/asf/aries-rsa/blob/69bb901e/discovery/zookeeper/src/test/java/org/apache/cxf/dosgi/discovery/zookeeper/ZookeeperDiscoveryTest.java
----------------------------------------------------------------------
diff --git a/discovery/zookeeper/src/test/java/org/apache/cxf/dosgi/discovery/zookeeper/ZookeeperDiscoveryTest.java b/discovery/zookeeper/src/test/java/org/apache/cxf/dosgi/discovery/zookeeper/ZookeeperDiscoveryTest.java
deleted file mode 100644
index ed38d5d..0000000
--- a/discovery/zookeeper/src/test/java/org/apache/cxf/dosgi/discovery/zookeeper/ZookeeperDiscoveryTest.java
+++ /dev/null
@@ -1,55 +0,0 @@
-package org.apache.cxf.dosgi.discovery.zookeeper;
-
-import java.util.Dictionary;
-import java.util.Hashtable;
-
-import org.apache.zookeeper.ZooKeeper;
-import org.easymock.EasyMock;
-import org.easymock.IMocksControl;
-import org.junit.Assert;
-import org.junit.Test;
-import org.osgi.framework.BundleContext;
-import org.osgi.service.cm.ConfigurationException;
-
-
-public class ZookeeperDiscoveryTest {
-
-    @Test
-    public void testDefaults() throws ConfigurationException {
-        IMocksControl c = EasyMock.createControl();
-        BundleContext bctx = c.createMock(BundleContext.class);
-        ZooKeeperDiscovery zkd = new ZooKeeperDiscovery(bctx) {
-            @Override
-            protected ZooKeeper createZooKeeper(String host, String port, int timeout) {
-                Assert.assertEquals("localhost", host);
-                Assert.assertEquals("2181", port);
-                Assert.assertEquals(3000, timeout);
-                return null;
-            }  
-        };
-        
-        Dictionary<String, Object> configuration = new Hashtable<String, Object>();
-        zkd.updated(configuration);
-    }
-    
-    @Test
-    public void testConfig() throws ConfigurationException {
-        IMocksControl c = EasyMock.createControl();
-        BundleContext bctx = c.createMock(BundleContext.class);
-        ZooKeeperDiscovery zkd = new ZooKeeperDiscovery(bctx) {
-            @Override
-            protected ZooKeeper createZooKeeper(String host, String port, int timeout) {
-                Assert.assertEquals("myhost", host);
-                Assert.assertEquals("1", port);
-                Assert.assertEquals(1000, timeout);
-                return null;
-            }  
-        };
-        
-        Dictionary<String, Object> configuration = new Hashtable<String, Object>();
-        configuration.put("zookeeper.host", "myhost");
-        configuration.put("zookeeper.port", "1");
-        configuration.put("zookeeper.timeout", "1000");
-        zkd.updated(configuration);
-    }
-}

http://git-wip-us.apache.org/repos/asf/aries-rsa/blob/69bb901e/discovery/zookeeper/src/test/java/org/apache/cxf/dosgi/discovery/zookeeper/publish/PublishingEndpointListenerFactoryTest.java
----------------------------------------------------------------------
diff --git a/discovery/zookeeper/src/test/java/org/apache/cxf/dosgi/discovery/zookeeper/publish/PublishingEndpointListenerFactoryTest.java b/discovery/zookeeper/src/test/java/org/apache/cxf/dosgi/discovery/zookeeper/publish/PublishingEndpointListenerFactoryTest.java
deleted file mode 100644
index a8498fd..0000000
--- a/discovery/zookeeper/src/test/java/org/apache/cxf/dosgi/discovery/zookeeper/publish/PublishingEndpointListenerFactoryTest.java
+++ /dev/null
@@ -1,100 +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.cxf.dosgi.discovery.zookeeper.publish;
-
-import java.util.Dictionary;
-import java.util.List;
-
-import junit.framework.TestCase;
-
-import org.apache.zookeeper.ZooKeeper;
-import org.easymock.EasyMock;
-import org.easymock.IMocksControl;
-import org.osgi.framework.BundleContext;
-import org.osgi.framework.ServiceRegistration;
-import org.osgi.service.remoteserviceadmin.EndpointListener;
-
-public class PublishingEndpointListenerFactoryTest extends TestCase {
-
-    @SuppressWarnings("unchecked")
-    public void testScope() {
-        IMocksControl c = EasyMock.createNiceControl();
-
-        BundleContext ctx = c.createMock(BundleContext.class);
-        ZooKeeper zk = c.createMock(ZooKeeper.class);
-        @SuppressWarnings("rawtypes")
-        ServiceRegistration sreg = c.createMock(ServiceRegistration.class);
-
-        PublishingEndpointListenerFactory eplf = new PublishingEndpointListenerFactory(zk, ctx);
-
-        EasyMock.expect(ctx.registerService(EasyMock.eq(EndpointListener.class.getName()), EasyMock.eq(eplf),
-                                            (Dictionary<String, String>)EasyMock.anyObject())).andReturn(sreg).once();
-
-        EasyMock.expect(ctx.getProperty(EasyMock.eq("org.osgi.framework.uuid"))).andReturn("myUUID").anyTimes();
-
-        c.replay();
-        eplf.start();
-        c.verify();
-
-    }
-
-    @SuppressWarnings("unchecked")
-    public void testServiceFactory() {
-        IMocksControl c = EasyMock.createNiceControl();
-
-        BundleContext ctx = c.createMock(BundleContext.class);
-        ZooKeeper zk = c.createMock(ZooKeeper.class);
-        @SuppressWarnings("rawtypes")
-        ServiceRegistration sreg = c.createMock(ServiceRegistration.class);
-
-        PublishingEndpointListenerFactory eplf = new PublishingEndpointListenerFactory(zk, ctx);
-
-        EasyMock.expect(ctx.registerService(EasyMock.eq(EndpointListener.class.getName()), EasyMock.eq(eplf),
-                                (Dictionary<String, String>)EasyMock.anyObject())).andReturn(sreg).once();
-
-        EasyMock.expect(ctx.getProperty(EasyMock.eq("org.osgi.framework.uuid"))).andReturn("myUUID").anyTimes();
-
-        PublishingEndpointListener eli = c.createMock(PublishingEndpointListener.class);
-        eli.close();
-        EasyMock.expectLastCall().once();
-
-        c.replay();
-        eplf.start();
-
-        PublishingEndpointListener service = eplf.getService(null, null);
-        assertNotNull(service);
-        assertTrue(service instanceof EndpointListener);
-
-        List<PublishingEndpointListener> listeners = eplf.getListeners();
-        assertEquals(1, listeners.size());
-        assertEquals(service, listeners.get(0));
-
-        eplf.ungetService(null, null, service);
-        listeners = eplf.getListeners();
-        assertEquals(0, listeners.size());
-
-        eplf.ungetService(null, null, eli); // no call to close
-        listeners.add(eli);
-        eplf.ungetService(null, null, eli); // call to close
-        listeners = eplf.getListeners();
-        assertEquals(0, listeners.size());
-
-        c.verify();
-    }
-}

http://git-wip-us.apache.org/repos/asf/aries-rsa/blob/69bb901e/discovery/zookeeper/src/test/java/org/apache/cxf/dosgi/discovery/zookeeper/publish/PublishingEndpointListenerTest.java
----------------------------------------------------------------------
diff --git a/discovery/zookeeper/src/test/java/org/apache/cxf/dosgi/discovery/zookeeper/publish/PublishingEndpointListenerTest.java b/discovery/zookeeper/src/test/java/org/apache/cxf/dosgi/discovery/zookeeper/publish/PublishingEndpointListenerTest.java
deleted file mode 100644
index 0c78d4a..0000000
--- a/discovery/zookeeper/src/test/java/org/apache/cxf/dosgi/discovery/zookeeper/publish/PublishingEndpointListenerTest.java
+++ /dev/null
@@ -1,207 +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.cxf.dosgi.discovery.zookeeper.publish;
-
-import static org.easymock.EasyMock.expect;
-
-import java.lang.reflect.Field;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-
-import org.apache.aries.rsa.discovery.endpoint.EndpointDescriptionParser;
-import org.apache.aries.rsa.discovery.endpoint.PropertiesMapper;
-import org.apache.zookeeper.CreateMode;
-import org.apache.zookeeper.KeeperException;
-import org.apache.zookeeper.ZooDefs.Ids;
-import org.apache.zookeeper.ZooKeeper;
-import org.easymock.EasyMock;
-import org.easymock.IAnswer;
-import org.easymock.IMocksControl;
-import org.osgi.framework.BundleContext;
-import org.osgi.framework.Constants;
-import org.osgi.framework.Filter;
-import org.osgi.framework.FrameworkUtil;
-import org.osgi.framework.InvalidSyntaxException;
-import org.osgi.framework.ServiceListener;
-import org.osgi.framework.ServiceReference;
-import org.osgi.service.remoteserviceadmin.EndpointDescription;
-import org.osgi.service.remoteserviceadmin.RemoteConstants;
-import org.osgi.xmlns.rsa.v1_0.EndpointDescriptionType;
-import org.osgi.xmlns.rsa.v1_0.PropertyType;
-
-import junit.framework.TestCase;
-
-public class PublishingEndpointListenerTest extends TestCase {
-
-    private static final String ENDPOINT_PATH = "/osgi/service_registry/myClass/google.de#80##test#sub";
-
-    public void testEndpointRemovalAdding() throws KeeperException, InterruptedException {
-        IMocksControl c = EasyMock.createNiceControl();
-
-        BundleContext ctx = c.createMock(BundleContext.class);
-        ZooKeeper zk = c.createMock(ZooKeeper.class);
-
-        String path = ENDPOINT_PATH;
-        expectCreated(zk, path);
-        expectDeleted(zk, path);
-
-        c.replay();
-
-        PublishingEndpointListener eli = new PublishingEndpointListener(zk, ctx);
-        EndpointDescription endpoint = createEndpoint();
-        eli.endpointAdded(endpoint, null);
-        eli.endpointAdded(endpoint, null); // should do nothing
-        eli.endpointRemoved(endpoint, null);
-        eli.endpointRemoved(endpoint, null); // should do nothing
-
-        c.verify();
-    }
-
-    public void testDiscoveryPlugin() throws Exception {
-        BundleContext ctx = EasyMock.createMock(BundleContext.class);
-        stubCreateFilter(ctx);
-        ctx.addServiceListener(EasyMock.isA(ServiceListener.class),
-                EasyMock.eq("(objectClass=" + DiscoveryPlugin.class.getName() + ")"));
-
-        ServiceReference<DiscoveryPlugin> sr1 = createAppendPlugin(ctx);
-        ServiceReference<DiscoveryPlugin> sr2 = createPropertyPlugin(ctx);
-
-        EasyMock.expect(ctx.getServiceReferences(DiscoveryPlugin.class.getName(), null))
-                .andReturn(new ServiceReference[]{sr1, sr2}).anyTimes();
-        EasyMock.replay(ctx);
-
-        EndpointDescription endpoint = createEndpoint();
-
-        Map<String, Object> expectedProps = new HashMap<String, Object>(endpoint.getProperties());
-        expectedProps.put("endpoint.id", "http://google.de:80/test/sub/appended");
-        expectedProps.put("foo", "bar");
-        expectedProps.put("service.imported", "true");
-
-        final ZooKeeper zk = EasyMock.createNiceMock(ZooKeeper.class);
-        String expectedFullPath = "/osgi/service_registry/org/foo/myClass/some.machine#9876##test";
-        
-        List<PropertyType> props2 = new PropertiesMapper().fromProps(expectedProps);
-        EndpointDescriptionType epd = new EndpointDescriptionType();
-        epd.getProperty().addAll(props2);
-        byte[] data = new EndpointDescriptionParser().getData(epd);
-        expectCreated(zk, expectedFullPath, EasyMock.aryEq(data));
-        EasyMock.replay(zk);
-
-        PublishingEndpointListener eli = new PublishingEndpointListener(zk, ctx);
-
-        List<EndpointDescription> endpoints = getEndpoints(eli);
-        assertEquals("Precondition", 0, endpoints.size());
-        eli.endpointAdded(endpoint, null);
-        assertEquals(1, endpoints.size());
-
-        //TODO enable
-        //EasyMock.verify(zk);
-    }
-
-
-
-    public void testClose() throws KeeperException, InterruptedException {
-        IMocksControl c = EasyMock.createNiceControl();
-        BundleContext ctx = c.createMock(BundleContext.class);
-        ZooKeeper zk = c.createMock(ZooKeeper.class);
-        expectCreated(zk, ENDPOINT_PATH);
-        expectDeleted(zk, ENDPOINT_PATH);
-
-        c.replay();
-
-        PublishingEndpointListener eli = new PublishingEndpointListener(zk, ctx);
-        EndpointDescription endpoint = createEndpoint();
-        eli.endpointAdded(endpoint, null);
-        eli.close(); // should result in zk.delete(...)
-
-        c.verify();
-    }
-
-    @SuppressWarnings("unchecked")
-    private ServiceReference<DiscoveryPlugin> createAppendPlugin(BundleContext ctx) {
-        DiscoveryPlugin plugin1 = new DiscoveryPlugin() {
-            public String process(Map<String, Object> mutableProperties, String endpointKey) {
-                String eid = (String) mutableProperties.get("endpoint.id");
-                mutableProperties.put("endpoint.id", eid + "/appended");
-                return endpointKey;
-            }
-        };
-        ServiceReference<DiscoveryPlugin> sr1 = EasyMock.createMock(ServiceReference.class);
-        EasyMock.expect(ctx.getService(sr1)).andReturn(plugin1).anyTimes();
-        return sr1;
-    }
-
-    @SuppressWarnings("unchecked")
-    private ServiceReference<DiscoveryPlugin> createPropertyPlugin(BundleContext ctx) {
-        DiscoveryPlugin plugin2 = new DiscoveryPlugin() {
-            public String process(Map<String, Object> mutableProperties, String endpointKey) {
-                mutableProperties.put("foo", "bar");
-                return endpointKey.replaceAll("localhost", "some.machine");
-            }
-        };
-        ServiceReference<DiscoveryPlugin> sr2 = EasyMock.createMock(ServiceReference.class);
-        EasyMock.expect(ctx.getService(sr2)).andReturn(plugin2).anyTimes();
-        return sr2;
-    }
-
-    @SuppressWarnings("unchecked")
-    private List<EndpointDescription> getEndpoints(PublishingEndpointListener eli) throws Exception {
-        Field field = eli.getClass().getDeclaredField("endpoints");
-        field.setAccessible(true);
-        return (List<EndpointDescription>) field.get(eli);
-    }
-
-    private void stubCreateFilter(BundleContext ctx) throws InvalidSyntaxException {
-        EasyMock.expect(ctx.createFilter(EasyMock.isA(String.class))).andAnswer(new IAnswer<Filter>() {
-            public Filter answer() throws Throwable {
-                return FrameworkUtil.createFilter((String) EasyMock.getCurrentArguments()[0]);
-            }
-        }).anyTimes();
-    }
-
-    private void expectCreated(ZooKeeper zk, String path, byte[] dataMatcher) throws KeeperException, InterruptedException {
-        expect(zk.create(EasyMock.eq(path), 
-                         dataMatcher, 
-                         EasyMock.eq(Ids.OPEN_ACL_UNSAFE),
-                         EasyMock.eq(CreateMode.EPHEMERAL)))
-            .andReturn("");
-    }
-    
-    private void expectCreated(ZooKeeper zk, String path) throws KeeperException, InterruptedException {
-        expect(zk.create(EasyMock.eq(path), 
-                         (byte[])EasyMock.anyObject(), 
-                         EasyMock.eq(Ids.OPEN_ACL_UNSAFE),
-                         EasyMock.eq(CreateMode.EPHEMERAL)))
-            .andReturn("");
-    }
-
-    private void expectDeleted(ZooKeeper zk, String path) throws InterruptedException, KeeperException {
-        zk.delete(EasyMock.eq(path), EasyMock.eq(-1));
-        EasyMock.expectLastCall().once();
-    }
-
-    private EndpointDescription createEndpoint() {
-        Map<String, Object> props = new HashMap<String, Object>();
-        props.put(Constants.OBJECTCLASS, new String[] {"myClass"});
-        props.put(RemoteConstants.ENDPOINT_ID, "http://google.de:80/test/sub");
-        props.put(RemoteConstants.SERVICE_IMPORTED_CONFIGS, "myConfig");
-        return new EndpointDescription(props);
-    }
-}

http://git-wip-us.apache.org/repos/asf/aries-rsa/blob/69bb901e/discovery/zookeeper/src/test/java/org/apache/cxf/dosgi/discovery/zookeeper/subscribe/InterfaceMonitorManagerTest.java
----------------------------------------------------------------------
diff --git a/discovery/zookeeper/src/test/java/org/apache/cxf/dosgi/discovery/zookeeper/subscribe/InterfaceMonitorManagerTest.java b/discovery/zookeeper/src/test/java/org/apache/cxf/dosgi/discovery/zookeeper/subscribe/InterfaceMonitorManagerTest.java
deleted file mode 100644
index 01aea63..0000000
--- a/discovery/zookeeper/src/test/java/org/apache/cxf/dosgi/discovery/zookeeper/subscribe/InterfaceMonitorManagerTest.java
+++ /dev/null
@@ -1,112 +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.cxf.dosgi.discovery.zookeeper.subscribe;
-
-import static org.junit.Assert.assertEquals;
-
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-
-import org.apache.zookeeper.ZooKeeper;
-import org.easymock.EasyMock;
-import org.easymock.IAnswer;
-import org.easymock.IMocksControl;
-import org.junit.Test;
-import org.osgi.framework.BundleContext;
-import org.osgi.framework.ServiceReference;
-import org.osgi.service.remoteserviceadmin.EndpointListener;
-
-public class InterfaceMonitorManagerTest {
-
-    @Test
-    public void testEndpointListenerTrackerCustomizer() {
-        IMocksControl c = EasyMock.createNiceControl();
-        BundleContext ctx = c.createMock(BundleContext.class);
-        ServiceReference<EndpointListener> sref = createService(c);
-        ServiceReference<EndpointListener> sref2 = createService(c);
-        ZooKeeper zk = c.createMock(ZooKeeper.class);
-        InterfaceMonitorManager eltc = new InterfaceMonitorManager(ctx, zk);
-
-        c.replay();
-
-        // sref has no scope -> nothing should happen
-        assertEquals(0, eltc.getEndpointListenerScopes().size());
-        assertEquals(0, eltc.getInterests().size());
-
-        eltc.addInterest(sref, "(objectClass=mine)", "mine");
-        assertScopeIncludes(sref, eltc);
-        assertEquals(1, eltc.getEndpointListenerScopes().size());
-        assertEquals(1, eltc.getInterests().size());
-
-        eltc.addInterest(sref, "(objectClass=mine)", "mine");
-        assertScopeIncludes(sref, eltc);
-        assertEquals(1, eltc.getEndpointListenerScopes().size());
-        assertEquals(1, eltc.getInterests().size());
-
-        eltc.addInterest(sref2, "(objectClass=mine)", "mine");
-        assertScopeIncludes(sref, eltc);
-        assertScopeIncludes(sref2, eltc);
-        assertEquals(2, eltc.getEndpointListenerScopes().size());
-        assertEquals(1, eltc.getInterests().size());
-
-        eltc.removeInterest(sref);
-        assertScopeIncludes(sref2, eltc);
-        assertEquals(1, eltc.getEndpointListenerScopes().size());
-        assertEquals(1, eltc.getInterests().size());
-
-        eltc.removeInterest(sref);
-        assertScopeIncludes(sref2, eltc);
-        assertEquals(1, eltc.getEndpointListenerScopes().size());
-        assertEquals(1, eltc.getInterests().size());
-
-        eltc.removeInterest(sref2);
-        assertEquals(0, eltc.getEndpointListenerScopes().size());
-        assertEquals(0, eltc.getInterests().size());
-
-        c.verify();
-    }
-
-    @SuppressWarnings("unchecked")
-    private ServiceReference<EndpointListener> createService(IMocksControl c) {
-        final Map<String, ?> p = new HashMap<String, Object>();
-        ServiceReference<EndpointListener> sref = c.createMock(ServiceReference.class);
-        EasyMock.expect(sref.getPropertyKeys()).andAnswer(new IAnswer<String[]>() {
-            public String[] answer() throws Throwable {
-                return p.keySet().toArray(new String[p.size()]);
-            }
-        }).anyTimes();
-
-        EasyMock.expect(sref.getProperty((String)EasyMock.anyObject())).andAnswer(new IAnswer<Object>() {
-            public Object answer() throws Throwable {
-                String key = (String)(EasyMock.getCurrentArguments()[0]);
-                return p.get(key);
-            }
-        }).anyTimes();
-        return sref;
-    }
-
-    private void assertScopeIncludes(ServiceReference<EndpointListener> sref, InterfaceMonitorManager eltc) {
-        List<String> srefScope = eltc.getEndpointListenerScopes().get(sref);
-        assertEquals(1, srefScope.size());
-        assertEquals("(objectClass=mine)", srefScope.get(0));
-        
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/aries-rsa/blob/69bb901e/discovery/zookeeper/src/test/java/org/apache/cxf/dosgi/discovery/zookeeper/subscribe/InterfaceMonitorTest.java
----------------------------------------------------------------------
diff --git a/discovery/zookeeper/src/test/java/org/apache/cxf/dosgi/discovery/zookeeper/subscribe/InterfaceMonitorTest.java b/discovery/zookeeper/src/test/java/org/apache/cxf/dosgi/discovery/zookeeper/subscribe/InterfaceMonitorTest.java
deleted file mode 100644
index 044b360..0000000
--- a/discovery/zookeeper/src/test/java/org/apache/cxf/dosgi/discovery/zookeeper/subscribe/InterfaceMonitorTest.java
+++ /dev/null
@@ -1,67 +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.cxf.dosgi.discovery.zookeeper.subscribe;
-
-import java.util.Collections;
-
-import junit.framework.TestCase;
-
-import org.apache.cxf.dosgi.discovery.zookeeper.util.Utils;
-import org.apache.zookeeper.KeeperException;
-import org.apache.zookeeper.WatchedEvent;
-import org.apache.zookeeper.Watcher.Event.EventType;
-import org.apache.zookeeper.Watcher.Event.KeeperState;
-import org.apache.zookeeper.ZooKeeper;
-import org.apache.zookeeper.data.Stat;
-import org.easymock.EasyMock;
-import org.easymock.IMocksControl;
-import org.osgi.service.remoteserviceadmin.EndpointListener;
-
-import static org.easymock.EasyMock.eq;
-import static org.easymock.EasyMock.expect;
-
-public class InterfaceMonitorTest extends TestCase {
-
-    public void testInterfaceMonitor() throws KeeperException, InterruptedException {
-        IMocksControl c = EasyMock.createControl();
-
-        ZooKeeper zk = c.createMock(ZooKeeper.class);
-        expect(zk.getState()).andReturn(ZooKeeper.States.CONNECTED).anyTimes();
-
-        String scope = "(myProp=test)";
-        String interf = "es.schaaf.test";
-        String node = Utils.getZooKeeperPath(interf);
-
-        EndpointListener endpointListener = c.createMock(EndpointListener.class);
-        InterfaceMonitor im = new InterfaceMonitor(zk, interf, endpointListener, scope);
-        zk.exists(eq(node), eq(im), eq(im), EasyMock.anyObject());
-        EasyMock.expectLastCall().once();
-
-        expect(zk.exists(eq(node), eq(false))).andReturn(new Stat()).anyTimes();
-        expect(zk.getChildren(eq(node), eq(false))).andReturn(Collections.<String> emptyList()).once();
-        expect(zk.getChildren(eq(node), eq(im))).andReturn(Collections.<String> emptyList()).once();
-
-        c.replay();
-        im.start();
-        // simulate a zk callback
-        WatchedEvent we = new WatchedEvent(EventType.NodeCreated, KeeperState.SyncConnected, node);
-        im.process(we);
-        c.verify();
-    }
-}

http://git-wip-us.apache.org/repos/asf/aries-rsa/blob/69bb901e/discovery/zookeeper/src/test/java/org/apache/cxf/dosgi/discovery/zookeeper/util/UtilsTest.java
----------------------------------------------------------------------
diff --git a/discovery/zookeeper/src/test/java/org/apache/cxf/dosgi/discovery/zookeeper/util/UtilsTest.java b/discovery/zookeeper/src/test/java/org/apache/cxf/dosgi/discovery/zookeeper/util/UtilsTest.java
deleted file mode 100644
index 1f72b88..0000000
--- a/discovery/zookeeper/src/test/java/org/apache/cxf/dosgi/discovery/zookeeper/util/UtilsTest.java
+++ /dev/null
@@ -1,35 +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.cxf.dosgi.discovery.zookeeper.util;
-
-import junit.framework.TestCase;
-
-public class UtilsTest extends TestCase {
-
-    public void testGetZooKeeperPath() {
-        assertEquals(Utils.PATH_PREFIX + '/' + "org/example/Test",
-            Utils.getZooKeeperPath("org.example.Test"));
-
-        // used for the recursive discovery
-        assertEquals(Utils.PATH_PREFIX, Utils.getZooKeeperPath(null));
-        assertEquals(Utils.PATH_PREFIX, Utils.getZooKeeperPath(""));
-    }
-
-
-}

http://git-wip-us.apache.org/repos/asf/aries-rsa/blob/69bb901e/examples/echotcp/Readme.md
----------------------------------------------------------------------
diff --git a/examples/echotcp/Readme.md b/examples/echotcp/Readme.md
new file mode 100644
index 0000000..c7b0525
--- /dev/null
+++ b/examples/echotcp/Readme.md
@@ -0,0 +1,44 @@
+# Example echo TCP
+
+Implements a simple echo service and exposes it using the Aries RSA TCP provider.
+
+# Install
+
+Download Apache Karaf 4.0.5
+
+## Service
+Extract to container_a and start. In the shell execute the commands below:
+
+config:property-set -p org.apache.aries.rsa.discovery.zookeeper zookeeper.port 2181
+config:property-set -p org.apache.aries.rsa.discovery.zookeeper.server clientPort 2181
+feature:repo-add aries-rsa 1.8-SNAPSHOT
+feature:install scr aries-rsa-provider-tcp aries-rsa-discovery-zookeeper
+install -s mvn:org.apache.aries.rsa.examples.echotcp/org.apache.aries.rsa.examples.echotcp.api
+install -s mvn:org.apache.aries.rsa.examples.echotcp/org.apache.aries.rsa.examples.echotcp.service
+
+The log should show that the service is exported using the tcp provider and published to zookeeper.
+It should look similar to this:
+
+2016-03-14 11:59:53,548 | INFO  | pool-50-thread-5 | TopologyManagerExport            | 57 - org.apache.aries.rsa.topology-manager - 1.8.0.SNAPSHOT | TopologyManager: export successful for [org.apache.aries.rsa.examples.echotcp.api.EchoService], endpoints: [{component.id=1, component.name=org.apache.aries.rsa.examples.echotcp.service.EchoServiceImpl, endpoint.framework.uuid=2b242970-0d54-49c4-a321-b0c323809c24, endpoint.id=tcp://192.168.0.129:36384, endpoint.package.version.org.apache.aries.rsa.examples.echotcp.api=1.0.0, endpoint.service.id=138, objectClass=[org.apache.aries.rsa.examples.echotcp.api.EchoService], service.bundleid=64, service.imported=true, service.imported.configs=[aries.tcp], service.scope=bundle}]
+2016-03-14 11:59:53,549 | INFO  | pool-50-thread-5 | PublishingEndpointListener       | 54 - org.apache.aries.rsa.discovery.zookeeper - 1.8.0.SNAPSHOT | Local EndpointDescription added: {component.id=1, component.name=org.apache.aries.rsa.examples.echotcp.service.EchoServiceImpl, endpoint.framework.uuid=2b242970-0d54-49c4-a321-b0c323809c24, endpoint.id=tcp://192.168.0.129:36384, endpoint.package.version.org.apache.aries.rsa.examples.echotcp.api=1.0.0, endpoint.service.id=138, objectClass=[org.apache.aries.rsa.examples.echotcp.api.EchoService], service.bundleid=64, service.imported=true, service.imported.configs=[aries.tcp], service.scope=bundle}
+
+
+## Consumer
+Extract to container_b and start. In the shell execute the commands below:
+
+config:property-set -p org.apache.aries.rsa.discovery.zookeeper zookeeper.port 2181
+feature:repo-add aries-rsa 1.8-SNAPSHOT
+feature:install scr aries-rsa-provider-tcp aries-rsa-discovery-zookeeper
+install -s mvn:org.apache.aries.rsa.examples.echotcp/org.apache.aries.rsa.examples.echotcp.api
+install -s mvn:org.apache.aries.rsa.examples.echotcp/org.apache.aries.rsa.examples.echotcp.consumer
+
+The consumer should start and show:
+Sending to echo service
+Good morning
+
+The log should show that the discovery picks up the endpoint from zookeeper and that the RemoteServiceAdmin imports the service.
+
+2016-03-14 12:03:30,518 | INFO  | er])-EventThread | InterfaceMonitor                 | 54 - org.apache.aries.rsa.discovery.zookeeper - 1.8.0.SNAPSHOT | found new node /osgi/service_registry/org/apache/aries/rsa/examples/echotcp/api/EchoService/[192.168.0.129#36384#]   ( []->child )  props: [1, org.apache.aries.rsa.examples.echotcp.service.EchoServiceImpl, 2b242970-0d54-49c4-a321-b0c323809c24, tcp://192.168.0.129:36384, 1.0.0, 138, [Ljava.lang.String;@69a6817f, 64, true, [Ljava.lang.String;@8514b3a, bundle]
+2016-03-14 12:03:30,520 | INFO  | er])-EventThread | InterfaceMonitorManager          | 54 - org.apache.aries.rsa.discovery.zookeeper - 1.8.0.SNAPSHOT | calling EndpointListener.endpointAdded: org.apache.aries.rsa.topologymanager.importer.TopologyManagerImport@2366e9c8 from bundle org.apache.aries.rsa.topology-manager for endpoint: {component.id=1, component.name=org.apache.aries.rsa.examples.echotcp.service.EchoServiceImpl, endpoint.framework.uuid=2b242970-0d54-49c4-a321-b0c323809c24, endpoint.id=tcp://192.168.0.129:36384, endpoint.package.version.org.apache.aries.rsa.examples.echotcp.api=1.0.0, endpoint.service.id=138, objectClass=[org.apache.aries.rsa.examples.echotcp.api.EchoService], service.bundleid=64, service.imported=true, service.imported.configs=[aries.tcp], service.scope=bundle}
+2016-03-14 12:03:30,522 | INFO  | pool-41-thread-1 | RemoteServiceAdminCore           | 52 - org.apache.aries.rsa.core - 1.8.0.SNAPSHOT | Importing service tcp://192.168.0.129:36384 with interfaces [org.apache.aries.rsa.examples.echotcp.api.EchoService] using handler class org.apache.aries.rsa.provider.tcp.TCPProvider.
+

http://git-wip-us.apache.org/repos/asf/aries-rsa/blob/69bb901e/examples/echotcp/api/bnd.bnd
----------------------------------------------------------------------
diff --git a/examples/echotcp/api/bnd.bnd b/examples/echotcp/api/bnd.bnd
new file mode 100644
index 0000000..73d19a4
--- /dev/null
+++ b/examples/echotcp/api/bnd.bnd
@@ -0,0 +1 @@
+Export-Package: org.apache.aries.rsa.examples.echotcp.api
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/aries-rsa/blob/69bb901e/examples/echotcp/api/pom.xml
----------------------------------------------------------------------
diff --git a/examples/echotcp/api/pom.xml b/examples/echotcp/api/pom.xml
new file mode 100644
index 0000000..e24452f
--- /dev/null
+++ b/examples/echotcp/api/pom.xml
@@ -0,0 +1,11 @@
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+  <modelVersion>4.0.0</modelVersion>
+  <parent>
+    <groupId>org.apache.aries.rsa.examples</groupId>
+    <artifactId>org.apache.aries.rsa.examples.echotcp</artifactId>
+    <version>1.8-SNAPSHOT</version>
+  </parent>
+  <groupId>org.apache.aries.rsa.examples.echotcp</groupId>
+  <artifactId>org.apache.aries.rsa.examples.echotcp.api</artifactId>
+  <packaging>bundle</packaging>
+</project>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/aries-rsa/blob/69bb901e/examples/echotcp/api/src/main/java/org/apache/aries/rsa/examples/echotcp/api/EchoService.java
----------------------------------------------------------------------
diff --git a/examples/echotcp/api/src/main/java/org/apache/aries/rsa/examples/echotcp/api/EchoService.java b/examples/echotcp/api/src/main/java/org/apache/aries/rsa/examples/echotcp/api/EchoService.java
new file mode 100644
index 0000000..998c0d7
--- /dev/null
+++ b/examples/echotcp/api/src/main/java/org/apache/aries/rsa/examples/echotcp/api/EchoService.java
@@ -0,0 +1,5 @@
+package org.apache.aries.rsa.examples.echotcp.api;
+
+public interface EchoService {
+    public String echo(String msg);
+}

http://git-wip-us.apache.org/repos/asf/aries-rsa/blob/69bb901e/examples/echotcp/api/src/main/java/org/apache/aries/rsa/examples/echotcp/api/packageinfo
----------------------------------------------------------------------
diff --git a/examples/echotcp/api/src/main/java/org/apache/aries/rsa/examples/echotcp/api/packageinfo b/examples/echotcp/api/src/main/java/org/apache/aries/rsa/examples/echotcp/api/packageinfo
new file mode 100644
index 0000000..c72722a
--- /dev/null
+++ b/examples/echotcp/api/src/main/java/org/apache/aries/rsa/examples/echotcp/api/packageinfo
@@ -0,0 +1,19 @@
+#
+# 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.
+#
+version 1.0.0

http://git-wip-us.apache.org/repos/asf/aries-rsa/blob/69bb901e/examples/echotcp/consumer/bnd.bnd
----------------------------------------------------------------------
diff --git a/examples/echotcp/consumer/bnd.bnd b/examples/echotcp/consumer/bnd.bnd
new file mode 100644
index 0000000..f29f0a2
--- /dev/null
+++ b/examples/echotcp/consumer/bnd.bnd
@@ -0,0 +1 @@
+-dsannotations: *
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/aries-rsa/blob/69bb901e/examples/echotcp/consumer/pom.xml
----------------------------------------------------------------------
diff --git a/examples/echotcp/consumer/pom.xml b/examples/echotcp/consumer/pom.xml
new file mode 100644
index 0000000..a479018
--- /dev/null
+++ b/examples/echotcp/consumer/pom.xml
@@ -0,0 +1,39 @@
+<?xml version='1.0' encoding='UTF-8' ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements. See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership. The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License. You may obtain a copy of the License at
+
+  http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied. See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+    <parent>
+        <groupId>org.apache.aries.rsa.examples</groupId>
+        <artifactId>org.apache.aries.rsa.examples.echotcp</artifactId>
+        <version>1.8-SNAPSHOT</version>
+    </parent>
+    <groupId>org.apache.aries.rsa.examples.echotcp</groupId>
+    <artifactId>org.apache.aries.rsa.examples.echotcp.consumer</artifactId>
+    <packaging>bundle</packaging>
+
+    <dependencies>
+        <dependency>
+            <groupId>org.apache.aries.rsa.examples.echotcp</groupId>
+            <artifactId>org.apache.aries.rsa.examples.echotcp.api</artifactId>
+            <version>${project.version}</version>
+        </dependency>
+    </dependencies>
+</project>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/aries-rsa/blob/69bb901e/examples/echotcp/consumer/src/main/java/org/apache/aries/rsa/examples/echotcp/consumer/EchoConsumer.java
----------------------------------------------------------------------
diff --git a/examples/echotcp/consumer/src/main/java/org/apache/aries/rsa/examples/echotcp/consumer/EchoConsumer.java b/examples/echotcp/consumer/src/main/java/org/apache/aries/rsa/examples/echotcp/consumer/EchoConsumer.java
new file mode 100644
index 0000000..988901f
--- /dev/null
+++ b/examples/echotcp/consumer/src/main/java/org/apache/aries/rsa/examples/echotcp/consumer/EchoConsumer.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.aries.rsa.examples.echotcp.consumer;
+
+import org.apache.aries.rsa.examples.echotcp.api.EchoService;
+import org.osgi.service.component.annotations.Activate;
+import org.osgi.service.component.annotations.Component;
+import org.osgi.service.component.annotations.Reference;
+
+@Component(immediate=true)
+public class EchoConsumer {
+    
+    EchoService echoService;
+
+    @Activate
+    public void activate() {
+        System.out.println("Sending to echo service");
+        System.out.println(echoService.echo("Good morning"));
+    }
+
+    @Reference
+    public void setEchoService(EchoService echoService) {
+        this.echoService = echoService;
+    }
+}

http://git-wip-us.apache.org/repos/asf/aries-rsa/blob/69bb901e/examples/echotcp/pom.xml
----------------------------------------------------------------------
diff --git a/examples/echotcp/pom.xml b/examples/echotcp/pom.xml
new file mode 100644
index 0000000..f12604b
--- /dev/null
+++ b/examples/echotcp/pom.xml
@@ -0,0 +1,76 @@
+<?xml version='1.0' encoding='UTF-8' ?>
+<!-- Licensed to the Apache Software Foundation (ASF) under one or more contributor 
+    license agreements. See the NOTICE file distributed with this work for additional 
+    information regarding copyright ownership. The ASF licenses this file to 
+    you under the Apache License, Version 2.0 (the "License"); you may not use 
+    this file except in compliance with the License. You may obtain a copy of 
+    the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required 
+    by applicable law or agreed to in writing, software distributed under the 
+    License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS 
+    OF ANY KIND, either express or implied. See the License for the specific 
+    language governing permissions and limitations under the License. -->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+    <parent>
+        <groupId>org.apache.aries.rsa</groupId>
+        <artifactId>examples</artifactId>
+        <version>1.8-SNAPSHOT</version>
+    </parent>
+    <groupId>org.apache.aries.rsa.examples</groupId>
+    <artifactId>org.apache.aries.rsa.examples.echotcp</artifactId>
+    <packaging>pom</packaging>
+
+    <modules>
+        <module>api</module>
+        <module>service</module>
+        <module>consumer</module>
+    </modules>
+
+    <dependencies>
+        <dependency>
+            <groupId>org.osgi</groupId>
+            <artifactId>org.osgi.core</artifactId>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.osgi</groupId>
+            <artifactId>org.osgi.compendium</artifactId>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.slf4j</groupId>
+            <artifactId>slf4j-api</artifactId>
+            <scope>provided</scope>
+        </dependency>
+    </dependencies>
+
+    <build>
+        <plugins>
+            <plugin>
+                <groupId>org.apache.felix</groupId>
+                <artifactId>maven-bundle-plugin</artifactId>
+                <version>3.0.1</version>
+                <extensions>true</extensions>
+                <configuration>
+                    <obrRepository>NONE</obrRepository>
+                    <instructions>
+                        <Export-Package>!*</Export-Package>
+                        <_include>-bnd.bnd</_include>
+                    </instructions>
+                </configuration>
+            </plugin>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-compiler-plugin</artifactId>
+                <version>3.5.1</version>
+                <configuration>
+                    <source>1.7</source>
+                    <target>1.7</target>
+                    <maxmem>256M</maxmem>
+                    <fork>false</fork>
+                </configuration>
+            </plugin>
+        </plugins>
+    </build>
+</project>

http://git-wip-us.apache.org/repos/asf/aries-rsa/blob/69bb901e/examples/echotcp/service/bnd.bnd
----------------------------------------------------------------------
diff --git a/examples/echotcp/service/bnd.bnd b/examples/echotcp/service/bnd.bnd
new file mode 100644
index 0000000..73d19a4
--- /dev/null
+++ b/examples/echotcp/service/bnd.bnd
@@ -0,0 +1 @@
+Export-Package: org.apache.aries.rsa.examples.echotcp.api
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/aries-rsa/blob/69bb901e/examples/echotcp/service/pom.xml
----------------------------------------------------------------------
diff --git a/examples/echotcp/service/pom.xml b/examples/echotcp/service/pom.xml
new file mode 100644
index 0000000..50506ac
--- /dev/null
+++ b/examples/echotcp/service/pom.xml
@@ -0,0 +1,39 @@
+<?xml version='1.0' encoding='UTF-8' ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements. See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership. The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License. You may obtain a copy of the License at
+
+  http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied. See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+    <parent>
+        <groupId>org.apache.aries.rsa.examples</groupId>
+        <artifactId>org.apache.aries.rsa.examples.echotcp</artifactId>
+        <version>1.8-SNAPSHOT</version>
+    </parent>
+    <groupId>org.apache.aries.rsa.examples.echotcp</groupId>
+    <artifactId>org.apache.aries.rsa.examples.echotcp.service</artifactId>
+    <packaging>bundle</packaging>
+
+    <dependencies>
+        <dependency>
+            <groupId>org.apache.aries.rsa.examples.echotcp</groupId>
+            <artifactId>org.apache.aries.rsa.examples.echotcp.api</artifactId>
+            <version>${project.version}</version>
+        </dependency>
+    </dependencies>
+</project>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/aries-rsa/blob/69bb901e/examples/echotcp/service/src/main/java/org/apache/aries/rsa/examples/echotcp/service/EchoServiceImpl.java
----------------------------------------------------------------------
diff --git a/examples/echotcp/service/src/main/java/org/apache/aries/rsa/examples/echotcp/service/EchoServiceImpl.java b/examples/echotcp/service/src/main/java/org/apache/aries/rsa/examples/echotcp/service/EchoServiceImpl.java
new file mode 100644
index 0000000..8b31e03
--- /dev/null
+++ b/examples/echotcp/service/src/main/java/org/apache/aries/rsa/examples/echotcp/service/EchoServiceImpl.java
@@ -0,0 +1,14 @@
+package org.apache.aries.rsa.examples.echotcp.service;
+
+import org.apache.aries.rsa.examples.echotcp.api.EchoService;
+import org.osgi.service.component.annotations.Component;
+
+@Component(property={"service.exported.interfaces=*"})
+public class EchoServiceImpl implements EchoService {
+
+    @Override
+    public String echo(String msg) {
+        return msg;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/aries-rsa/blob/69bb901e/examples/pom.xml
----------------------------------------------------------------------
diff --git a/examples/pom.xml b/examples/pom.xml
new file mode 100644
index 0000000..ba60a97
--- /dev/null
+++ b/examples/pom.xml
@@ -0,0 +1,43 @@
+<?xml version='1.0' encoding='UTF-8' ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements. See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership. The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License. You may obtain a copy of the License at
+
+  http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied. See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+
+    <modelVersion>4.0.0</modelVersion>
+
+    <parent>
+      <groupId>org.apache.aries.rsa</groupId>
+      <artifactId>parent</artifactId>
+      <version>1.8-SNAPSHOT</version>
+      <relativePath>../parent/pom.xml</relativePath>
+    </parent>
+    
+    <artifactId>examples</artifactId>
+    <packaging>pom</packaging>
+    
+    <name>Aries Remote Service Admin Examples</name>
+
+    <properties>
+      <topDirectoryLocation>..</topDirectoryLocation>
+    </properties>
+
+    <modules>
+    <module>echotcp</module>
+    </modules>
+</project>

http://git-wip-us.apache.org/repos/asf/aries-rsa/blob/69bb901e/features/src/main/resources/features.xml
----------------------------------------------------------------------
diff --git a/features/src/main/resources/features.xml b/features/src/main/resources/features.xml
index d4325fa..efa8ff2 100644
--- a/features/src/main/resources/features.xml
+++ b/features/src/main/resources/features.xml
@@ -24,8 +24,4 @@
         <bundle>mvn:org.apache.aries.rsa.discovery/zookeeper/${project.version}</bundle>
     </feature>
 
-    <feature name="aries-rsa-zookeeper-server" version="${project.version}">
-        <bundle>mvn:org.apache.zookeeper/zookeeper/${zookeeper.version}</bundle>
-        <bundle>mvn:org.apache.aries.rsa.discovery/zookeeper-server/${project.version}</bundle>
-    </feature>
 </features>

http://git-wip-us.apache.org/repos/asf/aries-rsa/blob/69bb901e/itests/felix/pom.xml
----------------------------------------------------------------------
diff --git a/itests/felix/pom.xml b/itests/felix/pom.xml
index c76dbe4..bf82d9c 100644
--- a/itests/felix/pom.xml
+++ b/itests/felix/pom.xml
@@ -34,6 +34,12 @@
             <version>1.8.8</version>
         </dependency>
         <dependency>
+            <groupId>org.apache.felix</groupId>
+            <artifactId>org.apache.felix.scr</artifactId>
+            <version>2.0.0</version>
+        </dependency>
+        
+        <dependency>
             <groupId>org.apache.aries.rsa</groupId>
             <artifactId>core</artifactId>
             <version>${project.version}</version>
@@ -58,21 +64,33 @@
             <version>${project.version}</version>
         </dependency>
         <dependency>
-            <groupId>org.apache.aries.rsa.discovery</groupId>
-            <artifactId>zookeeper-server</artifactId>
-            <version>${project.version}</version>
-        </dependency>
-        <dependency>
             <groupId>org.apache.aries.rsa.provider</groupId>
             <artifactId>tcp</artifactId>
             <version>${project.version}</version>
         </dependency>
 
         <dependency>
-            <groupId>org.apache.aries.rsa.itests</groupId>
-            <artifactId>testbundle-tcp-service</artifactId>
+            <groupId>org.apache.felix</groupId>
+            <artifactId>org.apache.felix.scr</artifactId>
+            <version>2.0.2</version>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.aries.rsa.examples.echotcp</groupId>
+            <artifactId>org.apache.aries.rsa.examples.echotcp.api</artifactId>
             <version>${project.version}</version>
         </dependency>
+        <dependency>
+            <groupId>org.apache.aries.rsa.examples.echotcp</groupId>
+            <artifactId>org.apache.aries.rsa.examples.echotcp.service</artifactId>
+            <version>${project.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.aries.rsa.examples.echotcp</groupId>
+            <artifactId>org.apache.aries.rsa.examples.echotcp.consumer</artifactId>
+            <version>${project.version}</version>
+        </dependency>
+        
+        
 
         <dependency>
             <groupId>org.apache.geronimo.specs</groupId>
@@ -99,19 +117,18 @@
             <artifactId>pax-exam-link-mvn</artifactId>
             <scope>test</scope>
         </dependency>
-
         <dependency>
             <groupId>org.ops4j.pax.url</groupId>
             <artifactId>pax-url-aether</artifactId>
             <scope>test</scope>
         </dependency>
-
         <dependency>
             <groupId>org.apache.felix</groupId>
             <artifactId>org.apache.felix.framework</artifactId>
             <version>5.0.1</version>
             <scope>test</scope>
         </dependency>
+
         <dependency>
             <groupId>org.apache.zookeeper</groupId>
             <artifactId>zookeeper</artifactId>

http://git-wip-us.apache.org/repos/asf/aries-rsa/blob/69bb901e/itests/felix/src/test/java/org/apache/aries/rsa/itests/felix/RsaTestBase.java
----------------------------------------------------------------------
diff --git a/itests/felix/src/test/java/org/apache/aries/rsa/itests/felix/RsaTestBase.java b/itests/felix/src/test/java/org/apache/aries/rsa/itests/felix/RsaTestBase.java
new file mode 100644
index 0000000..90856ff
--- /dev/null
+++ b/itests/felix/src/test/java/org/apache/aries/rsa/itests/felix/RsaTestBase.java
@@ -0,0 +1,120 @@
+package org.apache.aries.rsa.itests.felix;
+
+import static org.ops4j.pax.exam.CoreOptions.composite;
+import static org.ops4j.pax.exam.CoreOptions.junitBundles;
+import static org.ops4j.pax.exam.CoreOptions.mavenBundle;
+import static org.ops4j.pax.exam.CoreOptions.systemProperty;
+import static org.ops4j.pax.exam.CoreOptions.vmOption;
+import static org.ops4j.pax.exam.CoreOptions.when;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.InetSocketAddress;
+import java.net.ServerSocket;
+import java.util.Dictionary;
+import java.util.Hashtable;
+
+import javax.inject.Inject;
+
+import org.ops4j.pax.exam.Option;
+import org.ops4j.pax.exam.options.MavenArtifactProvisionOption;
+import org.ops4j.pax.exam.options.OptionalCompositeOption;
+import org.ops4j.pax.tinybundles.core.TinyBundles;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.Constants;
+import org.osgi.service.cm.ConfigurationAdmin;
+
+public class RsaTestBase {
+
+    @Inject
+    BundleContext bundleContext;
+
+    @Inject
+    ConfigurationAdmin configAdmin;
+
+    static OptionalCompositeOption localRepo() {
+        String localRepo = System.getProperty("maven.repo.local");
+        if (localRepo == null) {
+            localRepo = System.getProperty("org.ops4j.pax.url.mvn.localRepository");
+        }
+        return when(localRepo != null)
+            .useOptions(vmOption("-Dorg.ops4j.pax.url.mvn.localRepository=" + localRepo));
+    }
+
+    static MavenArtifactProvisionOption mvn(String groupId, String artifactId) {
+        return mavenBundle().groupId(groupId).artifactId(artifactId).versionAsInProject();
+    }
+
+    public void testInstalled() throws Exception {
+        for (Bundle bundle : bundleContext.getBundles()) {
+            System.out.println(bundle.getBundleId() + " " + bundle.getSymbolicName() + " " + bundle.getState()
+                               + " " + bundle.getVersion());
+        }
+    }
+
+    protected int configureZookeeper() throws IOException, InterruptedException {
+        final int zkPort = 12051;
+        // getFreePort(); does not seem to work
+        System.out.println("*** Port for ZooKeeper Server: " + zkPort);
+        updateZkServerConfig(zkPort, configAdmin);
+        Thread.sleep(1000); // To avoid exceptions in zookeeper client
+        updateZkClientConfig(zkPort, configAdmin);
+        return zkPort;
+    }
+
+    protected void updateZkClientConfig(final int zkPort, ConfigurationAdmin cadmin) throws IOException {
+        Dictionary<String, Object> cliProps = new Hashtable<String, Object>();
+        cliProps.put("zookeeper.host", "127.0.0.1");
+        cliProps.put("zookeeper.port", "" + zkPort);
+        cadmin.getConfiguration("org.apache.aries.rsa.discovery.zookeeper", null).update(cliProps);
+    }
+
+    protected void updateZkServerConfig(final int zkPort, ConfigurationAdmin cadmin) throws IOException {
+        Dictionary<String, Object> svrProps = new Hashtable<String, Object>();
+        svrProps.put("clientPort", zkPort);
+        cadmin.getConfiguration("org.apache.aries.rsa.discovery.zookeeper.server", null).update(svrProps);
+    }
+
+    protected int getFreePort() throws IOException {
+        ServerSocket socket = new ServerSocket();
+        try {
+            socket.setReuseAddress(true); // enables quickly reopening socket on same port
+            socket.bind(new InetSocketAddress(0)); // zero finds a free port
+            return socket.getLocalPort();
+        } finally {
+            socket.close();
+        }
+    }
+
+    static InputStream configBundleConsumer() {
+        return TinyBundles.bundle()
+            .add(ZookeeperDiscoveryConfigurer.class)
+            .set(Constants.BUNDLE_ACTIVATOR, ZookeeperDiscoveryConfigurer.class.getName())
+            .build(TinyBundles.withBnd());
+    }
+
+    static InputStream configBundleServer() {
+        return TinyBundles.bundle()
+            .add(ZookeeperServerConfigurer.class)
+            .set(Constants.BUNDLE_ACTIVATOR, ZookeeperServerConfigurer.class.getName())
+            .build(TinyBundles.withBnd());
+    }
+
+    static Option rsaTcpZookeeper() {
+        return composite(junitBundles(), 
+                         localRepo(),
+                         systemProperty("org.ops4j.pax.logging.DefaultServiceLog.level").value("INFO"),
+                         systemProperty("zkPort").value("15201"),
+                         mvn("org.apache.felix", "org.apache.felix.configadmin"),
+                         mvn("org.apache.aries.rsa", "core"), mvn("org.apache.aries.rsa", "spi"),
+                         mvn("org.apache.aries.rsa", "topology-manager"),
+                         mvn("org.apache.aries.rsa.provider", "tcp"),
+                         mvn("org.apache.aries.rsa.discovery", "local"),
+                         mvn("org.apache.zookeeper", "zookeeper"),
+                         mvn("org.apache.aries.rsa.discovery", "zookeeper")
+                         //CoreOptions.vmOption("-Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=5005")
+            );
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/aries-rsa/blob/69bb901e/itests/felix/src/test/java/org/apache/aries/rsa/itests/felix/TestDiscoveryExport.java
----------------------------------------------------------------------
diff --git a/itests/felix/src/test/java/org/apache/aries/rsa/itests/felix/TestDiscoveryExport.java b/itests/felix/src/test/java/org/apache/aries/rsa/itests/felix/TestDiscoveryExport.java
index 389c88a..dea4929 100644
--- a/itests/felix/src/test/java/org/apache/aries/rsa/itests/felix/TestDiscoveryExport.java
+++ b/itests/felix/src/test/java/org/apache/aries/rsa/itests/felix/TestDiscoveryExport.java
@@ -19,17 +19,10 @@ package org.apache.aries.rsa.itests.felix;
  */
 
 
-import static org.ops4j.pax.exam.CoreOptions.mavenBundle;
+import static org.ops4j.pax.exam.CoreOptions.streamBundle;
 import static org.ops4j.pax.exam.CoreOptions.systemProperty;
-import static org.ops4j.pax.exam.CoreOptions.vmOption;
-import static org.ops4j.pax.exam.CoreOptions.when;
 
 import java.io.ByteArrayInputStream;
-import java.io.IOException;
-import java.net.InetSocketAddress;
-import java.net.ServerSocket;
-import java.util.Dictionary;
-import java.util.Hashtable;
 import java.util.List;
 import java.util.Map;
 
@@ -37,7 +30,7 @@ import javax.inject.Inject;
 
 import org.apache.aries.rsa.discovery.endpoint.EndpointDescriptionParser;
 import org.apache.aries.rsa.discovery.endpoint.PropertiesMapper;
-import org.apache.aries.rsa.itests.tcp.api.EchoService;
+import org.apache.aries.rsa.examples.echotcp.api.EchoService;
 import org.apache.aries.rsa.spi.DistributionProvider;
 import org.apache.zookeeper.WatchedEvent;
 import org.apache.zookeeper.Watcher;
@@ -50,71 +43,35 @@ import org.ops4j.pax.exam.Configuration;
 import org.ops4j.pax.exam.CoreOptions;
 import org.ops4j.pax.exam.Option;
 import org.ops4j.pax.exam.junit.PaxExam;
-import org.osgi.framework.Bundle;
-import org.osgi.framework.BundleContext;
-import org.osgi.service.cm.ConfigurationAdmin;
 import org.osgi.service.remoteserviceadmin.EndpointDescription;
 import org.osgi.xmlns.rsa.v1_0.EndpointDescriptionType;
 
 @RunWith(PaxExam.class)
-public class TestDiscoveryExport {
-
-    private final class DummyWatcher implements Watcher {
-        @Override
-        public void process(WatchedEvent event) {
-        }
-    }
-
-    private static final String GREETER_ZOOKEEPER_NODE = "/osgi/service_registry/org/apache/aries/rsa/itests/tcp/api/EchoService";
-
-    @Inject
-    BundleContext bundleContext;
+public class TestDiscoveryExport extends RsaTestBase {
+    private static final String GREETER_ZOOKEEPER_NODE = "/osgi/service_registry/org/apache/aries/rsa/examples/echotcp/api/EchoService";
 
     @Inject
-    ConfigurationAdmin configAdmin;
-    
-    @Inject
     DistributionProvider tcpProvider;
 
     @Configuration
     public static Option[] configure() throws Exception {
-        String localRepo = System.getProperty("maven.repo.local");
 
-        if (localRepo == null) {
-            localRepo = System.getProperty("org.ops4j.pax.url.mvn.localRepository");
-        }
         return new Option[] {
                 CoreOptions.junitBundles(),
                 systemProperty("org.ops4j.pax.logging.DefaultServiceLog.level").value("INFO"),
-                mavenBundle().groupId("org.apache.felix").artifactId("org.apache.felix.configadmin").versionAsInProject(),
-                mavenBundle().groupId("org.apache.aries.rsa").artifactId("core").versionAsInProject(),
-                mavenBundle().groupId("org.apache.aries.rsa").artifactId("spi").versionAsInProject(),
-                mavenBundle().groupId("org.apache.aries.rsa").artifactId("topology-manager").versionAsInProject(),
-                mavenBundle().groupId("org.apache.aries.rsa.provider").artifactId("tcp").versionAsInProject(),
-                mavenBundle().groupId("org.apache.aries.rsa.discovery").artifactId("local").versionAsInProject(),
-                mavenBundle().groupId("org.apache.zookeeper").artifactId("zookeeper").versionAsInProject(),
-                mavenBundle().groupId("org.apache.aries.rsa.discovery").artifactId("zookeeper").versionAsInProject(),
-                mavenBundle().groupId("org.apache.aries.rsa.discovery").artifactId("zookeeper-server").versionAsInProject(),
-                mavenBundle().groupId("org.apache.aries.rsa.itests").artifactId("testbundle-tcp-service").versionAsInProject(),
-                when(localRepo != null).useOptions(vmOption("-Dorg.ops4j.pax.url.mvn.localRepository=" + localRepo))
+                RsaTestBase.rsaTcpZookeeper(),
+                mvn("org.apache.felix", "org.apache.felix.scr"),
+                mvn("org.apache.aries.rsa.examples.echotcp", "org.apache.aries.rsa.examples.echotcp.api"),
+                mvn("org.apache.aries.rsa.examples.echotcp", "org.apache.aries.rsa.examples.echotcp.service"),
+                localRepo(),
+                streamBundle(configBundleServer())
                 //CoreOptions.vmOption("-Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=5005")
         };
     }
-    
-    public void testInstalled() throws Exception {
-        for (Bundle bundle : bundleContext.getBundles()) {
-            System.out.println(bundle.getBundleId() + " " + bundle.getSymbolicName() + " " + bundle.getState() + " " + bundle.getVersion());
-        }
-    }
 
     @Test
     public void testDiscoveryExport() throws Exception {
-        final int zkPort = 12051;
-        //getFreePort(); does not seem to work 
-        System.out.println("*** Port for ZooKeeper Server: " + zkPort);
-        updateZkServerConfig(zkPort, configAdmin);
-        Thread.sleep(1000); // To avoid exceptions in clients
-        updateZkClientConfig(zkPort, configAdmin);
+        String zkPort = bundleContext.getProperty("zkPort");
         ZooKeeper zk = new ZooKeeper("localhost:" + zkPort, 1000, new DummyWatcher());
         assertNodeExists(zk, GREETER_ZOOKEEPER_NODE, 10000);
         List<String> children = zk.getChildren(GREETER_ZOOKEEPER_NODE, false);
@@ -143,28 +100,11 @@ public class TestDiscoveryExport {
         }
         Assert.assertNotNull("ZooKeeper node " + zNode + " was not found", stat);
     }
-
-    protected void updateZkClientConfig(final int zkPort, ConfigurationAdmin cadmin) throws IOException {
-        Dictionary<String, Object> cliProps = new Hashtable<String, Object>();
-        cliProps.put("zookeeper.host", "127.0.0.1");
-        cliProps.put("zookeeper.port", "" + zkPort);
-        cadmin.getConfiguration("org.apache.aries.rsa.discovery.zookeeper", null).update(cliProps);
-    }
-
-    protected void updateZkServerConfig(final int zkPort, ConfigurationAdmin cadmin) throws IOException {
-        Dictionary<String, Object> svrProps = new Hashtable<String, Object>();
-        svrProps.put("clientPort", zkPort);
-        cadmin.getConfiguration("org.apache.aries.rsa.discovery.zookeeper.server", null).update(svrProps);
-    }
     
-    protected int getFreePort() throws IOException {
-        ServerSocket socket = new ServerSocket();
-        try {
-            socket.setReuseAddress(true); // enables quickly reopening socket on same port
-            socket.bind(new InetSocketAddress(0)); // zero finds a free port
-            return socket.getLocalPort();
-        } finally {
-            socket.close();
+    private final class DummyWatcher implements Watcher {
+        @Override
+        public void process(WatchedEvent event) {
         }
     }
+
 }

http://git-wip-us.apache.org/repos/asf/aries-rsa/blob/69bb901e/itests/felix/src/test/java/org/apache/aries/rsa/itests/felix/TestRoundTrip.java
----------------------------------------------------------------------
diff --git a/itests/felix/src/test/java/org/apache/aries/rsa/itests/felix/TestRoundTrip.java b/itests/felix/src/test/java/org/apache/aries/rsa/itests/felix/TestRoundTrip.java
new file mode 100644
index 0000000..d20c808
--- /dev/null
+++ b/itests/felix/src/test/java/org/apache/aries/rsa/itests/felix/TestRoundTrip.java
@@ -0,0 +1,88 @@
+package org.apache.aries.rsa.itests.felix;
+/**
+ * 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.
+ */
+
+
+import static org.ops4j.pax.exam.CoreOptions.streamBundle;
+import static org.ops4j.pax.exam.CoreOptions.systemProperty;
+
+import java.io.IOException;
+
+import javax.inject.Inject;
+
+import org.apache.aries.rsa.examples.echotcp.api.EchoService;
+import org.junit.Assert;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.ops4j.pax.exam.Configuration;
+import org.ops4j.pax.exam.ExamSystem;
+import org.ops4j.pax.exam.Option;
+import org.ops4j.pax.exam.TestContainer;
+import org.ops4j.pax.exam.junit.PaxExam;
+import org.ops4j.pax.exam.spi.PaxExamRuntime;
+
+@RunWith(PaxExam.class)
+public class TestRoundTrip extends RsaTestBase {
+    private static TestContainer remoteContainer;
+
+    @Inject
+    EchoService echoService;
+    
+    public static void startRemote() throws IOException, InterruptedException {
+        ExamSystem testSystem = PaxExamRuntime.createTestSystem(remoteConfig());
+        remoteContainer = PaxExamRuntime.createContainer(testSystem);
+        remoteContainer.start();
+    }
+
+    private static Option[] remoteConfig() throws IOException {
+        return new Option[] {
+            rsaTcpZookeeper(),
+            mvn("org.apache.felix", "org.apache.felix.scr"),
+            mvn("org.apache.aries.rsa.examples.echotcp", "org.apache.aries.rsa.examples.echotcp.api"),
+            mvn("org.apache.aries.rsa.examples.echotcp", "org.apache.aries.rsa.examples.echotcp.service"),
+            streamBundle(RsaTestBase.configBundleServer()),
+            systemProperty("zkPort").value("15201")
+        };
+    }
+
+    @Configuration
+    public static Option[] configure() throws Exception {
+        startRemote();
+        return new Option[] {
+                rsaTcpZookeeper(),
+                mvn("org.apache.felix", "org.apache.felix.scr"),
+                mvn("org.apache.aries.rsa.examples.echotcp", "org.apache.aries.rsa.examples.echotcp.api"),
+                
+                // Consumer is needed to trigger service import. Pax exam inject does not work for it
+                mvn("org.apache.aries.rsa.examples.echotcp", "org.apache.aries.rsa.examples.echotcp.consumer"),
+                streamBundle(RsaTestBase.configBundleConsumer()),
+                
+        };
+    }
+
+    @Test
+    public void testCall() throws Exception {
+        String answer = echoService.echo("test");
+        Assert.assertEquals("test", answer);
+    }
+
+    public static void shutdownRemote() {
+        remoteContainer.stop();
+    }
+}

http://git-wip-us.apache.org/repos/asf/aries-rsa/blob/69bb901e/itests/felix/src/test/java/org/apache/aries/rsa/itests/felix/ZookeeperDiscoveryConfigurer.java
----------------------------------------------------------------------
diff --git a/itests/felix/src/test/java/org/apache/aries/rsa/itests/felix/ZookeeperDiscoveryConfigurer.java b/itests/felix/src/test/java/org/apache/aries/rsa/itests/felix/ZookeeperDiscoveryConfigurer.java
new file mode 100644
index 0000000..e12a988
--- /dev/null
+++ b/itests/felix/src/test/java/org/apache/aries/rsa/itests/felix/ZookeeperDiscoveryConfigurer.java
@@ -0,0 +1,28 @@
+package org.apache.aries.rsa.itests.felix;
+
+import java.util.Dictionary;
+import java.util.Hashtable;
+
+import org.osgi.framework.BundleActivator;
+import org.osgi.framework.BundleContext;
+import org.osgi.service.cm.ConfigurationAdmin;
+import org.osgi.util.tracker.ServiceTracker;
+
+public class ZookeeperDiscoveryConfigurer implements BundleActivator {
+
+    @Override
+    public void start(BundleContext context) throws Exception {
+        ServiceTracker<ConfigurationAdmin, Object> tracker = new ServiceTracker<>(context, ConfigurationAdmin.class, null);
+        tracker.open();
+        ConfigurationAdmin configAdmin = (ConfigurationAdmin)tracker.getService();
+        Dictionary<String, Object> cliProps = new Hashtable<String, Object>();
+        cliProps.put("zookeeper.host", "127.0.0.1");
+        cliProps.put("zookeeper.port", "" + context.getProperty("zkPort"));
+        configAdmin.getConfiguration("org.apache.aries.rsa.discovery.zookeeper", null).update(cliProps);
+        tracker.close();
+    }
+
+    @Override
+    public void stop(BundleContext context) throws Exception {
+    }
+}

http://git-wip-us.apache.org/repos/asf/aries-rsa/blob/69bb901e/itests/felix/src/test/java/org/apache/aries/rsa/itests/felix/ZookeeperServerConfigurer.java
----------------------------------------------------------------------
diff --git a/itests/felix/src/test/java/org/apache/aries/rsa/itests/felix/ZookeeperServerConfigurer.java b/itests/felix/src/test/java/org/apache/aries/rsa/itests/felix/ZookeeperServerConfigurer.java
new file mode 100644
index 0000000..e859207
--- /dev/null
+++ b/itests/felix/src/test/java/org/apache/aries/rsa/itests/felix/ZookeeperServerConfigurer.java
@@ -0,0 +1,32 @@
+package org.apache.aries.rsa.itests.felix;
+
+import java.util.Dictionary;
+import java.util.Hashtable;
+
+import org.osgi.framework.BundleActivator;
+import org.osgi.framework.BundleContext;
+import org.osgi.service.cm.ConfigurationAdmin;
+import org.osgi.util.tracker.ServiceTracker;
+
+public class ZookeeperServerConfigurer implements BundleActivator  {
+
+    @Override
+    public void start(BundleContext context) throws Exception {
+        ServiceTracker<ConfigurationAdmin, Object> tracker = new ServiceTracker<>(context, ConfigurationAdmin.class, null);
+        tracker.open();
+        ConfigurationAdmin configAdmin = (ConfigurationAdmin)tracker.getService();
+        String zkPort = context.getProperty("zkPort");
+        Dictionary<String, Object> svrProps = new Hashtable<String, Object>();
+        svrProps.put("clientPort", zkPort);
+        configAdmin.getConfiguration("org.apache.aries.rsa.discovery.zookeeper.server", null).update(svrProps);
+        Dictionary<String, Object> cliProps = new Hashtable<String, Object>();
+        cliProps.put("zookeeper.host", "127.0.0.1");
+        cliProps.put("zookeeper.port", "" + zkPort);
+        configAdmin.getConfiguration("org.apache.aries.rsa.discovery.zookeeper", null).update(cliProps);
+        tracker.close();
+    }
+
+    @Override
+    public void stop(BundleContext context) throws Exception {
+    }
+}

http://git-wip-us.apache.org/repos/asf/aries-rsa/blob/69bb901e/itests/pom.xml
----------------------------------------------------------------------
diff --git a/itests/pom.xml b/itests/pom.xml
index cb59984..7a6b227 100644
--- a/itests/pom.xml
+++ b/itests/pom.xml
@@ -33,7 +33,6 @@
 
     <modules>
         <module>felix</module>
-        <module>testbundle-service-tcp</module>
     </modules>
 
     <dependencyManagement>

http://git-wip-us.apache.org/repos/asf/aries-rsa/blob/69bb901e/itests/testbundle-service-tcp/bnd.bnd
----------------------------------------------------------------------
diff --git a/itests/testbundle-service-tcp/bnd.bnd b/itests/testbundle-service-tcp/bnd.bnd
deleted file mode 100644
index b0cfcc1..0000000
--- a/itests/testbundle-service-tcp/bnd.bnd
+++ /dev/null
@@ -1,3 +0,0 @@
-Bundle-Activator: org.apache.aries.rsa.itests.tcp.service.Activator
-Export-Package: org.apache.aries.rsa.itests.tcp.api
-Private-Package: org.apache.aries.rsa.itests.tcp.service
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/aries-rsa/blob/69bb901e/itests/testbundle-service-tcp/pom.xml
----------------------------------------------------------------------
diff --git a/itests/testbundle-service-tcp/pom.xml b/itests/testbundle-service-tcp/pom.xml
deleted file mode 100644
index 0fd4d3c..0000000
--- a/itests/testbundle-service-tcp/pom.xml
+++ /dev/null
@@ -1,40 +0,0 @@
-<?xml version='1.0' encoding='UTF-8' ?>
-<!--
-  Licensed to the Apache Software Foundation (ASF) under one
-  or more contributor license agreements. See the NOTICE file
-  distributed with this work for additional information
-  regarding copyright ownership. The ASF licenses this file
-  to you under the Apache License, Version 2.0 (the
-  "License"); you may not use this file except in compliance
-  with the License. You may obtain a copy of the License at
-
-  http://www.apache.org/licenses/LICENSE-2.0
-
-  Unless required by applicable law or agreed to in writing,
-  software distributed under the License is distributed on an
-  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
-  KIND, either express or implied. See the License for the
-  specific language governing permissions and limitations
-  under the License.
--->
-<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
-
-    <modelVersion>4.0.0</modelVersion>
-
-    <parent>
-      <groupId>org.apache.aries.rsa</groupId>
-      <artifactId>itests</artifactId>
-      <version>1.8-SNAPSHOT</version>
-      <relativePath>../pom.xml</relativePath>
-    </parent>
-
-    <groupId>org.apache.aries.rsa.itests</groupId>
-    <artifactId>testbundle-tcp-service</artifactId>
-    <packaging>bundle</packaging>
-
-    <name>Aries Remote Service Admin itests testbundle service tcp</name>
-
-    <dependencies>
-    </dependencies>
-
-</project>

http://git-wip-us.apache.org/repos/asf/aries-rsa/blob/69bb901e/itests/testbundle-service-tcp/src/main/java/org/apache/aries/rsa/itests/tcp/api/EchoService.java
----------------------------------------------------------------------
diff --git a/itests/testbundle-service-tcp/src/main/java/org/apache/aries/rsa/itests/tcp/api/EchoService.java b/itests/testbundle-service-tcp/src/main/java/org/apache/aries/rsa/itests/tcp/api/EchoService.java
deleted file mode 100644
index 877917b..0000000
--- a/itests/testbundle-service-tcp/src/main/java/org/apache/aries/rsa/itests/tcp/api/EchoService.java
+++ /dev/null
@@ -1,5 +0,0 @@
-package org.apache.aries.rsa.itests.tcp.api;
-
-public interface EchoService {
-    public String echo(String msg);
-}


[3/5] aries-rsa git commit: Adding roundtrip test

Posted by cs...@apache.org.
http://git-wip-us.apache.org/repos/asf/aries-rsa/blob/69bb901e/discovery/zookeeper/src/test/java/org/apache/aries/rsa/discovery/zookeeper/DiscoveryDriverTest.java
----------------------------------------------------------------------
diff --git a/discovery/zookeeper/src/test/java/org/apache/aries/rsa/discovery/zookeeper/DiscoveryDriverTest.java b/discovery/zookeeper/src/test/java/org/apache/aries/rsa/discovery/zookeeper/DiscoveryDriverTest.java
new file mode 100644
index 0000000..b0b187a
--- /dev/null
+++ b/discovery/zookeeper/src/test/java/org/apache/aries/rsa/discovery/zookeeper/DiscoveryDriverTest.java
@@ -0,0 +1,135 @@
+/**
+ * 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.aries.rsa.discovery.zookeeper;
+
+import junit.framework.TestCase;
+
+public class DiscoveryDriverTest extends TestCase {
+
+    public void testDUMMY() {
+        assertTrue(true);
+    }
+
+//    public void testDiscoveryDriver() throws Exception {
+//        BundleContext bc = getDefaultBundleContext();
+//        Dictionary<String, String> props = getDefaultProps();
+//
+//        final StringBuilder sb = new StringBuilder();
+//        DiscoveryDriver dd = new DiscoveryDriver(bc, props) {
+//            @Override
+//            ZooKeeper createZooKeeper() throws IOException {
+//                sb.append(zkHost + ":" + zkPort);
+//                ZooKeeper zk = EasyMock.createMock(ZooKeeper.class);
+//                EasyMock.replay(zk);
+//                return zk;
+//            }
+//        };
+//        EasyMock.verify(bc);
+//        assertEquals("somehost:1910", sb.toString());
+//
+//        EasyMock.verify(dd.zooKeeper);
+//        EasyMock.reset(dd.zooKeeper);
+//        dd.zooKeeper.close();
+//        EasyMock.expectLastCall();
+//        EasyMock.replay(dd.zooKeeper);
+//
+//        ServiceTracker st1 = EasyMock.createMock(ServiceTracker.class);
+//        st1.close();
+//        EasyMock.expectLastCall();
+//        EasyMock.replay(st1);
+//        ServiceTracker st2 = EasyMock.createMock(ServiceTracker.class);
+//        st2.close();
+//        EasyMock.expectLastCall();
+//        EasyMock.replay(st2);
+//
+//        dd.lookupTracker = st1;
+//        dd.publicationTracker = st2;
+//
+//        dd.destroy();
+//    }
+//
+//    private void expectServiceTrackerCalls(BundleContext bc, String objectClass)
+//            throws InvalidSyntaxException {
+//        Filter filter = EasyMock.createNiceMock(Filter.class);
+//        EasyMock.replay(filter);
+//
+//        EasyMock.expect(bc.createFilter("(objectClass=" + objectClass + ")"))
+//            .andReturn(filter).anyTimes();
+//        bc.addServiceListener((ServiceListener) EasyMock.anyObject(),
+//            EasyMock.eq("(objectClass=" + objectClass + ")"));
+//        EasyMock.expectLastCall().anyTimes();
+//        EasyMock.expect(bc.getServiceReferences(objectClass, null))
+//            .andReturn(new ServiceReference [0]).anyTimes();
+//    }
+//
+//    public void testProcessEvent() throws Exception {
+//        DiscoveryDriver db = new DiscoveryDriver(getDefaultBundleContext(), getDefaultProps()) {
+//            @Override
+//            ZooKeeper createZooKeeper() throws IOException {
+//                return null;
+//            }
+//        };
+//
+//        FindInZooKeeperCustomizer fc = new FindInZooKeeperCustomizer(null, null);
+//        List<InterfaceMonitor> l1 = new ArrayList<InterfaceMonitor>();
+//        InterfaceMonitor dm1a = EasyMock.createMock(InterfaceMonitor.class);
+//        dm1a.process();
+//        EasyMock.expectLastCall();
+//        EasyMock.replay(dm1a);
+//        InterfaceMonitor dm1b = EasyMock.createMock(InterfaceMonitor.class);
+//        dm1b.process();
+//        EasyMock.expectLastCall();
+//        EasyMock.replay(dm1b);
+//        l1.add(dm1a);
+//        l1.add(dm1b);
+//
+//        List<InterfaceMonitor> l2 = new ArrayList<InterfaceMonitor>();
+//        InterfaceMonitor dm2 = EasyMock.createMock(InterfaceMonitor.class);
+//        dm2.process();
+//        EasyMock.expectLastCall();
+//        EasyMock.replay(dm2);
+//        l2.add(dm2);
+//
+//        fc.watchers.put(EasyMock.createMock(DiscoveredServiceTracker.class), l1);
+//        fc.watchers.put(EasyMock.createMock(DiscoveredServiceTracker.class), l2);
+//
+//        db.finderCustomizer = fc;
+//        db.process(null);
+//
+//        EasyMock.verify(dm1a);
+//        EasyMock.verify(dm1b);
+//        EasyMock.verify(dm2);
+//    }
+//
+//    private BundleContext getDefaultBundleContext() throws InvalidSyntaxException {
+//        BundleContext bc = EasyMock.createMock(BundleContext.class);
+//        expectServiceTrackerCalls(bc, ServicePublication.class.getName());
+//        expectServiceTrackerCalls(bc, DiscoveredServiceTracker.class.getName());
+//        EasyMock.replay(bc);
+//        return bc;
+//    }
+//
+//    private Dictionary<String, String> getDefaultProps() {
+//        Dictionary<String, String> props = new Hashtable<String, String>();
+//        props.put("zookeeper.host", "somehost");
+//        props.put("zookeeper.port", "1910");
+//        props.put("zookeeper.timeout", "1500");
+//        return props;
+//    }
+}

http://git-wip-us.apache.org/repos/asf/aries-rsa/blob/69bb901e/discovery/zookeeper/src/test/java/org/apache/aries/rsa/discovery/zookeeper/FindInZooKeeperCustomizerTest.java
----------------------------------------------------------------------
diff --git a/discovery/zookeeper/src/test/java/org/apache/aries/rsa/discovery/zookeeper/FindInZooKeeperCustomizerTest.java b/discovery/zookeeper/src/test/java/org/apache/aries/rsa/discovery/zookeeper/FindInZooKeeperCustomizerTest.java
new file mode 100644
index 0000000..a0a828a
--- /dev/null
+++ b/discovery/zookeeper/src/test/java/org/apache/aries/rsa/discovery/zookeeper/FindInZooKeeperCustomizerTest.java
@@ -0,0 +1,301 @@
+/**
+ * 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.aries.rsa.discovery.zookeeper;
+
+import junit.framework.TestCase;
+
+public class FindInZooKeeperCustomizerTest extends TestCase {
+
+    public void testDUMMY() {
+        assertTrue(true);
+    }
+
+//    public void testAddingServiceInterface() {
+//        DiscoveredServiceTracker dst = new DiscoveredServiceTracker() {
+//            public void serviceChanged(DiscoveredServiceNotification dsn) {}
+//        };
+//
+//        ServiceReference sr = EasyMock.createMock(ServiceReference.class);
+//        EasyMock.expect(sr.getProperty(DiscoveredServiceTracker.INTERFACE_MATCH_CRITERIA))
+//            .andReturn(Collections.singleton(String.class.getName()));
+//        EasyMock.expect(sr.getProperty(DiscoveredServiceTracker.FILTER_MATCH_CRITERIA))
+//            .andReturn(null);
+//        EasyMock.replay(sr);
+//
+//        DiscoveredServiceTracker dst2 = new DiscoveredServiceTracker() {
+//            public void serviceChanged(DiscoveredServiceNotification dsn) {}
+//        };
+//
+//        ServiceReference sr2 = EasyMock.createMock(ServiceReference.class);
+//        EasyMock.expect(sr2.getProperty(DiscoveredServiceTracker.INTERFACE_MATCH_CRITERIA))
+//            .andReturn(Arrays.asList(Integer.class.getName(), Comparable.class.getName()));
+//        EasyMock.expect(sr2.getProperty(DiscoveredServiceTracker.FILTER_MATCH_CRITERIA))
+//            .andReturn(null);
+//        EasyMock.replay(sr2);
+//
+//        BundleContext bc = EasyMock.createMock(BundleContext.class);
+//        EasyMock.expect(bc.getService(sr)).andReturn(dst);
+//        EasyMock.expect(bc.getService(sr2)).andReturn(dst2);
+//        EasyMock.replay(bc);
+//
+//        ZooKeeper zk = EasyMock.createMock(ZooKeeper.class);
+//        zkExpectExists(zk, String.class.getName());
+//        zkExpectExists(zk, Integer.class.getName());
+//        zkExpectExists(zk, Comparable.class.getName());
+//        EasyMock.expectLastCall();
+//        EasyMock.replay(zk);
+//
+//        FindInZooKeeperCustomizer fc = new FindInZooKeeperCustomizer(bc, zk);
+//
+//        // ---------------------------------------------------------------
+//        // Test the addingService APIs
+//        // ---------------------------------------------------------------
+//
+//        assertEquals("Precondition failed", 0, fc.watchers.size());
+//        fc.addingService(sr);
+//        assertEquals(1, fc.watchers.size());
+//
+//        DiscoveredServiceTracker key = fc.watchers.keySet().iterator().next();
+//        assertSame(dst, key);
+//        List<InterfaceMonitor> dmList = fc.watchers.get(key);
+//        assertEquals(1, dmList.size());
+//        InterfaceMonitor dm = dmList.iterator().next();
+//        assertNotNull(dm.listener);
+//        assertSame(zk, dm.zookeeper);
+//        assertEquals(Utils.getZooKeeperPath(String.class.getName()), dm.znode);
+//
+//        assertEquals("Precondition failed", 1, fc.watchers.size());
+//        fc.addingService(sr2);
+//        assertEquals(2, fc.watchers.size());
+//
+//        assertTrue(fc.watchers.containsKey(dst));
+//        assertTrue(fc.watchers.containsKey(dst2));
+//        assertEquals(dmList, fc.watchers.get(dst));
+//        List<InterfaceMonitor> dmList2 = fc.watchers.get(dst2);
+//        assertEquals(2, dmList2.size());
+//
+//        Set<String> actual = new HashSet<String>();
+//        for (InterfaceMonitor im : dmList2) {
+//            actual.add(im.znode);
+//        }
+//        Set<String> expected = new HashSet<String>(Arrays.asList(
+//                Utils.getZooKeeperPath(Integer.class.getName()),
+//                Utils.getZooKeeperPath(Comparable.class.getName())));
+//        assertEquals(expected, actual);
+//
+//        EasyMock.verify(zk);
+//
+//        // ---------------------------------------------------------------
+//        // Test the modifiedService APIs
+//        // ---------------------------------------------------------------
+//        EasyMock.reset(zk);
+//        zkExpectExists(zk, List.class.getName());
+//        EasyMock.replay(zk);
+//
+//        EasyMock.reset(sr);
+//        EasyMock.expect(sr.getProperty(DiscoveredServiceTracker.INTERFACE_MATCH_CRITERIA))
+//            .andReturn(Collections.singleton(List.class.getName()));
+//        EasyMock.expect(sr.getProperty(DiscoveredServiceTracker.FILTER_MATCH_CRITERIA))
+//            .andReturn(null);
+//        EasyMock.replay(sr);
+//
+//        assertEquals("Precondition failed", 2, fc.watchers.size());
+//        fc.modifiedService(sr, dst);
+//        assertEquals("Precondition failed", 2, fc.watchers.size());
+//
+//        assertTrue(fc.watchers.containsKey(dst));
+//        assertTrue(fc.watchers.containsKey(dst2));
+//        assertEquals(dmList2, fc.watchers.get(dst2));
+//        List<InterfaceMonitor> dmList3 = fc.watchers.get(dst);
+//        assertEquals(1, dmList3.size());
+//        assertEquals(Utils.getZooKeeperPath(List.class.getName()), dmList3.iterator().next().znode);
+//
+//        EasyMock.verify(zk);
+//
+//        // ---------------------------------------------------------------
+//        // Test the removedService APIs
+//        // ---------------------------------------------------------------
+//        EasyMock.reset(zk);
+//        EasyMock.replay(zk);
+//
+//        assertEquals("Precondition failed", 2, fc.watchers.size());
+//        fc.removedService(sr2, dst2);
+//        assertEquals("Precondition failed", 1, fc.watchers.size());
+//
+//        assertEquals(dmList3, fc.watchers.get(dst));
+//        assertNull(fc.watchers.get(dst2));
+//
+//        EasyMock.verify(zk);
+//    }
+//
+//    public void testAddingServiceFilter() {
+//        DiscoveredServiceTracker dst = new DiscoveredServiceTracker() {
+//            public void serviceChanged(DiscoveredServiceNotification dsn) {}
+//        };
+//
+//        ServiceReference sr = EasyMock.createMock(ServiceReference.class);
+//        EasyMock.expect(sr.getProperty(DiscoveredServiceTracker.INTERFACE_MATCH_CRITERIA))
+//            .andReturn(null);
+//        Set<String> stringFilter = Collections.singleton("(objectClass=java.lang.String)");
+//        EasyMock.expect(sr.getProperty(DiscoveredServiceTracker.FILTER_MATCH_CRITERIA))
+//            .andReturn(stringFilter);
+//        EasyMock.replay(sr);
+//
+//        DiscoveredServiceTracker dst2 = new DiscoveredServiceTracker() {
+//            public void serviceChanged(DiscoveredServiceNotification dsn) {}
+//        };
+//
+//        ServiceReference sr2 = EasyMock.createMock(ServiceReference.class);
+//        EasyMock.expect(sr2.getProperty(DiscoveredServiceTracker.INTERFACE_MATCH_CRITERIA))
+//            .andReturn(null);
+//        List<String> combinedFilter =
+//            Arrays.asList("(objectClass=java.lang.Integer)", "(objectClass=java.lang.Comparable)");
+//        EasyMock.expect(sr2.getProperty(DiscoveredServiceTracker.FILTER_MATCH_CRITERIA))
+//            .andReturn(combinedFilter);
+//        EasyMock.replay(sr2);
+//
+//        BundleContext bc = EasyMock.createMock(BundleContext.class);
+//        EasyMock.expect(bc.getService(sr)).andReturn(dst);
+//        EasyMock.expect(bc.getService(sr2)).andReturn(dst2);
+//        EasyMock.replay(bc);
+//
+//        ZooKeeper zk = EasyMock.createMock(ZooKeeper.class);
+//        zkExpectExists(zk, String.class.getName());
+//        zkExpectExists(zk, Integer.class.getName());
+//        zkExpectExists(zk, Comparable.class.getName());
+//        EasyMock.expectLastCall();
+//        EasyMock.replay(zk);
+//
+//        FindInZooKeeperCustomizer fc = new FindInZooKeeperCustomizer(bc, zk);
+//
+//        // ---------------------------------------------------------------
+//        // Test the addingService APIs
+//        // ---------------------------------------------------------------
+//
+//        assertEquals("Precondition failed", 0, fc.watchers.size());
+//        fc.addingService(sr);
+//        assertEquals(1, fc.watchers.size());
+//
+//        DiscoveredServiceTracker key = fc.watchers.keySet().iterator().next();
+//        assertSame(dst, key);
+//        List<InterfaceMonitor> dmList = fc.watchers.get(key);
+//        assertEquals(1, dmList.size());
+//        InterfaceMonitor dm = dmList.iterator().next();
+//        assertNotNull(dm.listener);
+//        assertSame(zk, dm.zookeeper);
+//        assertEquals(Utils.getZooKeeperPath(String.class.getName()), dm.znode);
+//
+//        assertEquals("Precondition failed", 1, fc.watchers.size());
+//        fc.addingService(sr2);
+//        assertEquals(2, fc.watchers.size());
+//
+//        assertTrue(fc.watchers.containsKey(dst));
+//        assertTrue(fc.watchers.containsKey(dst2));
+//        assertEquals(dmList, fc.watchers.get(dst));
+//        List<InterfaceMonitor> dmList2 = fc.watchers.get(dst2);
+//        assertEquals(2, dmList2.size());
+//        Set<String> actual = new HashSet<String>();
+//        for (InterfaceMonitor im : dmList2) {
+//            actual.add(im.znode);
+//        }
+//        Set<String> expected = new HashSet<String>(Arrays.asList(
+//                Utils.getZooKeeperPath(Integer.class.getName()),
+//                Utils.getZooKeeperPath(Comparable.class.getName())));
+//        assertEquals(expected, actual);
+//
+//        EasyMock.verify(zk);
+//
+//        // ---------------------------------------------------------------
+//        // Test the modifiedService APIs
+//        // ---------------------------------------------------------------
+//        EasyMock.reset(zk);
+//        zkExpectExists(zk, List.class.getName());
+//        EasyMock.replay(zk);
+//
+//        EasyMock.reset(sr);
+//        Set<String> listFilter = Collections.singleton("(objectClass=java.util.List)");
+//        EasyMock.expect(sr.getProperty(DiscoveredServiceTracker.INTERFACE_MATCH_CRITERIA))
+//            .andReturn(null);
+//        EasyMock.expect(sr.getProperty(DiscoveredServiceTracker.FILTER_MATCH_CRITERIA))
+//            .andReturn(listFilter);
+//        EasyMock.replay(sr);
+//
+//        assertEquals("Precondition failed", 2, fc.watchers.size());
+//        fc.modifiedService(sr, dst);
+//        assertEquals("Precondition failed", 2, fc.watchers.size());
+//
+//        assertTrue(fc.watchers.containsKey(dst));
+//        assertTrue(fc.watchers.containsKey(dst2));
+//        assertEquals(dmList2, fc.watchers.get(dst2));
+//        List<InterfaceMonitor> dmList3 = fc.watchers.get(dst);
+//        assertEquals(1, dmList3.size());
+//        assertEquals(Utils.getZooKeeperPath(List.class.getName()), dmList3.iterator().next().znode);
+//
+//        EasyMock.verify(zk);
+//
+//        // ---------------------------------------------------------------
+//        // Test the removedService APIs
+//        // ---------------------------------------------------------------
+//        EasyMock.reset(zk);
+//        EasyMock.replay(zk);
+//
+//        assertEquals("Precondition failed", 2, fc.watchers.size());
+//        fc.removedService(sr2, dst2);
+//        assertEquals("Precondition failed", 1, fc.watchers.size());
+//
+//        assertEquals(dmList3, fc.watchers.get(dst));
+//        assertNull(fc.watchers.get(dst2));
+//
+//        EasyMock.verify(zk);
+//    }
+//
+//    public void testGetInterfacesFromFilter() {
+//        testGetInterfacesFromFilter("objectClass=org.apache_2.Some$FunnyClass",
+//                "org.apache_2.Some$FunnyClass");
+//        testGetInterfacesFromFilter("(&(a=b)(objectClass = org.acme.Q)",
+//                "org.acme.Q");
+//        testGetInterfacesFromFilter("(&(objectClassIdentifier=b)(objectClass = org.acme.Q)",
+//                "org.acme.Q");
+//        testGetInterfacesFromFilter("(|(OBJECTCLASS=   X  )(objectclass = Y)",
+//                "X", "Y");
+//        testGetInterfacesFromFilter(new String[] {"(objectClass=X)", "(objectClass=Y)"},
+//                "X", "Y");
+//    }
+//
+//    private void testGetInterfacesFromFilter(String filter, String ... interfaces) {
+//        testGetInterfacesFromFilter(new String[] {filter}, interfaces);
+//    }
+//
+//    private void testGetInterfacesFromFilter(String[] filters, String ... interfaces) {
+//        FindInZooKeeperCustomizer.getInterfacesFromFilter(Arrays.asList(filters));
+//    }
+//
+//    private void zkExpectExists(ZooKeeper zk, String className) {
+//        zk.exists(EasyMock.eq(Utils.getZooKeeperPath(className)),
+//                (Watcher) EasyMock.anyObject(),
+//                (StatCallback) EasyMock.anyObject(), EasyMock.isNull());
+//        EasyMock.expectLastCall().andAnswer(new IAnswer<Object>() {
+//            public Object answer() throws Throwable {
+//                assertEquals(EasyMock.getCurrentArguments()[1],
+//                        EasyMock.getCurrentArguments()[2]);
+//                return null;
+//            }
+//        });
+//    }
+}

http://git-wip-us.apache.org/repos/asf/aries-rsa/blob/69bb901e/discovery/zookeeper/src/test/java/org/apache/aries/rsa/discovery/zookeeper/InterfaceDataMonitorListenerImplTest.java
----------------------------------------------------------------------
diff --git a/discovery/zookeeper/src/test/java/org/apache/aries/rsa/discovery/zookeeper/InterfaceDataMonitorListenerImplTest.java b/discovery/zookeeper/src/test/java/org/apache/aries/rsa/discovery/zookeeper/InterfaceDataMonitorListenerImplTest.java
new file mode 100644
index 0000000..bac4f78
--- /dev/null
+++ b/discovery/zookeeper/src/test/java/org/apache/aries/rsa/discovery/zookeeper/InterfaceDataMonitorListenerImplTest.java
@@ -0,0 +1,183 @@
+/**
+ * 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.aries.rsa.discovery.zookeeper;
+
+import junit.framework.TestCase;
+
+public class InterfaceDataMonitorListenerImplTest extends TestCase {
+
+    public void testDUMMY() {
+        assertTrue(true);
+    }
+
+//    public void testChange() throws Exception {
+//        final List<DiscoveredServiceNotification> dsnCallbacks = new ArrayList<DiscoveredServiceNotification>();
+//        DiscoveredServiceTracker dst = new DiscoveredServiceTracker() {
+//            public void serviceChanged(DiscoveredServiceNotification dsn) {
+//                dsnCallbacks.add(dsn);
+//            }
+//        };
+//
+//        //----------------------------------------------------------------
+//        // Test DiscoveredServiceNotification.AVAILABLE
+//        //----------------------------------------------------------------
+//        Properties initial = new Properties();
+//        initial.put("a", "b");
+//        initial.put(ServicePublication.ENDPOINT_LOCATION, "http://somehost:12345/some/context");
+//        ByteArrayOutputStream propBytes = new ByteArrayOutputStream();
+//        initial.store(propBytes, "");
+//
+//        ZooKeeper zk = EasyMock.createMock(ZooKeeper.class);
+//        EasyMock.expect(zk.getChildren(Utils.getZooKeeperPath(String.class.getName()), false))
+//            .andReturn(Arrays.asList("x#y#z"));
+//        EasyMock.expect(zk.getData(Utils.getZooKeeperPath(String.class.getName()) + "/x#y#z", false, null))
+//            .andReturn(propBytes.toByteArray());
+//        EasyMock.replay(zk);
+//
+//        InterfaceDataMonitorListenerImpl dml = new InterfaceDataMonitorListenerImpl(zk, String.class.getName(), dst);
+//
+//        assertEquals("Precondition failed", 0, dsnCallbacks.size());
+//        dml.change();
+//        assertEquals(1, dsnCallbacks.size());
+//        DiscoveredServiceNotification dsn = dsnCallbacks.iterator().next();
+//        assertEquals(Collections.singleton(String.class.getName()), dsn.getInterfaces());
+//        assertEquals(DiscoveredServiceNotification.AVAILABLE, dsn.getType());
+//        assertEquals(0, dsn.getFilters().size());
+//        ServiceEndpointDescription sed = dsn.getServiceEndpointDescription();
+//        assertEquals(Collections.singleton(String.class.getName()), sed.getProvidedInterfaces());
+//
+//        Properties expected = new Properties();
+//        expected.load(new ByteArrayInputStream(propBytes.toByteArray()));
+//        expected.put("service.exported.configs", "org.apache.cxf.ws");
+//        expected.put("org.apache.cxf.ws.address", "http://somehost:12345/some/context");
+//
+//        assertEquals(expected, sed.getProperties());
+//        EasyMock.verify(zk);
+//
+//        // Again with the same data
+//        EasyMock.reset(zk);
+//        EasyMock.expect(zk.getChildren(Utils.getZooKeeperPath(String.class.getName()), false))
+//            .andReturn(Arrays.asList("x#y#z"));
+//        EasyMock.expect(zk.getData(Utils.getZooKeeperPath(String.class.getName()) + "/x#y#z", false, null))
+//            .andReturn(propBytes.toByteArray());
+//        EasyMock.replay(zk);
+//
+//        dsnCallbacks.clear();
+//        assertEquals("Precondition failed", 0, dsnCallbacks.size());
+//        dml.change();
+//        assertEquals(0, dsnCallbacks.size());
+//
+//        EasyMock.verify(zk);
+//        //----------------------------------------------------------------
+//        // Test DiscoveredServiceNotification.MODIFIED
+//        //----------------------------------------------------------------
+//        Properties modified = new Properties();
+//        modified.put("c", "d");
+//        modified.put(ServicePublication.ENDPOINT_LOCATION, "http://somehost:999/some/context");
+//        modified.put("service.exported.configs", "org.apache.cxf.rs");
+//        ByteArrayOutputStream modBytes = new ByteArrayOutputStream();
+//        modified.store(modBytes, "");
+//
+//        EasyMock.reset(zk);
+//        EasyMock.expect(zk.getChildren(Utils.getZooKeeperPath(String.class.getName()), false))
+//            .andReturn(Arrays.asList("x#y#z"));
+//        EasyMock.expect(zk.getData(Utils.getZooKeeperPath(String.class.getName()) + "/x#y#z", false, null))
+//            .andReturn(modBytes.toByteArray());
+//        EasyMock.replay(zk);
+//
+//        dsnCallbacks.clear();
+//        assertEquals("Precondition failed", 0, dsnCallbacks.size());
+//        dml.change();
+//        assertEquals(1, dsnCallbacks.size());
+//        DiscoveredServiceNotification dsn2 = dsnCallbacks.iterator().next();
+//        assertEquals(Collections.singleton(String.class.getName()), dsn2.getInterfaces());
+//        assertEquals(DiscoveredServiceNotification.MODIFIED, dsn2.getType());
+//        assertEquals(0, dsn2.getFilters().size());
+//        ServiceEndpointDescription sed2 = dsn2.getServiceEndpointDescription();
+//        assertEquals(Collections.singleton(String.class.getName()), sed2.getProvidedInterfaces());
+//        assertEquals(modified, sed2.getProperties());
+//
+//        EasyMock.verify(zk);
+//
+//        //----------------------------------------------------------------
+//        // Test DiscoveredServiceNotification.MODIFIED2
+//        //----------------------------------------------------------------
+//        Properties modified2 = new Properties();
+//        modified2.put("c", "d2");
+//        modified2.put(ServicePublication.ENDPOINT_LOCATION, "http://somehost:112/some/context");
+//        modified2.put("service.exported.configs", "org.apache.cxf.ws");
+//        modified2.put("org.apache.cxf.ws.address", "http://somewhereelse/123");
+//        ByteArrayOutputStream modBytes2 = new ByteArrayOutputStream();
+//        modified2.store(modBytes2, "");
+//
+//        EasyMock.reset(zk);
+//        EasyMock.expect(zk.getChildren(Utils.getZooKeeperPath(String.class.getName()), false))
+//            .andReturn(Arrays.asList("x#y#z"));
+//        EasyMock.expect(zk.getData(Utils.getZooKeeperPath(String.class.getName()) + "/x#y#z", false, null))
+//            .andReturn(modBytes2.toByteArray());
+//        EasyMock.replay(zk);
+//
+//        dsnCallbacks.clear();
+//        assertEquals("Precondition failed", 0, dsnCallbacks.size());
+//        dml.change();
+//        assertEquals(1, dsnCallbacks.size());
+//        DiscoveredServiceNotification dsn3 = dsnCallbacks.iterator().next();
+//        assertEquals(Collections.singleton(String.class.getName()), dsn3.getInterfaces());
+//        assertEquals(DiscoveredServiceNotification.MODIFIED, dsn3.getType());
+//        assertEquals(0, dsn3.getFilters().size());
+//        ServiceEndpointDescription sed3 = dsn3.getServiceEndpointDescription();
+//        assertEquals(Collections.singleton(String.class.getName()), sed3.getProvidedInterfaces());
+//        assertEquals(modified2, sed3.getProperties());
+//
+//        EasyMock.verify(zk);
+//        //----------------------------------------------------------------
+//        // Test DiscoveredServiceNotification.UNAVAILABLE
+//        //----------------------------------------------------------------
+//        EasyMock.reset(zk);
+//        EasyMock.expect(zk.getChildren(Utils.getZooKeeperPath(String.class.getName()), false))
+//            .andReturn(Collections.<String>emptyList());
+//        EasyMock.replay(zk);
+//
+//        dsnCallbacks.clear();
+//        assertEquals("Precondition failed", 0, dsnCallbacks.size());
+//        dml.change();
+//        assertEquals(1, dsnCallbacks.size());
+//        DiscoveredServiceNotification dsn4 = dsnCallbacks.iterator().next();
+//        assertEquals(Collections.singleton(String.class.getName()), dsn4.getInterfaces());
+//        assertEquals(DiscoveredServiceNotification.UNAVAILABLE, dsn4.getType());
+//        assertEquals(0, dsn4.getFilters().size());
+//        ServiceEndpointDescription sed4 = dsn4.getServiceEndpointDescription();
+//        assertEquals(Collections.singleton(String.class.getName()), sed4.getProvidedInterfaces());
+//        assertEquals(modified2, sed4.getProperties());
+//
+//        EasyMock.verify(zk);
+//
+//        // Try the same again...
+//        EasyMock.reset(zk);
+//        EasyMock.expect(zk.getChildren(Utils.getZooKeeperPath(String.class.getName()), false))
+//            .andReturn(Collections.<String>emptyList());
+//        EasyMock.replay(zk);
+//
+//        dsnCallbacks.clear();
+//        assertEquals("Precondition failed", 0, dsnCallbacks.size());
+//        dml.change();
+//        assertEquals("Should not receive a callback again...", 0, dsnCallbacks.size());
+//        EasyMock.verify(zk);
+//    }
+}

http://git-wip-us.apache.org/repos/asf/aries-rsa/blob/69bb901e/discovery/zookeeper/src/test/java/org/apache/aries/rsa/discovery/zookeeper/ZookeeperDiscoveryTest.java
----------------------------------------------------------------------
diff --git a/discovery/zookeeper/src/test/java/org/apache/aries/rsa/discovery/zookeeper/ZookeeperDiscoveryTest.java b/discovery/zookeeper/src/test/java/org/apache/aries/rsa/discovery/zookeeper/ZookeeperDiscoveryTest.java
new file mode 100644
index 0000000..8e4af45
--- /dev/null
+++ b/discovery/zookeeper/src/test/java/org/apache/aries/rsa/discovery/zookeeper/ZookeeperDiscoveryTest.java
@@ -0,0 +1,56 @@
+package org.apache.aries.rsa.discovery.zookeeper;
+
+import java.util.Dictionary;
+import java.util.Hashtable;
+
+import org.apache.aries.rsa.discovery.zookeeper.ZooKeeperDiscovery;
+import org.apache.zookeeper.ZooKeeper;
+import org.easymock.EasyMock;
+import org.easymock.IMocksControl;
+import org.junit.Assert;
+import org.junit.Test;
+import org.osgi.framework.BundleContext;
+import org.osgi.service.cm.ConfigurationException;
+
+
+public class ZookeeperDiscoveryTest {
+
+    @Test
+    public void testDefaults() throws ConfigurationException {
+        IMocksControl c = EasyMock.createControl();
+        BundleContext bctx = c.createMock(BundleContext.class);
+        ZooKeeperDiscovery zkd = new ZooKeeperDiscovery(bctx) {
+            @Override
+            protected ZooKeeper createZooKeeper(String host, String port, int timeout) {
+                Assert.assertEquals("localhost", host);
+                Assert.assertEquals("2181", port);
+                Assert.assertEquals(3000, timeout);
+                return null;
+            }  
+        };
+        
+        Dictionary<String, Object> configuration = new Hashtable<String, Object>();
+        zkd.updated(configuration);
+    }
+    
+    @Test
+    public void testConfig() throws ConfigurationException {
+        IMocksControl c = EasyMock.createControl();
+        BundleContext bctx = c.createMock(BundleContext.class);
+        ZooKeeperDiscovery zkd = new ZooKeeperDiscovery(bctx) {
+            @Override
+            protected ZooKeeper createZooKeeper(String host, String port, int timeout) {
+                Assert.assertEquals("myhost", host);
+                Assert.assertEquals("1", port);
+                Assert.assertEquals(1000, timeout);
+                return null;
+            }  
+        };
+        
+        Dictionary<String, Object> configuration = new Hashtable<String, Object>();
+        configuration.put("zookeeper.host", "myhost");
+        configuration.put("zookeeper.port", "1");
+        configuration.put("zookeeper.timeout", "1000");
+        zkd.updated(configuration);
+    }
+}

http://git-wip-us.apache.org/repos/asf/aries-rsa/blob/69bb901e/discovery/zookeeper/src/test/java/org/apache/aries/rsa/discovery/zookeeper/publish/PublishingEndpointListenerFactoryTest.java
----------------------------------------------------------------------
diff --git a/discovery/zookeeper/src/test/java/org/apache/aries/rsa/discovery/zookeeper/publish/PublishingEndpointListenerFactoryTest.java b/discovery/zookeeper/src/test/java/org/apache/aries/rsa/discovery/zookeeper/publish/PublishingEndpointListenerFactoryTest.java
new file mode 100644
index 0000000..0cbe7ca
--- /dev/null
+++ b/discovery/zookeeper/src/test/java/org/apache/aries/rsa/discovery/zookeeper/publish/PublishingEndpointListenerFactoryTest.java
@@ -0,0 +1,102 @@
+/**
+ * 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.aries.rsa.discovery.zookeeper.publish;
+
+import java.util.Dictionary;
+import java.util.List;
+
+import junit.framework.TestCase;
+
+import org.apache.aries.rsa.discovery.zookeeper.publish.PublishingEndpointListener;
+import org.apache.aries.rsa.discovery.zookeeper.publish.PublishingEndpointListenerFactory;
+import org.apache.zookeeper.ZooKeeper;
+import org.easymock.EasyMock;
+import org.easymock.IMocksControl;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.ServiceRegistration;
+import org.osgi.service.remoteserviceadmin.EndpointListener;
+
+public class PublishingEndpointListenerFactoryTest extends TestCase {
+
+    @SuppressWarnings("unchecked")
+    public void testScope() {
+        IMocksControl c = EasyMock.createNiceControl();
+
+        BundleContext ctx = c.createMock(BundleContext.class);
+        ZooKeeper zk = c.createMock(ZooKeeper.class);
+        @SuppressWarnings("rawtypes")
+        ServiceRegistration sreg = c.createMock(ServiceRegistration.class);
+
+        PublishingEndpointListenerFactory eplf = new PublishingEndpointListenerFactory(zk, ctx);
+
+        EasyMock.expect(ctx.registerService(EasyMock.eq(EndpointListener.class.getName()), EasyMock.eq(eplf),
+                                            (Dictionary<String, String>)EasyMock.anyObject())).andReturn(sreg).once();
+
+        EasyMock.expect(ctx.getProperty(EasyMock.eq("org.osgi.framework.uuid"))).andReturn("myUUID").anyTimes();
+
+        c.replay();
+        eplf.start();
+        c.verify();
+
+    }
+
+    @SuppressWarnings("unchecked")
+    public void testServiceFactory() {
+        IMocksControl c = EasyMock.createNiceControl();
+
+        BundleContext ctx = c.createMock(BundleContext.class);
+        ZooKeeper zk = c.createMock(ZooKeeper.class);
+        @SuppressWarnings("rawtypes")
+        ServiceRegistration sreg = c.createMock(ServiceRegistration.class);
+
+        PublishingEndpointListenerFactory eplf = new PublishingEndpointListenerFactory(zk, ctx);
+
+        EasyMock.expect(ctx.registerService(EasyMock.eq(EndpointListener.class.getName()), EasyMock.eq(eplf),
+                                (Dictionary<String, String>)EasyMock.anyObject())).andReturn(sreg).once();
+
+        EasyMock.expect(ctx.getProperty(EasyMock.eq("org.osgi.framework.uuid"))).andReturn("myUUID").anyTimes();
+
+        PublishingEndpointListener eli = c.createMock(PublishingEndpointListener.class);
+        eli.close();
+        EasyMock.expectLastCall().once();
+
+        c.replay();
+        eplf.start();
+
+        PublishingEndpointListener service = eplf.getService(null, null);
+        assertNotNull(service);
+        assertTrue(service instanceof EndpointListener);
+
+        List<PublishingEndpointListener> listeners = eplf.getListeners();
+        assertEquals(1, listeners.size());
+        assertEquals(service, listeners.get(0));
+
+        eplf.ungetService(null, null, service);
+        listeners = eplf.getListeners();
+        assertEquals(0, listeners.size());
+
+        eplf.ungetService(null, null, eli); // no call to close
+        listeners.add(eli);
+        eplf.ungetService(null, null, eli); // call to close
+        listeners = eplf.getListeners();
+        assertEquals(0, listeners.size());
+
+        c.verify();
+    }
+}

http://git-wip-us.apache.org/repos/asf/aries-rsa/blob/69bb901e/discovery/zookeeper/src/test/java/org/apache/aries/rsa/discovery/zookeeper/publish/PublishingEndpointListenerTest.java
----------------------------------------------------------------------
diff --git a/discovery/zookeeper/src/test/java/org/apache/aries/rsa/discovery/zookeeper/publish/PublishingEndpointListenerTest.java b/discovery/zookeeper/src/test/java/org/apache/aries/rsa/discovery/zookeeper/publish/PublishingEndpointListenerTest.java
new file mode 100644
index 0000000..6e6dfb9
--- /dev/null
+++ b/discovery/zookeeper/src/test/java/org/apache/aries/rsa/discovery/zookeeper/publish/PublishingEndpointListenerTest.java
@@ -0,0 +1,209 @@
+/**
+ * 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.aries.rsa.discovery.zookeeper.publish;
+
+import static org.easymock.EasyMock.expect;
+
+import java.lang.reflect.Field;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.aries.rsa.discovery.endpoint.EndpointDescriptionParser;
+import org.apache.aries.rsa.discovery.endpoint.PropertiesMapper;
+import org.apache.aries.rsa.discovery.zookeeper.publish.DiscoveryPlugin;
+import org.apache.aries.rsa.discovery.zookeeper.publish.PublishingEndpointListener;
+import org.apache.zookeeper.CreateMode;
+import org.apache.zookeeper.KeeperException;
+import org.apache.zookeeper.ZooDefs.Ids;
+import org.apache.zookeeper.ZooKeeper;
+import org.easymock.EasyMock;
+import org.easymock.IAnswer;
+import org.easymock.IMocksControl;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.Constants;
+import org.osgi.framework.Filter;
+import org.osgi.framework.FrameworkUtil;
+import org.osgi.framework.InvalidSyntaxException;
+import org.osgi.framework.ServiceListener;
+import org.osgi.framework.ServiceReference;
+import org.osgi.service.remoteserviceadmin.EndpointDescription;
+import org.osgi.service.remoteserviceadmin.RemoteConstants;
+import org.osgi.xmlns.rsa.v1_0.EndpointDescriptionType;
+import org.osgi.xmlns.rsa.v1_0.PropertyType;
+
+import junit.framework.TestCase;
+
+public class PublishingEndpointListenerTest extends TestCase {
+
+    private static final String ENDPOINT_PATH = "/osgi/service_registry/myClass/google.de#80##test#sub";
+
+    public void testEndpointRemovalAdding() throws KeeperException, InterruptedException {
+        IMocksControl c = EasyMock.createNiceControl();
+
+        BundleContext ctx = c.createMock(BundleContext.class);
+        ZooKeeper zk = c.createMock(ZooKeeper.class);
+
+        String path = ENDPOINT_PATH;
+        expectCreated(zk, path);
+        expectDeleted(zk, path);
+
+        c.replay();
+
+        PublishingEndpointListener eli = new PublishingEndpointListener(zk, ctx);
+        EndpointDescription endpoint = createEndpoint();
+        eli.endpointAdded(endpoint, null);
+        eli.endpointAdded(endpoint, null); // should do nothing
+        eli.endpointRemoved(endpoint, null);
+        eli.endpointRemoved(endpoint, null); // should do nothing
+
+        c.verify();
+    }
+
+    public void testDiscoveryPlugin() throws Exception {
+        BundleContext ctx = EasyMock.createMock(BundleContext.class);
+        stubCreateFilter(ctx);
+        ctx.addServiceListener(EasyMock.isA(ServiceListener.class),
+                EasyMock.eq("(objectClass=" + DiscoveryPlugin.class.getName() + ")"));
+
+        ServiceReference<DiscoveryPlugin> sr1 = createAppendPlugin(ctx);
+        ServiceReference<DiscoveryPlugin> sr2 = createPropertyPlugin(ctx);
+
+        EasyMock.expect(ctx.getServiceReferences(DiscoveryPlugin.class.getName(), null))
+                .andReturn(new ServiceReference[]{sr1, sr2}).anyTimes();
+        EasyMock.replay(ctx);
+
+        EndpointDescription endpoint = createEndpoint();
+
+        Map<String, Object> expectedProps = new HashMap<String, Object>(endpoint.getProperties());
+        expectedProps.put("endpoint.id", "http://google.de:80/test/sub/appended");
+        expectedProps.put("foo", "bar");
+        expectedProps.put("service.imported", "true");
+
+        final ZooKeeper zk = EasyMock.createNiceMock(ZooKeeper.class);
+        String expectedFullPath = "/osgi/service_registry/org/foo/myClass/some.machine#9876##test";
+        
+        List<PropertyType> props2 = new PropertiesMapper().fromProps(expectedProps);
+        EndpointDescriptionType epd = new EndpointDescriptionType();
+        epd.getProperty().addAll(props2);
+        byte[] data = new EndpointDescriptionParser().getData(epd);
+        expectCreated(zk, expectedFullPath, EasyMock.aryEq(data));
+        EasyMock.replay(zk);
+
+        PublishingEndpointListener eli = new PublishingEndpointListener(zk, ctx);
+
+        List<EndpointDescription> endpoints = getEndpoints(eli);
+        assertEquals("Precondition", 0, endpoints.size());
+        eli.endpointAdded(endpoint, null);
+        assertEquals(1, endpoints.size());
+
+        //TODO enable
+        //EasyMock.verify(zk);
+    }
+
+
+
+    public void testClose() throws KeeperException, InterruptedException {
+        IMocksControl c = EasyMock.createNiceControl();
+        BundleContext ctx = c.createMock(BundleContext.class);
+        ZooKeeper zk = c.createMock(ZooKeeper.class);
+        expectCreated(zk, ENDPOINT_PATH);
+        expectDeleted(zk, ENDPOINT_PATH);
+
+        c.replay();
+
+        PublishingEndpointListener eli = new PublishingEndpointListener(zk, ctx);
+        EndpointDescription endpoint = createEndpoint();
+        eli.endpointAdded(endpoint, null);
+        eli.close(); // should result in zk.delete(...)
+
+        c.verify();
+    }
+
+    @SuppressWarnings("unchecked")
+    private ServiceReference<DiscoveryPlugin> createAppendPlugin(BundleContext ctx) {
+        DiscoveryPlugin plugin1 = new DiscoveryPlugin() {
+            public String process(Map<String, Object> mutableProperties, String endpointKey) {
+                String eid = (String) mutableProperties.get("endpoint.id");
+                mutableProperties.put("endpoint.id", eid + "/appended");
+                return endpointKey;
+            }
+        };
+        ServiceReference<DiscoveryPlugin> sr1 = EasyMock.createMock(ServiceReference.class);
+        EasyMock.expect(ctx.getService(sr1)).andReturn(plugin1).anyTimes();
+        return sr1;
+    }
+
+    @SuppressWarnings("unchecked")
+    private ServiceReference<DiscoveryPlugin> createPropertyPlugin(BundleContext ctx) {
+        DiscoveryPlugin plugin2 = new DiscoveryPlugin() {
+            public String process(Map<String, Object> mutableProperties, String endpointKey) {
+                mutableProperties.put("foo", "bar");
+                return endpointKey.replaceAll("localhost", "some.machine");
+            }
+        };
+        ServiceReference<DiscoveryPlugin> sr2 = EasyMock.createMock(ServiceReference.class);
+        EasyMock.expect(ctx.getService(sr2)).andReturn(plugin2).anyTimes();
+        return sr2;
+    }
+
+    @SuppressWarnings("unchecked")
+    private List<EndpointDescription> getEndpoints(PublishingEndpointListener eli) throws Exception {
+        Field field = eli.getClass().getDeclaredField("endpoints");
+        field.setAccessible(true);
+        return (List<EndpointDescription>) field.get(eli);
+    }
+
+    private void stubCreateFilter(BundleContext ctx) throws InvalidSyntaxException {
+        EasyMock.expect(ctx.createFilter(EasyMock.isA(String.class))).andAnswer(new IAnswer<Filter>() {
+            public Filter answer() throws Throwable {
+                return FrameworkUtil.createFilter((String) EasyMock.getCurrentArguments()[0]);
+            }
+        }).anyTimes();
+    }
+
+    private void expectCreated(ZooKeeper zk, String path, byte[] dataMatcher) throws KeeperException, InterruptedException {
+        expect(zk.create(EasyMock.eq(path), 
+                         dataMatcher, 
+                         EasyMock.eq(Ids.OPEN_ACL_UNSAFE),
+                         EasyMock.eq(CreateMode.EPHEMERAL)))
+            .andReturn("");
+    }
+    
+    private void expectCreated(ZooKeeper zk, String path) throws KeeperException, InterruptedException {
+        expect(zk.create(EasyMock.eq(path), 
+                         (byte[])EasyMock.anyObject(), 
+                         EasyMock.eq(Ids.OPEN_ACL_UNSAFE),
+                         EasyMock.eq(CreateMode.EPHEMERAL)))
+            .andReturn("");
+    }
+
+    private void expectDeleted(ZooKeeper zk, String path) throws InterruptedException, KeeperException {
+        zk.delete(EasyMock.eq(path), EasyMock.eq(-1));
+        EasyMock.expectLastCall().once();
+    }
+
+    private EndpointDescription createEndpoint() {
+        Map<String, Object> props = new HashMap<String, Object>();
+        props.put(Constants.OBJECTCLASS, new String[] {"myClass"});
+        props.put(RemoteConstants.ENDPOINT_ID, "http://google.de:80/test/sub");
+        props.put(RemoteConstants.SERVICE_IMPORTED_CONFIGS, "myConfig");
+        return new EndpointDescription(props);
+    }
+}

http://git-wip-us.apache.org/repos/asf/aries-rsa/blob/69bb901e/discovery/zookeeper/src/test/java/org/apache/aries/rsa/discovery/zookeeper/server/ZookeeperStarterTest.java
----------------------------------------------------------------------
diff --git a/discovery/zookeeper/src/test/java/org/apache/aries/rsa/discovery/zookeeper/server/ZookeeperStarterTest.java b/discovery/zookeeper/src/test/java/org/apache/aries/rsa/discovery/zookeeper/server/ZookeeperStarterTest.java
new file mode 100644
index 0000000..7d58fe3
--- /dev/null
+++ b/discovery/zookeeper/src/test/java/org/apache/aries/rsa/discovery/zookeeper/server/ZookeeperStarterTest.java
@@ -0,0 +1,82 @@
+/**
+ * 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.aries.rsa.discovery.zookeeper.server;
+
+import java.io.File;
+import java.util.Dictionary;
+import java.util.Hashtable;
+
+import junit.framework.TestCase;
+
+import org.apache.aries.rsa.discovery.zookeeper.server.ZookeeperStarter;
+import org.apache.aries.rsa.discovery.zookeeper.server.ZookeeperStarter.MyZooKeeperServerMain;
+import org.apache.zookeeper.server.quorum.QuorumPeerConfig;
+import org.easymock.classextension.EasyMock;
+import org.easymock.classextension.IMocksControl;
+import org.osgi.framework.BundleContext;
+
+import static org.easymock.EasyMock.expect;
+import static org.easymock.classextension.EasyMock.replay;
+import static org.easymock.classextension.EasyMock.verify;
+
+public class ZookeeperStarterTest extends TestCase {
+
+    public void testUpdateConfig() throws Exception {
+        final File tempDir = new File("target");
+        IMocksControl control = EasyMock.createControl();
+        BundleContext bc = control.createMock(BundleContext.class);
+        expect(bc.getDataFile("")).andReturn(tempDir);
+        final MyZooKeeperServerMain mockServer = control.createMock(MyZooKeeperServerMain.class);
+        control.replay();
+
+        ZookeeperStarter starter = new ZookeeperStarter(bc) {
+            @Override
+            protected void startFromConfig(QuorumPeerConfig config) {
+                assertEquals(1234, config.getClientPortAddress().getPort());
+                assertTrue(config.getDataDir().contains(tempDir + File.separator + "zkdata"));
+                assertEquals(2000, config.getTickTime());
+                assertEquals(10, config.getInitLimit());
+                assertEquals(5, config.getSyncLimit());
+                this.main = mockServer;
+            }
+        };
+        Dictionary<String, Object> props = new Hashtable<String, Object>();
+        props.put("clientPort", "1234");
+        starter.updated(props);
+        assertNotNull(starter.main);
+
+        control.verify();
+    }
+
+    public void testRemoveConfiguration() throws Exception {
+        BundleContext bc = EasyMock.createMock(BundleContext.class);
+        MyZooKeeperServerMain zkServer = EasyMock.createMock(MyZooKeeperServerMain.class);
+        zkServer.shutdown();
+        EasyMock.expectLastCall();
+
+        replay(zkServer);
+
+        ZookeeperStarter starter = new ZookeeperStarter(bc);
+        starter.main = zkServer;
+        starter.updated(null);
+
+        verify(zkServer);
+        assertNull("main should be null", starter.main);
+    }
+}

http://git-wip-us.apache.org/repos/asf/aries-rsa/blob/69bb901e/discovery/zookeeper/src/test/java/org/apache/aries/rsa/discovery/zookeeper/subscribe/InterfaceMonitorManagerTest.java
----------------------------------------------------------------------
diff --git a/discovery/zookeeper/src/test/java/org/apache/aries/rsa/discovery/zookeeper/subscribe/InterfaceMonitorManagerTest.java b/discovery/zookeeper/src/test/java/org/apache/aries/rsa/discovery/zookeeper/subscribe/InterfaceMonitorManagerTest.java
new file mode 100644
index 0000000..49c9dad
--- /dev/null
+++ b/discovery/zookeeper/src/test/java/org/apache/aries/rsa/discovery/zookeeper/subscribe/InterfaceMonitorManagerTest.java
@@ -0,0 +1,113 @@
+/**
+ * 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.aries.rsa.discovery.zookeeper.subscribe;
+
+import static org.junit.Assert.assertEquals;
+
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.aries.rsa.discovery.zookeeper.subscribe.InterfaceMonitorManager;
+import org.apache.zookeeper.ZooKeeper;
+import org.easymock.EasyMock;
+import org.easymock.IAnswer;
+import org.easymock.IMocksControl;
+import org.junit.Test;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.ServiceReference;
+import org.osgi.service.remoteserviceadmin.EndpointListener;
+
+public class InterfaceMonitorManagerTest {
+
+    @Test
+    public void testEndpointListenerTrackerCustomizer() {
+        IMocksControl c = EasyMock.createNiceControl();
+        BundleContext ctx = c.createMock(BundleContext.class);
+        ServiceReference<EndpointListener> sref = createService(c);
+        ServiceReference<EndpointListener> sref2 = createService(c);
+        ZooKeeper zk = c.createMock(ZooKeeper.class);
+        InterfaceMonitorManager eltc = new InterfaceMonitorManager(ctx, zk);
+
+        c.replay();
+
+        // sref has no scope -> nothing should happen
+        assertEquals(0, eltc.getEndpointListenerScopes().size());
+        assertEquals(0, eltc.getInterests().size());
+
+        eltc.addInterest(sref, "(objectClass=mine)", "mine");
+        assertScopeIncludes(sref, eltc);
+        assertEquals(1, eltc.getEndpointListenerScopes().size());
+        assertEquals(1, eltc.getInterests().size());
+
+        eltc.addInterest(sref, "(objectClass=mine)", "mine");
+        assertScopeIncludes(sref, eltc);
+        assertEquals(1, eltc.getEndpointListenerScopes().size());
+        assertEquals(1, eltc.getInterests().size());
+
+        eltc.addInterest(sref2, "(objectClass=mine)", "mine");
+        assertScopeIncludes(sref, eltc);
+        assertScopeIncludes(sref2, eltc);
+        assertEquals(2, eltc.getEndpointListenerScopes().size());
+        assertEquals(1, eltc.getInterests().size());
+
+        eltc.removeInterest(sref);
+        assertScopeIncludes(sref2, eltc);
+        assertEquals(1, eltc.getEndpointListenerScopes().size());
+        assertEquals(1, eltc.getInterests().size());
+
+        eltc.removeInterest(sref);
+        assertScopeIncludes(sref2, eltc);
+        assertEquals(1, eltc.getEndpointListenerScopes().size());
+        assertEquals(1, eltc.getInterests().size());
+
+        eltc.removeInterest(sref2);
+        assertEquals(0, eltc.getEndpointListenerScopes().size());
+        assertEquals(0, eltc.getInterests().size());
+
+        c.verify();
+    }
+
+    @SuppressWarnings("unchecked")
+    private ServiceReference<EndpointListener> createService(IMocksControl c) {
+        final Map<String, ?> p = new HashMap<String, Object>();
+        ServiceReference<EndpointListener> sref = c.createMock(ServiceReference.class);
+        EasyMock.expect(sref.getPropertyKeys()).andAnswer(new IAnswer<String[]>() {
+            public String[] answer() throws Throwable {
+                return p.keySet().toArray(new String[p.size()]);
+            }
+        }).anyTimes();
+
+        EasyMock.expect(sref.getProperty((String)EasyMock.anyObject())).andAnswer(new IAnswer<Object>() {
+            public Object answer() throws Throwable {
+                String key = (String)(EasyMock.getCurrentArguments()[0]);
+                return p.get(key);
+            }
+        }).anyTimes();
+        return sref;
+    }
+
+    private void assertScopeIncludes(ServiceReference<EndpointListener> sref, InterfaceMonitorManager eltc) {
+        List<String> srefScope = eltc.getEndpointListenerScopes().get(sref);
+        assertEquals(1, srefScope.size());
+        assertEquals("(objectClass=mine)", srefScope.get(0));
+        
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/aries-rsa/blob/69bb901e/discovery/zookeeper/src/test/java/org/apache/aries/rsa/discovery/zookeeper/subscribe/InterfaceMonitorTest.java
----------------------------------------------------------------------
diff --git a/discovery/zookeeper/src/test/java/org/apache/aries/rsa/discovery/zookeeper/subscribe/InterfaceMonitorTest.java b/discovery/zookeeper/src/test/java/org/apache/aries/rsa/discovery/zookeeper/subscribe/InterfaceMonitorTest.java
new file mode 100644
index 0000000..3a54399
--- /dev/null
+++ b/discovery/zookeeper/src/test/java/org/apache/aries/rsa/discovery/zookeeper/subscribe/InterfaceMonitorTest.java
@@ -0,0 +1,68 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.aries.rsa.discovery.zookeeper.subscribe;
+
+import java.util.Collections;
+
+import junit.framework.TestCase;
+
+import org.apache.aries.rsa.discovery.zookeeper.subscribe.InterfaceMonitor;
+import org.apache.aries.rsa.discovery.zookeeper.util.Utils;
+import org.apache.zookeeper.KeeperException;
+import org.apache.zookeeper.WatchedEvent;
+import org.apache.zookeeper.Watcher.Event.EventType;
+import org.apache.zookeeper.Watcher.Event.KeeperState;
+import org.apache.zookeeper.ZooKeeper;
+import org.apache.zookeeper.data.Stat;
+import org.easymock.EasyMock;
+import org.easymock.IMocksControl;
+import org.osgi.service.remoteserviceadmin.EndpointListener;
+
+import static org.easymock.EasyMock.eq;
+import static org.easymock.EasyMock.expect;
+
+public class InterfaceMonitorTest extends TestCase {
+
+    public void testInterfaceMonitor() throws KeeperException, InterruptedException {
+        IMocksControl c = EasyMock.createControl();
+
+        ZooKeeper zk = c.createMock(ZooKeeper.class);
+        expect(zk.getState()).andReturn(ZooKeeper.States.CONNECTED).anyTimes();
+
+        String scope = "(myProp=test)";
+        String interf = "es.schaaf.test";
+        String node = Utils.getZooKeeperPath(interf);
+
+        EndpointListener endpointListener = c.createMock(EndpointListener.class);
+        InterfaceMonitor im = new InterfaceMonitor(zk, interf, endpointListener, scope);
+        zk.exists(eq(node), eq(im), eq(im), EasyMock.anyObject());
+        EasyMock.expectLastCall().once();
+
+        expect(zk.exists(eq(node), eq(false))).andReturn(new Stat()).anyTimes();
+        expect(zk.getChildren(eq(node), eq(false))).andReturn(Collections.<String> emptyList()).once();
+        expect(zk.getChildren(eq(node), eq(im))).andReturn(Collections.<String> emptyList()).once();
+
+        c.replay();
+        im.start();
+        // simulate a zk callback
+        WatchedEvent we = new WatchedEvent(EventType.NodeCreated, KeeperState.SyncConnected, node);
+        im.process(we);
+        c.verify();
+    }
+}

http://git-wip-us.apache.org/repos/asf/aries-rsa/blob/69bb901e/discovery/zookeeper/src/test/java/org/apache/aries/rsa/discovery/zookeeper/util/UtilsTest.java
----------------------------------------------------------------------
diff --git a/discovery/zookeeper/src/test/java/org/apache/aries/rsa/discovery/zookeeper/util/UtilsTest.java b/discovery/zookeeper/src/test/java/org/apache/aries/rsa/discovery/zookeeper/util/UtilsTest.java
new file mode 100644
index 0000000..4d41fb0
--- /dev/null
+++ b/discovery/zookeeper/src/test/java/org/apache/aries/rsa/discovery/zookeeper/util/UtilsTest.java
@@ -0,0 +1,37 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.aries.rsa.discovery.zookeeper.util;
+
+import org.apache.aries.rsa.discovery.zookeeper.util.Utils;
+
+import junit.framework.TestCase;
+
+public class UtilsTest extends TestCase {
+
+    public void testGetZooKeeperPath() {
+        assertEquals(Utils.PATH_PREFIX + '/' + "org/example/Test",
+            Utils.getZooKeeperPath("org.example.Test"));
+
+        // used for the recursive discovery
+        assertEquals(Utils.PATH_PREFIX, Utils.getZooKeeperPath(null));
+        assertEquals(Utils.PATH_PREFIX, Utils.getZooKeeperPath(""));
+    }
+
+
+}

http://git-wip-us.apache.org/repos/asf/aries-rsa/blob/69bb901e/discovery/zookeeper/src/test/java/org/apache/cxf/dosgi/discovery/zookeeper/DiscoveryDriverTest.java
----------------------------------------------------------------------
diff --git a/discovery/zookeeper/src/test/java/org/apache/cxf/dosgi/discovery/zookeeper/DiscoveryDriverTest.java b/discovery/zookeeper/src/test/java/org/apache/cxf/dosgi/discovery/zookeeper/DiscoveryDriverTest.java
deleted file mode 100644
index 84470c2..0000000
--- a/discovery/zookeeper/src/test/java/org/apache/cxf/dosgi/discovery/zookeeper/DiscoveryDriverTest.java
+++ /dev/null
@@ -1,135 +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.cxf.dosgi.discovery.zookeeper;
-
-import junit.framework.TestCase;
-
-public class DiscoveryDriverTest extends TestCase {
-
-    public void testDUMMY() {
-        assertTrue(true);
-    }
-
-//    public void testDiscoveryDriver() throws Exception {
-//        BundleContext bc = getDefaultBundleContext();
-//        Dictionary<String, String> props = getDefaultProps();
-//
-//        final StringBuilder sb = new StringBuilder();
-//        DiscoveryDriver dd = new DiscoveryDriver(bc, props) {
-//            @Override
-//            ZooKeeper createZooKeeper() throws IOException {
-//                sb.append(zkHost + ":" + zkPort);
-//                ZooKeeper zk = EasyMock.createMock(ZooKeeper.class);
-//                EasyMock.replay(zk);
-//                return zk;
-//            }
-//        };
-//        EasyMock.verify(bc);
-//        assertEquals("somehost:1910", sb.toString());
-//
-//        EasyMock.verify(dd.zooKeeper);
-//        EasyMock.reset(dd.zooKeeper);
-//        dd.zooKeeper.close();
-//        EasyMock.expectLastCall();
-//        EasyMock.replay(dd.zooKeeper);
-//
-//        ServiceTracker st1 = EasyMock.createMock(ServiceTracker.class);
-//        st1.close();
-//        EasyMock.expectLastCall();
-//        EasyMock.replay(st1);
-//        ServiceTracker st2 = EasyMock.createMock(ServiceTracker.class);
-//        st2.close();
-//        EasyMock.expectLastCall();
-//        EasyMock.replay(st2);
-//
-//        dd.lookupTracker = st1;
-//        dd.publicationTracker = st2;
-//
-//        dd.destroy();
-//    }
-//
-//    private void expectServiceTrackerCalls(BundleContext bc, String objectClass)
-//            throws InvalidSyntaxException {
-//        Filter filter = EasyMock.createNiceMock(Filter.class);
-//        EasyMock.replay(filter);
-//
-//        EasyMock.expect(bc.createFilter("(objectClass=" + objectClass + ")"))
-//            .andReturn(filter).anyTimes();
-//        bc.addServiceListener((ServiceListener) EasyMock.anyObject(),
-//            EasyMock.eq("(objectClass=" + objectClass + ")"));
-//        EasyMock.expectLastCall().anyTimes();
-//        EasyMock.expect(bc.getServiceReferences(objectClass, null))
-//            .andReturn(new ServiceReference [0]).anyTimes();
-//    }
-//
-//    public void testProcessEvent() throws Exception {
-//        DiscoveryDriver db = new DiscoveryDriver(getDefaultBundleContext(), getDefaultProps()) {
-//            @Override
-//            ZooKeeper createZooKeeper() throws IOException {
-//                return null;
-//            }
-//        };
-//
-//        FindInZooKeeperCustomizer fc = new FindInZooKeeperCustomizer(null, null);
-//        List<InterfaceMonitor> l1 = new ArrayList<InterfaceMonitor>();
-//        InterfaceMonitor dm1a = EasyMock.createMock(InterfaceMonitor.class);
-//        dm1a.process();
-//        EasyMock.expectLastCall();
-//        EasyMock.replay(dm1a);
-//        InterfaceMonitor dm1b = EasyMock.createMock(InterfaceMonitor.class);
-//        dm1b.process();
-//        EasyMock.expectLastCall();
-//        EasyMock.replay(dm1b);
-//        l1.add(dm1a);
-//        l1.add(dm1b);
-//
-//        List<InterfaceMonitor> l2 = new ArrayList<InterfaceMonitor>();
-//        InterfaceMonitor dm2 = EasyMock.createMock(InterfaceMonitor.class);
-//        dm2.process();
-//        EasyMock.expectLastCall();
-//        EasyMock.replay(dm2);
-//        l2.add(dm2);
-//
-//        fc.watchers.put(EasyMock.createMock(DiscoveredServiceTracker.class), l1);
-//        fc.watchers.put(EasyMock.createMock(DiscoveredServiceTracker.class), l2);
-//
-//        db.finderCustomizer = fc;
-//        db.process(null);
-//
-//        EasyMock.verify(dm1a);
-//        EasyMock.verify(dm1b);
-//        EasyMock.verify(dm2);
-//    }
-//
-//    private BundleContext getDefaultBundleContext() throws InvalidSyntaxException {
-//        BundleContext bc = EasyMock.createMock(BundleContext.class);
-//        expectServiceTrackerCalls(bc, ServicePublication.class.getName());
-//        expectServiceTrackerCalls(bc, DiscoveredServiceTracker.class.getName());
-//        EasyMock.replay(bc);
-//        return bc;
-//    }
-//
-//    private Dictionary<String, String> getDefaultProps() {
-//        Dictionary<String, String> props = new Hashtable<String, String>();
-//        props.put("zookeeper.host", "somehost");
-//        props.put("zookeeper.port", "1910");
-//        props.put("zookeeper.timeout", "1500");
-//        return props;
-//    }
-}

http://git-wip-us.apache.org/repos/asf/aries-rsa/blob/69bb901e/discovery/zookeeper/src/test/java/org/apache/cxf/dosgi/discovery/zookeeper/FindInZooKeeperCustomizerTest.java
----------------------------------------------------------------------
diff --git a/discovery/zookeeper/src/test/java/org/apache/cxf/dosgi/discovery/zookeeper/FindInZooKeeperCustomizerTest.java b/discovery/zookeeper/src/test/java/org/apache/cxf/dosgi/discovery/zookeeper/FindInZooKeeperCustomizerTest.java
deleted file mode 100644
index cb2180b..0000000
--- a/discovery/zookeeper/src/test/java/org/apache/cxf/dosgi/discovery/zookeeper/FindInZooKeeperCustomizerTest.java
+++ /dev/null
@@ -1,301 +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.cxf.dosgi.discovery.zookeeper;
-
-import junit.framework.TestCase;
-
-public class FindInZooKeeperCustomizerTest extends TestCase {
-
-    public void testDUMMY() {
-        assertTrue(true);
-    }
-
-//    public void testAddingServiceInterface() {
-//        DiscoveredServiceTracker dst = new DiscoveredServiceTracker() {
-//            public void serviceChanged(DiscoveredServiceNotification dsn) {}
-//        };
-//
-//        ServiceReference sr = EasyMock.createMock(ServiceReference.class);
-//        EasyMock.expect(sr.getProperty(DiscoveredServiceTracker.INTERFACE_MATCH_CRITERIA))
-//            .andReturn(Collections.singleton(String.class.getName()));
-//        EasyMock.expect(sr.getProperty(DiscoveredServiceTracker.FILTER_MATCH_CRITERIA))
-//            .andReturn(null);
-//        EasyMock.replay(sr);
-//
-//        DiscoveredServiceTracker dst2 = new DiscoveredServiceTracker() {
-//            public void serviceChanged(DiscoveredServiceNotification dsn) {}
-//        };
-//
-//        ServiceReference sr2 = EasyMock.createMock(ServiceReference.class);
-//        EasyMock.expect(sr2.getProperty(DiscoveredServiceTracker.INTERFACE_MATCH_CRITERIA))
-//            .andReturn(Arrays.asList(Integer.class.getName(), Comparable.class.getName()));
-//        EasyMock.expect(sr2.getProperty(DiscoveredServiceTracker.FILTER_MATCH_CRITERIA))
-//            .andReturn(null);
-//        EasyMock.replay(sr2);
-//
-//        BundleContext bc = EasyMock.createMock(BundleContext.class);
-//        EasyMock.expect(bc.getService(sr)).andReturn(dst);
-//        EasyMock.expect(bc.getService(sr2)).andReturn(dst2);
-//        EasyMock.replay(bc);
-//
-//        ZooKeeper zk = EasyMock.createMock(ZooKeeper.class);
-//        zkExpectExists(zk, String.class.getName());
-//        zkExpectExists(zk, Integer.class.getName());
-//        zkExpectExists(zk, Comparable.class.getName());
-//        EasyMock.expectLastCall();
-//        EasyMock.replay(zk);
-//
-//        FindInZooKeeperCustomizer fc = new FindInZooKeeperCustomizer(bc, zk);
-//
-//        // ---------------------------------------------------------------
-//        // Test the addingService APIs
-//        // ---------------------------------------------------------------
-//
-//        assertEquals("Precondition failed", 0, fc.watchers.size());
-//        fc.addingService(sr);
-//        assertEquals(1, fc.watchers.size());
-//
-//        DiscoveredServiceTracker key = fc.watchers.keySet().iterator().next();
-//        assertSame(dst, key);
-//        List<InterfaceMonitor> dmList = fc.watchers.get(key);
-//        assertEquals(1, dmList.size());
-//        InterfaceMonitor dm = dmList.iterator().next();
-//        assertNotNull(dm.listener);
-//        assertSame(zk, dm.zookeeper);
-//        assertEquals(Utils.getZooKeeperPath(String.class.getName()), dm.znode);
-//
-//        assertEquals("Precondition failed", 1, fc.watchers.size());
-//        fc.addingService(sr2);
-//        assertEquals(2, fc.watchers.size());
-//
-//        assertTrue(fc.watchers.containsKey(dst));
-//        assertTrue(fc.watchers.containsKey(dst2));
-//        assertEquals(dmList, fc.watchers.get(dst));
-//        List<InterfaceMonitor> dmList2 = fc.watchers.get(dst2);
-//        assertEquals(2, dmList2.size());
-//
-//        Set<String> actual = new HashSet<String>();
-//        for (InterfaceMonitor im : dmList2) {
-//            actual.add(im.znode);
-//        }
-//        Set<String> expected = new HashSet<String>(Arrays.asList(
-//                Utils.getZooKeeperPath(Integer.class.getName()),
-//                Utils.getZooKeeperPath(Comparable.class.getName())));
-//        assertEquals(expected, actual);
-//
-//        EasyMock.verify(zk);
-//
-//        // ---------------------------------------------------------------
-//        // Test the modifiedService APIs
-//        // ---------------------------------------------------------------
-//        EasyMock.reset(zk);
-//        zkExpectExists(zk, List.class.getName());
-//        EasyMock.replay(zk);
-//
-//        EasyMock.reset(sr);
-//        EasyMock.expect(sr.getProperty(DiscoveredServiceTracker.INTERFACE_MATCH_CRITERIA))
-//            .andReturn(Collections.singleton(List.class.getName()));
-//        EasyMock.expect(sr.getProperty(DiscoveredServiceTracker.FILTER_MATCH_CRITERIA))
-//            .andReturn(null);
-//        EasyMock.replay(sr);
-//
-//        assertEquals("Precondition failed", 2, fc.watchers.size());
-//        fc.modifiedService(sr, dst);
-//        assertEquals("Precondition failed", 2, fc.watchers.size());
-//
-//        assertTrue(fc.watchers.containsKey(dst));
-//        assertTrue(fc.watchers.containsKey(dst2));
-//        assertEquals(dmList2, fc.watchers.get(dst2));
-//        List<InterfaceMonitor> dmList3 = fc.watchers.get(dst);
-//        assertEquals(1, dmList3.size());
-//        assertEquals(Utils.getZooKeeperPath(List.class.getName()), dmList3.iterator().next().znode);
-//
-//        EasyMock.verify(zk);
-//
-//        // ---------------------------------------------------------------
-//        // Test the removedService APIs
-//        // ---------------------------------------------------------------
-//        EasyMock.reset(zk);
-//        EasyMock.replay(zk);
-//
-//        assertEquals("Precondition failed", 2, fc.watchers.size());
-//        fc.removedService(sr2, dst2);
-//        assertEquals("Precondition failed", 1, fc.watchers.size());
-//
-//        assertEquals(dmList3, fc.watchers.get(dst));
-//        assertNull(fc.watchers.get(dst2));
-//
-//        EasyMock.verify(zk);
-//    }
-//
-//    public void testAddingServiceFilter() {
-//        DiscoveredServiceTracker dst = new DiscoveredServiceTracker() {
-//            public void serviceChanged(DiscoveredServiceNotification dsn) {}
-//        };
-//
-//        ServiceReference sr = EasyMock.createMock(ServiceReference.class);
-//        EasyMock.expect(sr.getProperty(DiscoveredServiceTracker.INTERFACE_MATCH_CRITERIA))
-//            .andReturn(null);
-//        Set<String> stringFilter = Collections.singleton("(objectClass=java.lang.String)");
-//        EasyMock.expect(sr.getProperty(DiscoveredServiceTracker.FILTER_MATCH_CRITERIA))
-//            .andReturn(stringFilter);
-//        EasyMock.replay(sr);
-//
-//        DiscoveredServiceTracker dst2 = new DiscoveredServiceTracker() {
-//            public void serviceChanged(DiscoveredServiceNotification dsn) {}
-//        };
-//
-//        ServiceReference sr2 = EasyMock.createMock(ServiceReference.class);
-//        EasyMock.expect(sr2.getProperty(DiscoveredServiceTracker.INTERFACE_MATCH_CRITERIA))
-//            .andReturn(null);
-//        List<String> combinedFilter =
-//            Arrays.asList("(objectClass=java.lang.Integer)", "(objectClass=java.lang.Comparable)");
-//        EasyMock.expect(sr2.getProperty(DiscoveredServiceTracker.FILTER_MATCH_CRITERIA))
-//            .andReturn(combinedFilter);
-//        EasyMock.replay(sr2);
-//
-//        BundleContext bc = EasyMock.createMock(BundleContext.class);
-//        EasyMock.expect(bc.getService(sr)).andReturn(dst);
-//        EasyMock.expect(bc.getService(sr2)).andReturn(dst2);
-//        EasyMock.replay(bc);
-//
-//        ZooKeeper zk = EasyMock.createMock(ZooKeeper.class);
-//        zkExpectExists(zk, String.class.getName());
-//        zkExpectExists(zk, Integer.class.getName());
-//        zkExpectExists(zk, Comparable.class.getName());
-//        EasyMock.expectLastCall();
-//        EasyMock.replay(zk);
-//
-//        FindInZooKeeperCustomizer fc = new FindInZooKeeperCustomizer(bc, zk);
-//
-//        // ---------------------------------------------------------------
-//        // Test the addingService APIs
-//        // ---------------------------------------------------------------
-//
-//        assertEquals("Precondition failed", 0, fc.watchers.size());
-//        fc.addingService(sr);
-//        assertEquals(1, fc.watchers.size());
-//
-//        DiscoveredServiceTracker key = fc.watchers.keySet().iterator().next();
-//        assertSame(dst, key);
-//        List<InterfaceMonitor> dmList = fc.watchers.get(key);
-//        assertEquals(1, dmList.size());
-//        InterfaceMonitor dm = dmList.iterator().next();
-//        assertNotNull(dm.listener);
-//        assertSame(zk, dm.zookeeper);
-//        assertEquals(Utils.getZooKeeperPath(String.class.getName()), dm.znode);
-//
-//        assertEquals("Precondition failed", 1, fc.watchers.size());
-//        fc.addingService(sr2);
-//        assertEquals(2, fc.watchers.size());
-//
-//        assertTrue(fc.watchers.containsKey(dst));
-//        assertTrue(fc.watchers.containsKey(dst2));
-//        assertEquals(dmList, fc.watchers.get(dst));
-//        List<InterfaceMonitor> dmList2 = fc.watchers.get(dst2);
-//        assertEquals(2, dmList2.size());
-//        Set<String> actual = new HashSet<String>();
-//        for (InterfaceMonitor im : dmList2) {
-//            actual.add(im.znode);
-//        }
-//        Set<String> expected = new HashSet<String>(Arrays.asList(
-//                Utils.getZooKeeperPath(Integer.class.getName()),
-//                Utils.getZooKeeperPath(Comparable.class.getName())));
-//        assertEquals(expected, actual);
-//
-//        EasyMock.verify(zk);
-//
-//        // ---------------------------------------------------------------
-//        // Test the modifiedService APIs
-//        // ---------------------------------------------------------------
-//        EasyMock.reset(zk);
-//        zkExpectExists(zk, List.class.getName());
-//        EasyMock.replay(zk);
-//
-//        EasyMock.reset(sr);
-//        Set<String> listFilter = Collections.singleton("(objectClass=java.util.List)");
-//        EasyMock.expect(sr.getProperty(DiscoveredServiceTracker.INTERFACE_MATCH_CRITERIA))
-//            .andReturn(null);
-//        EasyMock.expect(sr.getProperty(DiscoveredServiceTracker.FILTER_MATCH_CRITERIA))
-//            .andReturn(listFilter);
-//        EasyMock.replay(sr);
-//
-//        assertEquals("Precondition failed", 2, fc.watchers.size());
-//        fc.modifiedService(sr, dst);
-//        assertEquals("Precondition failed", 2, fc.watchers.size());
-//
-//        assertTrue(fc.watchers.containsKey(dst));
-//        assertTrue(fc.watchers.containsKey(dst2));
-//        assertEquals(dmList2, fc.watchers.get(dst2));
-//        List<InterfaceMonitor> dmList3 = fc.watchers.get(dst);
-//        assertEquals(1, dmList3.size());
-//        assertEquals(Utils.getZooKeeperPath(List.class.getName()), dmList3.iterator().next().znode);
-//
-//        EasyMock.verify(zk);
-//
-//        // ---------------------------------------------------------------
-//        // Test the removedService APIs
-//        // ---------------------------------------------------------------
-//        EasyMock.reset(zk);
-//        EasyMock.replay(zk);
-//
-//        assertEquals("Precondition failed", 2, fc.watchers.size());
-//        fc.removedService(sr2, dst2);
-//        assertEquals("Precondition failed", 1, fc.watchers.size());
-//
-//        assertEquals(dmList3, fc.watchers.get(dst));
-//        assertNull(fc.watchers.get(dst2));
-//
-//        EasyMock.verify(zk);
-//    }
-//
-//    public void testGetInterfacesFromFilter() {
-//        testGetInterfacesFromFilter("objectClass=org.apache_2.Some$FunnyClass",
-//                "org.apache_2.Some$FunnyClass");
-//        testGetInterfacesFromFilter("(&(a=b)(objectClass = org.acme.Q)",
-//                "org.acme.Q");
-//        testGetInterfacesFromFilter("(&(objectClassIdentifier=b)(objectClass = org.acme.Q)",
-//                "org.acme.Q");
-//        testGetInterfacesFromFilter("(|(OBJECTCLASS=   X  )(objectclass = Y)",
-//                "X", "Y");
-//        testGetInterfacesFromFilter(new String[] {"(objectClass=X)", "(objectClass=Y)"},
-//                "X", "Y");
-//    }
-//
-//    private void testGetInterfacesFromFilter(String filter, String ... interfaces) {
-//        testGetInterfacesFromFilter(new String[] {filter}, interfaces);
-//    }
-//
-//    private void testGetInterfacesFromFilter(String[] filters, String ... interfaces) {
-//        FindInZooKeeperCustomizer.getInterfacesFromFilter(Arrays.asList(filters));
-//    }
-//
-//    private void zkExpectExists(ZooKeeper zk, String className) {
-//        zk.exists(EasyMock.eq(Utils.getZooKeeperPath(className)),
-//                (Watcher) EasyMock.anyObject(),
-//                (StatCallback) EasyMock.anyObject(), EasyMock.isNull());
-//        EasyMock.expectLastCall().andAnswer(new IAnswer<Object>() {
-//            public Object answer() throws Throwable {
-//                assertEquals(EasyMock.getCurrentArguments()[1],
-//                        EasyMock.getCurrentArguments()[2]);
-//                return null;
-//            }
-//        });
-//    }
-}


[4/5] aries-rsa git commit: Adding roundtrip test

Posted by cs...@apache.org.
http://git-wip-us.apache.org/repos/asf/aries-rsa/blob/69bb901e/discovery/zookeeper/src/main/java/org/apache/aries/rsa/discovery/zookeeper/subscribe/InterfaceMonitor.java
----------------------------------------------------------------------
diff --git a/discovery/zookeeper/src/main/java/org/apache/aries/rsa/discovery/zookeeper/subscribe/InterfaceMonitor.java b/discovery/zookeeper/src/main/java/org/apache/aries/rsa/discovery/zookeeper/subscribe/InterfaceMonitor.java
new file mode 100644
index 0000000..f50848f
--- /dev/null
+++ b/discovery/zookeeper/src/main/java/org/apache/aries/rsa/discovery/zookeeper/subscribe/InterfaceMonitor.java
@@ -0,0 +1,262 @@
+/**
+ * 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.aries.rsa.discovery.zookeeper.subscribe;
+
+import java.io.ByteArrayInputStream;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.aries.rsa.discovery.endpoint.EndpointDescriptionParser;
+import org.apache.aries.rsa.discovery.endpoint.PropertiesMapper;
+import org.apache.aries.rsa.discovery.zookeeper.util.Utils;
+import org.apache.zookeeper.AsyncCallback.StatCallback;
+import org.apache.zookeeper.KeeperException;
+import org.apache.zookeeper.KeeperException.Code;
+import org.apache.zookeeper.WatchedEvent;
+import org.apache.zookeeper.Watcher;
+import org.apache.zookeeper.ZooKeeper;
+import org.apache.zookeeper.data.Stat;
+import org.osgi.service.remoteserviceadmin.EndpointDescription;
+import org.osgi.service.remoteserviceadmin.EndpointListener;
+import org.osgi.xmlns.rsa.v1_0.EndpointDescriptionType;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Monitors ZooKeeper for changes in published endpoints.
+ * <p>
+ * Specifically, it monitors the node path associated with a given interface class,
+ * whose data is a serialized version of an EndpointDescription, and notifies an
+ * EndpointListener when changes are detected (which can then propagate the
+ * notification to other EndpointListeners with a matching scope).
+ * <p>
+ * Note that the EndpointListener is used here as a decoupling interface for
+ * convenience, and is not necessarily used according to its documented contract.
+ */
+public class InterfaceMonitor implements Watcher, StatCallback {
+
+    private static final Logger LOG = LoggerFactory.getLogger(InterfaceMonitor.class);
+
+    private final String znode;
+    private final ZooKeeper zk;
+    private final EndpointListener endpointListener;
+    private final boolean recursive;
+    private volatile boolean closed;
+
+    // This map reference changes, so don't synchronize on it
+    private Map<String, EndpointDescription> nodes = new HashMap<String, EndpointDescription>();
+
+    private EndpointDescriptionParser parser;
+
+    public InterfaceMonitor(ZooKeeper zk, String objClass, EndpointListener endpointListener, String scope) {
+        this.zk = zk;
+        this.znode = Utils.getZooKeeperPath(objClass);
+        this.recursive = objClass == null || objClass.isEmpty();
+        this.endpointListener = endpointListener;
+        this.parser = new EndpointDescriptionParser();
+        LOG.debug("Creating new InterfaceMonitor {} for scope [{}] and objectClass [{}]",
+                new Object[] {recursive ? "(recursive)" : "", scope, objClass});
+    }
+
+    /**
+     * Returns all endpoints that are currently known to this monitor.
+     *
+     * @return all endpoints that are currently known to this monitor
+     */
+    public synchronized List<EndpointDescription> getEndpoints() {
+        return new ArrayList<EndpointDescription>(nodes.values());
+    }
+
+    public void start() {
+        watch();
+    }
+
+    private void watch() {
+        LOG.debug("registering a ZooKeeper.exists({}) callback", znode);
+        zk.exists(znode, this, this, null);
+    }
+
+    /**
+     * Zookeeper Watcher interface callback.
+     */
+    public void process(WatchedEvent event) {
+        LOG.debug("ZooKeeper watcher callback on node {} for event {}", znode, event);
+        processDelta();
+    }
+
+    /**
+     * Zookeeper StatCallback interface callback.
+     */
+    @SuppressWarnings("deprecation")
+    public void processResult(int rc, String path, Object ctx, Stat stat) {
+        LOG.debug("ZooKeeper callback on node: {} code: {}", znode, rc);
+
+        switch (rc) {
+        case Code.Ok:
+        case Code.NoNode:
+            processDelta();
+            return;
+
+        case Code.SessionExpired:
+        case Code.NoAuth:
+        case Code.ConnectionLoss:
+            return;
+
+        default:
+            watch();
+        }
+    }
+
+    private void processDelta() {
+        if (closed) {
+            return;
+        }
+
+        if (zk.getState() != ZooKeeper.States.CONNECTED) {
+            LOG.debug("ZooKeeper connection was already closed! Not processing changed event.");
+            return;
+        }
+
+        try {
+            if (zk.exists(znode, false) != null) {
+                zk.getChildren(znode, this);
+                refreshNodes();
+            } else {
+                LOG.debug("znode {} doesn't exist -> not processing any changes", znode);
+            }
+        } catch (Exception e) {
+            if (zk.getState() != ZooKeeper.States.CONNECTED) {
+                LOG.debug("Error getting Zookeeper data: " + e); // e.g. session expired, handled by ZooKeeperDiscovery
+            } else {
+                LOG.error("Error getting ZooKeeper data.", e);
+            }
+        }
+    }
+
+    public synchronized void close() {
+        closed = true;
+        for (EndpointDescription endpoint : nodes.values()) {
+            endpointListener.endpointRemoved(endpoint, null);
+        }
+        nodes.clear();
+    }
+
+    private synchronized void refreshNodes() {
+        if (closed) {
+            return;
+        }
+        LOG.info("Processing change on node: {}", znode);
+
+        Map<String, EndpointDescription> newNodes = new HashMap<String, EndpointDescription>();
+        Map<String, EndpointDescription> prevNodes = new HashMap<String, EndpointDescription>(nodes);
+        processChildren(znode, newNodes, prevNodes);
+
+        // whatever is left in prevNodes now has been removed from Discovery
+        LOG.debug("processChildren done. Nodes that are missing now and need to be removed: {}", prevNodes.values());
+        for (EndpointDescription endpoint : prevNodes.values()) {
+            endpointListener.endpointRemoved(endpoint, null);
+        }
+        nodes = newNodes;
+    }
+
+    /**
+     * Iterates through all child nodes of the given node and tries to find
+     * endpoints. If the recursive flag is set it also traverses into the child
+     * nodes.
+     *
+     * @return true if an endpoint was found and if the node therefore needs to
+     *         be monitored for changes
+     */
+    private boolean processChildren(String zn, Map<String, EndpointDescription> newNodes,
+            Map<String, EndpointDescription> prevNodes) {
+        List<String> children;
+        try {
+            LOG.debug("Processing the children of {}", zn);
+            children = zk.getChildren(zn, false);
+
+            boolean foundANode = false;
+            for (String child : children) {
+                String childZNode = zn + '/' + child;
+                EndpointDescription endpoint = getEndpointDescriptionFromNode(childZNode);
+                if (endpoint != null) {
+                    EndpointDescription prevEndpoint = prevNodes.get(child);
+                    LOG.info("found new node " + zn + "/[" + child + "]   ( []->child )  props: "
+                            + endpoint.getProperties().values());
+                    newNodes.put(child, endpoint);
+                    prevNodes.remove(child);
+                    foundANode = true;
+                    LOG.debug("Properties: {}", endpoint.getProperties());
+                    if (prevEndpoint == null) {
+                        // This guy is new
+                        endpointListener.endpointAdded(endpoint, null);
+                    } else if (!prevEndpoint.getProperties().equals(endpoint.getProperties())) {
+                        // TODO
+                    }
+                }
+                if (recursive && processChildren(childZNode, newNodes, prevNodes)) {
+                    zk.getChildren(childZNode, this);
+                }
+            }
+
+            return foundANode;
+        } catch (KeeperException e) {
+            LOG.error("Problem processing ZooKeeper node", e);
+        } catch (InterruptedException e) {
+            LOG.error("Problem processing ZooKeeper node", e);
+        }
+        return false;
+    }
+
+    /**
+     * Retrieves data from the given node and parses it into an EndpointDescription.
+     *
+     * @param node a node path
+     * @return endpoint found in the node or null if no endpoint was found
+     */
+    private EndpointDescription getEndpointDescriptionFromNode(String node) {
+        try {
+            Stat stat = zk.exists(node, false);
+            if (stat == null || stat.getDataLength() <= 0) {
+                return null;
+            }
+            byte[] data = zk.getData(node, false, null);
+            LOG.debug("Got data for node: {}", node);
+
+            EndpointDescription endpoint = getFirstEnpointDescription(data);
+            if (endpoint != null) {
+                return endpoint;
+            }
+            LOG.warn("No Discovery information found for node: {}", node);
+        } catch (Exception e) {
+            LOG.error("Problem getting EndpointDescription from node " + node, e);
+        }
+        return null;
+    }
+
+    public EndpointDescription getFirstEnpointDescription(byte[] data) {
+        List<EndpointDescriptionType> elements = parser.getEndpointDescriptions(new ByteArrayInputStream(data));
+        if (elements.isEmpty()) {
+            return null;
+        }
+        Map<String, Object> props = new PropertiesMapper().toProps(elements.get(0).getProperty());
+        return new EndpointDescription(props);
+    }
+}

http://git-wip-us.apache.org/repos/asf/aries-rsa/blob/69bb901e/discovery/zookeeper/src/main/java/org/apache/aries/rsa/discovery/zookeeper/subscribe/InterfaceMonitorManager.java
----------------------------------------------------------------------
diff --git a/discovery/zookeeper/src/main/java/org/apache/aries/rsa/discovery/zookeeper/subscribe/InterfaceMonitorManager.java b/discovery/zookeeper/src/main/java/org/apache/aries/rsa/discovery/zookeeper/subscribe/InterfaceMonitorManager.java
new file mode 100644
index 0000000..3a02a48
--- /dev/null
+++ b/discovery/zookeeper/src/main/java/org/apache/aries/rsa/discovery/zookeeper/subscribe/InterfaceMonitorManager.java
@@ -0,0 +1,261 @@
+/**
+ * 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.aries.rsa.discovery.zookeeper.subscribe;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Dictionary;
+import java.util.HashMap;
+import java.util.Hashtable;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.CopyOnWriteArrayList;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import org.apache.aries.rsa.discovery.zookeeper.ZooKeeperDiscovery;
+import org.apache.aries.rsa.discovery.zookeeper.util.Utils;
+import org.apache.aries.rsa.util.StringPlus;
+import org.apache.zookeeper.ZooKeeper;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.Filter;
+import org.osgi.framework.ServiceReference;
+import org.osgi.service.remoteserviceadmin.EndpointDescription;
+import org.osgi.service.remoteserviceadmin.EndpointListener;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Manages the EndpointListeners and the scopes they are interested in.
+ * For each scope with interested EndpointListeners an InterfaceMonitor is created.
+ * The InterfaceMonitor calls back when it detects added or removed external Endpoints.
+ * These events are then forwarded to all interested EndpointListeners.
+ */
+public class InterfaceMonitorManager {
+    private static final Logger LOG = LoggerFactory.getLogger(InterfaceMonitorManager.class);
+    private static final Pattern OBJECTCLASS_PATTERN = Pattern.compile(".*\\(objectClass=([^)]+)\\).*");
+
+    private final BundleContext bctx;
+    private final ZooKeeper zk;
+    // map of EndpointListeners and the scopes they are interested in
+    private final Map<ServiceReference<EndpointListener>, List<String>> endpointListenerScopes =
+            new HashMap<ServiceReference<EndpointListener>, List<String>>();
+    // map of scopes and their interest data
+    private final Map<String, Interest> interests = new HashMap<String, Interest>();
+
+    protected static class Interest {
+        List<ServiceReference<EndpointListener>> endpointListeners = 
+            new CopyOnWriteArrayList<ServiceReference<EndpointListener>>();
+        InterfaceMonitor monitor;
+    }
+
+    public InterfaceMonitorManager(BundleContext bctx, ZooKeeper zk) {
+        this.bctx = bctx;
+        this.zk = zk;
+    }
+
+    public void addInterest(ServiceReference<EndpointListener> endpointListener) {
+        if (isOurOwnEndpointListener(endpointListener)) {
+            LOG.debug("Skipping our own EndpointListener");
+            return;
+        }
+
+        LOG.info("updating EndpointListener interests: {}", endpointListener);
+        if (LOG.isDebugEnabled()) {
+            LOG.debug("updated EndpointListener properties: {}", getProperties(endpointListener));
+        }
+        for (String scope : getScopes(endpointListener)) {
+            String objClass = getObjectClass(scope);
+            LOG.debug("Adding interest in scope {}, objectClass {}", scope, objClass);
+            addInterest(endpointListener, scope, objClass);
+        }
+    }
+
+    private static boolean isOurOwnEndpointListener(ServiceReference<EndpointListener> endpointListener) {
+        return Boolean.parseBoolean(String.valueOf(
+                endpointListener.getProperty(ZooKeeperDiscovery.DISCOVERY_ZOOKEEPER_ID)));
+    }
+
+    public synchronized void addInterest(ServiceReference<EndpointListener> endpointListener, 
+                                         String scope, String objClass) {
+        // get or create interest for given scope and add listener to it
+        Interest interest = interests.get(scope);
+        if (interest == null) {
+            // create interest, add listener and start monitor
+            interest = new Interest();
+            interests.put(scope, interest);
+            interest.endpointListeners.add(endpointListener); // add it before monitor starts so we don't miss events
+            interest.monitor = createInterfaceMonitor(scope, objClass, interest);
+            interest.monitor.start();
+        } else {
+            // interest already exists, so just add listener to it
+            if (!interest.endpointListeners.contains(endpointListener)) {
+                interest.endpointListeners.add(endpointListener);
+            }
+            // notify listener of all known endpoints for given scope
+            // (as EndpointListener contract requires of all added/modified listeners)
+            for (EndpointDescription endpoint : interest.monitor.getEndpoints()) {
+                notifyListeners(endpoint, scope, true, Arrays.asList(endpointListener));
+            }
+        }
+
+        // add scope to listener's scopes list
+        List<String> scopes = endpointListenerScopes.get(endpointListener);
+        if (scopes == null) {
+            scopes = new ArrayList<String>(1);
+            endpointListenerScopes.put(endpointListener, scopes);
+        }
+        if (!scopes.contains(scope)) {
+            scopes.add(scope);
+        }
+    }
+
+    public synchronized void removeInterest(ServiceReference<EndpointListener> endpointListener) {
+        LOG.info("removing EndpointListener interests: {}", endpointListener);
+        List<String> scopes = endpointListenerScopes.get(endpointListener);
+        if (scopes == null) {
+            return;
+        }
+
+        for (String scope : scopes) {
+            Interest interest = interests.get(scope);
+            if (interest != null) {
+                interest.endpointListeners.remove(endpointListener);
+                if (interest.endpointListeners.isEmpty()) {
+                    interest.monitor.close();
+                    interests.remove(scope);
+                }
+            }
+        }
+        endpointListenerScopes.remove(endpointListener);
+    }
+
+    protected InterfaceMonitor createInterfaceMonitor(final String scope, String objClass, final Interest interest) {
+        // holding this object's lock in the callbacks can lead to a deadlock with InterfaceMonitor
+        EndpointListener endpointListener = new EndpointListener() {
+
+            public void endpointRemoved(EndpointDescription endpoint, String matchedFilter) {
+                notifyListeners(endpoint, scope, false, interest.endpointListeners);
+            }
+
+            public void endpointAdded(EndpointDescription endpoint, String matchedFilter) {
+                notifyListeners(endpoint, scope, true, interest.endpointListeners);
+            }
+        };
+        return new InterfaceMonitor(zk, objClass, endpointListener, scope);
+    }
+
+    private void notifyListeners(EndpointDescription endpoint, String currentScope, boolean isAdded,
+            List<ServiceReference<EndpointListener>> endpointListeners) {
+        for (ServiceReference<EndpointListener> endpointListenerRef : endpointListeners) {
+            EndpointListener service = bctx.getService(endpointListenerRef);
+            try {
+                EndpointListener endpointListener = (EndpointListener)service;
+                LOG.trace("matching {} against {}", endpoint, currentScope);
+                if (matchFilter(bctx, currentScope, endpoint)) {
+                    LOG.debug("Matched {} against {}", endpoint, currentScope);
+                    notifyListener(endpoint, currentScope, isAdded, endpointListenerRef.getBundle(),
+                                   endpointListener);
+                }
+            } finally {
+                if (service != null) {
+                    bctx.ungetService(endpointListenerRef);
+                }
+            }
+        }
+    }
+    
+    private static boolean matchFilter(BundleContext bctx, String filter, EndpointDescription endpoint) {
+        if (filter == null) {
+            return false;
+        }
+    
+        try {
+            Filter f = bctx.createFilter(filter);
+            Dictionary<String, Object> dict = new Hashtable<String, Object>(endpoint.getProperties());
+            return f.match(dict);
+        } catch (Exception e) {
+            return false;
+        }
+    }
+
+
+    private void notifyListener(EndpointDescription endpoint, String currentScope, boolean isAdded,
+                                Bundle endpointListenerBundle, EndpointListener endpointListener) {
+        if (endpointListenerBundle == null) {
+            LOG.info("listening service was unregistered, ignoring");
+        } else if (isAdded) {
+            LOG.info("calling EndpointListener.endpointAdded: " + endpointListener + " from bundle "
+                    + endpointListenerBundle.getSymbolicName() + " for endpoint: " + endpoint);
+            endpointListener.endpointAdded(endpoint, currentScope);
+        } else {
+            LOG.info("calling EndpointListener.endpointRemoved: " + endpointListener + " from bundle "
+                    + endpointListenerBundle.getSymbolicName() + " for endpoint: " + endpoint);
+            endpointListener.endpointRemoved(endpoint, currentScope);
+        }
+    }
+
+    public synchronized void close() {
+        for (Interest interest : interests.values()) {
+            interest.monitor.close();
+        }
+        interests.clear();
+        endpointListenerScopes.clear();
+    }
+
+    /**
+     * Only for test case!
+     */
+    protected synchronized Map<String, Interest> getInterests() {
+        return interests;
+    }
+
+    /**
+     * Only for test case!
+     */
+    protected synchronized Map<ServiceReference<EndpointListener>, List<String>> getEndpointListenerScopes() {
+        return endpointListenerScopes;
+    }
+
+    protected List<String> getScopes(ServiceReference<?> sref) {
+        return Utils.removeEmpty(StringPlus.normalize(sref.getProperty(EndpointListener.ENDPOINT_LISTENER_SCOPE)));
+    }
+    
+    public static String getObjectClass(String scope) {
+        Matcher m = OBJECTCLASS_PATTERN.matcher(scope);
+        return m.matches() ? m.group(1) : null;
+    }
+
+    /**
+     * Returns a service's properties as a map.
+     *
+     * @param serviceReference a service reference
+     * @return the service's properties as a map
+     */
+    public static Map<String, Object> getProperties(ServiceReference<?> serviceReference) {
+        String[] keys = serviceReference.getPropertyKeys();
+        Map<String, Object> props = new HashMap<String, Object>(keys.length);
+        for (String key : keys) {
+            Object val = serviceReference.getProperty(key);
+            props.put(key, val);
+        }
+        return props;
+    }
+}

http://git-wip-us.apache.org/repos/asf/aries-rsa/blob/69bb901e/discovery/zookeeper/src/main/java/org/apache/aries/rsa/discovery/zookeeper/util/Utils.java
----------------------------------------------------------------------
diff --git a/discovery/zookeeper/src/main/java/org/apache/aries/rsa/discovery/zookeeper/util/Utils.java b/discovery/zookeeper/src/main/java/org/apache/aries/rsa/discovery/zookeeper/util/Utils.java
new file mode 100644
index 0000000..82ccb85
--- /dev/null
+++ b/discovery/zookeeper/src/main/java/org/apache/aries/rsa/discovery/zookeeper/util/Utils.java
@@ -0,0 +1,54 @@
+/**
+ * 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.aries.rsa.discovery.zookeeper.util;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public final class Utils {
+
+    static final String PATH_PREFIX = "/osgi/service_registry";
+
+    private Utils() {
+        // never constructed
+    }
+
+    public static String getZooKeeperPath(String name) {
+        return name == null || name.isEmpty() ? PATH_PREFIX : PATH_PREFIX + '/' + name.replace('.', '/');
+    }
+
+    /**
+     * Removes nulls and empty strings from the given string array.
+     *
+     * @param strings an array of strings
+     * @return a new array containing the non-null and non-empty
+     *         elements of the original array in the same order
+     */
+    public static List<String> removeEmpty(List<String> strings) {
+        List<String> result = new ArrayList<String>();
+        for (String s : strings) {
+            if (s != null && !s.isEmpty()) {
+                result.add(s);
+            }
+        }
+        return result;
+    }
+
+
+}

http://git-wip-us.apache.org/repos/asf/aries-rsa/blob/69bb901e/discovery/zookeeper/src/main/java/org/apache/cxf/dosgi/discovery/zookeeper/Activator.java
----------------------------------------------------------------------
diff --git a/discovery/zookeeper/src/main/java/org/apache/cxf/dosgi/discovery/zookeeper/Activator.java b/discovery/zookeeper/src/main/java/org/apache/cxf/dosgi/discovery/zookeeper/Activator.java
deleted file mode 100644
index 1e6c551..0000000
--- a/discovery/zookeeper/src/main/java/org/apache/cxf/dosgi/discovery/zookeeper/Activator.java
+++ /dev/null
@@ -1,43 +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.cxf.dosgi.discovery.zookeeper;
-
-import java.util.Dictionary;
-import java.util.Hashtable;
-
-import org.osgi.framework.BundleActivator;
-import org.osgi.framework.BundleContext;
-import org.osgi.framework.Constants;
-import org.osgi.service.cm.ManagedService;
-
-public class Activator implements BundleActivator {
-
-    private ZooKeeperDiscovery zkd;
-
-    public synchronized void start(BundleContext bc) throws Exception {
-        zkd = new ZooKeeperDiscovery(bc);
-        Dictionary<String, String> props = new Hashtable<String, String>();
-        props.put(Constants.SERVICE_PID, "org.apache.aries.rsa.discovery.zookeeper");
-        bc.registerService(ManagedService.class.getName(), zkd, props);
-    }
-
-    public synchronized void stop(BundleContext bc) throws Exception {
-        zkd.stop(true);
-    }
-}

http://git-wip-us.apache.org/repos/asf/aries-rsa/blob/69bb901e/discovery/zookeeper/src/main/java/org/apache/cxf/dosgi/discovery/zookeeper/ZooKeeperDiscovery.java
----------------------------------------------------------------------
diff --git a/discovery/zookeeper/src/main/java/org/apache/cxf/dosgi/discovery/zookeeper/ZooKeeperDiscovery.java b/discovery/zookeeper/src/main/java/org/apache/cxf/dosgi/discovery/zookeeper/ZooKeeperDiscovery.java
deleted file mode 100644
index 3a7f2c4..0000000
--- a/discovery/zookeeper/src/main/java/org/apache/cxf/dosgi/discovery/zookeeper/ZooKeeperDiscovery.java
+++ /dev/null
@@ -1,186 +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.cxf.dosgi.discovery.zookeeper;
-
-import java.io.IOException;
-import java.util.Dictionary;
-import java.util.Enumeration;
-import java.util.HashMap;
-import java.util.Map;
-
-import org.apache.cxf.dosgi.discovery.zookeeper.publish.PublishingEndpointListenerFactory;
-import org.apache.cxf.dosgi.discovery.zookeeper.subscribe.EndpointListenerTracker;
-import org.apache.cxf.dosgi.discovery.zookeeper.subscribe.InterfaceMonitorManager;
-import org.apache.zookeeper.WatchedEvent;
-import org.apache.zookeeper.Watcher;
-import org.apache.zookeeper.ZooKeeper;
-import org.osgi.framework.BundleContext;
-import org.osgi.service.cm.ConfigurationException;
-import org.osgi.service.cm.ManagedService;
-import org.osgi.service.remoteserviceadmin.EndpointListener;
-import org.osgi.util.tracker.ServiceTracker;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-public class ZooKeeperDiscovery implements Watcher, ManagedService {
-
-    public static final String DISCOVERY_ZOOKEEPER_ID = "org.apache.cxf.dosgi.discovery.zookeeper";
-
-    private static final Logger LOG = LoggerFactory.getLogger(ZooKeeperDiscovery.class);
-
-    private final BundleContext bctx;
-
-    private PublishingEndpointListenerFactory endpointListenerFactory;
-    private ServiceTracker<EndpointListener, EndpointListener> endpointListenerTracker;
-    private InterfaceMonitorManager imManager;
-    private ZooKeeper zkClient;
-    private boolean closed;
-    private boolean started;
-
-    private Dictionary<String, ?> curConfiguration;
-
-    public ZooKeeperDiscovery(BundleContext bctx) {
-        this.bctx = bctx;
-    }
-
-    public synchronized void updated(Dictionary<String, ?> configuration) throws ConfigurationException {
-        LOG.debug("Received configuration update for Zookeeper Discovery: {}", configuration);
-        // make changes only if config actually changed, to prevent unnecessary ZooKeeper reconnections
-        if (!ZooKeeperDiscovery.toMap(configuration).equals(ZooKeeperDiscovery.toMap(curConfiguration))) {
-            stop(false);
-            curConfiguration = configuration;
-            // config is null if it doesn't exist, is being deleted or has not yet been loaded
-            // in which case we just stop running
-            if (!closed && configuration != null) {
-                try {
-                    createZookeeper(configuration);
-                } catch (IOException e) {
-                    throw new ConfigurationException(null, "Error starting zookeeper client", e);
-                }
-            }
-        }
-    }
-
-    private synchronized void start() {
-        if (closed) {
-            return;
-        }
-        if (started) {
-            // we must be re-entrant, i.e. can be called when already started
-            LOG.debug("ZookeeperDiscovery already started");
-            return;
-        }
-        LOG.debug("starting ZookeeperDiscovery");
-        endpointListenerFactory = new PublishingEndpointListenerFactory(zkClient, bctx);
-        endpointListenerFactory.start();
-        imManager = new InterfaceMonitorManager(bctx, zkClient);
-        endpointListenerTracker = new EndpointListenerTracker(bctx, imManager);
-        endpointListenerTracker.open();
-        started = true;
-    }
-
-    public synchronized void stop(boolean close) {
-        if (started) {
-            LOG.debug("stopping ZookeeperDiscovery");
-        }
-        started = false;
-        closed |= close;
-        if (endpointListenerFactory != null) {
-            endpointListenerFactory.stop();
-        }
-        if (endpointListenerTracker != null) {
-            endpointListenerTracker.close();
-        }
-        if (imManager != null) {
-            imManager.close();
-        }
-        if (zkClient != null) {
-            try {
-                zkClient.close();
-            } catch (InterruptedException e) {
-                LOG.error("Error closing ZooKeeper", e);
-            }
-        }
-    }
-
-    protected ZooKeeper createZooKeeper(String host, String port, int timeout) throws IOException {
-        LOG.info("ZooKeeper discovery connecting to {}:{} with timeout {}",
-                new Object[]{host, port, timeout});
-        return new ZooKeeper(host + ":" + port, timeout, this);
-    }
-
-    /* Callback for ZooKeeper */
-    public void process(WatchedEvent event) {
-        LOG.debug("got ZooKeeper event " + event);
-        switch (event.getState()) {
-        case SyncConnected:
-            LOG.info("Connection to ZooKeeper established");
-            // this event can be triggered more than once in a row (e.g. after Disconnected event),
-            // so we must be re-entrant here
-            start();
-            break;
-
-        case Expired:
-            LOG.info("Connection to ZooKeeper expired. Trying to create a new connection");
-            stop(false);
-            try {
-                createZookeeper(curConfiguration);
-            } catch (IOException e) {
-                LOG.error("Error starting zookeeper client", e);
-            }
-            break;
-
-        default:
-            // ignore other events
-            break;
-        }
-    }
-
-    private void createZookeeper(Dictionary<String, ?> config) throws IOException {
-        String host = (String)getWithDefault(config, "zookeeper.host", "localhost");
-        String port = (String)getWithDefault(config, "zookeeper.port", "2181");
-        int timeout = Integer.parseInt((String)getWithDefault(config, "zookeeper.timeout", "3000"));
-        zkClient = createZooKeeper(host, port, timeout);
-    }
-    
-    public Object getWithDefault(Dictionary<String, ?> config, String key, Object defaultValue) {
-        Object value = config.get(key);
-        return value != null ? value : defaultValue;
-    }
-    
-    /**
-     * Converts the given Dictionary to a Map.
-     *
-     * @param dict a dictionary
-     * @param <K> the key type
-     * @param <V> the value type
-     * @return the converted map, or an empty map if the given dictionary is null
-     */
-    public static <K, V> Map<K, V> toMap(Dictionary<K, V> dict) {
-        Map<K, V> map = new HashMap<K, V>();
-        if (dict != null) {
-            Enumeration<K> keys = dict.keys();
-            while (keys.hasMoreElements()) {
-                K key = keys.nextElement();
-                map.put(key, dict.get(key));
-            }
-        }
-        return map;
-    }
-}

http://git-wip-us.apache.org/repos/asf/aries-rsa/blob/69bb901e/discovery/zookeeper/src/main/java/org/apache/cxf/dosgi/discovery/zookeeper/publish/DiscoveryPlugin.java
----------------------------------------------------------------------
diff --git a/discovery/zookeeper/src/main/java/org/apache/cxf/dosgi/discovery/zookeeper/publish/DiscoveryPlugin.java b/discovery/zookeeper/src/main/java/org/apache/cxf/dosgi/discovery/zookeeper/publish/DiscoveryPlugin.java
deleted file mode 100644
index 5d46585..0000000
--- a/discovery/zookeeper/src/main/java/org/apache/cxf/dosgi/discovery/zookeeper/publish/DiscoveryPlugin.java
+++ /dev/null
@@ -1,54 +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.cxf.dosgi.discovery.zookeeper.publish;
-
-import java.util.Map;
-
-/**
- * This interface allows transformation of service registration information before it is pushed into the ZooKeeper
- * discovery system.
- * It can be useful for situations where a host name or port number needs to be changed in cases where the host running
- * the service is known differently from the outside to what the local Java process thinks it is.
- * Extra service properties can also be added to the registration which can be useful to refine the remote service
- * lookup process. <p/>
- *
- * DiscoveryPlugins use the OSGi WhiteBoard pattern. To add one to the system, register an instance under this interface
- * with the OSGi Service Registry. All registered DiscoveryPlugin instances are visited and given a chance to
- * process the information before it is pushed into ZooKeeper. <p/>
- *
- * Note that the changes made using this plugin do not modify the local service registration.
- *
- */
-public interface DiscoveryPlugin {
-
-    /**
-     * Process service registration information. Plugins can change this information before it is published into the
-     * ZooKeeper discovery system.
-     *
-     * @param mutableProperties A map of service registration properties. The map is mutable and any changes to the map
-     * will be reflected in the ZooKeeper registration.
-     * @param endpointKey The key under which the service is registered in ZooKeeper. This key typically has the
-     * following format: hostname#port##context. While the actual value of this key is not actually used by the
-     * system (people can use it as a hint to understand where the service is located), the value <i>must</i> be
-     * unique for all services of a given type.
-     * @return The <tt>endpointKey</tt> value to be used. If there is no need to change this simply return the value
-     * of the <tt>endpointKey</tt> parameter.
-     */
-    String process(Map<String, Object> mutableProperties, String endpointKey);
-}

http://git-wip-us.apache.org/repos/asf/aries-rsa/blob/69bb901e/discovery/zookeeper/src/main/java/org/apache/cxf/dosgi/discovery/zookeeper/publish/PublishingEndpointListener.java
----------------------------------------------------------------------
diff --git a/discovery/zookeeper/src/main/java/org/apache/cxf/dosgi/discovery/zookeeper/publish/PublishingEndpointListener.java b/discovery/zookeeper/src/main/java/org/apache/cxf/dosgi/discovery/zookeeper/publish/PublishingEndpointListener.java
deleted file mode 100644
index 9bcfe72..0000000
--- a/discovery/zookeeper/src/main/java/org/apache/cxf/dosgi/discovery/zookeeper/publish/PublishingEndpointListener.java
+++ /dev/null
@@ -1,210 +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.cxf.dosgi.discovery.zookeeper.publish;
-
-import java.io.IOException;
-import java.net.URI;
-import java.net.URISyntaxException;
-import java.net.UnknownHostException;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collection;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-
-import org.apache.aries.rsa.discovery.endpoint.EndpointDescriptionParser;
-import org.apache.aries.rsa.discovery.endpoint.PropertiesMapper;
-import org.apache.cxf.dosgi.discovery.zookeeper.util.Utils;
-import org.apache.zookeeper.CreateMode;
-import org.apache.zookeeper.KeeperException;
-import org.apache.zookeeper.KeeperException.NoNodeException;
-import org.apache.zookeeper.KeeperException.NodeExistsException;
-import org.apache.zookeeper.ZooDefs.Ids;
-import org.apache.zookeeper.ZooKeeper;
-import org.osgi.framework.BundleContext;
-import org.osgi.service.remoteserviceadmin.EndpointDescription;
-import org.osgi.service.remoteserviceadmin.EndpointListener;
-import org.osgi.util.tracker.ServiceTracker;
-import org.osgi.xmlns.rsa.v1_0.EndpointDescriptionType;
-import org.osgi.xmlns.rsa.v1_0.PropertyType;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-/**
- * Listens for local Endpoints and publishes them to ZooKeeper.
- */
-public class PublishingEndpointListener implements EndpointListener {
-
-    private static final Logger LOG = LoggerFactory.getLogger(PublishingEndpointListener.class);
-
-    private final ZooKeeper zk;
-    private final ServiceTracker<DiscoveryPlugin, DiscoveryPlugin> discoveryPluginTracker;
-    private final List<EndpointDescription> endpoints = new ArrayList<EndpointDescription>();
-    private boolean closed;
-
-    private final EndpointDescriptionParser endpointDescriptionParser;
-
-    public PublishingEndpointListener(ZooKeeper zk, BundleContext bctx) {
-        this.zk = zk;
-        discoveryPluginTracker = new ServiceTracker<DiscoveryPlugin, DiscoveryPlugin>(bctx, 
-            DiscoveryPlugin.class, null);
-        discoveryPluginTracker.open();
-        endpointDescriptionParser = new EndpointDescriptionParser();
-    }
-
-    public void endpointAdded(EndpointDescription endpoint, String matchedFilter) {
-        LOG.info("Local EndpointDescription added: {}", endpoint);
-
-        synchronized (endpoints) {
-            if (closed) {
-                return;
-            }
-            if (endpoints.contains(endpoint)) {
-                // TODO -> Should the published endpoint be updated here?
-                return;
-            }
-
-            try {
-                addEndpoint(endpoint);
-                endpoints.add(endpoint);
-            } catch (Exception ex) {
-                LOG.error("Exception while processing the addition of an endpoint.", ex);
-            }
-        }
-    }
-
-    private void addEndpoint(EndpointDescription endpoint) throws URISyntaxException, KeeperException,
-                                                                  InterruptedException, IOException {
-        Collection<String> interfaces = endpoint.getInterfaces();
-        String endpointKey = getKey(endpoint);
-        Map<String, Object> props = new HashMap<String, Object>(endpoint.getProperties());
-
-        // process plugins
-        Object[] plugins = discoveryPluginTracker.getServices();
-        if (plugins != null) {
-            for (Object plugin : plugins) {
-                if (plugin instanceof DiscoveryPlugin) {
-                    endpointKey = ((DiscoveryPlugin)plugin).process(props, endpointKey);
-                }
-            }
-        }
-
-        for (String name : interfaces) {
-            String path = Utils.getZooKeeperPath(name);
-            String fullPath = path + '/' + endpointKey;
-            LOG.info("Creating ZooKeeper node for service with path {}", fullPath);
-            createPath(path, zk);
-            List<PropertyType> propsOut = new PropertiesMapper().fromProps(props);
-            EndpointDescriptionType epd = new EndpointDescriptionType();
-            epd.getProperty().addAll(propsOut);
-            byte[] epData = endpointDescriptionParser.getData(epd);
-            createEphemeralNode(fullPath, epData);
-        }
-    }
-
-    private void createEphemeralNode(String fullPath, byte[] data) throws KeeperException, InterruptedException {
-        try {
-            zk.create(fullPath, data, Ids.OPEN_ACL_UNSAFE, CreateMode.EPHEMERAL);
-        } catch (NodeExistsException nee) {
-            // this sometimes happens after a ZooKeeper node dies and the ephemeral node
-            // that belonged to the old session was not yet deleted. We need to make our
-            // session the owner of the node so it won't get deleted automatically -
-            // we do this by deleting and recreating it ourselves.
-            LOG.info("node for endpoint already exists, recreating: {}", fullPath);
-            try {
-                zk.delete(fullPath, -1);
-            } catch (NoNodeException nne) {
-                // it's a race condition, but as long as it got deleted - it's ok
-            }
-            zk.create(fullPath, data, Ids.OPEN_ACL_UNSAFE, CreateMode.EPHEMERAL);
-        }
-    }
-
-    public void endpointRemoved(EndpointDescription endpoint, String matchedFilter) {
-        LOG.info("Local EndpointDescription removed: {}", endpoint);
-
-        synchronized (endpoints) {
-            if (closed) {
-                return;
-            }
-            if (!endpoints.contains(endpoint)) {
-                return;
-            }
-
-            try {
-                removeEndpoint(endpoint);
-                endpoints.remove(endpoint);
-            } catch (Exception ex) {
-                LOG.error("Exception while processing the removal of an endpoint", ex);
-            }
-        }
-    }
-
-    private void removeEndpoint(EndpointDescription endpoint) throws UnknownHostException, URISyntaxException {
-        Collection<String> interfaces = endpoint.getInterfaces();
-        String endpointKey = getKey(endpoint);
-        for (String name : interfaces) {
-            String path = Utils.getZooKeeperPath(name);
-            String fullPath = path + '/' + endpointKey;
-            LOG.debug("Removing ZooKeeper node: {}", fullPath);
-            try {
-                zk.delete(fullPath, -1);
-            } catch (Exception ex) {
-                LOG.debug("Error while removing endpoint: {}", ex); // e.g. session expired
-            }
-        }
-    }
-
-    private static void createPath(String path, ZooKeeper zk) throws KeeperException, InterruptedException {
-        StringBuilder current = new StringBuilder();
-        List<String> parts = Utils.removeEmpty(Arrays.asList(path.split("/")));
-        for (String part : parts) {
-            current.append('/');
-            current.append(part);
-            try {
-                zk.create(current.toString(), new byte[0], Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);
-            } catch (NodeExistsException nee) {
-                // it's not the first node with this path to ever exist - that's normal
-            }
-        }
-    }
-
-    private static String getKey(EndpointDescription endpoint) throws URISyntaxException {
-        URI uri = new URI(endpoint.getId());
-        return new StringBuilder().append(uri.getHost()).append("#").append(uri.getPort())
-            .append("#").append(uri.getPath().replace('/', '#')).toString();
-    }
-
-    public void close() {
-        LOG.debug("closing - removing all endpoints");
-        synchronized (endpoints) {
-            closed = true;
-            for (EndpointDescription endpoint : endpoints) {
-                try {
-                    removeEndpoint(endpoint);
-                } catch (Exception ex) {
-                    LOG.error("Exception while removing endpoint during close", ex);
-                }
-            }
-            endpoints.clear();
-        }
-        discoveryPluginTracker.close();
-    }
-}

http://git-wip-us.apache.org/repos/asf/aries-rsa/blob/69bb901e/discovery/zookeeper/src/main/java/org/apache/cxf/dosgi/discovery/zookeeper/publish/PublishingEndpointListenerFactory.java
----------------------------------------------------------------------
diff --git a/discovery/zookeeper/src/main/java/org/apache/cxf/dosgi/discovery/zookeeper/publish/PublishingEndpointListenerFactory.java b/discovery/zookeeper/src/main/java/org/apache/cxf/dosgi/discovery/zookeeper/publish/PublishingEndpointListenerFactory.java
deleted file mode 100644
index 99a9849..0000000
--- a/discovery/zookeeper/src/main/java/org/apache/cxf/dosgi/discovery/zookeeper/publish/PublishingEndpointListenerFactory.java
+++ /dev/null
@@ -1,105 +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.cxf.dosgi.discovery.zookeeper.publish;
-
-import java.util.ArrayList;
-import java.util.Dictionary;
-import java.util.Hashtable;
-import java.util.List;
-
-import org.apache.cxf.dosgi.discovery.zookeeper.ZooKeeperDiscovery;
-import org.apache.zookeeper.ZooKeeper;
-import org.osgi.framework.Bundle;
-import org.osgi.framework.BundleContext;
-import org.osgi.framework.Constants;
-import org.osgi.framework.ServiceFactory;
-import org.osgi.framework.ServiceRegistration;
-import org.osgi.service.remoteserviceadmin.EndpointListener;
-import org.osgi.service.remoteserviceadmin.RemoteConstants;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-/**
- * Creates local EndpointListeners that publish to ZooKeeper.
- */
-public class PublishingEndpointListenerFactory implements ServiceFactory<PublishingEndpointListener> {
-
-    private static final Logger LOG = LoggerFactory.getLogger(PublishingEndpointListenerFactory.class);
-
-    private final BundleContext bctx;
-    private final ZooKeeper zk;
-    private final List<PublishingEndpointListener> listeners = new ArrayList<PublishingEndpointListener>();
-    private ServiceRegistration<?> serviceRegistration;
-
-    public PublishingEndpointListenerFactory(ZooKeeper zk, BundleContext bctx) {
-        this.bctx = bctx;
-        this.zk = zk;
-    }
-
-    public PublishingEndpointListener getService(Bundle b, ServiceRegistration<PublishingEndpointListener> sr) {
-        LOG.debug("new EndpointListener from factory");
-        synchronized (listeners) {
-            PublishingEndpointListener pel = new PublishingEndpointListener(zk, bctx);
-            listeners.add(pel);
-            return pel;
-        }
-    }
-
-    public void ungetService(Bundle b, ServiceRegistration<PublishingEndpointListener> sr, 
-                             PublishingEndpointListener pel) {
-        LOG.debug("remove EndpointListener");
-        synchronized (listeners) {
-            if (listeners.remove(pel)) {
-                pel.close();
-            }
-        }
-    }
-
-    public synchronized void start() {
-        Dictionary<String, String> props = new Hashtable<String, String>();
-        String uuid = bctx.getProperty(Constants.FRAMEWORK_UUID);
-        props.put(EndpointListener.ENDPOINT_LISTENER_SCOPE, 
-                  String.format("(&(%s=*)(%s=%s))", Constants.OBJECTCLASS, 
-                                RemoteConstants.ENDPOINT_FRAMEWORK_UUID, uuid));
-        props.put(ZooKeeperDiscovery.DISCOVERY_ZOOKEEPER_ID, "true");
-        serviceRegistration = bctx.registerService(EndpointListener.class.getName(), this, props);
-    }
-    
-    public synchronized void stop() {
-        if (serviceRegistration != null) {
-            serviceRegistration.unregister();
-            serviceRegistration = null;
-        }
-        synchronized (listeners) {
-            for (PublishingEndpointListener pel : listeners) {
-                pel.close();
-            }
-            listeners.clear();
-        }
-    }
-
-    /**
-     * Only for the test case!
-     */
-    protected List<PublishingEndpointListener> getListeners() {
-        synchronized (listeners) {
-            return listeners;
-        }
-    }
-}

http://git-wip-us.apache.org/repos/asf/aries-rsa/blob/69bb901e/discovery/zookeeper/src/main/java/org/apache/cxf/dosgi/discovery/zookeeper/subscribe/EndpointListenerTracker.java
----------------------------------------------------------------------
diff --git a/discovery/zookeeper/src/main/java/org/apache/cxf/dosgi/discovery/zookeeper/subscribe/EndpointListenerTracker.java b/discovery/zookeeper/src/main/java/org/apache/cxf/dosgi/discovery/zookeeper/subscribe/EndpointListenerTracker.java
deleted file mode 100644
index 4d0a25f..0000000
--- a/discovery/zookeeper/src/main/java/org/apache/cxf/dosgi/discovery/zookeeper/subscribe/EndpointListenerTracker.java
+++ /dev/null
@@ -1,56 +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.cxf.dosgi.discovery.zookeeper.subscribe;
-
-import org.osgi.framework.BundleContext;
-import org.osgi.framework.ServiceReference;
-import org.osgi.service.remoteserviceadmin.EndpointListener;
-import org.osgi.util.tracker.ServiceTracker;
-
-/**
- * Tracks interest in EndpointListeners. Delegates to InterfaceMonitorManager to manage
- * interest in the scopes of each EndpointListener.
- */
-public class EndpointListenerTracker extends ServiceTracker<EndpointListener, EndpointListener> {
-    private final InterfaceMonitorManager imManager;
-
-    public EndpointListenerTracker(BundleContext bctx, InterfaceMonitorManager imManager) {
-        super(bctx, EndpointListener.class, null);
-        this.imManager = imManager;
-    }
-
-    @Override
-    public EndpointListener addingService(ServiceReference<EndpointListener> endpointListener) {
-        imManager.addInterest(endpointListener);
-        return null;
-    }
-
-    @Override
-    public void modifiedService(ServiceReference<EndpointListener> endpointListener, EndpointListener service) {
-        // called when an EndpointListener updates its service properties,
-        // e.g. when its interest scope is expanded/reduced
-        imManager.addInterest(endpointListener);
-    }
-
-    @Override
-    public void removedService(ServiceReference<EndpointListener> endpointListener, EndpointListener service) {
-        imManager.removeInterest(endpointListener);
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/aries-rsa/blob/69bb901e/discovery/zookeeper/src/main/java/org/apache/cxf/dosgi/discovery/zookeeper/subscribe/InterfaceMonitor.java
----------------------------------------------------------------------
diff --git a/discovery/zookeeper/src/main/java/org/apache/cxf/dosgi/discovery/zookeeper/subscribe/InterfaceMonitor.java b/discovery/zookeeper/src/main/java/org/apache/cxf/dosgi/discovery/zookeeper/subscribe/InterfaceMonitor.java
deleted file mode 100644
index 3822b6e..0000000
--- a/discovery/zookeeper/src/main/java/org/apache/cxf/dosgi/discovery/zookeeper/subscribe/InterfaceMonitor.java
+++ /dev/null
@@ -1,262 +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.cxf.dosgi.discovery.zookeeper.subscribe;
-
-import java.io.ByteArrayInputStream;
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-
-import org.apache.aries.rsa.discovery.endpoint.EndpointDescriptionParser;
-import org.apache.aries.rsa.discovery.endpoint.PropertiesMapper;
-import org.apache.cxf.dosgi.discovery.zookeeper.util.Utils;
-import org.apache.zookeeper.AsyncCallback.StatCallback;
-import org.apache.zookeeper.KeeperException;
-import org.apache.zookeeper.KeeperException.Code;
-import org.apache.zookeeper.WatchedEvent;
-import org.apache.zookeeper.Watcher;
-import org.apache.zookeeper.ZooKeeper;
-import org.apache.zookeeper.data.Stat;
-import org.osgi.service.remoteserviceadmin.EndpointDescription;
-import org.osgi.service.remoteserviceadmin.EndpointListener;
-import org.osgi.xmlns.rsa.v1_0.EndpointDescriptionType;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-/**
- * Monitors ZooKeeper for changes in published endpoints.
- * <p>
- * Specifically, it monitors the node path associated with a given interface class,
- * whose data is a serialized version of an EndpointDescription, and notifies an
- * EndpointListener when changes are detected (which can then propagate the
- * notification to other EndpointListeners with a matching scope).
- * <p>
- * Note that the EndpointListener is used here as a decoupling interface for
- * convenience, and is not necessarily used according to its documented contract.
- */
-public class InterfaceMonitor implements Watcher, StatCallback {
-
-    private static final Logger LOG = LoggerFactory.getLogger(InterfaceMonitor.class);
-
-    private final String znode;
-    private final ZooKeeper zk;
-    private final EndpointListener endpointListener;
-    private final boolean recursive;
-    private volatile boolean closed;
-
-    // This map reference changes, so don't synchronize on it
-    private Map<String, EndpointDescription> nodes = new HashMap<String, EndpointDescription>();
-
-    private EndpointDescriptionParser parser;
-
-    public InterfaceMonitor(ZooKeeper zk, String objClass, EndpointListener endpointListener, String scope) {
-        this.zk = zk;
-        this.znode = Utils.getZooKeeperPath(objClass);
-        this.recursive = objClass == null || objClass.isEmpty();
-        this.endpointListener = endpointListener;
-        this.parser = new EndpointDescriptionParser();
-        LOG.debug("Creating new InterfaceMonitor {} for scope [{}] and objectClass [{}]",
-                new Object[] {recursive ? "(recursive)" : "", scope, objClass});
-    }
-
-    /**
-     * Returns all endpoints that are currently known to this monitor.
-     *
-     * @return all endpoints that are currently known to this monitor
-     */
-    public synchronized List<EndpointDescription> getEndpoints() {
-        return new ArrayList<EndpointDescription>(nodes.values());
-    }
-
-    public void start() {
-        watch();
-    }
-
-    private void watch() {
-        LOG.debug("registering a ZooKeeper.exists({}) callback", znode);
-        zk.exists(znode, this, this, null);
-    }
-
-    /**
-     * Zookeeper Watcher interface callback.
-     */
-    public void process(WatchedEvent event) {
-        LOG.debug("ZooKeeper watcher callback on node {} for event {}", znode, event);
-        processDelta();
-    }
-
-    /**
-     * Zookeeper StatCallback interface callback.
-     */
-    @SuppressWarnings("deprecation")
-    public void processResult(int rc, String path, Object ctx, Stat stat) {
-        LOG.debug("ZooKeeper callback on node: {} code: {}", znode, rc);
-
-        switch (rc) {
-        case Code.Ok:
-        case Code.NoNode:
-            processDelta();
-            return;
-
-        case Code.SessionExpired:
-        case Code.NoAuth:
-        case Code.ConnectionLoss:
-            return;
-
-        default:
-            watch();
-        }
-    }
-
-    private void processDelta() {
-        if (closed) {
-            return;
-        }
-
-        if (zk.getState() != ZooKeeper.States.CONNECTED) {
-            LOG.debug("ZooKeeper connection was already closed! Not processing changed event.");
-            return;
-        }
-
-        try {
-            if (zk.exists(znode, false) != null) {
-                zk.getChildren(znode, this);
-                refreshNodes();
-            } else {
-                LOG.debug("znode {} doesn't exist -> not processing any changes", znode);
-            }
-        } catch (Exception e) {
-            if (zk.getState() != ZooKeeper.States.CONNECTED) {
-                LOG.debug("Error getting Zookeeper data: " + e); // e.g. session expired, handled by ZooKeeperDiscovery
-            } else {
-                LOG.error("Error getting ZooKeeper data.", e);
-            }
-        }
-    }
-
-    public synchronized void close() {
-        closed = true;
-        for (EndpointDescription endpoint : nodes.values()) {
-            endpointListener.endpointRemoved(endpoint, null);
-        }
-        nodes.clear();
-    }
-
-    private synchronized void refreshNodes() {
-        if (closed) {
-            return;
-        }
-        LOG.info("Processing change on node: {}", znode);
-
-        Map<String, EndpointDescription> newNodes = new HashMap<String, EndpointDescription>();
-        Map<String, EndpointDescription> prevNodes = new HashMap<String, EndpointDescription>(nodes);
-        processChildren(znode, newNodes, prevNodes);
-
-        // whatever is left in prevNodes now has been removed from Discovery
-        LOG.debug("processChildren done. Nodes that are missing now and need to be removed: {}", prevNodes.values());
-        for (EndpointDescription endpoint : prevNodes.values()) {
-            endpointListener.endpointRemoved(endpoint, null);
-        }
-        nodes = newNodes;
-    }
-
-    /**
-     * Iterates through all child nodes of the given node and tries to find
-     * endpoints. If the recursive flag is set it also traverses into the child
-     * nodes.
-     *
-     * @return true if an endpoint was found and if the node therefore needs to
-     *         be monitored for changes
-     */
-    private boolean processChildren(String zn, Map<String, EndpointDescription> newNodes,
-            Map<String, EndpointDescription> prevNodes) {
-        List<String> children;
-        try {
-            LOG.debug("Processing the children of {}", zn);
-            children = zk.getChildren(zn, false);
-
-            boolean foundANode = false;
-            for (String child : children) {
-                String childZNode = zn + '/' + child;
-                EndpointDescription endpoint = getEndpointDescriptionFromNode(childZNode);
-                if (endpoint != null) {
-                    EndpointDescription prevEndpoint = prevNodes.get(child);
-                    LOG.info("found new node " + zn + "/[" + child + "]   ( []->child )  props: "
-                            + endpoint.getProperties().values());
-                    newNodes.put(child, endpoint);
-                    prevNodes.remove(child);
-                    foundANode = true;
-                    LOG.debug("Properties: {}", endpoint.getProperties());
-                    if (prevEndpoint == null) {
-                        // This guy is new
-                        endpointListener.endpointAdded(endpoint, null);
-                    } else if (!prevEndpoint.getProperties().equals(endpoint.getProperties())) {
-                        // TODO
-                    }
-                }
-                if (recursive && processChildren(childZNode, newNodes, prevNodes)) {
-                    zk.getChildren(childZNode, this);
-                }
-            }
-
-            return foundANode;
-        } catch (KeeperException e) {
-            LOG.error("Problem processing ZooKeeper node", e);
-        } catch (InterruptedException e) {
-            LOG.error("Problem processing ZooKeeper node", e);
-        }
-        return false;
-    }
-
-    /**
-     * Retrieves data from the given node and parses it into an EndpointDescription.
-     *
-     * @param node a node path
-     * @return endpoint found in the node or null if no endpoint was found
-     */
-    private EndpointDescription getEndpointDescriptionFromNode(String node) {
-        try {
-            Stat stat = zk.exists(node, false);
-            if (stat == null || stat.getDataLength() <= 0) {
-                return null;
-            }
-            byte[] data = zk.getData(node, false, null);
-            LOG.debug("Got data for node: {}", node);
-
-            EndpointDescription endpoint = getFirstEnpointDescription(data);
-            if (endpoint != null) {
-                return endpoint;
-            }
-            LOG.warn("No Discovery information found for node: {}", node);
-        } catch (Exception e) {
-            LOG.error("Problem getting EndpointDescription from node " + node, e);
-        }
-        return null;
-    }
-
-    public EndpointDescription getFirstEnpointDescription(byte[] data) {
-        List<EndpointDescriptionType> elements = parser.getEndpointDescriptions(new ByteArrayInputStream(data));
-        if (elements.isEmpty()) {
-            return null;
-        }
-        Map<String, Object> props = new PropertiesMapper().toProps(elements.get(0).getProperty());
-        return new EndpointDescription(props);
-    }
-}

http://git-wip-us.apache.org/repos/asf/aries-rsa/blob/69bb901e/discovery/zookeeper/src/main/java/org/apache/cxf/dosgi/discovery/zookeeper/subscribe/InterfaceMonitorManager.java
----------------------------------------------------------------------
diff --git a/discovery/zookeeper/src/main/java/org/apache/cxf/dosgi/discovery/zookeeper/subscribe/InterfaceMonitorManager.java b/discovery/zookeeper/src/main/java/org/apache/cxf/dosgi/discovery/zookeeper/subscribe/InterfaceMonitorManager.java
deleted file mode 100644
index f44b5af..0000000
--- a/discovery/zookeeper/src/main/java/org/apache/cxf/dosgi/discovery/zookeeper/subscribe/InterfaceMonitorManager.java
+++ /dev/null
@@ -1,261 +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.cxf.dosgi.discovery.zookeeper.subscribe;
-
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Dictionary;
-import java.util.HashMap;
-import java.util.Hashtable;
-import java.util.List;
-import java.util.Map;
-import java.util.concurrent.CopyOnWriteArrayList;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
-
-import org.apache.aries.rsa.util.StringPlus;
-import org.apache.cxf.dosgi.discovery.zookeeper.ZooKeeperDiscovery;
-import org.apache.cxf.dosgi.discovery.zookeeper.util.Utils;
-import org.apache.zookeeper.ZooKeeper;
-import org.osgi.framework.Bundle;
-import org.osgi.framework.BundleContext;
-import org.osgi.framework.Filter;
-import org.osgi.framework.ServiceReference;
-import org.osgi.service.remoteserviceadmin.EndpointDescription;
-import org.osgi.service.remoteserviceadmin.EndpointListener;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-/**
- * Manages the EndpointListeners and the scopes they are interested in.
- * For each scope with interested EndpointListeners an InterfaceMonitor is created.
- * The InterfaceMonitor calls back when it detects added or removed external Endpoints.
- * These events are then forwarded to all interested EndpointListeners.
- */
-public class InterfaceMonitorManager {
-    private static final Logger LOG = LoggerFactory.getLogger(InterfaceMonitorManager.class);
-    private static final Pattern OBJECTCLASS_PATTERN = Pattern.compile(".*\\(objectClass=([^)]+)\\).*");
-
-    private final BundleContext bctx;
-    private final ZooKeeper zk;
-    // map of EndpointListeners and the scopes they are interested in
-    private final Map<ServiceReference<EndpointListener>, List<String>> endpointListenerScopes =
-            new HashMap<ServiceReference<EndpointListener>, List<String>>();
-    // map of scopes and their interest data
-    private final Map<String, Interest> interests = new HashMap<String, Interest>();
-
-    protected static class Interest {
-        List<ServiceReference<EndpointListener>> endpointListeners = 
-            new CopyOnWriteArrayList<ServiceReference<EndpointListener>>();
-        InterfaceMonitor monitor;
-    }
-
-    public InterfaceMonitorManager(BundleContext bctx, ZooKeeper zk) {
-        this.bctx = bctx;
-        this.zk = zk;
-    }
-
-    public void addInterest(ServiceReference<EndpointListener> endpointListener) {
-        if (isOurOwnEndpointListener(endpointListener)) {
-            LOG.debug("Skipping our own EndpointListener");
-            return;
-        }
-
-        LOG.info("updating EndpointListener interests: {}", endpointListener);
-        if (LOG.isDebugEnabled()) {
-            LOG.debug("updated EndpointListener properties: {}", getProperties(endpointListener));
-        }
-        for (String scope : getScopes(endpointListener)) {
-            String objClass = getObjectClass(scope);
-            LOG.debug("Adding interest in scope {}, objectClass {}", scope, objClass);
-            addInterest(endpointListener, scope, objClass);
-        }
-    }
-
-    private static boolean isOurOwnEndpointListener(ServiceReference<EndpointListener> endpointListener) {
-        return Boolean.parseBoolean(String.valueOf(
-                endpointListener.getProperty(ZooKeeperDiscovery.DISCOVERY_ZOOKEEPER_ID)));
-    }
-
-    public synchronized void addInterest(ServiceReference<EndpointListener> endpointListener, 
-                                         String scope, String objClass) {
-        // get or create interest for given scope and add listener to it
-        Interest interest = interests.get(scope);
-        if (interest == null) {
-            // create interest, add listener and start monitor
-            interest = new Interest();
-            interests.put(scope, interest);
-            interest.endpointListeners.add(endpointListener); // add it before monitor starts so we don't miss events
-            interest.monitor = createInterfaceMonitor(scope, objClass, interest);
-            interest.monitor.start();
-        } else {
-            // interest already exists, so just add listener to it
-            if (!interest.endpointListeners.contains(endpointListener)) {
-                interest.endpointListeners.add(endpointListener);
-            }
-            // notify listener of all known endpoints for given scope
-            // (as EndpointListener contract requires of all added/modified listeners)
-            for (EndpointDescription endpoint : interest.monitor.getEndpoints()) {
-                notifyListeners(endpoint, scope, true, Arrays.asList(endpointListener));
-            }
-        }
-
-        // add scope to listener's scopes list
-        List<String> scopes = endpointListenerScopes.get(endpointListener);
-        if (scopes == null) {
-            scopes = new ArrayList<String>(1);
-            endpointListenerScopes.put(endpointListener, scopes);
-        }
-        if (!scopes.contains(scope)) {
-            scopes.add(scope);
-        }
-    }
-
-    public synchronized void removeInterest(ServiceReference<EndpointListener> endpointListener) {
-        LOG.info("removing EndpointListener interests: {}", endpointListener);
-        List<String> scopes = endpointListenerScopes.get(endpointListener);
-        if (scopes == null) {
-            return;
-        }
-
-        for (String scope : scopes) {
-            Interest interest = interests.get(scope);
-            if (interest != null) {
-                interest.endpointListeners.remove(endpointListener);
-                if (interest.endpointListeners.isEmpty()) {
-                    interest.monitor.close();
-                    interests.remove(scope);
-                }
-            }
-        }
-        endpointListenerScopes.remove(endpointListener);
-    }
-
-    protected InterfaceMonitor createInterfaceMonitor(final String scope, String objClass, final Interest interest) {
-        // holding this object's lock in the callbacks can lead to a deadlock with InterfaceMonitor
-        EndpointListener endpointListener = new EndpointListener() {
-
-            public void endpointRemoved(EndpointDescription endpoint, String matchedFilter) {
-                notifyListeners(endpoint, scope, false, interest.endpointListeners);
-            }
-
-            public void endpointAdded(EndpointDescription endpoint, String matchedFilter) {
-                notifyListeners(endpoint, scope, true, interest.endpointListeners);
-            }
-        };
-        return new InterfaceMonitor(zk, objClass, endpointListener, scope);
-    }
-
-    private void notifyListeners(EndpointDescription endpoint, String currentScope, boolean isAdded,
-            List<ServiceReference<EndpointListener>> endpointListeners) {
-        for (ServiceReference<EndpointListener> endpointListenerRef : endpointListeners) {
-            EndpointListener service = bctx.getService(endpointListenerRef);
-            try {
-                EndpointListener endpointListener = (EndpointListener)service;
-                LOG.trace("matching {} against {}", endpoint, currentScope);
-                if (matchFilter(bctx, currentScope, endpoint)) {
-                    LOG.debug("Matched {} against {}", endpoint, currentScope);
-                    notifyListener(endpoint, currentScope, isAdded, endpointListenerRef.getBundle(),
-                                   endpointListener);
-                }
-            } finally {
-                if (service != null) {
-                    bctx.ungetService(endpointListenerRef);
-                }
-            }
-        }
-    }
-    
-    private static boolean matchFilter(BundleContext bctx, String filter, EndpointDescription endpoint) {
-        if (filter == null) {
-            return false;
-        }
-    
-        try {
-            Filter f = bctx.createFilter(filter);
-            Dictionary<String, Object> dict = new Hashtable<String, Object>(endpoint.getProperties());
-            return f.match(dict);
-        } catch (Exception e) {
-            return false;
-        }
-    }
-
-
-    private void notifyListener(EndpointDescription endpoint, String currentScope, boolean isAdded,
-                                Bundle endpointListenerBundle, EndpointListener endpointListener) {
-        if (endpointListenerBundle == null) {
-            LOG.info("listening service was unregistered, ignoring");
-        } else if (isAdded) {
-            LOG.info("calling EndpointListener.endpointAdded: " + endpointListener + " from bundle "
-                    + endpointListenerBundle.getSymbolicName() + " for endpoint: " + endpoint);
-            endpointListener.endpointAdded(endpoint, currentScope);
-        } else {
-            LOG.info("calling EndpointListener.endpointRemoved: " + endpointListener + " from bundle "
-                    + endpointListenerBundle.getSymbolicName() + " for endpoint: " + endpoint);
-            endpointListener.endpointRemoved(endpoint, currentScope);
-        }
-    }
-
-    public synchronized void close() {
-        for (Interest interest : interests.values()) {
-            interest.monitor.close();
-        }
-        interests.clear();
-        endpointListenerScopes.clear();
-    }
-
-    /**
-     * Only for test case!
-     */
-    protected synchronized Map<String, Interest> getInterests() {
-        return interests;
-    }
-
-    /**
-     * Only for test case!
-     */
-    protected synchronized Map<ServiceReference<EndpointListener>, List<String>> getEndpointListenerScopes() {
-        return endpointListenerScopes;
-    }
-
-    protected List<String> getScopes(ServiceReference<?> sref) {
-        return Utils.removeEmpty(StringPlus.normalize(sref.getProperty(EndpointListener.ENDPOINT_LISTENER_SCOPE)));
-    }
-    
-    public static String getObjectClass(String scope) {
-        Matcher m = OBJECTCLASS_PATTERN.matcher(scope);
-        return m.matches() ? m.group(1) : null;
-    }
-
-    /**
-     * Returns a service's properties as a map.
-     *
-     * @param serviceReference a service reference
-     * @return the service's properties as a map
-     */
-    public static Map<String, Object> getProperties(ServiceReference<?> serviceReference) {
-        String[] keys = serviceReference.getPropertyKeys();
-        Map<String, Object> props = new HashMap<String, Object>(keys.length);
-        for (String key : keys) {
-            Object val = serviceReference.getProperty(key);
-            props.put(key, val);
-        }
-        return props;
-    }
-}

http://git-wip-us.apache.org/repos/asf/aries-rsa/blob/69bb901e/discovery/zookeeper/src/main/java/org/apache/cxf/dosgi/discovery/zookeeper/util/Utils.java
----------------------------------------------------------------------
diff --git a/discovery/zookeeper/src/main/java/org/apache/cxf/dosgi/discovery/zookeeper/util/Utils.java b/discovery/zookeeper/src/main/java/org/apache/cxf/dosgi/discovery/zookeeper/util/Utils.java
deleted file mode 100644
index afd9c0a..0000000
--- a/discovery/zookeeper/src/main/java/org/apache/cxf/dosgi/discovery/zookeeper/util/Utils.java
+++ /dev/null
@@ -1,54 +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.cxf.dosgi.discovery.zookeeper.util;
-
-import java.util.ArrayList;
-import java.util.List;
-
-public final class Utils {
-
-    static final String PATH_PREFIX = "/osgi/service_registry";
-
-    private Utils() {
-        // never constructed
-    }
-
-    public static String getZooKeeperPath(String name) {
-        return name == null || name.isEmpty() ? PATH_PREFIX : PATH_PREFIX + '/' + name.replace('.', '/');
-    }
-
-    /**
-     * Removes nulls and empty strings from the given string array.
-     *
-     * @param strings an array of strings
-     * @return a new array containing the non-null and non-empty
-     *         elements of the original array in the same order
-     */
-    public static List<String> removeEmpty(List<String> strings) {
-        List<String> result = new ArrayList<String>();
-        for (String s : strings) {
-            if (s != null && !s.isEmpty()) {
-                result.add(s);
-            }
-        }
-        return result;
-    }
-
-
-}

http://git-wip-us.apache.org/repos/asf/aries-rsa/blob/69bb901e/discovery/zookeeper/src/main/resources/OSGI-INF/metatype/zookeeper.xml
----------------------------------------------------------------------
diff --git a/discovery/zookeeper/src/main/resources/OSGI-INF/metatype/zookeeper.xml b/discovery/zookeeper/src/main/resources/OSGI-INF/metatype/zookeeper.xml
new file mode 100644
index 0000000..361fa1e
--- /dev/null
+++ b/discovery/zookeeper/src/main/resources/OSGI-INF/metatype/zookeeper.xml
@@ -0,0 +1,34 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements. See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership. The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License. You may obtain a copy of the License at
+
+  http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied. See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<MetaData xmlns="http://www.osgi.org/xmlns/metadata/v1.0.0"
+	 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+	 xsi:schemaLocation="
+		 http://www.osgi.org/xmlns/metadata/v1.0.0 http://www.osgi.org/xmlns/metatype/v1.1.0/metatype.xsd
+	 ">
+	 <OCD description="" name="Zookeeper server config" id="zookeeper.server">
+        <AD id="clientPort" required="false" type="String" default="2181" description=""/>
+	 	<AD id="tickTime" required="false" type="String" default="2000" description=""/>
+        <AD id="initLimit" required="false" type="String" default="10" description=""/>
+        <AD id="syncLimit" required="false" type="String" default="5" description=""/>
+	 </OCD>
+	 <Designate pid="org.apache.aries.rsa.discovery.zookeeper.server">
+	 	<Object ocdref="zookeeper.server"/>
+	 </Designate>
+</MetaData>
\ No newline at end of file