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:21 UTC

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

http://git-wip-us.apache.org/repos/asf/aries-rsa/blob/d73a3a7f/systests2/multi-bundle/src/test/java/org/apache/cxf/dosgi/systests2/multi/TestExportService.java
----------------------------------------------------------------------
diff --git a/systests2/multi-bundle/src/test/java/org/apache/cxf/dosgi/systests2/multi/TestExportService.java b/systests2/multi-bundle/src/test/java/org/apache/cxf/dosgi/systests2/multi/TestExportService.java
deleted file mode 100644
index fa4a63e..0000000
--- a/systests2/multi-bundle/src/test/java/org/apache/cxf/dosgi/systests2/multi/TestExportService.java
+++ /dev/null
@@ -1,137 +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.systests2.multi;
-
-import java.io.IOException;
-import java.net.URL;
-import java.util.Map;
-
-import javax.xml.parsers.DocumentBuilder;
-import javax.xml.parsers.DocumentBuilderFactory;
-import javax.xml.parsers.ParserConfigurationException;
-
-import org.w3c.dom.Document;
-import org.w3c.dom.Element;
-import org.xml.sax.SAXException;
-import org.apache.cxf.dosgi.samples.greeter.GreeterData;
-import org.apache.cxf.dosgi.samples.greeter.GreeterException;
-import org.apache.cxf.dosgi.samples.greeter.GreeterService;
-import org.apache.cxf.dosgi.samples.greeter.GreetingPhrase;
-import org.apache.cxf.frontend.ClientProxyFactoryBean;
-import org.junit.Assert;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.ops4j.pax.exam.Configuration;
-import org.ops4j.pax.exam.Option;
-import org.ops4j.pax.exam.junit.PaxExam;
-
-import static org.ops4j.pax.exam.CoreOptions.frameworkStartLevel;
-import static org.ops4j.pax.exam.CoreOptions.mavenBundle;
-import static org.ops4j.pax.exam.CoreOptions.systemProperty;
-
-@RunWith(PaxExam.class)
-public class TestExportService extends AbstractDosgiTest {
-
-    @Configuration
-    public static Option[] configure() throws Exception {
-        return new Option[] {
-            MultiBundleTools.getDistroWithDiscovery(),
-            systemProperty("org.ops4j.pax.logging.DefaultServiceLog.level").value("INFO"),
-            mavenBundle().groupId("org.apache.servicemix.bundles")
-                .artifactId("org.apache.servicemix.bundles.junit").version("4.9_2"),
-            mavenBundle().groupId("org.apache.cxf.dosgi.samples")
-                .artifactId("cxf-dosgi-ri-samples-greeter-interface").versionAsInProject(),
-            mavenBundle().groupId("org.apache.cxf.dosgi.samples")
-                .artifactId("cxf-dosgi-ri-samples-greeter-impl").versionAsInProject(),
-            mavenBundle().groupId("org.apache.cxf.dosgi.systests")
-                .artifactId("cxf-dosgi-ri-systests2-common").versionAsInProject(), frameworkStartLevel(100),
-            //CoreOptions.vmOption("-Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=5005")
-        };
-    }
-
-    @Test
-    public void testAccessEndpoint() throws Exception {
-        assertBundlesStarted();
-        waitPort(9090);
-
-        checkWsdl(new URL("http://localhost:9090/greeter?wsdl"));
-
-        ClassLoader cl = Thread.currentThread().getContextClassLoader();
-        Thread.currentThread().setContextClassLoader(ClientProxyFactoryBean.class.getClassLoader());
-        try {
-            checkServiceCall("http://localhost:9090/greeter");
-        } finally {
-            Thread.currentThread().setContextClassLoader(cl);
-        }
-    }
-
-    private void checkServiceCall(String serviceUri) {
-        GreeterService client = createGreeterServiceProxy(serviceUri);
-
-        Map<GreetingPhrase, String> greetings = client.greetMe("Fred");
-        Assert.assertEquals("Fred", greetings.get(new GreetingPhrase("Hello")));
-        System.out.println("Invocation result: " + greetings);
-
-        try {
-            GreeterData gd = new GreeterDataImpl("Stranger", 11, true);
-            client.greetMe(gd);
-            Assert.fail("GreeterException has to be thrown");
-        } catch (GreeterException ex) {
-            Assert.assertEquals("Wrong exception message", "GreeterService can not greet Stranger",
-                                ex.toString());
-        }
-    }
-
-    private void checkWsdl(URL wsdlURL) throws ParserConfigurationException, SAXException, IOException {
-        DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
-        dbf.setNamespaceAware(true);
-        dbf.setValidating(false);
-        DocumentBuilder db = dbf.newDocumentBuilder();
-        Document doc = db.parse(wsdlURL.openStream());
-        Element el = doc.getDocumentElement();
-        Assert.assertEquals("definitions", el.getLocalName());
-        Assert.assertEquals("http://schemas.xmlsoap.org/wsdl/", el.getNamespaceURI());
-        Assert.assertEquals("GreeterService", el.getAttribute("name"));
-    }
-
-    class GreeterDataImpl implements GreeterData {
-
-        private String name;
-        private int age;
-        private boolean exception;
-
-        GreeterDataImpl(String n, int a, boolean ex) {
-            name = n;
-            age = a;
-            exception = ex;
-        }
-
-        public String getName() {
-            return name;
-        }
-
-        public int getAge() {
-            return age;
-        }
-
-        public boolean isException() {
-            return exception;
-        }
-    }
-}

