cxf-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From cschnei...@apache.org
Subject [2/2] cxf-dosgi git commit: Further refactoring TopologyManager
Date Thu, 10 Mar 2016 16:18:04 GMT
Further refactoring TopologyManager


Project: http://git-wip-us.apache.org/repos/asf/cxf-dosgi/repo
Commit: http://git-wip-us.apache.org/repos/asf/cxf-dosgi/commit/e5db6fdd
Tree: http://git-wip-us.apache.org/repos/asf/cxf-dosgi/tree/e5db6fdd
Diff: http://git-wip-us.apache.org/repos/asf/cxf-dosgi/diff/e5db6fdd

Branch: refs/heads/master
Commit: e5db6fdd7bf5311c0ef0eea723cceea3632f59d7
Parents: ba591ef
Author: Christian Schneider <chris@die-schneider.net>
Authored: Thu Mar 10 17:17:21 2016 +0100
Committer: Christian Schneider <chris@die-schneider.net>
Committed: Thu Mar 10 17:17:21 2016 +0100

----------------------------------------------------------------------
 dsw/cxf-topology-manager/pom.xml                |  11 ++
 .../cxf/dosgi/topologymanager/Activator.java    | 122 ++++++++++--
 .../exporter/EndpointListenerNotifier.java      | 117 ++++--------
 .../exporter/EndpointRepository.java            |  27 ++-
 .../topologymanager/exporter/StringPlus.java    |  57 ++++++
 .../exporter/TopologyManagerExport.java         | 144 ++++----------
 .../importer/EndpointListenerManager.java       |   2 +-
 .../topologymanager/importer/FilterHelper.java  |  43 +++++
 .../importer/ListenerHookImpl.java              |   3 +-
 .../topologymanager/importer/RSATracker.java    |  26 +++
 .../importer/TopologyManagerImport.java         |  39 ++--
 .../util/SimpleServiceTracker.java              | 151 ---------------
 .../util/SimpleServiceTrackerListener.java      |  54 ------
 .../cxf/dosgi/topologymanager/util/Utils.java   |  81 --------
 .../exporter/EndpointListenerNotifierTest.java  | 188 +++++++------------
 .../exporter/ExportServiceTest.java             | 143 --------------
 .../exporter/TopologyManagerExportTest.java     | 139 ++++++++++++++
 .../importer/TopologyManagerImportTest.java     |  19 +-
 .../util/SimpleServiceTrackerTest.java          | 164 ----------------
 19 files changed, 574 insertions(+), 956 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/cxf-dosgi/blob/e5db6fdd/dsw/cxf-topology-manager/pom.xml
----------------------------------------------------------------------
diff --git a/dsw/cxf-topology-manager/pom.xml b/dsw/cxf-topology-manager/pom.xml
index cb91f1f..2c64d28 100644
--- a/dsw/cxf-topology-manager/pom.xml
+++ b/dsw/cxf-topology-manager/pom.xml
@@ -56,10 +56,21 @@
             <scope>test</scope>
         </dependency>
         <dependency>
+            <groupId>org.slf4j</groupId>
+            <artifactId>slf4j-jdk14</artifactId>
+            <version>1.7.16</version>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
             <groupId>org.easymock</groupId>
             <artifactId>easymockclassextension</artifactId>
             <scope>test</scope>
         </dependency>
+        <dependency>
+            <groupId>org.hamcrest</groupId>
+            <artifactId>hamcrest-all</artifactId>
+            <version>1.3</version>
+        </dependency>
     </dependencies>
 
     <build>

http://git-wip-us.apache.org/repos/asf/cxf-dosgi/blob/e5db6fdd/dsw/cxf-topology-manager/src/main/java/org/apache/cxf/dosgi/topologymanager/Activator.java
----------------------------------------------------------------------
diff --git a/dsw/cxf-topology-manager/src/main/java/org/apache/cxf/dosgi/topologymanager/Activator.java b/dsw/cxf-topology-manager/src/main/java/org/apache/cxf/dosgi/topologymanager/Activator.java
index 5cf8479..46f98a7 100644
--- a/dsw/cxf-topology-manager/src/main/java/org/apache/cxf/dosgi/topologymanager/Activator.java
+++ b/dsw/cxf-topology-manager/src/main/java/org/apache/cxf/dosgi/topologymanager/Activator.java
@@ -18,38 +18,132 @@
  */
 package org.apache.cxf.dosgi.topologymanager;
 
+import java.util.concurrent.LinkedBlockingQueue;
+import java.util.concurrent.ThreadPoolExecutor;
+import java.util.concurrent.TimeUnit;
+
+import org.apache.cxf.dosgi.topologymanager.exporter.EndpointListenerNotifier;
+import org.apache.cxf.dosgi.topologymanager.exporter.EndpointRepository;
 import org.apache.cxf.dosgi.topologymanager.exporter.TopologyManagerExport;
 import org.apache.cxf.dosgi.topologymanager.importer.TopologyManagerImport;
-import org.apache.cxf.dosgi.topologymanager.util.SimpleServiceTracker;
 import org.osgi.framework.BundleActivator;
 import org.osgi.framework.BundleContext;
+import org.osgi.framework.Constants;
+import org.osgi.framework.Filter;
+import org.osgi.framework.InvalidSyntaxException;
+import org.osgi.framework.ServiceReference;
+import org.osgi.service.remoteserviceadmin.EndpointListener;
+import org.osgi.service.remoteserviceadmin.RemoteConstants;
 import org.osgi.service.remoteserviceadmin.RemoteServiceAdmin;
