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/11 20:43:37 UTC

[38/50] [abbrv] aries-rsa git commit: Switch project setup to Aries

http://git-wip-us.apache.org/repos/asf/aries-rsa/blob/d73a3a7f/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
new file mode 100644
index 0000000..95277d3
--- /dev/null
+++ b/discovery/zookeeper/src/main/java/org/apache/cxf/dosgi/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.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.cxf.dosgi.discovery.zookeeper.util.Utils;
+import org.apache.cxf.dosgi.endpointdesc.EndpointDescriptionParser;
+import org.apache.cxf.dosgi.endpointdesc.PropertiesMapper;
+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/d73a3a7f/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
new file mode 100644
index 0000000..240e5ea
--- /dev/null
+++ b/discovery/zookeeper/src/main/java/org/apache/cxf/dosgi/discovery/zookeeper/subscribe/InterfaceMonitorManager.java
@@ -0,0 +1,218 @@
+/**
+ * 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.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.CopyOnWriteArrayList;
+
+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.ServiceReference;
+import org.osgi.service.remoteserviceadmin.EndpointDescription;
+import org.osgi.service.remoteserviceadmin.EndpointListener;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import static org.apache.cxf.dosgi.discovery.local.util.Utils.matchFilter;
+
+/**
+ * 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 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: {}", Utils.getProperties(endpointListener));
+        }
+        for (String scope : Utils.getScopes(endpointListener)) {
+            String objClass = Utils.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)));
+    }
+
+    @SuppressWarnings("unchecked")
+    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 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;
+    }
+}

http://git-wip-us.apache.org/repos/asf/aries-rsa/blob/d73a3a7f/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
new file mode 100644
index 0000000..5fcb111
--- /dev/null
+++ b/discovery/zookeeper/src/main/java/org/apache/cxf/dosgi/discovery/zookeeper/util/Utils.java
@@ -0,0 +1,165 @@
+/**
+ * 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.Arrays;
+import java.util.Collection;
+import java.util.Dictionary;
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.UUID;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.ServiceReference;
+import org.osgi.service.remoteserviceadmin.EndpointListener;
+
+public final class Utils {
+
+    static final String PATH_PREFIX = "/osgi/service_registry";
+    static final Pattern OBJECTCLASS_PATTERN = Pattern.compile(".*\\(objectClass=([^)]+)\\).*");
+
+    private Utils() {
+        // never constructed
+    }
+
+    public static String getZooKeeperPath(String name) {
+        return name == null || name.isEmpty() ? PATH_PREFIX : PATH_PREFIX + '/' + name.replace('.', '/');
+    }
+
+    /**
+     * Returns the value of a "string+" property as an array of strings.
+     * <p>
+     * A "string+" property can have a value which is either a string,
+     * an array of strings, or a collection of strings.
+     * <p>
+     * If the given value is not of one of the valid types, or is null,
+     * an empty array is returned.
+     *
+     * @param property a "string+" property value
+     * @return the property value as an array of strings, or an empty array
+     */
+    public static String[] getStringPlusProperty(Object property) {
+        if (property instanceof String) {
+            return new String[] {(String)property};
+        } else if (property instanceof String[]) {
+            return (String[])property;
+        } else if (property instanceof Collection) {
+            try {
+                @SuppressWarnings("unchecked")
+                Collection<String> strings = (Collection<String>)property;
+                return strings.toArray(new String[strings.size()]);
+            } catch (ArrayStoreException ase) {
+                // ignore collections with wrong type
+            }
+        }
+        return new String[0];
+    }
+
+    /**
+     * 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 String[] removeEmpty(String[] strings) {
+        String[] result = new String[strings.length];
+        int copied = 0;
+        for (String s : strings) {
+            if (s != null && !s.isEmpty()) {
+                result[copied++] = s;
+            }
+        }
+        return copied == result.length ? result : Arrays.copyOf(result, copied);
+    }
+
+    public static String[] getScopes(ServiceReference<?> sref) {
+        return removeEmpty(getStringPlusProperty(sref.getProperty(EndpointListener.ENDPOINT_LISTENER_SCOPE)));
+    }
+
+    // copied from the DSW OSGiUtils class
+    public static String getUUID(BundleContext bc) {
+        synchronized ("org.osgi.framework.uuid") {
+            String uuid = bc.getProperty("org.osgi.framework.uuid");
+            if (uuid == null) {
+                uuid = UUID.randomUUID().toString();
+                System.setProperty("org.osgi.framework.uuid", uuid);
+            }
+            return uuid;
+        }
+    }
+
+    /**
+     * 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;
+    }
+
+    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/d73a3a7f/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
new file mode 100644
index 0000000..84470c2
--- /dev/null
+++ b/discovery/zookeeper/src/test/java/org/apache/cxf/dosgi/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.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/d73a3a7f/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
new file mode 100644
index 0000000..cb2180b
--- /dev/null
+++ b/discovery/zookeeper/src/test/java/org/apache/cxf/dosgi/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.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;
+//            }
+//        });
+//    }
+}

http://git-wip-us.apache.org/repos/asf/aries-rsa/blob/d73a3a7f/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
new file mode 100644
index 0000000..53b6139
--- /dev/null
+++ b/discovery/zookeeper/src/test/java/org/apache/cxf/dosgi/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.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/d73a3a7f/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
new file mode 100644
index 0000000..e63b805
--- /dev/null
+++ b/discovery/zookeeper/src/test/java/org/apache/cxf/dosgi/discovery/zookeeper/publish/PublishingEndpointListenerFactoryTest.java
@@ -0,0 +1,100 @@
+/**
+ * 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.classextension.EasyMock;
+import org.easymock.classextension.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/d73a3a7f/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
new file mode 100644
index 0000000..aa1b68e
--- /dev/null
+++ b/discovery/zookeeper/src/test/java/org/apache/cxf/dosgi/discovery/zookeeper/publish/PublishingEndpointListenerTest.java
@@ -0,0 +1,201 @@
+/**
+ * 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.lang.reflect.Field;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import junit.framework.TestCase;
+
+import org.apache.cxf.dosgi.endpointdesc.EndpointDescriptionParser;
+import org.apache.cxf.dosgi.endpointdesc.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.IAnswer;
+import org.easymock.classextension.EasyMock;
+import org.easymock.classextension.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.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;
+
+public class PublishingEndpointListenerTest extends TestCase {
+
+    public void testEndpointRemovalAdding() throws KeeperException, InterruptedException {
+        IMocksControl c = EasyMock.createNiceControl();
+
+        BundleContext ctx = c.createMock(BundleContext.class);
+        ZooKeeper zk = c.createMock(ZooKeeper.class);
+
+        String path = "/osgi/service_registry/myClass/google.de#80##test";
+        EasyMock.expect(zk.create(EasyMock.eq(path),
+                (byte[])EasyMock.anyObject(), EasyMock.eq(Ids.OPEN_ACL_UNSAFE),
+                EasyMock.eq(CreateMode.EPHEMERAL))).andReturn("").once();
+
+        zk.delete(EasyMock.eq("/osgi/service_registry/myClass/google.de#80##test"), EasyMock.eq(-1));
+        EasyMock.expectLastCall().once();
+
+        c.replay();
+
+        PublishingEndpointListener eli = new PublishingEndpointListener(zk, ctx);
+
+        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");
+        props.put(RemoteConstants.SERVICE_IMPORTED_CONFIGS, "myConfig");
+
+        EndpointDescription endpoint = new EndpointDescription(props);
+
+        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 {
+        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;
+            }
+        };
+        @SuppressWarnings("unchecked")
+        ServiceReference<DiscoveryPlugin> sr1 = EasyMock.createMock(ServiceReference.class);
+
+        DiscoveryPlugin plugin2 = new DiscoveryPlugin() {
+            public String process(Map<String, Object> mutableProperties, String endpointKey) {
+                mutableProperties.put("foo", "bar");
+                return endpointKey.replaceAll("localhost", "some.machine");
+            }
+        };
+        @SuppressWarnings("unchecked")
+        ServiceReference<DiscoveryPlugin> sr2 = EasyMock.createMock(ServiceReference.class);
+
+        BundleContext ctx = EasyMock.createMock(BundleContext.class);
+        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();
+        ctx.addServiceListener(EasyMock.isA(ServiceListener.class),
+                EasyMock.eq("(objectClass=" + DiscoveryPlugin.class.getName() + ")"));
+        EasyMock.expect(ctx.getService(sr1)).andReturn(plugin1).anyTimes();
+        EasyMock.expect(ctx.getService(sr2)).andReturn(plugin2).anyTimes();
+        EasyMock.expect(ctx.getServiceReferences(DiscoveryPlugin.class.getName(), null))
+                .andReturn(new ServiceReference[]{sr1, sr2}).anyTimes();
+        EasyMock.replay(ctx);
+
+        Map<String, Object> props = new HashMap<String, Object>();
+        props.put(Constants.OBJECTCLASS, new String[] {"org.foo.myClass"});
+        props.put(RemoteConstants.ENDPOINT_ID, "http://localhost:9876/test");
+        props.put(RemoteConstants.SERVICE_IMPORTED_CONFIGS, "myConfig");
+        EndpointDescription endpoint = new EndpointDescription(props);
+
+        Map<String, Object> expectedProps = new HashMap<String, Object>(props);
+        expectedProps.put("endpoint.id", "http://localhost:9876/test/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);
+        EasyMock.expect(zk.create(
+                EasyMock.eq(expectedFullPath),
+                EasyMock.aryEq(data),
+                EasyMock.eq(Ids.OPEN_ACL_UNSAFE),
+                EasyMock.eq(CreateMode.EPHEMERAL))).andReturn("");
+        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);
+    }
+
+    @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);
+    }
+
+    public void testClose() throws KeeperException, InterruptedException {
+        IMocksControl c = EasyMock.createNiceControl();
+
+        BundleContext ctx = c.createMock(BundleContext.class);
+        ZooKeeper zk = c.createMock(ZooKeeper.class);
+
+        String path = "/osgi/service_registry/myClass/google.de#80##test";
+        EasyMock.expect(zk.create(EasyMock.eq(path),
+                (byte[])EasyMock.anyObject(), EasyMock.eq(Ids.OPEN_ACL_UNSAFE),
+                EasyMock.eq(CreateMode.EPHEMERAL))).andReturn("").once();
+
+        zk.delete(EasyMock.eq("/osgi/service_registry/myClass/google.de#80##test"), EasyMock.eq(-1));
+        EasyMock.expectLastCall().once();
+
+        c.replay();
+
+        PublishingEndpointListener eli = new PublishingEndpointListener(zk, ctx);
+
+        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");
+        props.put(RemoteConstants.SERVICE_IMPORTED_CONFIGS, "myConfig");
+
+        EndpointDescription endpoint = new EndpointDescription(props);
+
+        eli.endpointAdded(endpoint, null);
+
+        eli.close(); // should result in zk.delete(...)
+
+        c.verify();
+    }
+
+    public void testGetKey() throws Exception {
+        assertEquals("somehost#9090##org#example#TestEndpoint",
+            PublishingEndpointListener.getKey("http://somehost:9090/org/example/TestEndpoint"));
+    }
+}

http://git-wip-us.apache.org/repos/asf/aries-rsa/blob/d73a3a7f/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
new file mode 100644
index 0000000..7d6f67f
--- /dev/null
+++ b/discovery/zookeeper/src/test/java/org/apache/cxf/dosgi/discovery/zookeeper/subscribe/InterfaceMonitorManagerTest.java
@@ -0,0 +1,139 @@
+/**
+ * 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.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.zookeeper.ZooKeeper;
+import org.easymock.IAnswer;
+import org.easymock.classextension.EasyMock;
+import org.easymock.classextension.IMocksControl;
+import org.junit.Test;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.ServiceReference;
+import org.osgi.service.remoteserviceadmin.EndpointListener;
+
+import static org.junit.Assert.assertEquals;
+
+public class InterfaceMonitorManagerTest {
+
+    @Test
+    public void testEndpointListenerTrackerCustomizer() {
+        IMocksControl c = EasyMock.createNiceControl();
+
+        BundleContext ctx = c.createMock(BundleContext.class);
+        ZooKeeper zk = c.createMock(ZooKeeper.class);
+
+        @SuppressWarnings("unchecked")
+        ServiceReference<EndpointListener> sref = c.createMock(ServiceReference.class);
+        @SuppressWarnings("unchecked")
+        ServiceReference<EndpointListener> sref2 = c.createMock(ServiceReference.class);
+
+        final Map<String, ?> p = new HashMap<String, Object>();
+
+        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();
+
+        EasyMock.expect(sref2.getPropertyKeys()).andAnswer(new IAnswer<String[]>() {
+            public String[] answer() throws Throwable {
+                return p.keySet().toArray(new String[p.size()]);
+            }
+        }).anyTimes();
+
+        EasyMock.expect(sref2.getProperty((String)EasyMock.anyObject())).andAnswer(new IAnswer<Object>() {
+            public Object answer() throws Throwable {
+                String key = (String)(EasyMock.getCurrentArguments()[0]);
+                return p.get(key);
+            }
+        }).anyTimes();
+
+        final List<IMocksControl> controls = new ArrayList<IMocksControl>();
+
+        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());
+
+        //p.put(EndpointListener.ENDPOINT_LISTENER_SCOPE, );
+
+        eltc.addInterest(sref, "(objectClass=mine)", "mine");
+
+        assertEquals(1, eltc.getEndpointListenerScopes().size());
+        assertEquals(1, eltc.getEndpointListenerScopes().get(sref).size());
+        assertEquals("(objectClass=mine)", eltc.getEndpointListenerScopes().get(sref).get(0));
+        assertEquals(1, eltc.getInterests().size());
+
+        eltc.addInterest(sref, "(objectClass=mine)", "mine");
+
+        assertEquals(1, eltc.getEndpointListenerScopes().size());
+        assertEquals(1, eltc.getEndpointListenerScopes().get(sref).size());
+        assertEquals("(objectClass=mine)", eltc.getEndpointListenerScopes().get(sref).get(0));
+        assertEquals(1, eltc.getInterests().size());
+
+        eltc.addInterest(sref2, "(objectClass=mine)", "mine");
+
+        assertEquals(2, eltc.getEndpointListenerScopes().size());
+        assertEquals(1, eltc.getEndpointListenerScopes().get(sref).size());
+        assertEquals(1, eltc.getEndpointListenerScopes().get(sref2).size());
+        assertEquals("(objectClass=mine)", eltc.getEndpointListenerScopes().get(sref).get(0));
+        assertEquals("(objectClass=mine)", eltc.getEndpointListenerScopes().get(sref2).get(0));
+        assertEquals(1, eltc.getInterests().size());
+
+        eltc.removeInterest(sref);
+
+        assertEquals(1, eltc.getEndpointListenerScopes().size());
+        assertEquals(1, eltc.getEndpointListenerScopes().get(sref2).size());
+        assertEquals("(objectClass=mine)", eltc.getEndpointListenerScopes().get(sref2).get(0));
+        assertEquals(1, eltc.getInterests().size());
+
+        eltc.removeInterest(sref);
+
+        assertEquals(1, eltc.getEndpointListenerScopes().size());
+        assertEquals(1, eltc.getEndpointListenerScopes().get(sref2).size());
+        assertEquals("(objectClass=mine)", eltc.getEndpointListenerScopes().get(sref2).get(0));
+        assertEquals(1, eltc.getInterests().size());
+
+        eltc.removeInterest(sref2);
+
+        assertEquals(0, eltc.getEndpointListenerScopes().size());
+        assertEquals(0, eltc.getInterests().size());
+
+        c.verify();
+        for (IMocksControl control : controls) {
+            control.verify();
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/aries-rsa/blob/d73a3a7f/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
new file mode 100644
index 0000000..67afb16
--- /dev/null
+++ b/discovery/zookeeper/src/test/java/org/apache/cxf/dosgi/discovery/zookeeper/subscribe/InterfaceMonitorTest.java
@@ -0,0 +1,67 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.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.classextension.EasyMock;
+import org.easymock.classextension.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/d73a3a7f/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
new file mode 100644
index 0000000..08c830c
--- /dev/null
+++ b/discovery/zookeeper/src/test/java/org/apache/cxf/dosgi/discovery/zookeeper/util/UtilsTest.java
@@ -0,0 +1,110 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.cxf.dosgi.discovery.zookeeper.util;
+
+import java.util.Arrays;
+
+import junit.framework.TestCase;
+
+import org.easymock.classextension.EasyMock;
+import org.easymock.classextension.IMocksControl;
+import org.osgi.framework.ServiceReference;
+import org.osgi.service.remoteserviceadmin.EndpointListener;
+
+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(""));
+    }
+
+    public void testGetStringPlusProperty() {
+        String[] out = Utils.getStringPlusProperty("MyString");
+        assertEquals(1, out.length);
+        assertEquals("MyString", out[0]);
+
+        out = Utils.getStringPlusProperty(new String[]{"MyString"});
+        assertEquals(1, out.length);
+        assertEquals("MyString", out[0]);
+
+        out = Utils.getStringPlusProperty(Arrays.asList("MyString"));
+        assertEquals(1, out.length);
+        assertEquals("MyString", out[0]);
+
+        out = Utils.getStringPlusProperty(Arrays.asList(1));
+        assertEquals(0, out.length);
+
+        out = Utils.getStringPlusProperty(new Object());
+        assertEquals(0, out.length);
+
+        out = Utils.getStringPlusProperty(null);
+        assertEquals(0, out.length);
+    }
+
+    public void testRemoveEmpty() {
+        String[] out = Utils.removeEmpty(new String[0]);
+        assertEquals(0, out.length);
+
+        out = Utils.removeEmpty(new String[]{null});
+        assertEquals(0, out.length);
+
+        out = Utils.removeEmpty(new String[]{""});
+        assertEquals(0, out.length);
+
+        out = Utils.removeEmpty(new String[]{"hi"});
+        assertEquals(1, out.length);
+        assertEquals("hi", out[0]);
+
+        out = Utils.removeEmpty(new String[]{"", "hi", null});
+        assertEquals(1, out.length);
+        assertEquals("hi", out[0]);
+
+        out = Utils.removeEmpty(new String[]{"hi", null, "", ""});
+        assertEquals(1, out.length);
+        assertEquals("hi", out[0]);
+
+        out = Utils.removeEmpty(new String[]{"", "hi", null, "", "", "bye", null});
+        assertEquals(2, out.length);
+        assertEquals("hi", out[0]);
+        assertEquals("bye", out[1]);
+    }
+
+    public void testGetScopes() {
+        IMocksControl c = EasyMock.createNiceControl();
+
+        String[] scopes = new String[]{"myScope=test", ""};
+
+        @SuppressWarnings("unchecked")
+        ServiceReference<EndpointListener> sref = c.createMock(ServiceReference.class);
+        EasyMock.expect(sref.getProperty(EasyMock.eq(EndpointListener.ENDPOINT_LISTENER_SCOPE)))
+            .andReturn(scopes).anyTimes();
+
+        c.replay();
+
+        String[] ret = Utils.getScopes(sref);
+
+        c.verify();
+        assertEquals(1, ret.length);
+        assertEquals(scopes[0], ret[0]);
+    }
+}