http://git-wip-us.apache.org/repos/asf/aries-rsa/blob/d73a3a7f/systests2/multi-bundle/src/test/java/org/apache/cxf/dosgi/systests2/multi/TestImportService.java
----------------------------------------------------------------------
diff --git a/systests2/multi-bundle/src/test/java/org/apache/cxf/dosgi/systests2/multi/TestImportService.java b/systests2/multi-bundle/src/test/java/org/apache/cxf/dosgi/systests2/multi/TestImportService.java
deleted file mode 100644
index efc334b..0000000
--- a/systests2/multi-bundle/src/test/java/org/apache/cxf/dosgi/systests2/multi/TestImportService.java
+++ /dev/null
@@ -1,161 +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.systests2.multi;
-
-import java.io.InputStream;
-import java.util.Dictionary;
-import java.util.HashMap;
-import java.util.Hashtable;
-import java.util.Map;
-
-import javax.inject.Inject;
-
-import org.apache.cxf.aegis.databinding.AegisDatabinding;
-import org.apache.cxf.dosgi.samples.greeter.GreeterData;
-import org.apache.cxf.dosgi.samples.greeter.GreeterException;
-import org.apache.cxf.dosgi.samples.greeter.GreeterService;
-import org.apache.cxf.dosgi.samples.greeter.GreetingPhrase;
-import org.apache.cxf.dosgi.systests2.common.test1.GreeterDataImpl;
-import org.apache.cxf.dosgi.systests2.common.test1.MyActivator;
-import org.apache.cxf.dosgi.systests2.common.test1.MyServiceTracker;
-import org.apache.cxf.dosgi.systests2.common.test1.StartServiceTracker;
-import org.apache.cxf.endpoint.Server;
-import org.apache.cxf.frontend.ServerFactoryBean;
-import org.junit.Assert;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.ops4j.pax.exam.Configuration;
-import org.ops4j.pax.exam.Option;
-import org.ops4j.pax.exam.junit.PaxExam;
-import org.ops4j.pax.tinybundles.core.TinyBundles;
-import org.osgi.framework.BundleContext;
-import org.osgi.framework.Constants;
-import org.osgi.framework.ServiceReference;
-
-import static org.ops4j.pax.exam.CoreOptions.frameworkStartLevel;
-import static org.ops4j.pax.exam.CoreOptions.mavenBundle;
-import static org.ops4j.pax.exam.CoreOptions.provision;
-import static org.ops4j.pax.exam.CoreOptions.systemProperty;
-
-@RunWith(PaxExam.class)
-public class TestImportService extends AbstractDosgiTest {
-
-    @Inject
-    BundleContext bundleContext;
-
-    @Configuration
-    public static Option[] configure() throws Exception {
-        return new Option[] {
-                MultiBundleTools.getDistroWithDiscovery(),
-                systemProperty("org.ops4j.pax.logging.DefaultServiceLog.level").value("INFO"),
-                mavenBundle().groupId("org.apache.cxf.dosgi.samples")
-                    .artifactId("cxf-dosgi-ri-samples-greeter-interface").versionAsInProject(),
-                mavenBundle().groupId("org.apache.servicemix.bundles")
-                    .artifactId("org.apache.servicemix.bundles.junit").version("4.9_2"),
-                mavenBundle().groupId("org.apache.cxf.dosgi.systests")
-                    .artifactId("cxf-dosgi-ri-systests2-common").versionAsInProject(),
-                provision(createServiceConsumerBundle()),
-                // increase for debugging
-                systemProperty("org.apache.cxf.dosgi.test.serviceWaitTimeout").value(
-                        System.getProperty("org.apache.cxf.dosgi.test.serviceWaitTimeout", "200")),
-                frameworkStartLevel(100),
-                //CoreOptions.vmOption("-Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=5005")
-        };
-    }
-
-    protected static InputStream createServiceConsumerBundle() {
-        return TinyBundles.bundle()
-            .add(MyActivator.class)
-            .add(MyServiceTracker.class)
-            .add(StartServiceTracker.class)
-            .add(GreeterDataImpl.class)
-            .add("OSGI-INF/remote-service/remote-services.xml", TestImportService.class.getResource("/rs-test1.xml"))
-            .set(Constants.BUNDLE_SYMBOLICNAME, "testClientBundle")
-            .set(Constants.EXPORT_PACKAGE, "org.apache.cxf.dosgi.systests2.common.test1")
-            .set(Constants.BUNDLE_ACTIVATOR, MyActivator.class.getName())
-            .build(TinyBundles.withBnd());
-    }
-
-    @Test
-    public void testClientConsumer() throws Exception {
-        // This test tests the consumer side of Distributed OSGi. It works as follows:
-        // 1. It creates a little test bundle on the fly and starts that in the framework
-        //    (this happens in the configure() method above). The test bundle waits until its
-        //    instructed to start doing stuff. It's give this instruction via a service that is
-        //    registered by this test (the service is of type java.lang.Object and has testName=test1).
-        // 2. The test manually creates a CXF server of the appropriate type (using ServerFactoryBean)
-        // 3. It signals the client bundle by registering a service to start doing its work.
-        //    This registers a ServiceTracker in the client bundle for the remote service that is created
-        //    by the test in step 2. The client bundle knows about the address through the
-        //    remote-services.xml file.
-        // 4. The client bundle will invoke the remote service and record the results in a service that it
-        //    registers in the Service Registry.
-        // 5. The test waits for this service to appear and then checks the results which are available as
-        //    a service property.
-
-        // Set up a Server in the test
-        Server server = null;
-        try {
-            server = publishTestGreeter();
-
-            Dictionary<String, Object> props = new Hashtable<String, Object>();
-            props.put("testName", "test1");
-            bundleContext.registerService(Object.class.getName(), new Object(), props);
-
-            // Wait for the service tracker in the test bundle to register a service with the test result
-            @SuppressWarnings("rawtypes")
-            ServiceReference ref = waitService(bundleContext, String.class, "(testResult=test1)", 20);
-            Assert.assertEquals("HiOSGi;exception", ref.getProperty("result"));
-        } finally {
-            if (server != null) {
-                server.stop();
-            }
-            
-        }
-    }
-
-    private Server publishTestGreeter() {
-        ClassLoader cl = Thread.currentThread().getContextClassLoader();
-        try {
-            Thread.currentThread().setContextClassLoader(ServerFactoryBean.class.getClassLoader());
-            ServerFactoryBean factory = new ServerFactoryBean();
-            factory.setServiceClass(GreeterService.class);
-            factory.setAddress("http://localhost:9191/grrr");
-            factory.getServiceFactory().setDataBinding(new AegisDatabinding());
-            factory.setServiceBean(new TestGreeter());
-            return factory.create();
-        } finally {
-            Thread.currentThread().setContextClassLoader(cl);
-        }
-    }
-
-    public static class TestGreeter implements GreeterService {
-
-        public Map<GreetingPhrase, String> greetMe(String name) {
-            Map<GreetingPhrase, String> m = new HashMap<GreetingPhrase, String>();
-            GreetingPhrase gp = new GreetingPhrase("Hi");
-            m.put(gp, name);
-            return m;
-        }
-
-        public GreetingPhrase[] greetMe(GreeterData gd) throws GreeterException {
-            throw new GreeterException("TestGreeter");
-        }
-    }
-}