+import org.osgi.util.tracker.ServiceTracker;
+import org.osgi.util.tracker.ServiceTrackerCustomizer;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 public class Activator implements BundleActivator {
-
+    private static final String DOSGI_SERVICES = "(" + RemoteConstants.SERVICE_EXPORTED_INTERFACES + "=*)";
+    private static final String ENDPOINT_LISTENER_FILTER =
+        "(&(" + Constants.OBJECTCLASS + "=" + EndpointListener.class.getName() + ")"
+        + "(" + EndpointListener.ENDPOINT_LISTENER_SCOPE + "=*))";
     private static final Logger LOG = LoggerFactory.getLogger(Activator.class);
 
-    private TopologyManagerExport topologyManagerExport;
-    private TopologyManagerImport topologyManagerImport;
-    private SimpleServiceTracker<RemoteServiceAdmin> rsaTracker;
+    private TopologyManagerExport exportManager;
+    private TopologyManagerImport importManager;
+    private EndpointListenerNotifier notifier;
+    private ServiceTracker<RemoteServiceAdmin, RemoteServiceAdmin> rsaTracker;
+    private ThreadPoolExecutor exportExecutor;
+    private ServiceTracker<EndpointListener, EndpointListener> epListenerTracker;
 
-    public void start(BundleContext bc) throws Exception {
+    public void start(final BundleContext bc) throws Exception {
         LOG.debug("TopologyManager: start()");
-        rsaTracker = new SimpleServiceTracker<RemoteServiceAdmin>(bc, RemoteServiceAdmin.class);
-        topologyManagerExport = new TopologyManagerExport(bc, rsaTracker);
-        topologyManagerImport = new TopologyManagerImport(bc, rsaTracker);
-
+        EndpointRepository endpointRepo = new EndpointRepository();
+        notifier = new EndpointListenerNotifier(endpointRepo);
+        epListenerTracker = new ServiceTracker<EndpointListener, EndpointListener>(bc, EndpointListener.class, null) {
+            @Override
+            public EndpointListener addingService(ServiceReference<EndpointListener> reference) {
+                EndpointListener listener = super.addingService(reference);
+                notifier.add(listener, EndpointListenerNotifier.getFiltersFromEndpointListenerScope(reference));
+                return listener;
+            }
+            
+            @Override
+            public void modifiedService(ServiceReference<EndpointListener> reference,
+                                        EndpointListener listener) {
+                super.modifiedService(reference, listener);
+                notifier.add(listener, EndpointListenerNotifier.getFiltersFromEndpointListenerScope(reference));
+            }
+            
+            @Override
+            public void removedService(ServiceReference<EndpointListener> reference,
+                                       EndpointListener listener) {
+                notifier.remove(listener);
+                super.removedService(reference, listener);
+            }
+        };
+        endpointRepo.setNotifier(notifier);
+        exportExecutor = new ThreadPoolExecutor(5, 10, 50, TimeUnit.SECONDS, new LinkedBlockingQueue<Runnable>());
+        exportManager = new TopologyManagerExport(endpointRepo, exportExecutor);
+        importManager = new TopologyManagerImport(bc);
+        rsaTracker = new RSATracker(bc, RemoteServiceAdmin.class, null);
+        bc.addServiceListener(exportManager);
         rsaTracker.open();
-        topologyManagerExport.start();
-        topologyManagerImport.start();
+        epListenerTracker.open();
+        exportExistingServices(bc);
+        importManager.start();
     }
 
     public void stop(BundleContext bc) throws Exception {
         LOG.debug("TopologyManager: stop()");
-        topologyManagerExport.stop();
-        topologyManagerImport.stop();
+        epListenerTracker.close();
+        bc.removeServiceListener(exportManager);
+        exportExecutor.shutdown();
+        importManager.stop();
         rsaTracker.close();
     }
+    
+    public static Filter epListenerFilter(BundleContext bctx) {
+        try {
+            return bctx.createFilter(ENDPOINT_LISTENER_FILTER);
+        } catch (InvalidSyntaxException e) {
+            throw new RuntimeException("Unexpected exception creating filter", e);
+        }
+    }
+    
+    public void exportExistingServices(BundleContext context) {
+        try {
+            // cast to String is necessary for compiling against OSGi core version >= 4.3
+            ServiceReference<?>[] references = context.getServiceReferences((String)null, DOSGI_SERVICES);
+            if (references != null) {
+                for (ServiceReference<?> sref : references) {
+                    exportManager.export(sref);
+                }
+            }
+        } catch (InvalidSyntaxException e) {
+            LOG.error("Error in filter {}. This should not occur!", DOSGI_SERVICES);
+        }
+    }
+    
+    private final class RSATracker extends ServiceTracker<RemoteServiceAdmin, RemoteServiceAdmin> {
+        private RSATracker(BundleContext context, Class<RemoteServiceAdmin> clazz,
+                           ServiceTrackerCustomizer<RemoteServiceAdmin, RemoteServiceAdmin> customizer) {
+            super(context, clazz, customizer);
+        }
+
+        @Override
+        public RemoteServiceAdmin addingService(ServiceReference<RemoteServiceAdmin> reference) {
+            RemoteServiceAdmin rsa = super.addingService(reference);
+            LOG.debug("New RemoteServiceAdmin {} detected, trying to import and export services with it", rsa);
+            importManager.add(rsa);
+            exportManager.add(rsa);
+            return rsa;
+        }
+
+        @Override
+        public void removedService(ServiceReference<RemoteServiceAdmin> reference,
+                                   RemoteServiceAdmin rsa) {
+            exportManager.remove(rsa);
+            importManager.remove(rsa);
+            super.removedService(reference, rsa);
+        }
+    }
 }

http://git-wip-us.apache.org/repos/asf/cxf-dosgi/blob/e5db6fdd/dsw/cxf-topology-manager/src/main/java/org/apache/cxf/dosgi/topologymanager/exporter/EndpointListenerNotifier.java
----------------------------------------------------------------------
diff --git a/dsw/cxf-topology-manager/src/main/java/org/apache/cxf/dosgi/topologymanager/exporter/EndpointListenerNotifier.java b/dsw/cxf-topology-manager/src/main/java/org/apache/cxf/dosgi/topologymanager/exporter/EndpointListenerNotifier.java
index e01f5dd..8f33add 100644
--- a/dsw/cxf-topology-manager/src/main/java/org/apache/cxf/dosgi/topologymanager/exporter/EndpointListenerNotifier.java
+++ b/dsw/cxf-topology-manager/src/main/java/org/apache/cxf/dosgi/topologymanager/exporter/EndpointListenerNotifier.java
@@ -18,18 +18,16 @@
  */
 package org.apache.cxf.dosgi.topologymanager.exporter;
 
-import java.util.ArrayList;
 import java.util.Collection;
 import java.util.Dictionary;
+import java.util.HashSet;
 import java.util.Hashtable;
-import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.ConcurrentHashMap;
 
-import org.apache.cxf.dosgi.topologymanager.util.SimpleServiceTracker;
-import org.apache.cxf.dosgi.topologymanager.util.SimpleServiceTrackerListener;
-import org.apache.cxf.dosgi.topologymanager.util.Utils;
-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.ServiceReference;
 import org.osgi.service.remoteserviceadmin.EndpointDescription;
@@ -41,92 +39,61 @@ import org.slf4j.LoggerFactory;
  * Tracks EndpointListeners and allows to notify them of endpoints.
  */
 public class EndpointListenerNotifier {
-
-    private static final String ENDPOINT_LISTENER_FILTER =
-        "(&(" + Constants.OBJECTCLASS + "=" + EndpointListener.class.getName() + ")"
-        + "(" + EndpointListener.ENDPOINT_LISTENER_SCOPE + "=*))";
     private static final Logger LOG = LoggerFactory.getLogger(EndpointListenerNotifier.class);
-    private BundleContext bctx;
-    private SimpleServiceTracker<EndpointListener> endpointListenerTracker;
-
-    public EndpointListenerNotifier(BundleContext bctx, final EndpointRepository endpointRepository) {
-        this.bctx = bctx;
-        Filter filter;
-        try {
-            filter = bctx.createFilter(ENDPOINT_LISTENER_FILTER);
-        } catch (InvalidSyntaxException e) {
-            throw new RuntimeException("Unexpected exception creating filter", e);
-        }
-        this.endpointListenerTracker = new SimpleServiceTracker<EndpointListener>(bctx, filter);
-        this.endpointListenerTracker.addListener(new SimpleServiceTrackerListener<EndpointListener>() {
-            @Override
-            public void added(ServiceReference<EndpointListener> reference, EndpointListener service) {
-                LOG.debug("new EndpointListener detected");
-                notifyListener(true, reference, endpointRepository.getAllEndpoints());
-            }
-
-            @Override
-            public void modified(ServiceReference<EndpointListener> reference, EndpointListener service) {
-                LOG.debug("EndpointListener modified");
-                notifyListener(true, reference, endpointRepository.getAllEndpoints());
-            }
+    public enum NotifyType { ADDED, REMOVED };
+    private Map<EndpointListener, Set<Filter>> listeners;
+    private EndpointRepository endpointRepo;
 
-            @Override
-            public void removed(ServiceReference<EndpointListener> reference, EndpointListener service) {
-            }
-        });
+    public EndpointListenerNotifier(final EndpointRepository endpointRepo) {
+        this.endpointRepo = endpointRepo;
+        this.listeners = new ConcurrentHashMap<EndpointListener, Set<Filter>>();
     }
 
-    public void start() {
-        endpointListenerTracker.open();
+    public void add(EndpointListener ep, Set<Filter> filters) {
+        LOG.debug("new EndpointListener detected");
+        listeners.put(ep, filters);
+        notifyListener(NotifyType.ADDED, ep, filters, endpointRepo.getAllEndpoints());
     }
-
-    public void stop() {
-        endpointListenerTracker.close();
+    
+    public void remove(EndpointListener ep) {
+        LOG.debug("EndpointListener modified");
+        listeners.remove(ep);
     }
-
+    
     /**
      * Notifies all endpoint listeners about endpoints being added or removed.
      *
      * @param added specifies whether endpoints were added (true) or removed (false)
      * @param endpoints the endpoints the listeners should be notified about
      */
-    void notifyListeners(boolean added, Collection<EndpointDescription> endpoints) {
+    public void notifyListeners(NotifyType type, Collection<EndpointDescription> endpoints) {
         if (endpoints.isEmpty()) { // a little optimization to prevent unnecessary processing
             return;
         }
-        for (ServiceReference<EndpointListener> eplReference : endpointListenerTracker.getAllServiceReferences()) {
-            notifyListener(added, eplReference, endpoints);
+        for (EndpointListener listener : listeners.keySet()) {
+            notifyListener(type, listener, listeners.get(listener), endpoints);
         }
     }
 
     /**
      * Notifies an endpoint listener about endpoints being added or removed.
      *
-     * @param added specifies whether endpoints were added (true) or removed (false)
+     * @param type specifies whether endpoints were added (true) or removed (false)
      * @param endpointListenerRef the ServiceReference of an EndpointListener to notify
      * @param endpoints the endpoints the listener should be notified about
      */
-    void notifyListener(boolean added, ServiceReference<EndpointListener> endpointListenerRef,
-                                Collection<EndpointDescription> endpoints) {
-        List<Filter> filters = getFiltersFromEndpointListenerScope(endpointListenerRef, bctx);
-        EndpointListener endpointListener = bctx.getService(endpointListenerRef);
-        try {
-            LOG.debug("notifyListener (added={})", added);
-            for (EndpointDescription endpoint : endpoints) {
-                List<Filter> matchingFilters = getMatchingFilters(filters, endpoint);
-                for (Filter filter : matchingFilters) {
-                    if (added) {
-                        endpointListener.endpointAdded(endpoint, filter.toString());
-                    } else {
-                        endpointListener.endpointRemoved(endpoint, filter.toString());
-                    }
+    void notifyListener(NotifyType type, EndpointListener listener, Set<Filter> filters, 
+                        Collection<EndpointDescription> endpoints) {
+        LOG.debug("Endpoint {}", type);
+        for (EndpointDescription endpoint : endpoints) {
+            Set<Filter> matchingFilters = getMatchingFilters(filters, endpoint);
+            for (Filter filter : matchingFilters) {
+                if (type == NotifyType.ADDED) {
+                    listener.endpointAdded(endpoint, filter.toString());
+                } else {
+                    listener.endpointRemoved(endpoint, filter.toString());
                 }
             }
-        } finally {
-            if (endpointListener != null) {
-                bctx.ungetService(endpointListenerRef);
-            }
         }
     }
 
@@ -136,7 +103,7 @@ public class EndpointListenerNotifier {
      * @param endpoint an endpoint description
      * @return endpoint properties (will never return null)
      */
-    public static Dictionary<String, Object> getEndpointProperties(EndpointDescription endpoint) {
+    private static Dictionary<String, Object> getEndpointProperties(EndpointDescription endpoint) {
         if (endpoint == null || endpoint.getProperties() == null) {
             return new Hashtable<String, Object>();
         } else {
@@ -144,13 +111,12 @@ public class EndpointListenerNotifier {
         }
     }
 
-    static List<Filter> getFiltersFromEndpointListenerScope(ServiceReference<EndpointListener> sref, 
-                                                            BundleContext bctx) {
-        List<Filter> filters = new ArrayList<Filter>();
-        String[] scopes = Utils.getStringPlusProperty(sref.getProperty(EndpointListener.ENDPOINT_LISTENER_SCOPE));
+    public static Set<Filter> getFiltersFromEndpointListenerScope(ServiceReference<EndpointListener> sref) {
+        Set<Filter> filters = new HashSet<Filter>();
+        String[] scopes = StringPlus.parse(sref.getProperty(EndpointListener.ENDPOINT_LISTENER_SCOPE));
         for (String scope : scopes) {
             try {
-                filters.add(bctx.createFilter(scope));
+                filters.add(FrameworkUtil.createFilter(scope));
             } catch (InvalidSyntaxException e) {
                 LOG.error("invalid endpoint listener scope: {}", scope, e);
             }
@@ -158,10 +124,9 @@ public class EndpointListenerNotifier {
         return filters;
     }
 
-    private static List<Filter> getMatchingFilters(List<Filter> filters, EndpointDescription endpoint) {
-        List<Filter> matchingFilters = new ArrayList<Filter>();
+    private static Set<Filter> getMatchingFilters(Set<Filter> filters, EndpointDescription endpoint) {
+        Set<Filter> matchingFilters = new HashSet<Filter>();
         Dictionary<String, Object> dict = EndpointListenerNotifier.getEndpointProperties(endpoint);
-
         for (Filter filter : filters) {
             if (filter.match(dict)) {
                 LOG.debug("Filter {} matches endpoint {}", filter, dict);

http://git-wip-us.apache.org/repos/asf/cxf-dosgi/blob/e5db6fdd/dsw/cxf-topology-manager/src/main/java/org/apache/cxf/dosgi/topologymanager/exporter/EndpointRepository.java
----------------------------------------------------------------------
diff --git a/dsw/cxf-topology-manager/src/main/java/org/apache/cxf/dosgi/topologymanager/exporter/EndpointRepository.java b/dsw/cxf-topology-manager/src/main/java/org/apache/cxf/dosgi/topologymanager/exporter/EndpointRepository.java
index bdcdda5..7984822 100644
--- a/dsw/cxf-topology-manager/src/main/java/org/apache/cxf/dosgi/topologymanager/exporter/EndpointRepository.java
+++ b/dsw/cxf-topology-manager/src/main/java/org/apache/cxf/dosgi/topologymanager/exporter/EndpointRepository.java
@@ -26,7 +26,7 @@ import java.util.List;
 import java.util.Map;
 import java.util.Set;
 
-import org.apache.cxf.dosgi.topologymanager.util.Utils;
+import org.apache.cxf.dosgi.topologymanager.exporter.EndpointListenerNotifier.NotifyType;
 import org.osgi.framework.ServiceReference;
 import org.osgi.service.remoteserviceadmin.EndpointDescription;
 import org.osgi.service.remoteserviceadmin.RemoteServiceAdmin;
@@ -39,20 +39,28 @@ import org.slf4j.LoggerFactory;
  * endpoints.
  */
 @SuppressWarnings("rawtypes")
-class EndpointRepository {
+public class EndpointRepository {
 
     private static final Logger LOG = LoggerFactory.getLogger(EndpointRepository.class);
 
     private final Map<ServiceReference, Map<RemoteServiceAdmin, Collection<EndpointDescription>>> exportedServices
         = new LinkedHashMap<ServiceReference, Map<RemoteServiceAdmin, Collection<EndpointDescription>>>();
 
+    private EndpointListenerNotifier notifier;
+    
+    public void setNotifier(EndpointListenerNotifier notifier) {
+        this.notifier = notifier;
+    }
+    
+    
     /**
      * Remove all services exported by the given rsa.
      *
      * @param rsa the RemoteServiceAdmin to remove
      * @return list of removed endpoints
      */
-    synchronized List<EndpointDescription> removeRemoteServiceAdmin(RemoteServiceAdmin rsa) {
+    public synchronized List<EndpointDescription> removeRemoteServiceAdmin(RemoteServiceAdmin rsa) {
+        LOG.debug("RemoteServiceAdmin removed: {}", rsa.getClass().getName());
         List<EndpointDescription> removedEndpoints = new ArrayList<EndpointDescription>();
         for (Map<RemoteServiceAdmin, Collection<EndpointDescription>> exports : exportedServices.values()) {
             Collection<EndpointDescription> endpoints = exports.get(rsa);
@@ -61,10 +69,11 @@ class EndpointRepository {
                 exports.remove(rsa);
             }
         }
+        notifier.notifyListeners(NotifyType.REMOVED, removedEndpoints);
         return removedEndpoints;
     }
 
-    synchronized List<EndpointDescription> removeService(ServiceReference sref) {
+    synchronized void removeService(ServiceReference sref) {
         List<EndpointDescription> removedEndpoints = new ArrayList<EndpointDescription>();
         Map<RemoteServiceAdmin, Collection<EndpointDescription>> rsas = exportedServices.get(sref);
         if (rsas != null) {
@@ -73,12 +82,12 @@ class EndpointRepository {
             }
             exportedServices.remove(sref);
         }
-        return removedEndpoints;
+        notifier.notifyListeners(NotifyType.REMOVED, removedEndpoints);
     }
 
     synchronized void addService(ServiceReference sref) {
         if (!exportedServices.containsKey(sref)) {
-            LOG.info("Marking service from bundle {} for export", Utils.getBundleName(sref));
+            LOG.info("Marking service from bundle {} for export", sref.getBundle().getSymbolicName());
             exportedServices.put(sref, new LinkedHashMap<RemoteServiceAdmin, Collection<EndpointDescription>>());
         }
     }
@@ -91,6 +100,7 @@ class EndpointRepository {
         addService(sref);
         Map<RemoteServiceAdmin, Collection<EndpointDescription>> exports = exportedServices.get(sref);
         exports.put(rsa, endpoints);
+        notifier.notifyListeners(NotifyType.ADDED, endpoints);
     }
 
     synchronized boolean isAlreadyExportedForRsa(ServiceReference sref, RemoteServiceAdmin rsa) {
@@ -98,7 +108,7 @@ class EndpointRepository {
         return exports != null && exports.containsKey(rsa);
     }
 
-    synchronized Collection<EndpointDescription> getAllEndpoints() {
+    public synchronized Collection<EndpointDescription> getAllEndpoints() {
         List<EndpointDescription> allEndpoints = new ArrayList<EndpointDescription>();
         for (Map<RemoteServiceAdmin, Collection<EndpointDescription>> exports : exportedServices.values()) {
             for (Collection<EndpointDescription> endpoints : exports.values()) {
@@ -108,7 +118,7 @@ class EndpointRepository {
         return allEndpoints;
     }
 
-    synchronized Set<ServiceReference> getServicesToBeExportedFor(RemoteServiceAdmin rsa) {
+    public synchronized Set<ServiceReference> getServicesToBeExportedFor(RemoteServiceAdmin rsa) {
         Set<ServiceReference> servicesToBeExported = new HashSet<ServiceReference>();
         for (Map.Entry<ServiceReference, Map<RemoteServiceAdmin, Collection<EndpointDescription>>> entry
                 : exportedServices.entrySet()) {
@@ -118,4 +128,5 @@ class EndpointRepository {
         }
         return servicesToBeExported;
     }
+
 }

http://git-wip-us.apache.org/repos/asf/cxf-dosgi/blob/e5db6fdd/dsw/cxf-topology-manager/src/main/java/org/apache/cxf/dosgi/topologymanager/exporter/StringPlus.java
----------------------------------------------------------------------
diff --git a/dsw/cxf-topology-manager/src/main/java/org/apache/cxf/dosgi/topologymanager/exporter/StringPlus.java b/dsw/cxf-topology-manager/src/main/java/org/apache/cxf/dosgi/topologymanager/exporter/StringPlus.java
new file mode 100644
index 0000000..1198154
--- /dev/null
+++ b/dsw/cxf-topology-manager/src/main/java/org/apache/cxf/dosgi/topologymanager/exporter/StringPlus.java
@@ -0,0 +1,57 @@
+/**
+ * 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.topologymanager.exporter;
+
+import java.util.Collection;
+
+public final class StringPlus {
+
+    private StringPlus() {
+    }
+
+    /**
+     * 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[] parse(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];
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/cxf-dosgi/blob/e5db6fdd/dsw/cxf-topology-manager/src/main/java/org/apache/cxf/dosgi/topologymanager/exporter/TopologyManagerExport.java
----------------------------------------------------------------------
diff --git a/dsw/cxf-topology-manager/src/main/java/org/apache/cxf/dosgi/topologymanager/exporter/TopologyManagerExport.java b/dsw/cxf-topology-manager/src/main/java/org/apache/cxf/dosgi/topologymanager/exporter/TopologyManagerExport.java
index 446ab07..d7db57f 100644
--- a/dsw/cxf-topology-manager/src/main/java/org/apache/cxf/dosgi/topologymanager/exporter/TopologyManagerExport.java
+++ b/dsw/cxf-topology-manager/src/main/java/org/apache/cxf/dosgi/topologymanager/exporter/TopologyManagerExport.java
@@ -20,17 +20,11 @@ package org.apache.cxf.dosgi.topologymanager.exporter;
 
 import java.util.ArrayList;
 import java.util.Collection;
+import java.util.HashSet;
 import java.util.List;
-import java.util.concurrent.ExecutorService;
-import java.util.concurrent.LinkedBlockingQueue;
-import java.util.concurrent.ThreadPoolExecutor;
-import java.util.concurrent.TimeUnit;
+import java.util.Set;
+import java.util.concurrent.Executor;
 
-import org.apache.cxf.dosgi.topologymanager.util.SimpleServiceTracker;
-import org.apache.cxf.dosgi.topologymanager.util.SimpleServiceTrackerListener;
-import org.apache.cxf.dosgi.topologymanager.util.Utils;
-import org.osgi.framework.BundleContext;
-import org.osgi.framework.InvalidSyntaxException;
 import org.osgi.framework.ServiceEvent;
 import org.osgi.framework.ServiceListener;
 import org.osgi.framework.ServiceReference;
@@ -53,71 +47,32 @@ import org.slf4j.LoggerFactory;
  * <li> When a service is unpublished the EndpointListeners are notified.
  *      The endpoints are not closed as the ExportRegistration takes care of this
  */
-public class TopologyManagerExport {
-
-    private static final String DOSGI_SERVICES = "(" + RemoteConstants.SERVICE_EXPORTED_INTERFACES + "=*)";
-
+public class TopologyManagerExport implements ServiceListener {
     private static final Logger LOG = LoggerFactory.getLogger(TopologyManagerExport.class);
 
-    private final BundleContext bctx;
-    private final EndpointListenerNotifier epListenerNotifier;
-    private final ExecutorService execService;
-    private final SimpleServiceTracker<RemoteServiceAdmin> remoteServiceAdminTracker;
-    private final ServiceListener serviceListener;
+    private final Executor execService;
     private final EndpointRepository endpointRepo;
+    private final Set<RemoteServiceAdmin> rsaSet;
 
-    public TopologyManagerExport(BundleContext ctx, SimpleServiceTracker<RemoteServiceAdmin> rsaTracker) {
-        this(ctx, rsaTracker, null);
+    public TopologyManagerExport(final EndpointRepository endpointRepo, Executor executor) {
+        this.endpointRepo = endpointRepo;
+        this.rsaSet = new HashSet<RemoteServiceAdmin>();
+        this.execService = executor;
     }
 
-    public TopologyManagerExport(BundleContext ctx, SimpleServiceTracker<RemoteServiceAdmin> rsaTracker,
-                                 EndpointListenerNotifier notif) {
-        endpointRepo = new EndpointRepository();
-        epListenerNotifier = notif == null ? new EndpointListenerNotifier(ctx, endpointRepo) : notif;
-        execService = new ThreadPoolExecutor(5, 10, 50, TimeUnit.SECONDS, new LinkedBlockingQueue<Runnable>());
-        bctx = ctx;
-        remoteServiceAdminTracker = rsaTracker;
-
-        // track RemoteServiceAdmins through which we can export services
-        remoteServiceAdminTracker.addListener(new SimpleServiceTrackerListener<RemoteServiceAdmin>() {
-
-            public void added(ServiceReference<RemoteServiceAdmin> reference, RemoteServiceAdmin rsa) {
-                LOG.debug("RemoteServiceAdmin added: {}, total {}",
-                        rsa, remoteServiceAdminTracker.getAllServices().size());
-                for (ServiceReference<?> serviceRef : endpointRepo.getServicesToBeExportedFor(rsa)) {
-                    triggerExport(serviceRef);
-                }
-            }
-
-            public void modified(ServiceReference<RemoteServiceAdmin> reference, RemoteServiceAdmin rsa) {
+    // track all service registrations so we can export any services that are configured to be exported
+    // ServiceListener events may be delivered out of order, concurrently, re-entrant, etc. (see spec or docs)
+    public void serviceChanged(ServiceEvent event) {
+        ServiceReference<?> sref = event.getServiceReference();
+        if (event.getType() == ServiceEvent.REGISTERED) {
+            LOG.debug("Received REGISTERED ServiceEvent: {}", event);
+            if (shouldExportService(sref)) {
+                export(sref);
             }
-
-            public void removed(ServiceReference<RemoteServiceAdmin> reference, RemoteServiceAdmin rsa) {
-                LOG.debug("RemoteServiceAdmin removed: {}, total {}", rsa,
-                        remoteServiceAdminTracker.getAllServices().size());
-                List<EndpointDescription> endpoints = endpointRepo.removeRemoteServiceAdmin(rsa);
-                epListenerNotifier.notifyListeners(false, endpoints);
-            }
-        });
-
-        // track all service registrations so we can export any services that are configured to be exported
-        // ServiceListener events may be delivered out of order, concurrently, re-entrant, etc. (see spec or docs)
-        serviceListener = new ServiceListener() {
-
-            public void serviceChanged(ServiceEvent event) {
-                ServiceReference<?> sref = event.getServiceReference();
-                if (event.getType() == ServiceEvent.REGISTERED) {
-                    LOG.debug("Received REGISTERED ServiceEvent: {}", event);
-                    if (shouldExportService(sref)) {
-                        triggerExport(sref);
-                    }
-                } else if (event.getType() == ServiceEvent.UNREGISTERING) {
-                    LOG.debug("Received UNREGISTERING ServiceEvent: {}", event);
-                    List<EndpointDescription> endpoints = endpointRepo.removeService(sref);
-                    epListenerNotifier.notifyListeners(false, endpoints);
-                }
-            }
-        };
+        } else if (event.getType() == ServiceEvent.UNREGISTERING) {
+            LOG.debug("Received UNREGISTERING ServiceEvent: {}", event);
+            endpointRepo.removeService(sref);
+        }
     }
 
     /**
@@ -127,19 +82,19 @@ public class TopologyManagerExport {
         return sref.getProperty(RemoteConstants.SERVICE_EXPORTED_INTERFACES) != null;
     }
 
-    public void start() {
-        epListenerNotifier.start();
-        bctx.addServiceListener(serviceListener);
-        exportExistingServices();
-    }
-
-    public void stop() {
-        execService.shutdown();
-        bctx.removeServiceListener(serviceListener);
-        epListenerNotifier.stop();
-    }
-
-    protected void triggerExport(final ServiceReference<?> sref) {
+    public void add(RemoteServiceAdmin rsa) {
+        rsaSet.add(rsa);
+        for (ServiceReference<?> serviceRef : endpointRepo.getServicesToBeExportedFor(rsa)) {
+            export(serviceRef);
+        }
+    };
+    
+    public void remove(RemoteServiceAdmin rsa) {
+        rsaSet.remove(rsa);
+        endpointRepo.removeRemoteServiceAdmin(rsa);
+    };
+
+    public void export(final ServiceReference<?> sref) {
         execService.execute(new Runnable() {
             public void run() {
                 try {
@@ -154,16 +109,15 @@ public class TopologyManagerExport {
     protected void doExportService(final ServiceReference<?> sref) {
         LOG.debug("Exporting service {}", sref);
         endpointRepo.addService(sref); // mark for future export even if there are currently no RSAs
-        List<RemoteServiceAdmin> rsaList = remoteServiceAdminTracker.getAllServices();
-        if (rsaList.isEmpty()) {
+        if (rsaSet.size() == 0) {
             LOG.error("No RemoteServiceAdmin available! Unable to export service from bundle {}, interfaces: {}",
-                    Utils.getBundleName(sref),
+                    sref.getBundle().getSymbolicName(),
                     sref.getProperty(org.osgi.framework.Constants.OBJECTCLASS));
+            return;
         }
 
-        for (final RemoteServiceAdmin remoteServiceAdmin : rsaList) {
+        for (RemoteServiceAdmin remoteServiceAdmin : rsaSet) {
             LOG.info("TopologyManager: handling remoteServiceAdmin " + remoteServiceAdmin);
-
             if (endpointRepo.isAlreadyExportedForRsa(sref, remoteServiceAdmin)) {
                 // already handled by this remoteServiceAdmin
                 LOG.debug("already handled by this remoteServiceAdmin -> skipping");
@@ -186,10 +140,6 @@ public class TopologyManagerExport {
         LOG.debug("exporting {}...", sref);
         // TODO: additional parameter Map?
         Collection<ExportRegistration> exportRegs = remoteServiceAdmin.exportService(sref, null);
-        if (exportRegs.isEmpty()) {
-            LOG.warn("TopologyManager: nothing was exported for {}", sref);
-            return;
-        }
         // process successful/failed registrations
         List<EndpointDescription> endpoints = new ArrayList<EndpointDescription>();
         for (ExportRegistration reg : exportRegs) {
@@ -198,7 +148,6 @@ public class TopologyManagerExport {
                 LOG.info("TopologyManager: export succeeded for {}, endpoint ", sref, endpoint);
                 endpoints.add(endpoint);
             } else {
-                // TODO: what should we do with failed exports?
                 LOG.error("TopologyManager: export failed for {}", sref);
                 reg.close();
             }
@@ -217,7 +166,6 @@ public class TopologyManagerExport {
         if (!endpoints.isEmpty()) {
             LOG.info("TopologyManager: export successful for {}, endpoints: {}", sref, endpoints);
             endpointRepo.addEndpoints(sref, remoteServiceAdmin, endpoints);
-            epListenerNotifier.notifyListeners(true, endpoints); // notify after endpoints are added to repo
         }
     }
 
@@ -232,17 +180,5 @@ public class TopologyManagerExport {
         return (ref == null) ? null : ref.getExportedEndpoint();
     }
 
-    private void exportExistingServices() {
-        try {
-            // cast to String is necessary for compiling against OSGi core version >= 4.3
-            ServiceReference<?>[] references = bctx.getServiceReferences((String)null, DOSGI_SERVICES);
-            if (references != null) {
-                for (ServiceReference<?> sref : references) {
-                    triggerExport(sref);
-                }
-            }
-        } catch (InvalidSyntaxException e) {
-            LOG.error("Error in filter {}. This should not occur!", DOSGI_SERVICES);
-        }
-    }
+
 }

http://git-wip-us.apache.org/repos/asf/cxf-dosgi/blob/e5db6fdd/dsw/cxf-topology-manager/src/main/java/org/apache/cxf/dosgi/topologymanager/importer/EndpointListenerManager.java
----------------------------------------------------------------------
diff --git a/dsw/cxf-topology-manager/src/main/java/org/apache/cxf/dosgi/topologymanager/importer/EndpointListenerManager.java b/dsw/cxf-topology-manager/src/main/java/org/apache/cxf/dosgi/topologymanager/importer/EndpointListenerManager.java
index f222606..7812e52 100644
--- a/dsw/cxf-topology-manager/src/main/java/org/apache/cxf/dosgi/topologymanager/importer/EndpointListenerManager.java
+++ b/dsw/cxf-topology-manager/src/main/java/org/apache/cxf/dosgi/topologymanager/importer/EndpointListenerManager.java
@@ -41,7 +41,7 @@ public class EndpointListenerManager {
     private final List<String> filters = new ArrayList<String>();
     private final EndpointListener endpointListener;
 
-    protected EndpointListenerManager(BundleContext bc, EndpointListener endpointListener) {
+    public EndpointListenerManager(BundleContext bc, EndpointListener endpointListener) {
         this.bctx = bc;
         this.endpointListener = endpointListener;
     }

http://git-wip-us.apache.org/repos/asf/cxf-dosgi/blob/e5db6fdd/dsw/cxf-topology-manager/src/main/java/org/apache/cxf/dosgi/topologymanager/importer/FilterHelper.java
----------------------------------------------------------------------
diff --git a/dsw/cxf-topology-manager/src/main/java/org/apache/cxf/dosgi/topologymanager/importer/FilterHelper.java b/dsw/cxf-topology-manager/src/main/java/org/apache/cxf/dosgi/topologymanager/importer/FilterHelper.java
new file mode 100644
index 0000000..3739f16
--- /dev/null
+++ b/dsw/cxf-topology-manager/src/main/java/org/apache/cxf/dosgi/topologymanager/importer/FilterHelper.java
@@ -0,0 +1,43 @@
+/**
+ * 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.topologymanager.importer;
+
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import org.osgi.framework.Constants;
+
+public final class FilterHelper {
+    private static final String OBJECTCLASS_EXPRESSION = ".*\\(" + Constants.OBJECTCLASS + "=([a-zA-Z_0-9.]+)\\).*";
+    private static final Pattern OBJECTCLASS_PATTERN = Pattern.compile(OBJECTCLASS_EXPRESSION);
+
+    private FilterHelper() {
+        // prevent instantiation
+    }
+
+    public static String getObjectClass(String filter) {
+        if (filter != null) {
+            Matcher matcher = OBJECTCLASS_PATTERN.matcher(filter);
+            if (matcher.matches() && matcher.groupCount() >= 1) {
+                return matcher.group(1);
+            }
+        }
+        return null;
+    }
+}

http://git-wip-us.apache.org/repos/asf/cxf-dosgi/blob/e5db6fdd/dsw/cxf-topology-manager/src/main/java/org/apache/cxf/dosgi/topologymanager/importer/ListenerHookImpl.java
----------------------------------------------------------------------
diff --git a/dsw/cxf-topology-manager/src/main/java/org/apache/cxf/dosgi/topologymanager/importer/ListenerHookImpl.java b/dsw/cxf-topology-manager/src/main/java/org/apache/cxf/dosgi/topologymanager/importer/ListenerHookImpl.java
index f01754d..6d0bee1 100644
--- a/dsw/cxf-topology-manager/src/main/java/org/apache/cxf/dosgi/topologymanager/importer/ListenerHookImpl.java
+++ b/dsw/cxf-topology-manager/src/main/java/org/apache/cxf/dosgi/topologymanager/importer/ListenerHookImpl.java
@@ -22,7 +22,6 @@ import java.util.Collection;
 import java.util.HashSet;
 import java.util.Set;
 
-import org.apache.cxf.dosgi.topologymanager.util.Utils;
 import org.osgi.framework.BundleContext;
 import org.osgi.framework.Constants;
 import org.osgi.framework.hooks.service.ListenerHook;
@@ -64,7 +63,7 @@ public class ListenerHookImpl implements ListenerHook {
         for (ListenerInfo listenerInfo : listeners) {
             LOG.debug("Filter {}", listenerInfo.getFilter());
 
-            String className = Utils.getObjectClass(listenerInfo.getFilter());
+            String className = FilterHelper.getObjectClass(listenerInfo.getFilter());
 
             if (listenerInfo.getBundleContext().getBundle().equals(bctx.getBundle())) {
                 LOG.debug("ListenerHookImpl: skipping request from myself");

http://git-wip-us.apache.org/repos/asf/cxf-dosgi/blob/e5db6fdd/dsw/cxf-topology-manager/src/main/java/org/apache/cxf/dosgi/topologymanager/importer/RSATracker.java
----------------------------------------------------------------------
diff --git a/dsw/cxf-topology-manager/src/main/java/org/apache/cxf/dosgi/topologymanager/importer/RSATracker.java b/dsw/cxf-topology-manager/src/main/java/org/apache/cxf/dosgi/topologymanager/importer/RSATracker.java
new file mode 100644
index 0000000..56e98e8
--- /dev/null
+++ b/dsw/cxf-topology-manager/src/main/java/org/apache/cxf/dosgi/topologymanager/importer/RSATracker.java
@@ -0,0 +1,26 @@
+/**
+ * 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.topologymanager.importer;
+
+import org.osgi.service.remoteserviceadmin.RemoteServiceAdmin;
+
+public interface RSATracker {
+    void added(RemoteServiceAdmin rsa);
+    void removed(RemoteServiceAdmin rsa);
+}

http://git-wip-us.apache.org/repos/asf/cxf-dosgi/blob/e5db6fdd/dsw/cxf-topology-manager/src/main/java/org/apache/cxf/dosgi/topologymanager/importer/TopologyManagerImport.java
----------------------------------------------------------------------
diff --git a/dsw/cxf-topology-manager/src/main/java/org/apache/cxf/dosgi/topologymanager/importer/TopologyManagerImport.java b/dsw/cxf-topology-manager/src/main/java/org/apache/cxf/dosgi/topologymanager/importer/TopologyManagerImport.java
index 366d391..30fe4c2 100644
--- a/dsw/cxf-topology-manager/src/main/java/org/apache/cxf/dosgi/topologymanager/importer/TopologyManagerImport.java
+++ b/dsw/cxf-topology-manager/src/main/java/org/apache/cxf/dosgi/topologymanager/importer/TopologyManagerImport.java
@@ -22,18 +22,17 @@ import java.util.ArrayList;
 import java.util.Collection;
 import java.util.Collections;
 import java.util.HashMap;
+import java.util.HashSet;
 import java.util.Iterator;
 import java.util.List;
 import java.util.Map;
+import java.util.Set;
 import java.util.concurrent.ExecutorService;
 import java.util.concurrent.LinkedBlockingQueue;
 import java.util.concurrent.ThreadPoolExecutor;
 import java.util.concurrent.TimeUnit;
 
-import org.apache.cxf.dosgi.topologymanager.util.SimpleServiceTracker;
-import org.apache.cxf.dosgi.topologymanager.util.SimpleServiceTrackerListener;
 import org.osgi.framework.BundleContext;
-import org.osgi.framework.ServiceReference;
 import org.osgi.framework.hooks.service.ListenerHook;
 import org.osgi.service.remoteserviceadmin.EndpointDescription;
 import org.osgi.service.remoteserviceadmin.EndpointListener;
@@ -58,7 +57,7 @@ public class TopologyManagerImport implements EndpointListener, RemoteServiceAdm
 
     private final EndpointListenerManager endpointListenerManager;
     private final BundleContext bctx;
-    private final SimpleServiceTracker<RemoteServiceAdmin> remoteServiceAdminTracker;
+    private Set<RemoteServiceAdmin> rsaSet;
     private final ListenerHookImpl listenerHook;
 
     /**
@@ -88,28 +87,16 @@ public class TopologyManagerImport implements EndpointListener, RemoteServiceAdm
      */
     private final Map<String /* filter */, List<ImportRegistration>> importedServices
         = new HashMap<String, List<ImportRegistration>>();
+    
 
-    public TopologyManagerImport(BundleContext bc, SimpleServiceTracker<RemoteServiceAdmin> rsaTracker) {
+    public TopologyManagerImport(BundleContext bc) {
+        this.rsaSet = new HashSet<RemoteServiceAdmin>();
         bctx = bc;
-        remoteServiceAdminTracker = rsaTracker;
-        remoteServiceAdminTracker.addListener(new SimpleServiceTrackerListener<RemoteServiceAdmin>() {
-
-            public void added(ServiceReference<RemoteServiceAdmin> reference, RemoteServiceAdmin rsa) {
-                triggerImportsForRemoteServiceAdmin(rsa);
-            }
-
-            public void modified(ServiceReference<RemoteServiceAdmin> reference, RemoteServiceAdmin rsa) {
-            }
-
-            public void removed(ServiceReference<RemoteServiceAdmin> reference, RemoteServiceAdmin rsa) {
-                // the RSA's imports will be closed by its shutdown, so nothing to do here
-            }
-        });
         endpointListenerManager = new EndpointListenerManager(bctx, this);
         execService = new ThreadPoolExecutor(5, 10, 50, TimeUnit.SECONDS, new LinkedBlockingQueue<Runnable>());
         listenerHook = new ListenerHookImpl(bc, this);
     }
-
+    
     public void start() {
         bctx.registerService(RemoteServiceAdminListener.class, this, null);
         bctx.registerService(ListenerHook.class, listenerHook, null);
@@ -192,14 +179,19 @@ public class TopologyManagerImport implements EndpointListener, RemoteServiceAdm
         }
     }
 
-    public void triggerImportsForRemoteServiceAdmin(RemoteServiceAdmin rsa) {
-        LOG.debug("New RemoteServiceAdmin {} detected, trying to import services with it", rsa);
+    public void add(RemoteServiceAdmin rsa) {
+        rsaSet.add(rsa);
         synchronized (importPossibilities) {
             for (String filter : importPossibilities.keySet()) {
                 triggerImport(filter);
             }
         }
     }
+    
+    public void remove(RemoteServiceAdmin rsa) {
+        rsaSet.remove(rsa);
+    }
+
 
     private void triggerImport(final String filter) {
         LOG.debug("Import of a service for filter {} was queued", filter);
@@ -292,7 +284,7 @@ public class TopologyManagerImport implements EndpointListener, RemoteServiceAdm
      * @return import registration of the first successful import
      */
     private ImportRegistration importService(EndpointDescription endpoint) {
-        for (RemoteServiceAdmin rsa : remoteServiceAdminTracker.getAllServices()) {
+        for (RemoteServiceAdmin rsa : rsaSet) {
             ImportRegistration ir = rsa.importService(endpoint);
             if (ir != null) {
                 if (ir.getException() == null) {
@@ -349,4 +341,5 @@ public class TopologyManagerImport implements EndpointListener, RemoteServiceAdm
             removeImport(null, event.getImportReference());
         }
     }
+
 }

http://git-wip-us.apache.org/repos/asf/cxf-dosgi/blob/e5db6fdd/dsw/cxf-topology-manager/src/main/java/org/apache/cxf/dosgi/topologymanager/util/SimpleServiceTracker.java
----------------------------------------------------------------------
diff --git a/dsw/cxf-topology-manager/src/main/java/org/apache/cxf/dosgi/topologymanager/util/SimpleServiceTracker.java b/dsw/cxf-topology-manager/src/main/java/org/apache/cxf/dosgi/topologymanager/util/SimpleServiceTracker.java
deleted file mode 100644
index fc5b35e..0000000
--- a/dsw/cxf-topology-manager/src/main/java/org/apache/cxf/dosgi/topologymanager/util/SimpleServiceTracker.java
+++ /dev/null
@@ -1,151 +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.topologymanager.util;
-
-import java.util.ArrayList;
-import java.util.List;
-import java.util.concurrent.ConcurrentHashMap;
-import java.util.concurrent.ConcurrentMap;
-import java.util.concurrent.CopyOnWriteArrayList;
-
-import org.osgi.framework.BundleContext;
-import org.osgi.framework.Filter;
-import org.osgi.framework.ServiceReference;
-import org.osgi.util.tracker.ServiceTracker;
-
-/**
- * A {@link ServiceTracker} extension that simplifies its usage.
- * <p>
- * It enhances {@code ServiceTracker} by adding:
- * <ul>
- * <li>Multiple event listeners for service add/remove events
- * <li>Simpler event callbacks that do not need to deal with getting/ungetting
- *     services, calling super methods or returning service objects
- * <li>Generics support, which means the callback and {@code getList()} methods
- *     are type-safe and require no casting
- * <li>A {@link #getAllServices()} method which returns all currently tracked services;
- *     Unlike {@link ServiceTracker#getServices()}, if it is called from within a service
- *     {@link SimpleServiceTrackerListener#added added} event handler, the returned list
- *     will include the newly added service (this is the source of several bugs when using
- *     the original {@code getServices()})
- * </ul>
- *
- * @param <T> the service interface type
- */
-public class SimpleServiceTracker<T> extends ServiceTracker<T, T> {
-
-    // we must use a map with references as keys, so as not to invoke equals remotely on service objects
-    private final ConcurrentMap<ServiceReference<T>, T> services = new ConcurrentHashMap<ServiceReference<T>, T>();
-    private final List<SimpleServiceTrackerListener<T>> listeners =
-        new CopyOnWriteArrayList<SimpleServiceTrackerListener<T>>();
-
-    /**
-     * Create a {@code SimpleServiceTracker} on the specified class name.
-     * <p>
-     * Services registered under the specified class name will be tracked by
-     * this {@code SimpleServiceTracker}.
-     *
-     * @param context the {@code BundleContext} against which the tracking is done
-     * @param clazz the class of the services to be tracked
-     */
-    public SimpleServiceTracker(BundleContext context, Class<T> clazz) {
-        super(context, clazz.getName(), null);
-    }
-
-    /**
-     * Create a {@code SimpleServiceTracker} on the specified {@code Filter} object.
-     * <p>
-     * Services which match the specified {@code Filter} object will be tracked by
-     * this {@code SimpleServiceTracker}.
-     *
-     * @param context the {@code BundleContext} against which the tracking is done
-     * @param filter The {@code Filter} to select the services to be tracked
-     */
-    public SimpleServiceTracker(BundleContext context, Filter filter) {
-        super(context, filter, null);
-    }
-
-    /**
-     * Adds a listener to be notified of services added or removed.
-     *
-     * @param listener the listener to add
-     */
-    public void addListener(SimpleServiceTrackerListener<T> listener) {
-        listeners.add(listener);
-    }
-
-    @Override
-    public T addingService(ServiceReference<T> reference) {
-        T service = super.addingService(reference);
-        services.put(reference, service);
-        for (SimpleServiceTrackerListener<T> listener : listeners) {
-            listener.added(reference, service);
-        }
-        return service;
-    }
-
-    @Override
-    public void modifiedService(ServiceReference<T> reference, T service) {
-        for (SimpleServiceTrackerListener<T> listener : listeners) {
-            listener.modified(reference, service);
-        }
-        super.modifiedService(reference, service);
-    }
-
-    @Override
-    public void removedService(ServiceReference<T> reference, T service) {
-        services.remove(reference, service);
-        for (SimpleServiceTrackerListener<T> listener : listeners) {
-            listener.removed(reference, service);
-        }
-        super.removedService(reference, service);
-    }
-
-    @Override
-    public void close() {
-        super.close();
-        services.clear();
-    }
-
-    /**
-     * Returns all currently tracked services.
-     * <p>
-     * Unlike {@link ServiceTracker#getServices()}, if it is called from within a service
-     * {@link SimpleServiceTrackerListener#added added} event handler, the returned list
-     * will include the newly added service.
-     *
-     * @return all currently tracked services
-     */
-    public List<T> getAllServices() {
-        return new ArrayList<T>(services.values());
-    }
-
-    /**
-     * Returns all currently tracked service references.
-     * <p>
-     * Unlike {@link ServiceTracker#getServiceReferences()}, if it is called from within a service
-     * {@link SimpleServiceTrackerListener#added added} event handler, the returned list
-     * will include the newly added service reference.
-     *
-     * @return all currently tracked service references
-     */
-    public List<ServiceReference<T>> getAllServiceReferences() {
-        return new ArrayList<ServiceReference<T>>(services.keySet());
-    }
-}

http://git-wip-us.apache.org/repos/asf/cxf-dosgi/blob/e5db6fdd/dsw/cxf-topology-manager/src/main/java/org/apache/cxf/dosgi/topologymanager/util/SimpleServiceTrackerListener.java
----------------------------------------------------------------------
diff --git a/dsw/cxf-topology-manager/src/main/java/org/apache/cxf/dosgi/topologymanager/util/SimpleServiceTrackerListener.java b/dsw/cxf-topology-manager/src/main/java/org/apache/cxf/dosgi/topologymanager/util/SimpleServiceTrackerListener.java
deleted file mode 100644
index ef67b61..0000000
--- a/dsw/cxf-topology-manager/src/main/java/org/apache/cxf/dosgi/topologymanager/util/SimpleServiceTrackerListener.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.topologymanager.util;
-
-import org.osgi.framework.ServiceReference;
-
-/**
- * Callback interface for notifications of services that are
- * added to or removed from tracking by a {@link SimpleServiceTracker}.
- *
- * @param <T> the service interface type
- */
-public interface SimpleServiceTrackerListener<T> {
-
-    /**
-     * Called when a new service is added to the tracked services.
-     *
-     * @param reference the newly added service reference
-     * @param service the newly added service
-     */
-    void added(ServiceReference<T> reference, T service);
-
-    /**
-     * Called when a tracked service is modified.
-     *
-     * @param reference the modified service reference
-     * @param service the modified service
-     */
-    void modified(ServiceReference<T> reference, T service);
-
-    /**
-     * Called when a service is removed from the tracked services.
-     *
-     * @param reference the removed service reference
-     * @param service the removed service
-     */
-    void removed(ServiceReference<T> reference, T service);
-}

http://git-wip-us.apache.org/repos/asf/cxf-dosgi/blob/e5db6fdd/dsw/cxf-topology-manager/src/main/java/org/apache/cxf/dosgi/topologymanager/util/Utils.java
----------------------------------------------------------------------
diff --git a/dsw/cxf-topology-manager/src/main/java/org/apache/cxf/dosgi/topologymanager/util/Utils.java b/dsw/cxf-topology-manager/src/main/java/org/apache/cxf/dosgi/topologymanager/util/Utils.java
deleted file mode 100644
index 021cc55..0000000
--- a/dsw/cxf-topology-manager/src/main/java/org/apache/cxf/dosgi/topologymanager/util/Utils.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.topologymanager.util;
-
-import java.util.Collection;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
-
-import org.osgi.framework.Bundle;
-import org.osgi.framework.Constants;
-import org.osgi.framework.ServiceReference;
-
-public final class Utils {
-
-    private static final String OBJECTCLASS_EXPRESSION = ".*\\(" + Constants.OBJECTCLASS + "=([a-zA-Z_0-9.]+)\\).*";
-    private static final Pattern OBJECTCLASS_PATTERN = Pattern.compile(OBJECTCLASS_EXPRESSION);
-
-    private Utils() {
-        // prevent instantiation
-    }
-
-    public static String getObjectClass(String filter) {
-        if (filter != null) {
-            Matcher matcher = OBJECTCLASS_PATTERN.matcher(filter);
-            if (matcher.matches() && matcher.groupCount() >= 1) {
-                return matcher.group(1);
-            }
-        }
-        return null;
-    }
-
-    /**
-     * 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];
-    }
-
-    public static String getBundleName(ServiceReference<?> sref) {
-        Bundle bundle = sref.getBundle();
-        return bundle == null ? "<unregistered>" : bundle.getSymbolicName();
-    }
-}

http://git-wip-us.apache.org/repos/asf/cxf-dosgi/blob/e5db6fdd/dsw/cxf-topology-manager/src/test/java/org/apache/cxf/dosgi/topologymanager/exporter/EndpointListenerNotifierTest.java
----------------------------------------------------------------------
diff --git a/dsw/cxf-topology-manager/src/test/java/org/apache/cxf/dosgi/topologymanager/exporter/EndpointListenerNotifierTest.java b/dsw/cxf-topology-manager/src/test/java/org/apache/cxf/dosgi/topologymanager/exporter/EndpointListenerNotifierTest.java
index b5bd5d1..0e60d3e 100644
--- a/dsw/cxf-topology-manager/src/test/java/org/apache/cxf/dosgi/topologymanager/exporter/EndpointListenerNotifierTest.java
+++ b/dsw/cxf-topology-manager/src/test/java/org/apache/cxf/dosgi/topologymanager/exporter/EndpointListenerNotifierTest.java
@@ -18,25 +18,33 @@
  */
 package org.apache.cxf.dosgi.topologymanager.exporter;
 
-import java.util.ArrayList;
+
+
+import java.util.Arrays;
 import java.util.Collection;
-import java.util.HashMap;
+import java.util.Dictionary;
+import java.util.HashSet;
+import java.util.Hashtable;
+import java.util.Iterator;
 import java.util.List;
 import java.util.Map;
+import java.util.Set;
 
+import org.apache.cxf.dosgi.topologymanager.exporter.EndpointListenerNotifier.NotifyType;
 import org.easymock.EasyMock;
-import org.easymock.IAnswer;
-import org.easymock.IMocksControl;
+import org.junit.Assert;
 import org.junit.Test;
-import org.osgi.framework.BundleContext;
 import org.osgi.framework.Filter;
 import org.osgi.framework.FrameworkUtil;
 import org.osgi.framework.InvalidSyntaxException;
 import org.osgi.framework.ServiceReference;
 import org.osgi.service.remoteserviceadmin.EndpointDescription;
 import org.osgi.service.remoteserviceadmin.EndpointListener;
+import org.osgi.service.remoteserviceadmin.RemoteConstants;
 
+import static org.hamcrest.core.Is.is;
 import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertThat;
 
 @SuppressWarnings({
     "rawtypes", "unchecked"
@@ -45,142 +53,80 @@ public class EndpointListenerNotifierTest {
 
     @Test
     public void testNotifyListenersOfRemovalIfAppropriate() throws InvalidSyntaxException {
-        IMocksControl c = EasyMock.createNiceControl();
+        EndpointDescription endpoint1 = createEndpoint("myClass");
+        EndpointDescription endpoint2 = createEndpoint("notMyClass");
 
-        BundleContext bc = c.createMock(BundleContext.class);
-        ServiceReference sref = c.createMock(ServiceReference.class);
+        // Expect listener to be called for endpoint1 but not for endpoint2 
         EndpointListener epl = EasyMock.createMock(EndpointListener.class);
-        EndpointDescription endpoint = c.createMock(EndpointDescription.class);
-        EndpointDescription endpoint2 = c.createMock(EndpointDescription.class);
-
-        Map<String, Object> props = new HashMap<String, Object>();
-        String[] oc = new String[1];
-        oc[0] = "myClass";
-        props.put("objectClass", oc);
-
-        Map<String, Object> props2 = new HashMap<String, Object>();
-        oc = new String[1];
-        oc[0] = "notMyClass";
-        props2.put("objectClass", oc);
-
-        EasyMock.expect(bc.getService(EasyMock.eq(sref))).andReturn(epl).anyTimes();
-        EasyMock.expect(bc.createFilter((String)EasyMock.anyObject())).andAnswer(new IAnswer<Filter>() {
-            public Filter answer() throws Throwable {
-                return FrameworkUtil.createFilter((String)EasyMock.getCurrentArguments()[0]);
-            }
-        }).anyTimes();
-        EasyMock.expect(sref.getProperty(EasyMock.eq(EndpointListener.ENDPOINT_LISTENER_SCOPE)))
-            .andReturn("(objectClass=myClass)").anyTimes();
-
-        EasyMock.expect(endpoint.getProperties()).andReturn(props).anyTimes();
-        EasyMock.expect(endpoint2.getProperties()).andReturn(props2).anyTimes();
-
-        // must only be called for the first EndpointDescription!
-        epl.endpointRemoved(EasyMock.eq(endpoint), EasyMock.eq("(objectClass=myClass)"));
+        epl.endpointRemoved(EasyMock.eq(endpoint1), EasyMock.eq("(objectClass=myClass)"));
         EasyMock.expectLastCall().once();
-
-        EndpointRepository exportRepository = EasyMock.createMock(EndpointRepository.class);
-
-        c.replay();
         EasyMock.replay(epl);
 
-        EndpointListenerNotifier tm = new EndpointListenerNotifier(bc, exportRepository);
-
-        List<EndpointDescription> endpoints = new ArrayList<EndpointDescription>();
-        endpoints.add(endpoint);
-        endpoints.add(endpoint2);
+        EndpointRepository exportRepository = new EndpointRepository();
+        EndpointListenerNotifier tm = new EndpointListenerNotifier(exportRepository);
 
-        tm.notifyListener(false, sref, endpoints);
+        List<EndpointDescription> endpoints = Arrays.asList(endpoint1, endpoint2);
+        Set<Filter> filters = new HashSet<Filter>();
+        filters.add(FrameworkUtil.createFilter("(objectClass=myClass)"));
+        tm.notifyListener(NotifyType.REMOVED, epl, filters, endpoints);
 
-        c.verify();
         EasyMock.verify(epl);
     }
+    
+    public EndpointDescription createEndpoint(String iface) {
+        Map<String, Object> props = new Hashtable<String, Object>(); 
+        props.put("objectClass", new String[]{iface});
+        props.put(RemoteConstants.ENDPOINT_ID, iface);
+        props.put(RemoteConstants.SERVICE_IMPORTED_CONFIGS, "any");
+        return new EndpointDescription(props);
+    }
 
     @Test
     public void testNormalizeScopeForSingleString() {
-        try {
-            ServiceReference sr = EasyMock.createMock(ServiceReference.class);
-            EasyMock.expect(sr.getProperty(EndpointListener.ENDPOINT_LISTENER_SCOPE))
-                .andReturn("Filterstring");
-
-            Filter f = EasyMock.createNiceMock(Filter.class);
-
-            BundleContext bc = EasyMock.createNiceMock(BundleContext.class);
-            EasyMock.expect(bc.createFilter((String)EasyMock.anyObject())).andReturn(f);
-
-            EasyMock.replay(sr);
-            EasyMock.replay(bc);
-
-            List<Filter> res = EndpointListenerNotifier.getFiltersFromEndpointListenerScope(sr, bc);
-
-            assertEquals(1, res.size());
-            assertEquals(f, res.get(0));
-
-            EasyMock.verify(sr);
-            EasyMock.verify(bc);
-        } catch (InvalidSyntaxException e) {
-            e.printStackTrace();
-        }
+        ServiceReference sr = createListenerServiceWithFilter("(myProp=A)");
+        Set<Filter> res = EndpointListenerNotifier.getFiltersFromEndpointListenerScope(sr);
+        assertEquals(1, res.size());
+        Filter filter = res.iterator().next();
+        filterMatches(filter);
     }
 
     @Test
     public void testNormalizeScopeForStringArray() {
-        try {
-            String[] filterStrings = {"f1", "f2", "f3"};
-
-            ServiceReference sr = EasyMock.createMock(ServiceReference.class);
-            EasyMock.expect(sr.getProperty(EndpointListener.ENDPOINT_LISTENER_SCOPE))
-                .andReturn(filterStrings);
-
-            Filter f = EasyMock.createNiceMock(Filter.class);
-
-            BundleContext bc = EasyMock.createNiceMock(BundleContext.class);
-            EasyMock.expect(bc.createFilter((String)EasyMock.anyObject())).andReturn(f).times(filterStrings.length);
-
-            EasyMock.replay(sr);
-            EasyMock.replay(bc);
-
-            List<Filter> res = EndpointListenerNotifier.getFiltersFromEndpointListenerScope(sr, bc);
-
-            assertEquals(filterStrings.length, res.size());
-            assertEquals(f, res.get(0));
-
-            EasyMock.verify(sr);
-            EasyMock.verify(bc);
-        } catch (InvalidSyntaxException e) {
-            e.printStackTrace();
-        }
+        String[] filters = {"(myProp=A)", "(otherProp=B)"};
+        ServiceReference sr = createListenerServiceWithFilter(filters); 
+        Set<Filter> res = EndpointListenerNotifier.getFiltersFromEndpointListenerScope(sr);
+        assertEquals(filters.length, res.size());
+        Iterator<Filter> it = res.iterator();
+        Filter filter1 = it.next();
+        Filter filter2 = it.next();
+        Dictionary<String, String> props = new Hashtable();
+        props.put("myProp", "A");
+        assertThat(filter1.match(props) || filter2.match(props), is(true));
     }
 
     @Test
     public void testNormalizeScopeForCollection() {
-        try {
-            Collection<String> collection = new ArrayList<String>();
-            collection.add("f1");
-            collection.add("f2");
-            collection.add("f3");
-
-            ServiceReference sr = EasyMock.createMock(ServiceReference.class);
-            EasyMock.expect(sr.getProperty(EndpointListener.ENDPOINT_LISTENER_SCOPE))
-                .andReturn(collection);
-
-            Filter f = EasyMock.createNiceMock(Filter.class);
-
-            BundleContext bc = EasyMock.createNiceMock(BundleContext.class);
-            EasyMock.expect(bc.createFilter((String)EasyMock.anyObject())).andReturn(f).times(collection.size());
-
-            EasyMock.replay(sr);
-            EasyMock.replay(bc);
-
-            List<Filter> res = EndpointListenerNotifier.getFiltersFromEndpointListenerScope(sr, bc);
-
-            assertEquals(collection.size(), res.size());
-            assertEquals(f, res.get(0));
+        Collection<String> collection = Arrays.asList("(myProp=A)", "(otherProp=B)");
+        ServiceReference sr = createListenerServiceWithFilter(collection);
+        Set<Filter> res = EndpointListenerNotifier.getFiltersFromEndpointListenerScope(sr);
+        Iterator<Filter> it = res.iterator();
+        Filter filter1 = it.next();
+        Filter filter2 = it.next();
+        Dictionary<String, String> props = new Hashtable();
+        props.put("myProp", "A");
+        Assert.assertThat(filter1.match(props) || filter2.match(props), is(true));
+    }
+    
+    private void filterMatches(Filter filter) {
+        Dictionary<String, String> props = new Hashtable();
+        props.put("myProp", "A");
+        Assert.assertTrue("Filter should match", filter.match(props));
+    }
 
-            EasyMock.verify(sr);
-            EasyMock.verify(bc);
-        } catch (InvalidSyntaxException e) {
-            e.printStackTrace();
-        }
+    private ServiceReference createListenerServiceWithFilter(Object filters) {
+        ServiceReference sr = EasyMock.createMock(ServiceReference.class);
+        EasyMock.expect(sr.getProperty(EndpointListener.ENDPOINT_LISTENER_SCOPE)).andReturn(filters);
+        EasyMock.replay(sr);
+        return sr;
     }
 }

http://git-wip-us.apache.org/repos/asf/cxf-dosgi/blob/e5db6fdd/dsw/cxf-topology-manager/src/test/java/org/apache/cxf/dosgi/topologymanager/exporter/ExportServiceTest.java
----------------------------------------------------------------------
diff --git a/dsw/cxf-topology-manager/src/test/java/org/apache/cxf/dosgi/topologymanager/exporter/ExportServiceTest.java b/dsw/cxf-topology-manager/src/test/java/org/apache/cxf/dosgi/topologymanager/exporter/ExportServiceTest.java
deleted file mode 100644
index cb4c407..0000000
--- a/dsw/cxf-topology-manager/src/test/java/org/apache/cxf/dosgi/topologymanager/exporter/ExportServiceTest.java
+++ /dev/null
@@ -1,143 +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.topologymanager.exporter;
-
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.Map;
-
-import org.apache.cxf.dosgi.topologymanager.util.SimpleServiceTracker;
-import org.apache.cxf.dosgi.topologymanager.util.SimpleServiceTrackerListener;
-import org.easymock.EasyMock;
-import org.easymock.IAnswer;
-import org.easymock.IMocksControl;
-import org.junit.Test;
-import org.osgi.framework.Bundle;
-import org.osgi.framework.BundleContext;
-import org.osgi.framework.Constants;
-import org.osgi.framework.ServiceEvent;
-import org.osgi.framework.ServiceListener;
-import org.osgi.framework.ServiceReference;
-import org.osgi.service.remoteserviceadmin.EndpointDescription;
-import org.osgi.service.remoteserviceadmin.ExportReference;
-import org.osgi.service.remoteserviceadmin.ExportRegistration;
-import org.osgi.service.remoteserviceadmin.RemoteConstants;
-import org.osgi.service.remoteserviceadmin.RemoteServiceAdmin;
-
-@SuppressWarnings({
-    "rawtypes", "unchecked"
-   })
-public class ExportServiceTest {
-
-    /**
-     * This tests if the topology manager handles a service marked to be
-     * exported correctly by exporting it to an available RemoteServiceAdmin
-     * and notifying an EndpointListener afterwards.
-     *
-     * @throws Exception
-     */
-    @Test
-    public void testServiceExport() throws Exception {
-        IMocksControl c = EasyMock.createControl();
-
-        BundleContext bctx = c.createMock(BundleContext.class);
-        RemoteServiceAdmin rsa = c.createMock(RemoteServiceAdmin.class);
-        final EndpointListenerNotifier mockEpListenerNotifier = c.createMock(EndpointListenerNotifier.class);
-        mockEpListenerNotifier.start();
-        EasyMock.expectLastCall().once();
-
-        final ServiceReference sref = createUserServiceBundle(c);
-
-        EasyMock
-            .expect(bctx.getServiceReferences(EasyMock.<String> anyObject(), EasyMock.<String> anyObject()))
-            .andReturn(null).atLeastOnce();
-
-        SimpleServiceTracker<RemoteServiceAdmin> rsaTracker = createSingleRsaTracker(c, rsa);
-
-        EndpointDescription endpoint = createEndpoint(c);
-        ExportRegistration exportRegistration = createExportRegistration(c, endpoint);
-
-        // Main assertions
-        simulateUserServicePublished(bctx, sref);
-        EasyMock.expect(rsa.exportService(EasyMock.same(sref), (Map<String, Object>)EasyMock.anyObject()))
-            .andReturn(Collections.singletonList(exportRegistration)).once();
-        mockEpListenerNotifier.notifyListeners(EasyMock.eq(true), EasyMock.eq(Collections.singletonList(endpoint)));
-        EasyMock.expectLastCall().once();
-
-        c.replay();
-
-        TopologyManagerExport topManager = new TopologyManagerExport(bctx, rsaTracker, mockEpListenerNotifier) {
-            // override to perform export from the same thread rather than asynchronously
-            @Override
-            protected void triggerExport(ServiceReference sref) {
-                doExportService(sref);
-            }
-        };
-        topManager.start();
-        c.verify();
-    }
-
-    private void simulateUserServicePublished(BundleContext bctx, final ServiceReference sref) {
-        bctx.addServiceListener((ServiceListener)EasyMock.anyObject());
-        EasyMock.expectLastCall().andAnswer(new IAnswer<Object>() {
-            public Object answer() throws Throwable {
-                System.out.println("Simulating publishing the user service");
-                ServiceListener sl = (ServiceListener)EasyMock.getCurrentArguments()[0];
-                ServiceEvent se = new ServiceEvent(ServiceEvent.REGISTERED, sref);
-                sl.serviceChanged(se);
-                return null;
-            }
-        }).once();
-    }
-
-    private SimpleServiceTracker<RemoteServiceAdmin> createSingleRsaTracker(IMocksControl c, RemoteServiceAdmin rsa) {
-        SimpleServiceTracker<RemoteServiceAdmin> rsaTracker = c.createMock(SimpleServiceTracker.class);
-        rsaTracker.addListener(EasyMock.<SimpleServiceTrackerListener> anyObject());
-        EasyMock.expectLastCall().once();
-        EasyMock.expect(rsaTracker.getAllServices()).andReturn(Collections.singletonList(rsa));
-        return rsaTracker;
-    }
-
-    private ExportRegistration createExportRegistration(IMocksControl c, EndpointDescription endpoint) {
-        ExportRegistration exportRegistration = c.createMock(ExportRegistration.class);
-        ExportReference exportReference = c.createMock(ExportReference.class);
-        EasyMock.expect(exportRegistration.getExportReference()).andReturn(exportReference).anyTimes();
-        EasyMock.expect(exportRegistration.getException()).andReturn(null).anyTimes();
-        EasyMock.expect(exportReference.getExportedEndpoint()).andReturn(endpoint).anyTimes();
-        return exportRegistration;
-    }
-
-    private EndpointDescription createEndpoint(IMocksControl c) {
-        Map<String, Object> props = new HashMap<String, Object>();
-        props.put(RemoteConstants.ENDPOINT_ID, "1");
-        props.put(Constants.OBJECTCLASS, new String[] {"abc"});
-        props.put(RemoteConstants.SERVICE_IMPORTED_CONFIGS, "cxf");
-        return new EndpointDescription(props);
-    }
-
-    private ServiceReference createUserServiceBundle(IMocksControl c) {
-        final ServiceReference sref = c.createMock(ServiceReference.class);
-        EasyMock.expect(sref.getProperty(EasyMock.same(RemoteConstants.SERVICE_EXPORTED_INTERFACES)))
-            .andReturn("*").anyTimes();
-        Bundle srefBundle = c.createMock(Bundle.class);
-        EasyMock.expect(sref.getBundle()).andReturn(srefBundle).atLeastOnce();
-        EasyMock.expect(srefBundle.getSymbolicName()).andReturn("serviceBundleName").atLeastOnce();
-        return sref;
-    }
-}

http://git-wip-us.apache.org/repos/asf/cxf-dosgi/blob/e5db6fdd/dsw/cxf-topology-manager/src/test/java/org/apache/cxf/dosgi/topologymanager/exporter/TopologyManagerExportTest.java
----------------------------------------------------------------------
diff --git a/dsw/cxf-topology-manager/src/test/java/org/apache/cxf/dosgi/topologymanager/exporter/TopologyManagerExportTest.java b/dsw/cxf-topology-manager/src/test/java/org/apache/cxf/dosgi/topologymanager/exporter/TopologyManagerExportTest.java
new file mode 100644
index 0000000..cb9dc36
--- /dev/null
+++ b/dsw/cxf-topology-manager/src/test/java/org/apache/cxf/dosgi/topologymanager/exporter/TopologyManagerExportTest.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.topologymanager.exporter;
+
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.concurrent.Executor;
+
+import org.apache.cxf.dosgi.topologymanager.exporter.EndpointListenerNotifier.NotifyType;
+import org.easymock.EasyMock;
+import org.easymock.IMocksControl;
+import org.junit.Test;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.Constants;
+import org.osgi.framework.ServiceEvent;
+import org.osgi.framework.ServiceReference;
+import org.osgi.service.remoteserviceadmin.EndpointDescription;
+import org.osgi.service.remoteserviceadmin.ExportReference;
+import org.osgi.service.remoteserviceadmin.ExportRegistration;
+import org.osgi.service.remoteserviceadmin.RemoteConstants;
+import org.osgi.service.remoteserviceadmin.RemoteServiceAdmin;
+
+@SuppressWarnings({"rawtypes", "unchecked"})
+public class TopologyManagerExportTest {
+
+    /**
+     * This tests if the topology manager handles a service marked to be exported correctly by exporting it to
+     * an available RemoteServiceAdmin and notifying an EndpointListener afterwards.
+     *
+     * @throws Exception
+     */
+    @Test
+    public void testServiceExportUnexport() throws Exception {
+        IMocksControl c = EasyMock.createControl();
+        RemoteServiceAdmin rsa = c.createMock(RemoteServiceAdmin.class);
+        final EndpointListenerNotifier mockEpListenerNotifier = c.createMock(EndpointListenerNotifier.class);
+        final ServiceReference sref = createUserService(c);
+        EndpointDescription epd = createEndpoint();
+        expectServiceExported(c, rsa, mockEpListenerNotifier, sref, epd);
+        c.replay();
+        EndpointRepository endpointRepo = new EndpointRepository();
+        endpointRepo.setNotifier(mockEpListenerNotifier);
+        Executor executor = syncExecutor();
+        TopologyManagerExport exportManager = new TopologyManagerExport(endpointRepo, executor);
+        exportManager.add(rsa);
+        exportManager.serviceChanged(new ServiceEvent(ServiceEvent.REGISTERED, sref));
+        c.verify();
+        
+        c.reset();
+        mockEpListenerNotifier.notifyListeners(EasyMock.eq(NotifyType.REMOVED), 
+                                               EasyMock.eq(Collections.singletonList(epd)));
+        EasyMock.expectLastCall().once();
+        c.replay();
+        exportManager.serviceChanged(new ServiceEvent(ServiceEvent.UNREGISTERING, sref));
+        c.verify();
+    }
+
+    @Test
+    public void testExportExisting() throws Exception {
+        IMocksControl c = EasyMock.createControl();
+        RemoteServiceAdmin rsa = c.createMock(RemoteServiceAdmin.class);
+        final EndpointListenerNotifier mockEpListenerNotifier = c.createMock(EndpointListenerNotifier.class);
+        final ServiceReference sref = createUserService(c);
+        expectServiceExported(c, rsa, mockEpListenerNotifier, sref, createEndpoint());
+        c.replay();
+
+        EndpointRepository endpointRepo = new EndpointRepository();
+        endpointRepo.setNotifier(mockEpListenerNotifier);
+        TopologyManagerExport exportManager = new TopologyManagerExport(endpointRepo, syncExecutor());
+        exportManager.export(sref);
+        exportManager.add(rsa);
+        c.verify();
+    }
+
+    private void expectServiceExported(IMocksControl c, RemoteServiceAdmin rsa,
+                                       final EndpointListenerNotifier mockEpListenerNotifier,
+                                       final ServiceReference sref, EndpointDescription epd) {
+        ExportRegistration exportRegistration = createExportRegistration(c, epd);
+        EasyMock.expect(rsa.exportService(EasyMock.same(sref), (Map<String, Object>)EasyMock.anyObject()))
+            .andReturn(Collections.singletonList(exportRegistration)).once();
+        mockEpListenerNotifier.notifyListeners(EasyMock.eq(NotifyType.ADDED), 
+                                               EasyMock.eq(Collections.singletonList(epd)));
+        EasyMock.expectLastCall().once();
+    }
+
+    private Executor syncExecutor() {
+        return new Executor() {
+            @Override
+            public void execute(Runnable command) {
+                command.run();
+            }
+        };
+    }
+
+    private ExportRegistration createExportRegistration(IMocksControl c, EndpointDescription endpoint) {
+        ExportRegistration exportRegistration = c.createMock(ExportRegistration.class);
+        ExportReference exportReference = c.createMock(ExportReference.class);
+        EasyMock.expect(exportRegistration.getExportReference()).andReturn(exportReference).anyTimes();
+        EasyMock.expect(exportRegistration.getException()).andReturn(null).anyTimes();
+        EasyMock.expect(exportReference.getExportedEndpoint()).andReturn(endpoint).anyTimes();
+        return exportRegistration;
+    }
+
+    private EndpointDescription createEndpoint() {
+        Map<String, Object> props = new HashMap<String, Object>();
+        props.put(RemoteConstants.ENDPOINT_ID, "1");
+        props.put(Constants.OBJECTCLASS, new String[] {"abc"});
+        props.put(RemoteConstants.SERVICE_IMPORTED_CONFIGS, "cxf");
+        return new EndpointDescription(props);
+    }
+
+    private ServiceReference createUserService(IMocksControl c) {
+        final ServiceReference sref = c.createMock(ServiceReference.class);
+        EasyMock.expect(sref.getProperty(EasyMock.same(RemoteConstants.SERVICE_EXPORTED_INTERFACES)))
+            .andReturn("*").anyTimes();
+        Bundle srefBundle = c.createMock(Bundle.class);
+        EasyMock.expect(sref.getBundle()).andReturn(srefBundle).atLeastOnce();
+        EasyMock.expect(sref.getProperty("objectClass")).andReturn("org.My").anyTimes();
+        EasyMock.expect(srefBundle.getSymbolicName()).andReturn("serviceBundleName").atLeastOnce();
+        return sref;
+    }
+}


Mime
View raw message