http://git-wip-us.apache.org/repos/asf/aries-rsa/blob/d73a3a7f/systests2/multi-bundle/src/test/java/org/apache/cxf/dosgi/systests2/multi/customintent/AddGreetingPhraseInterceptor.java
----------------------------------------------------------------------
diff --git a/systests2/multi-bundle/src/test/java/org/apache/cxf/dosgi/systests2/multi/customintent/AddGreetingPhraseInterceptor.java b/systests2/multi-bundle/src/test/java/org/apache/cxf/dosgi/systests2/multi/customintent/AddGreetingPhraseInterceptor.java
deleted file mode 100644
index a3a19be..0000000
--- a/systests2/multi-bundle/src/test/java/org/apache/cxf/dosgi/systests2/multi/customintent/AddGreetingPhraseInterceptor.java
+++ /dev/null
@@ -1,44 +0,0 @@
-/**
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-package org.apache.cxf.dosgi.systests2.multi.customintent;
-
-import java.util.List;
-import java.util.Map;
-
-import org.apache.cxf.dosgi.samples.greeter.GreetingPhrase;
-import org.apache.cxf.helpers.CastUtils;
-import org.apache.cxf.interceptor.Fault;
-import org.apache.cxf.message.Message;
-import org.apache.cxf.message.MessageContentsList;
-import org.apache.cxf.phase.AbstractPhaseInterceptor;
-
-public final class AddGreetingPhraseInterceptor extends AbstractPhaseInterceptor<Message> {
-
-    AddGreetingPhraseInterceptor(String phase) {
-        super(phase);
-    }
-
-    public void handleMessage(Message message) throws Fault {
-        MessageContentsList contents = (MessageContentsList) message.getContent(List.class);
-        Map<GreetingPhrase, String> result = CastUtils.cast((Map<?, ?>)contents.get(0));
-        result.put(new GreetingPhrase("Hi from custom intent"), "customintent");
-        //Object content1 = contents.iterator().next();
-        System.out.println(message);
-    }
-}

http://git-wip-us.apache.org/repos/asf/aries-rsa/blob/d73a3a7f/systests2/multi-bundle/src/test/java/org/apache/cxf/dosgi/systests2/multi/customintent/CustomFeature.java
----------------------------------------------------------------------
diff --git a/systests2/multi-bundle/src/test/java/org/apache/cxf/dosgi/systests2/multi/customintent/CustomFeature.java b/systests2/multi-bundle/src/test/java/org/apache/cxf/dosgi/systests2/multi/customintent/CustomFeature.java
deleted file mode 100644
index abac14f..0000000
--- a/systests2/multi-bundle/src/test/java/org/apache/cxf/dosgi/systests2/multi/customintent/CustomFeature.java
+++ /dev/null
@@ -1,33 +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.systests2.multi.customintent;
-
-import org.apache.cxf.Bus;
-import org.apache.cxf.feature.AbstractFeature;
-import org.apache.cxf.interceptor.InterceptorProvider;
-import org.apache.cxf.phase.Phase;
-
-public final class CustomFeature extends AbstractFeature {
-
-    @Override
-    protected void initializeProvider(InterceptorProvider provider, Bus bus) {
-        provider.getOutInterceptors().add(0, new AddGreetingPhraseInterceptor(Phase.USER_LOGICAL));
-        super.initializeProvider(provider, bus);
-    }
-}

http://git-wip-us.apache.org/repos/asf/aries-rsa/blob/d73a3a7f/systests2/multi-bundle/src/test/java/org/apache/cxf/dosgi/systests2/multi/customintent/CustomIntentActivator.java
----------------------------------------------------------------------
diff --git a/systests2/multi-bundle/src/test/java/org/apache/cxf/dosgi/systests2/multi/customintent/CustomIntentActivator.java b/systests2/multi-bundle/src/test/java/org/apache/cxf/dosgi/systests2/multi/customintent/CustomIntentActivator.java
deleted file mode 100644
index ca4efda..0000000
--- a/systests2/multi-bundle/src/test/java/org/apache/cxf/dosgi/systests2/multi/customintent/CustomIntentActivator.java
+++ /dev/null
@@ -1,37 +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.systests2.multi.customintent;
-
-import java.util.Dictionary;
-import java.util.Hashtable;
-
-import org.osgi.framework.BundleActivator;
-import org.osgi.framework.BundleContext;
-
-public class CustomIntentActivator implements BundleActivator {
-
-    public void start(BundleContext context) throws Exception {
-        Dictionary<String, String> props = new Hashtable<String, String>();
-        props.put("org.apache.cxf.dosgi.IntentName", "myIntent");
-        context.registerService(Object.class.getName(), new CustomFeature(), props);
-    }
-
-    public void stop(BundleContext context) throws Exception {
-    }
-}

http://git-wip-us.apache.org/repos/asf/aries-rsa/blob/d73a3a7f/systests2/multi-bundle/src/test/java/org/apache/cxf/dosgi/systests2/multi/customintent/service/EmptyGreeterService.java
----------------------------------------------------------------------
diff --git a/systests2/multi-bundle/src/test/java/org/apache/cxf/dosgi/systests2/multi/customintent/service/EmptyGreeterService.java b/systests2/multi-bundle/src/test/java/org/apache/cxf/dosgi/systests2/multi/customintent/service/EmptyGreeterService.java
deleted file mode 100644
index 2c0108d..0000000
--- a/systests2/multi-bundle/src/test/java/org/apache/cxf/dosgi/systests2/multi/customintent/service/EmptyGreeterService.java
+++ /dev/null
@@ -1,41 +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.systests2.multi.customintent.service;
-
-import java.util.HashMap;
-import java.util.Map;
-
-import org.apache.cxf.dosgi.samples.greeter.GreeterData;
-import org.apache.cxf.dosgi.samples.greeter.GreeterException;
-import org.apache.cxf.dosgi.samples.greeter.GreeterService;
-import org.apache.cxf.dosgi.samples.greeter.GreetingPhrase;
-
-public final class EmptyGreeterService implements GreeterService {
-
-    /**
-     * Return an empty array. Our custom intent should add a GreetingPhrase
-     */
-    public GreetingPhrase[] greetMe(GreeterData name) throws GreeterException {
-        return new GreetingPhrase[]{};
-    }
-
-    public Map<GreetingPhrase, String> greetMe(String name) {
-        return new HashMap<GreetingPhrase, String>();
-    }
-}

http://git-wip-us.apache.org/repos/asf/aries-rsa/blob/d73a3a7f/systests2/multi-bundle/src/test/java/org/apache/cxf/dosgi/systests2/multi/customintent/service/GreeterServiceWithCustomIntentActivator.java
----------------------------------------------------------------------
diff --git a/systests2/multi-bundle/src/test/java/org/apache/cxf/dosgi/systests2/multi/customintent/service/GreeterServiceWithCustomIntentActivator.java b/systests2/multi-bundle/src/test/java/org/apache/cxf/dosgi/systests2/multi/customintent/service/GreeterServiceWithCustomIntentActivator.java
deleted file mode 100644
index bcf6016..0000000
--- a/systests2/multi-bundle/src/test/java/org/apache/cxf/dosgi/systests2/multi/customintent/service/GreeterServiceWithCustomIntentActivator.java
+++ /dev/null
@@ -1,42 +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.systests2.multi.customintent.service;
-
-import java.util.Dictionary;
-import java.util.Hashtable;
-
-import org.apache.cxf.dosgi.samples.greeter.GreeterService;
-import org.osgi.framework.BundleActivator;
-import org.osgi.framework.BundleContext;
-import org.osgi.service.remoteserviceadmin.RemoteConstants;
-
-public class GreeterServiceWithCustomIntentActivator implements BundleActivator {
-
-    public void start(BundleContext context) throws Exception {
-        Dictionary<String, String> props = new Hashtable<String, String>();
-        props.put(RemoteConstants.SERVICE_EXPORTED_INTERFACES, "*");
-        props.put(RemoteConstants.SERVICE_EXPORTED_CONFIGS, "org.apache.cxf.ws");
-        props.put("org.apache.cxf.ws.address", "http://localhost:9090/greeter");
-        props.put(RemoteConstants.SERVICE_EXPORTED_INTENTS, "myIntent");
-        context.registerService(GreeterService.class.getName(), new EmptyGreeterService(), props);
-    }
-
-    public void stop(BundleContext context) throws Exception {
-    }
-}

http://git-wip-us.apache.org/repos/asf/aries-rsa/blob/d73a3a7f/systests2/multi-bundle/src/test/java/org/apache/cxf/dosgi/systests2/multi/rest/RestTranslate.java
----------------------------------------------------------------------
diff --git a/systests2/multi-bundle/src/test/java/org/apache/cxf/dosgi/systests2/multi/rest/RestTranslate.java b/systests2/multi-bundle/src/test/java/org/apache/cxf/dosgi/systests2/multi/rest/RestTranslate.java
deleted file mode 100644
index 3a55c0e..0000000
--- a/systests2/multi-bundle/src/test/java/org/apache/cxf/dosgi/systests2/multi/rest/RestTranslate.java
+++ /dev/null
@@ -1,34 +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.systests2.multi.rest;
-
-import javax.ws.rs.GET;
-import javax.ws.rs.Path;
-import javax.ws.rs.PathParam;
-
-public interface RestTranslate {
-
-    @GET
-    String englishWords();
-
-    @GET
-    @Path("/{word}")
-    String getTranslation(@PathParam("word") String word);
-
-}

http://git-wip-us.apache.org/repos/asf/aries-rsa/blob/d73a3a7f/systests2/multi-bundle/src/test/java/org/apache/cxf/dosgi/systests2/multi/rest/RestTranslateImpl.java
----------------------------------------------------------------------
diff --git a/systests2/multi-bundle/src/test/java/org/apache/cxf/dosgi/systests2/multi/rest/RestTranslateImpl.java b/systests2/multi-bundle/src/test/java/org/apache/cxf/dosgi/systests2/multi/rest/RestTranslateImpl.java
deleted file mode 100644
index 640b0c9..0000000
--- a/systests2/multi-bundle/src/test/java/org/apache/cxf/dosgi/systests2/multi/rest/RestTranslateImpl.java
+++ /dev/null
@@ -1,41 +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.systests2.multi.rest;
-
-import java.util.HashMap;
-import java.util.Map;
-
-public class RestTranslateImpl implements RestTranslate {
-    Map<String, String> translation;
-    
-    public RestTranslateImpl() {
-        translation = new HashMap<String, String>();
-        translation.put("hello", "hallo");
-    }
-    
-    @Override
-    public String englishWords() {
-        return translation.keySet().toString();
-    }
-    
-    @Override
-    public String getTranslation(String word) {
-        return translation.get(word);
-    }
-}

http://git-wip-us.apache.org/repos/asf/aries-rsa/blob/d73a3a7f/systests2/multi-bundle/src/test/java/org/apache/cxf/dosgi/systests2/multi/rest/TranslateActivator.java
----------------------------------------------------------------------
diff --git a/systests2/multi-bundle/src/test/java/org/apache/cxf/dosgi/systests2/multi/rest/TranslateActivator.java b/systests2/multi-bundle/src/test/java/org/apache/cxf/dosgi/systests2/multi/rest/TranslateActivator.java
deleted file mode 100644
index 1c48fb5..0000000
--- a/systests2/multi-bundle/src/test/java/org/apache/cxf/dosgi/systests2/multi/rest/TranslateActivator.java
+++ /dev/null
@@ -1,40 +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.systests2.multi.rest;
-
-import java.util.Dictionary;
-import java.util.Hashtable;
-
-import org.osgi.framework.BundleActivator;
-import org.osgi.framework.BundleContext;
-
-public class TranslateActivator implements BundleActivator {
-
-    public void start(BundleContext context) throws Exception {
-        Dictionary<String, String> props = new Hashtable<String, String>();
-        props.put("service.exported.interfaces", "*");
-        props.put("service.exported.configs", "org.apache.cxf.rs");
-        props.put("service.exported.intents", "HTTP");
-        props.put("org.apache.cxf.rs.address", "/translate");
-        context.registerService(RestTranslate.class.getName(), new RestTranslateImpl(), props);
-    }
-
-    public void stop(BundleContext context) throws Exception {
-    }
-}

http://git-wip-us.apache.org/repos/asf/aries-rsa/blob/d73a3a7f/systests2/multi-bundle/src/test/resources/log4j.properties
----------------------------------------------------------------------
diff --git a/systests2/multi-bundle/src/test/resources/log4j.properties b/systests2/multi-bundle/src/test/resources/log4j.properties
deleted file mode 100644
index 2f206d5..0000000
--- a/systests2/multi-bundle/src/test/resources/log4j.properties
+++ /dev/null
@@ -1,13 +0,0 @@
-# Set root logger level to DEBUG and its only appender to A1.
-log4j.rootLogger=INFO, A1
-
-# A1 is set to be a ConsoleAppender.
-log4j.appender.A1=org.apache.log4j.ConsoleAppender
-
-# A1 uses PatternLayout.
-log4j.appender.A1.layout=org.apache.log4j.PatternLayout
-log4j.appender.A1.layout.ConversionPattern=%-4r [%t] %-5p %c %x - %m%n
-
-log4j.logger.org.ops4j.pax.scanner=WARN
-log4j.logger.org.ops4j.pax.runner=WARN
-log4j.logger.org.ops4j.pax.url=WARN

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

http://git-wip-us.apache.org/repos/asf/aries-rsa/blob/d73a3a7f/topology-manager/bnd.bnd
----------------------------------------------------------------------
diff --git a/topology-manager/bnd.bnd b/topology-manager/bnd.bnd
new file mode 100644
index 0000000..3ff22e0
--- /dev/null
+++ b/topology-manager/bnd.bnd
@@ -0,0 +1 @@
+Bundle-Activator: org.apache.cxf.dosgi.topologymanager.Activator

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

http://git-wip-us.apache.org/repos/asf/aries-rsa/blob/d73a3a7f/topology-manager/src/main/java/org/apache/cxf/dosgi/topologymanager/Activator.java
----------------------------------------------------------------------
diff --git a/topology-manager/src/main/java/org/apache/cxf/dosgi/topologymanager/Activator.java b/topology-manager/src/main/java/org/apache/cxf/dosgi/topologymanager/Activator.java
new file mode 100644
index 0000000..62ec1a9
--- /dev/null
+++ b/topology-manager/src/main/java/org/apache/cxf/dosgi/topologymanager/Activator.java
@@ -0,0 +1,192 @@
+/**
+ * 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;
+
+import java.util.Dictionary;
+import java.util.Hashtable;
+import java.util.concurrent.LinkedBlockingQueue;
+import java.util.concurrent.ThreadPoolExecutor;
+import java.util.concurrent.TimeUnit;
+
+import org.apache.cxf.dosgi.dsw.api.ExportPolicy;
+import org.apache.cxf.dosgi.topologymanager.exporter.DefaultExportPolicy;
+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.osgi.framework.BundleActivator;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.Filter;
+import org.osgi.framework.FrameworkUtil;
+import org.osgi.framework.InvalidSyntaxException;
+import org.osgi.framework.ServiceEvent;
+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 {
+    public static final String RSA_EXPORT_POLICY_FILTER = "rsa.export.policy.filter";
+    static final String DOSGI_SERVICES = "(" + RemoteConstants.SERVICE_EXPORTED_INTERFACES + "=*)";
+    private static final Logger LOG = LoggerFactory.getLogger(Activator.class);
+
+    private TopologyManagerExport exportManager;
+    private TopologyManagerImport importManager;
+    private EndpointListenerNotifier notifier;
+    private ServiceTracker<RemoteServiceAdmin, RemoteServiceAdmin> rsaTracker;
+    private ThreadPoolExecutor exportExecutor;
+    private ServiceTracker<EndpointListener, EndpointListener> epListenerTracker;
+    private ServiceTracker<ExportPolicy, ExportPolicy> policyTracker;
+
+    public void start(final BundleContext bc) throws Exception {
+        Dictionary<String, String> props = new Hashtable<String, String>();
+        props.put("name", "default");
+        bc.registerService(ExportPolicy.class, new DefaultExportPolicy(), props);
+
+        Filter policyFilter = exportPolicyFilter(bc);
+        policyTracker = new ServiceTracker<ExportPolicy, ExportPolicy>(bc, policyFilter, null) {
+
+            @Override
+            public ExportPolicy addingService(ServiceReference<ExportPolicy> reference) {
+                ExportPolicy policy = super.addingService(reference);
+                if (exportManager == null) {
+                    doStart(bc, policy);
+                }
+                return policy;
+            }
+
+            @Override
+            public void removedService(ServiceReference<ExportPolicy> reference, ExportPolicy service) {
+                if (exportManager != null) {
+                    doStop(bc);
+                }
+                super.removedService(reference, service);
+            }
+        };
+        policyTracker.open();
+    }
+
+    private Filter exportPolicyFilter(BundleContext bc) throws InvalidSyntaxException {
+        String filter = bc.getProperty(RSA_EXPORT_POLICY_FILTER);
+        if (filter == null) {
+            filter = "(name=default)";
+        }
+        return FrameworkUtil.createFilter(String.format("(&(objectClass=%s)%s)", ExportPolicy.class.getName(), filter));
+    }
+
+    public void doStart(final BundleContext bc, ExportPolicy policy) {
+        LOG.debug("TopologyManager: start()");
+        EndpointRepository endpointRepo = new EndpointRepository();
+        notifier = new EndpointListenerNotifier(endpointRepo);
+        epListenerTracker = new EndpointListenerTracker(bc);
+        endpointRepo.setNotifier(notifier);
+        exportExecutor = new ThreadPoolExecutor(5, 10, 50, TimeUnit.SECONDS, new LinkedBlockingQueue<Runnable>());
+        exportManager = new TopologyManagerExport(endpointRepo, exportExecutor, policy);
+        importManager = new TopologyManagerImport(bc);
+        rsaTracker = new RSATracker(bc, RemoteServiceAdmin.class, null);
+        bc.addServiceListener(exportManager);
+        rsaTracker.open();
+        epListenerTracker.open();
+        exportExistingServices(bc);
+        importManager.start();
+    }
+
+    public void stop(BundleContext bc) throws Exception {
+        policyTracker.close();
+    }
+
+    public void doStop(BundleContext bc) {
+        LOG.debug("TopologyManager: stop()");
+        epListenerTracker.close();
+        bc.removeServiceListener(exportManager);
+        exportExecutor.shutdown();
+        importManager.stop();
+        rsaTracker.close();
+        exportManager = null;
+    }
+
+    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.serviceChanged(new ServiceEvent(ServiceEvent.REGISTERED, sref));
+                }
+            }
+        } catch (InvalidSyntaxException e) {
+            LOG.error("Error in filter {}. This should not occur!", DOSGI_SERVICES);
+        }
+    }
+    
+    private final class EndpointListenerTracker extends ServiceTracker<EndpointListener, EndpointListener> {
+        private EndpointListenerTracker(BundleContext context) {
+            super(context, 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);
+        }
+    }
+
+    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/aries-rsa/blob/d73a3a7f/topology-manager/src/main/java/org/apache/cxf/dosgi/topologymanager/exporter/DefaultExportPolicy.java
----------------------------------------------------------------------
diff --git a/topology-manager/src/main/java/org/apache/cxf/dosgi/topologymanager/exporter/DefaultExportPolicy.java b/topology-manager/src/main/java/org/apache/cxf/dosgi/topologymanager/exporter/DefaultExportPolicy.java
new file mode 100644
index 0000000..689ebab
--- /dev/null
+++ b/topology-manager/src/main/java/org/apache/cxf/dosgi/topologymanager/exporter/DefaultExportPolicy.java
@@ -0,0 +1,37 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.cxf.dosgi.topologymanager.exporter;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import org.apache.cxf.dosgi.dsw.api.ExportPolicy;
+import org.osgi.framework.ServiceReference;
+
+/**
+ * The default is to not customize the way services are exported
+ */
+public class DefaultExportPolicy implements ExportPolicy {
+
+    @Override
+    public Map<String, ?> additionalParameters(ServiceReference<?> sref) {
+        return new HashMap<String, Object>();
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/aries-rsa/blob/d73a3a7f/topology-manager/src/main/java/org/apache/cxf/dosgi/topologymanager/exporter/EndpointListenerNotifier.java
----------------------------------------------------------------------
diff --git a/topology-manager/src/main/java/org/apache/cxf/dosgi/topologymanager/exporter/EndpointListenerNotifier.java b/topology-manager/src/main/java/org/apache/cxf/dosgi/topologymanager/exporter/EndpointListenerNotifier.java
new file mode 100644
index 0000000..13d7dab
--- /dev/null
+++ b/topology-manager/src/main/java/org/apache/cxf/dosgi/topologymanager/exporter/EndpointListenerNotifier.java
@@ -0,0 +1,133 @@
+/**
+ * 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.Dictionary;
+import java.util.HashSet;
+import java.util.Hashtable;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.ConcurrentHashMap;
+
+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.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Tracks EndpointListeners and allows to notify them of endpoints.
+ */
+public class EndpointListenerNotifier implements EndpointListener {
+    private static final Logger LOG = LoggerFactory.getLogger(EndpointListenerNotifier.class);
+    private enum NotifyType { ADDED, REMOVED };
+    private Map<EndpointListener, Set<Filter>> listeners;
+    private EndpointRepository endpointRepo;
+
+    public EndpointListenerNotifier(final EndpointRepository endpointRepo) {
+        this.endpointRepo = endpointRepo;
+        this.listeners = new ConcurrentHashMap<EndpointListener, Set<Filter>>();
+    }
+    
+    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(FrameworkUtil.createFilter(scope));
+            } catch (InvalidSyntaxException e) {
+                LOG.error("invalid endpoint listener scope: {}", scope, e);
+            }
+        }
+        return filters;
+    }
+
+    public void add(EndpointListener ep, Set<Filter> filters) {
+        LOG.debug("new EndpointListener detected");
+        listeners.put(ep, filters);
+        for (EndpointDescription endpoint : endpointRepo.getAllEndpoints()) {
+            notifyListener(NotifyType.ADDED, ep, filters, endpoint);
+        }
+    }
+    
+    public void remove(EndpointListener ep) {
+        LOG.debug("EndpointListener modified");
+        listeners.remove(ep);
+    }
+    
+    @Override
+    public void endpointAdded(EndpointDescription endpoint, String matchedFilter) {
+        notifyListeners(NotifyType.ADDED, endpoint);
+    }
+
+    @Override
+    public void endpointRemoved(EndpointDescription endpoint, String matchedFilter) {
+        notifyListeners(NotifyType.REMOVED, endpoint);
+    }
+
+    /**
+     * 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
+     */
+    private void notifyListeners(NotifyType type, EndpointDescription endpoint) {
+        for (EndpointListener listener : listeners.keySet()) {
+            notifyListener(type, listener, listeners.get(listener), endpoint);
+        }
+    }
+
+    /**
+     * Notifies an endpoint listener about endpoints being added or removed.
+     *
+     * @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
+     */
+    private void notifyListener(NotifyType type, EndpointListener listener, Set<Filter> filters, 
+                        EndpointDescription endpoint) {
+        LOG.debug("Endpoint {}", type);
+        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());
+            }
+        }
+    }
+    
+    private static Set<Filter> getMatchingFilters(Set<Filter> filters, EndpointDescription endpoint) {
+        Set<Filter> matchingFilters = new HashSet<Filter>();
+        Dictionary<String, Object> dict = new Hashtable<String, Object>(endpoint.getProperties());
+        for (Filter filter : filters) {
+            if (filter.match(dict)) {
+                LOG.debug("Filter {} matches endpoint {}", filter, dict);
+                matchingFilters.add(filter);
+            } else {
+                LOG.trace("Filter {} does not match endpoint {}", filter, dict);
+            }
+        }
+        return matchingFilters;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/aries-rsa/blob/d73a3a7f/topology-manager/src/main/java/org/apache/cxf/dosgi/topologymanager/exporter/EndpointRepository.java
----------------------------------------------------------------------
diff --git a/topology-manager/src/main/java/org/apache/cxf/dosgi/topologymanager/exporter/EndpointRepository.java b/topology-manager/src/main/java/org/apache/cxf/dosgi/topologymanager/exporter/EndpointRepository.java
new file mode 100644
index 0000000..2a7bab3
--- /dev/null
+++ b/topology-manager/src/main/java/org/apache/cxf/dosgi/topologymanager/exporter/EndpointRepository.java
@@ -0,0 +1,140 @@
+/**
+ * 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.ArrayList;
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import org.osgi.framework.ServiceReference;
+import org.osgi.service.remoteserviceadmin.EndpointDescription;
+import org.osgi.service.remoteserviceadmin.EndpointListener;
+import org.osgi.service.remoteserviceadmin.RemoteServiceAdmin;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Holds all endpoints that are exported by a TopologyManager. For each ServiceReference that is exported a
+ * map is maintained which contains information on the endpoints for each RemoteAdminService that created the
+ * endpoints.
+ */
+@SuppressWarnings("rawtypes")
+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 EndpointListener notifier;
+    
+    public void setNotifier(EndpointListener notifier) {
+        this.notifier = notifier;
+    }
+    
+    
+    /**
+     * Remove all services exported by the given rsa.
+     *
+     * @param rsa the RemoteServiceAdmin to remove
+     * @return list of removed endpoints
+     */
+    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);
+            if (endpoints != null) {
+                removedEndpoints.addAll(endpoints);
+                exports.remove(rsa);
+            }
+        }
+        endpointsRemoved(removedEndpoints);
+        return removedEndpoints;
+    }
+
+    public synchronized void removeService(ServiceReference sref) {
+        List<EndpointDescription> removedEndpoints = new ArrayList<EndpointDescription>();
+        Map<RemoteServiceAdmin, Collection<EndpointDescription>> rsaToEndpoints = exportedServices.get(sref);
+        if (rsaToEndpoints != null) {
+            for (Collection<EndpointDescription> endpoints : rsaToEndpoints.values()) {
+                removedEndpoints.addAll(endpoints);
+            }
+            exportedServices.remove(sref);
+        }
+        endpointsRemoved(removedEndpoints);
+    }
+
+    public synchronized void addService(ServiceReference sref) {
+        if (!exportedServices.containsKey(sref)) {
+            LOG.info("Marking service from bundle {} for export", sref.getBundle().getSymbolicName());
+            exportedServices.put(sref, new LinkedHashMap<RemoteServiceAdmin, Collection<EndpointDescription>>());
+        }
+    }
+
+    public synchronized void addEndpoints(ServiceReference sref, RemoteServiceAdmin rsa,
+                                   List<EndpointDescription> endpoints) {
+        addService(sref);
+        Map<RemoteServiceAdmin, Collection<EndpointDescription>> exports = exportedServices.get(sref);
+        exports.put(rsa, endpoints);
+        endpointsAdded(endpoints);
+    }
+
+    synchronized boolean isAlreadyExportedForRsa(ServiceReference sref, RemoteServiceAdmin rsa) {
+        Map<RemoteServiceAdmin, Collection<EndpointDescription>> exports = exportedServices.get(sref);
+        return exports != null && exports.containsKey(rsa);
+    }
+
+    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()) {
+                allEndpoints.addAll(endpoints);
+            }
+        }
+        return allEndpoints;
+    }
+
+    public synchronized Set<ServiceReference> getServicesToBeExportedFor(RemoteServiceAdmin rsa) {
+        Set<ServiceReference> servicesToBeExported = new HashSet<ServiceReference>();
+        for (Map.Entry<ServiceReference, Map<RemoteServiceAdmin, Collection<EndpointDescription>>> entry
+                : exportedServices.entrySet()) {
+            if (!entry.getValue().containsKey(rsa)) {
+                servicesToBeExported.add(entry.getKey());
+            }
+        }
+        return servicesToBeExported;
+    }
+
+    private void endpointsAdded(List<EndpointDescription> endpoints) {
+        for (EndpointDescription epd : endpoints) {
+            notifier.endpointAdded(epd, null);
+        }
+    }
+    
+    private void endpointsRemoved(List<EndpointDescription> endpoints) {
+        for (EndpointDescription epd : endpoints) {
+            notifier.endpointRemoved(epd, null);
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/aries-rsa/blob/d73a3a7f/topology-manager/src/main/java/org/apache/cxf/dosgi/topologymanager/exporter/StringPlus.java
----------------------------------------------------------------------
diff --git a/topology-manager/src/main/java/org/apache/cxf/dosgi/topologymanager/exporter/StringPlus.java b/topology-manager/src/main/java/org/apache/cxf/dosgi/topologymanager/exporter/StringPlus.java
new file mode 100644
index 0000000..1198154
--- /dev/null
+++ b/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/aries-rsa/blob/d73a3a7f/topology-manager/src/main/java/org/apache/cxf/dosgi/topologymanager/exporter/TopologyManagerExport.java
----------------------------------------------------------------------
diff --git a/topology-manager/src/main/java/org/apache/cxf/dosgi/topologymanager/exporter/TopologyManagerExport.java b/topology-manager/src/main/java/org/apache/cxf/dosgi/topologymanager/exporter/TopologyManagerExport.java
new file mode 100644
index 0000000..ad3736c
--- /dev/null
+++ b/topology-manager/src/main/java/org/apache/cxf/dosgi/topologymanager/exporter/TopologyManagerExport.java
@@ -0,0 +1,195 @@
+/**
+ * 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.ArrayList;
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.Executor;
+
+import org.apache.cxf.dosgi.dsw.api.ExportPolicy;
+import org.osgi.framework.Bundle;
+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;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Manages exported endpoints of DOSGi services and notifies EndpointListeners of changes.
+ *
+ * <li> Tracks local RemoteServiceAdmin instances by using a ServiceTracker
+ * <li> Uses a ServiceListener to track local OSGi services
+ * <li> When a service is published that is supported by DOSGi the
+ *      known RemoteServiceAdmins are instructed to export the service and
+ *      the EndpointListeners are notified
+ * <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 implements ServiceListener {
+    private static final Logger LOG = LoggerFactory.getLogger(TopologyManagerExport.class);
+
+    private final Executor execService;
+    private final EndpointRepository endpointRepo;
+    private ExportPolicy policy;
+    private final Set<RemoteServiceAdmin> rsaSet;
+
+
+    public TopologyManagerExport(final EndpointRepository endpointRepo, Executor executor, ExportPolicy policy) {
+        this.endpointRepo = endpointRepo;
+        this.policy = policy;
+        this.rsaSet = new HashSet<RemoteServiceAdmin>();
+        this.execService = executor;
+    }
+
+    // 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);
+            export(sref);
+        } else if (event.getType() == ServiceEvent.UNREGISTERING) {
+            LOG.debug("Received UNREGISTERING ServiceEvent: {}", event);
+            endpointRepo.removeService(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);
+    };
+
+    private void export(final ServiceReference<?> sref) {
+        execService.execute(new Runnable() {
+            public void run() {
+                doExport(sref);
+            }
+        });
+    }
+
+    private void doExport(final ServiceReference<?> sref) {
+        Map<String, ?> addProps = policy.additionalParameters(sref);
+        if (!shouldExport(sref, addProps)) {
+            LOG.debug("Skipping service {}", sref);
+            return;
+        }
+        LOG.debug("Exporting service {}", sref);
+        endpointRepo.addService(sref); // mark for future export even if there are currently no RSAs
+        if (rsaSet.size() == 0) {
+            LOG.error("No RemoteServiceAdmin available! Unable to export service from bundle {}, interfaces: {}",
+                    getSymbolicName(sref.getBundle()),
+                    sref.getProperty(org.osgi.framework.Constants.OBJECTCLASS));
+            return;
+        }
+
+        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");
+            } else {
+                
+                exportServiceUsingRemoteServiceAdmin(sref, remoteServiceAdmin, addProps);
+            }
+        }
+    }
+
+    private boolean shouldExport(ServiceReference<?> sref, Map<String, ?> addProps) {
+        String exported = (String)sref.getProperty(RemoteConstants.SERVICE_EXPORTED_INTERFACES);
+        String addExported = (String)addProps.get(RemoteConstants.SERVICE_EXPORTED_INTERFACES);
+        String effectiveExported = addExported != null ? addExported : exported;
+        return (effectiveExported != null) && !effectiveExported.isEmpty();
+    }
+
+    private Object getSymbolicName(Bundle bundle) {
+        return bundle == null ? null : bundle.getSymbolicName();
+    }
+
+    private void exportServiceUsingRemoteServiceAdmin(final ServiceReference<?> sref,
+                                                      final RemoteServiceAdmin remoteServiceAdmin, 
+                                                      Map<String, ?> addProps) {
+        // abort if the service was unregistered by the time we got here
+        // (we check again at the end, but this optimization saves unnecessary heavy processing)
+        if (sref.getBundle() == null) {
+            LOG.info("TopologyManager: export aborted for {} since it was unregistered", sref);
+            endpointRepo.removeService(sref);
+            return;
+        }
+        // do the export
+        LOG.debug("exporting {}...", sref);
+        // TODO: additional parameter Map?
+        Collection<ExportRegistration> exportRegs = remoteServiceAdmin.exportService(sref, addProps);
+        // process successful/failed registrations
+        List<EndpointDescription> endpoints = new ArrayList<EndpointDescription>();
+        for (ExportRegistration reg : exportRegs) {
+            if (reg.getException() == null) {
+                EndpointDescription endpoint = getExportedEndpoint(reg);
+                LOG.info("TopologyManager: export succeeded for {}, endpoint ", sref, endpoint);
+                endpoints.add(endpoint);
+            } else {
+                LOG.error("TopologyManager: export failed for {}", sref);
+                reg.close();
+            }
+        }
+        // abort export if service was unregistered in the meanwhile (since we have a race
+        // with the unregister event which may have already been handled, so we'll miss it)
+        if (sref.getBundle() == null) {
+            LOG.info("TopologyManager: export reverted for {} since service was unregistered", sref);
+            endpointRepo.removeService(sref);
+            for (ExportRegistration reg : exportRegs) {
+                reg.close();
+            }
+            return;
+        }
+        // add the new exported endpoints
+        if (!endpoints.isEmpty()) {
+            LOG.info("TopologyManager: export successful for {}, endpoints: {}", sref, endpoints);
+            endpointRepo.addEndpoints(sref, remoteServiceAdmin, endpoints);
+        }
+    }
+
+    /**
+     * Retrieves an exported Endpoint (while safely handling nulls).
+     *
+     * @param exReg an export registration
+     * @return exported Endpoint or null if not present
+     */
+    private EndpointDescription getExportedEndpoint(ExportRegistration exReg) {
+        ExportReference ref = (exReg == null) ? null : exReg.getExportReference();
+        return (ref == null) ? null : ref.getExportedEndpoint();
+    }
+
+
+}

http://git-wip-us.apache.org/repos/asf/aries-rsa/blob/d73a3a7f/topology-manager/src/main/java/org/apache/cxf/dosgi/topologymanager/importer/EndpointListenerManager.java
----------------------------------------------------------------------
diff --git a/topology-manager/src/main/java/org/apache/cxf/dosgi/topologymanager/importer/EndpointListenerManager.java b/topology-manager/src/main/java/org/apache/cxf/dosgi/topologymanager/importer/EndpointListenerManager.java
new file mode 100644
index 0000000..7812e52
--- /dev/null
+++ b/topology-manager/src/main/java/org/apache/cxf/dosgi/topologymanager/importer/EndpointListenerManager.java
@@ -0,0 +1,98 @@
+/**
+ * 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.ArrayList;
+import java.util.Dictionary;
+import java.util.Hashtable;
+import java.util.List;
+
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.ServiceRegistration;
+import org.osgi.service.remoteserviceadmin.EndpointListener;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Manages an EndpointListener and adjusts its scope according to requested service filters.
+ */
+public class EndpointListenerManager {
+
+    private static final Logger LOG = LoggerFactory.getLogger(EndpointListenerManager.class);
+
+    private final BundleContext bctx;
+    private volatile ServiceRegistration<EndpointListener> serviceRegistration;
+    private final List<String> filters = new ArrayList<String>();
+    private final EndpointListener endpointListener;
+
+    public EndpointListenerManager(BundleContext bc, EndpointListener endpointListener) {
+        this.bctx = bc;
+        this.endpointListener = endpointListener;
+    }
+
+    protected void start() {
+        serviceRegistration = bctx.registerService(EndpointListener.class, endpointListener,
+                                                   getRegistrationProperties());
+    }
+
+    public void stop() {
+        if (serviceRegistration != null) {
+            serviceRegistration.unregister();
+        }
+    }
+
+    protected void extendScope(String filter) {
+        if (filter == null) {
+            return;
+        }
+        LOG.debug("EndpointListener: extending scope by {}", filter);
+        synchronized (filters) {
+            filters.add(filter);
+        }
+        updateRegistration();
+    }
+
+    protected void reduceScope(String filter) {
+        if (filter == null) {
+            return;
+        }
+        LOG.debug("EndpointListener: reducing scope by {}", filter);
+        synchronized (filters) {
+            filters.remove(filter);
+        }
+        updateRegistration();
+    }
+
+    private Dictionary<String, Object> getRegistrationProperties() {
+        Dictionary<String, Object> p = new Hashtable<String, Object>();
+
+        synchronized (filters) {
+            LOG.debug("Current filter: {}", filters);
+            p.put(EndpointListener.ENDPOINT_LISTENER_SCOPE, new ArrayList<String>(filters));
+        }
+
+        return p;
+    }
+
+    private void updateRegistration() {
+        if (serviceRegistration != null) {
+            serviceRegistration.setProperties(getRegistrationProperties());
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/aries-rsa/blob/d73a3a7f/topology-manager/src/main/java/org/apache/cxf/dosgi/topologymanager/importer/FilterHelper.java
----------------------------------------------------------------------
diff --git a/topology-manager/src/main/java/org/apache/cxf/dosgi/topologymanager/importer/FilterHelper.java b/topology-manager/src/main/java/org/apache/cxf/dosgi/topologymanager/importer/FilterHelper.java
new file mode 100644
index 0000000..3739f16
--- /dev/null
+++ b/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/aries-rsa/blob/d73a3a7f/topology-manager/src/main/java/org/apache/cxf/dosgi/topologymanager/importer/ListenerHookImpl.java
----------------------------------------------------------------------
diff --git a/topology-manager/src/main/java/org/apache/cxf/dosgi/topologymanager/importer/ListenerHookImpl.java b/topology-manager/src/main/java/org/apache/cxf/dosgi/topologymanager/importer/ListenerHookImpl.java
new file mode 100644
index 0000000..03ec9da
--- /dev/null
+++ b/topology-manager/src/main/java/org/apache/cxf/dosgi/topologymanager/importer/ListenerHookImpl.java
@@ -0,0 +1,119 @@
+/**
+ * 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.Collection;
+import java.util.HashSet;
+import java.util.Set;
+
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.Constants;
+import org.osgi.framework.hooks.service.ListenerHook;
+import org.osgi.service.remoteserviceadmin.RemoteConstants;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Listens for service listeners and informs ServiceInterestListener about added and removed interest
+ * in services
+ */
+public class ListenerHookImpl implements ListenerHook {
+
+    private static final Logger LOG = LoggerFactory.getLogger(ListenerHookImpl.class);
+
+    // From the old impl.
+    private static final Set<String> SYSTEM_PACKAGES;
+    static {
+        SYSTEM_PACKAGES = new HashSet<String>();
+        SYSTEM_PACKAGES.add("org.osgi.service");
+        SYSTEM_PACKAGES.add("org.apache.felix");
+        SYSTEM_PACKAGES.add("org.ops4j.pax.logging");
+        SYSTEM_PACKAGES.add("ch.ethz.iks.slp");
+        SYSTEM_PACKAGES.add("org.ungoverned.osgi.service");
+        SYSTEM_PACKAGES.add("org.springframework.osgi.context.event.OsgiBundleApplicationContextListener");
+        SYSTEM_PACKAGES.add("java.net.ContentHandler");
+    }
+
+    private final BundleContext bctx;
+    private final ServiceInterestListener serviceInterestListener;
+    private final String frameworkUUID;
+
+    public ListenerHookImpl(BundleContext bc, ServiceInterestListener serviceInterestListener) {
+        this.bctx = bc;
+        this.frameworkUUID = bctx.getProperty(Constants.FRAMEWORK_UUID);
+        this.serviceInterestListener = serviceInterestListener;
+    }
+
+    @Override
+    public void added(Collection<ListenerInfo> listeners) {
+        LOG.debug("added listeners {}", listeners);
+        for (ListenerInfo listenerInfo : listeners) {
+            LOG.debug("Filter {}", listenerInfo.getFilter());
+
+            String className = FilterHelper.getObjectClass(listenerInfo.getFilter());
+
+            if (listenerInfo.getBundleContext().equals(bctx)) {
+                LOG.debug("ListenerHookImpl: skipping request from myself");
+                continue;
+            }
+
+            if (listenerInfo.getFilter() == null) {
+                LOG.debug("skipping empty filter");
+                continue;
+            }
+
+            if (isClassExcluded(className)) {
+                LOG.debug("Skipping import request for excluded class [{}]", className);
+                continue;
+            }
+            String exFilter = extendFilter(listenerInfo.getFilter());
+            serviceInterestListener.addServiceInterest(exFilter);
+        }
+    }
+
+    @Override
+    public void removed(Collection<ListenerInfo> listeners) {
+        LOG.debug("removed listeners {}", listeners);
+
+        for (ListenerInfo listenerInfo : listeners) {
+            LOG.debug("Filter {}", listenerInfo.getFilter());
+
+            // TODO: determine if service was handled?
+            String exFilter = extendFilter(listenerInfo.getFilter());
+            serviceInterestListener.removeServiceInterest(exFilter);
+        }
+    }
+
+    private static boolean isClassExcluded(String className) {
+        if (className == null) {
+            return true;
+        }
+
+        for (String p : SYSTEM_PACKAGES) {
+            if (className.startsWith(p)) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    String extendFilter(String filter) {
+        return "(&" + filter + "(!(" + RemoteConstants.ENDPOINT_FRAMEWORK_UUID + "=" + frameworkUUID + ")))";
+    }
+}

http://git-wip-us.apache.org/repos/asf/aries-rsa/blob/d73a3a7f/topology-manager/src/main/java/org/apache/cxf/dosgi/topologymanager/importer/RSATracker.java
----------------------------------------------------------------------
diff --git a/topology-manager/src/main/java/org/apache/cxf/dosgi/topologymanager/importer/RSATracker.java b/topology-manager/src/main/java/org/apache/cxf/dosgi/topologymanager/importer/RSATracker.java
new file mode 100644
index 0000000..56e98e8
--- /dev/null
+++ b/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/aries-rsa/blob/d73a3a7f/topology-manager/src/main/java/org/apache/cxf/dosgi/topologymanager/importer/ReferenceCounter.java
----------------------------------------------------------------------
diff --git a/topology-manager/src/main/java/org/apache/cxf/dosgi/topologymanager/importer/ReferenceCounter.java b/topology-manager/src/main/java/org/apache/cxf/dosgi/topologymanager/importer/ReferenceCounter.java
new file mode 100644
index 0000000..6ecff31
--- /dev/null
+++ b/topology-manager/src/main/java/org/apache/cxf/dosgi/topologymanager/importer/ReferenceCounter.java
@@ -0,0 +1,76 @@
+/**
+ * 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.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
+
+/**
+ * Manages a reference count per key.
+ *
+ * @param <K> the key type
+ */
+public class ReferenceCounter<K> {
+
+    private final ConcurrentMap<K, Integer> counts = new ConcurrentHashMap<K, Integer>();
+
+    /**
+     * Increases the reference count for the given key,
+     * or sets it to 1 if the key has no existing count.
+     *
+     * @param key a key
+     * @return the updated reference count
+     */
+    public int add(K key) {
+        while (true) {
+            Integer count = counts.get(key);
+            if (count == null) {
+                if (counts.putIfAbsent(key, 1) == null) {
+                    return 1;
+                }
+            } else if (counts.replace(key, count, count + 1)) {
+                return count + 1;
+            }
+        }
+    }
+
+    /**
+     * Decreases the reference count for the given key,
+     * and removes it if it reaches 0.
+     * If the key has no existing count, -1 is returned.
+     *
+     * @param key a key
+     * @return the updated reference count, or -1 if the key has no existing count
+     */
+    public int remove(K key) {
+        while (true) {
+            Integer count = counts.get(key);
+            if (count == null) {
+                return -1;
+            }
+            if (count == 1) {
+                if (counts.remove(key, 1)) {
+                    return 0;
+                }
+            } else if (counts.replace(key, count, count - 1)) {
+                return count - 1;
+            }
+        }
+    }
+}