[maven-release-plugin]  copy for tag cxf-dosgi-ri-1.6.0

git-svn-id: https://svn.apache.org/repos/asf/cxf/dosgi/tags/cxf-dosgi-ri-1.6.0@1558808 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/trunk/.gitignore b/trunk/.gitignore
new file mode 100644
index 0000000..9629ccf
--- /dev/null
+++ b/trunk/.gitignore
@@ -0,0 +1,10 @@
+*.i??
+.DS_Store
+.checkstyle
+.classpath
+.pmd
+.project
+.ruleset
+.settings/
+target/
+velocity.log
diff --git a/trunk/discovery/distributed/cxf-discovery/pom.xml b/trunk/discovery/distributed/cxf-discovery/pom.xml
new file mode 100644
index 0000000..608af11
--- /dev/null
+++ b/trunk/discovery/distributed/cxf-discovery/pom.xml
@@ -0,0 +1,117 @@
+<?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>
+    <artifactId>cxf-dosgi-ri-discovery-distributed</artifactId>
+    <packaging>bundle</packaging>
+    <name>CXF DOSGi ZooKeeper-based Discovery Service Bundle</name>
+    <description>An implementation of the Distributed OSGi Discovery Service using ZooKeeper</description>
+
+    <parent>
+        <groupId>org.apache.cxf.dosgi</groupId>
+        <artifactId>cxf-dosgi-ri-parent</artifactId>
+        <version>1.6.0</version>
+        <relativePath>../../../parent/pom.xml</relativePath>
+    </parent>
+
+    <properties>
+        <topDirectoryLocation>../../..</topDirectoryLocation>
+    </properties>
+
+    <dependencies>
+        <dependency>
+            <groupId>org.osgi</groupId>
+            <artifactId>org.osgi.core</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.osgi</groupId>
+            <artifactId>org.osgi.compendium</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>org.apache.zookeeper</groupId>
+            <artifactId>zookeeper</artifactId>
+            <version>${zookeeper.version}</version>
+            <exclusions>
+                <exclusion>
+                    <groupId>com.sun.jdmk</groupId>
+                    <artifactId>jmxtools</artifactId>
+                </exclusion>
+                <exclusion>
+                    <groupId>com.sun.jmx</groupId>
+                    <artifactId>jmxri</artifactId>
+                </exclusion>
+                <exclusion>
+                    <groupId>log4j</groupId>
+                    <artifactId>log4j</artifactId>
+                </exclusion>
+            </exclusions>
+        </dependency>
+
+        <!--  We need the newer log4j as the one from zookeeper has some ugly dependencies -->
+        <dependency>
+            <groupId>log4j</groupId>
+            <artifactId>log4j</artifactId>
+            <version>${log4j.version}</version>
+        </dependency>
+
+        <dependency>
+            <groupId>org.apache.cxf.dosgi</groupId>
+            <artifactId>cxf-dosgi-ri-discovery-local</artifactId>
+            <version>${project.version}</version>
+            <scope>provided</scope>
+        </dependency>
+
+        <dependency>
+            <groupId>org.slf4j</groupId>
+            <artifactId>slf4j-api</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>junit</groupId>
+            <artifactId>junit</artifactId>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.easymock</groupId>
+            <artifactId>easymockclassextension</artifactId>
+            <scope>test</scope>
+        </dependency>
+    </dependencies>
+
+    <build>
+        <plugins>
+            <plugin>
+                <groupId>org.apache.felix</groupId>
+                <artifactId>maven-bundle-plugin</artifactId>
+                <configuration>
+                    <instructions>
+                        <Bundle-SymbolicName>${project.artifactId}</Bundle-SymbolicName>
+                        <Bundle-Activator>org.apache.cxf.dosgi.discovery.zookeeper.Activator</Bundle-Activator>
+                        <Export-Package>
+                            !*
+                        </Export-Package>
+                    </instructions>
+                </configuration>
+            </plugin>
+        </plugins>
+    </build>
+</project>
diff --git a/trunk/discovery/distributed/cxf-discovery/src/main/java/org/apache/cxf/dosgi/discovery/zookeeper/Activator.java b/trunk/discovery/distributed/cxf-discovery/src/main/java/org/apache/cxf/dosgi/discovery/zookeeper/Activator.java
new file mode 100644
index 0000000..cbbea58
--- /dev/null
+++ b/trunk/discovery/distributed/cxf-discovery/src/main/java/org/apache/cxf/dosgi/discovery/zookeeper/Activator.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.discovery.zookeeper;
+
+import java.util.Dictionary;
+import java.util.Hashtable;
+
+import org.osgi.framework.BundleActivator;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.Constants;
+import org.osgi.service.cm.ManagedService;
+
+public class Activator implements BundleActivator {
+
+    private ZooKeeperDiscovery zkd;
+
+    public synchronized void start(BundleContext bc) throws Exception {
+        zkd = new ZooKeeperDiscovery(bc);
+        Dictionary<String, String> props = new Hashtable<String, String>();
+        props.put(Constants.SERVICE_PID, "org.apache.cxf.dosgi.discovery.zookeeper");
+        bc.registerService(ManagedService.class.getName(), zkd, props);
+    }
+
+    public synchronized void stop(BundleContext bc) throws Exception {
+        zkd.stop(true);
+    }
+}
diff --git a/trunk/discovery/distributed/cxf-discovery/src/main/java/org/apache/cxf/dosgi/discovery/zookeeper/ZooKeeperDiscovery.java b/trunk/discovery/distributed/cxf-discovery/src/main/java/org/apache/cxf/dosgi/discovery/zookeeper/ZooKeeperDiscovery.java
new file mode 100644
index 0000000..191ced2
--- /dev/null
+++ b/trunk/discovery/distributed/cxf-discovery/src/main/java/org/apache/cxf/dosgi/discovery/zookeeper/ZooKeeperDiscovery.java
@@ -0,0 +1,153 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.cxf.dosgi.discovery.zookeeper;
+
+import java.io.IOException;
+import java.util.Dictionary;
+
+import org.apache.cxf.dosgi.discovery.zookeeper.publish.PublishingEndpointListenerFactory;
+import org.apache.cxf.dosgi.discovery.zookeeper.subscribe.EndpointListenerTracker;
+import org.apache.cxf.dosgi.discovery.zookeeper.subscribe.InterfaceMonitorManager;
+import org.apache.cxf.dosgi.discovery.zookeeper.util.Utils;
+import org.apache.zookeeper.WatchedEvent;
+import org.apache.zookeeper.Watcher;
+import org.apache.zookeeper.ZooKeeper;
+import org.osgi.framework.BundleContext;
+import org.osgi.service.cm.ConfigurationException;
+import org.osgi.service.cm.ManagedService;
+import org.osgi.service.remoteserviceadmin.EndpointListener;
+import org.osgi.util.tracker.ServiceTracker;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class ZooKeeperDiscovery implements Watcher, ManagedService {
+
+    public static final String DISCOVERY_ZOOKEEPER_ID = "org.apache.cxf.dosgi.discovery.zookeeper";
+
+    private static final Logger LOG = LoggerFactory.getLogger(ZooKeeperDiscovery.class);
+
+    private final BundleContext bctx;
+
+    private PublishingEndpointListenerFactory endpointListenerFactory;
+    private ServiceTracker<EndpointListener, EndpointListener> endpointListenerTracker;
+    private InterfaceMonitorManager imManager;
+    private ZooKeeper zk;
+    private boolean closed;
+    private boolean started;
+
+    private Dictionary<String , ?> curConfiguration;
+
+    public ZooKeeperDiscovery(BundleContext bctx) {
+        this.bctx = bctx;
+        this.curConfiguration = null;
+    }
+
+    public synchronized void updated(Dictionary<String, ?> configuration) throws ConfigurationException {
+        LOG.debug("Received configuration update for Zookeeper Discovery: {}", configuration);
+
+        stop(false);
+
+        if (configuration == null) {
+            return;
+        }
+        curConfiguration = configuration;
+        createZooKeeper(configuration);
+    }
+
+    private synchronized void start() {
+        if (closed) {
+            return;
+        }
+        if (started) {
+            // we must be re-entrant, i.e. can be called when already started
+            LOG.debug("ZookeeperDiscovery already started");
+            return;
+        }
+        LOG.debug("starting ZookeeperDiscovery");
+        endpointListenerFactory = new PublishingEndpointListenerFactory(zk, bctx);
+        endpointListenerFactory.start();
+        imManager = new InterfaceMonitorManager(bctx, zk);
+        endpointListenerTracker = new EndpointListenerTracker(bctx, imManager); 
+        endpointListenerTracker.open();
+        started = true;
+    }
+
+    public synchronized void stop(boolean close) {
+        if (started) {
+            LOG.debug("stopping ZookeeperDiscovery");
+        }
+        started = false;
+        closed |= close;
+        if (endpointListenerFactory != null) {
+            endpointListenerFactory.stop();
+        }
+        if (endpointListenerTracker != null) {
+            endpointListenerTracker.close();
+        }
+        if (imManager != null) {
+            imManager.close();
+        }
+        if (zk != null) {
+            try {
+                zk.close();
+            } catch (InterruptedException e) {
+                LOG.error("Error closing ZooKeeper", e);
+            }
+        }
+    }
+
+    private synchronized void createZooKeeper(Dictionary<String, ?> props) {
+        if (closed) {
+            return;
+        }
+        String host = Utils.getProp(props, "zookeeper.host", "localhost");
+        String port = Utils.getProp(props, "zookeeper.port", "2181");
+        int timeout = Utils.getProp(props, "zookeeper.timeout", 3000);
+        LOG.debug("ZooKeeper configuration: connecting to {}:{} with timeout {}",
+                new Object[]{host, port, timeout});
+        try {
+            zk = new ZooKeeper(host + ":" + port, timeout, this);
+        } catch (IOException e) {
+            LOG.error("Failed to start the ZooKeeper Discovery component.", e);
+        }
+    }
+
+    /* Callback for ZooKeeper */
+    public void process(WatchedEvent event) {
+        LOG.debug("got ZooKeeper event " + event);
+        switch (event.getState()) {
+        case SyncConnected:
+            LOG.info("Connection to ZooKeeper established");
+            // this event can be triggered more than once in a row (e.g. after Disconnected event),
+            // so we must be re-entrant here
+            start();
+            break;
+
+        case Expired:
+            LOG.info("Connection to ZooKeeper expired. Trying to create a new connection");
+            stop(false);
+            createZooKeeper(curConfiguration);
+            break;
+
+        default:
+            // ignore other events
+            break;
+        }
+    }
+}
diff --git a/trunk/discovery/distributed/cxf-discovery/src/main/java/org/apache/cxf/dosgi/discovery/zookeeper/publish/DiscoveryPlugin.java b/trunk/discovery/distributed/cxf-discovery/src/main/java/org/apache/cxf/dosgi/discovery/zookeeper/publish/DiscoveryPlugin.java
new file mode 100644
index 0000000..5d46585
--- /dev/null
+++ b/trunk/discovery/distributed/cxf-discovery/src/main/java/org/apache/cxf/dosgi/discovery/zookeeper/publish/DiscoveryPlugin.java
@@ -0,0 +1,54 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.cxf.dosgi.discovery.zookeeper.publish;
+
+import java.util.Map;
+
+/**
+ * This interface allows transformation of service registration information before it is pushed into the ZooKeeper
+ * discovery system.
+ * It can be useful for situations where a host name or port number needs to be changed in cases where the host running
+ * the service is known differently from the outside to what the local Java process thinks it is.
+ * Extra service properties can also be added to the registration which can be useful to refine the remote service
+ * lookup process. <p/>
+ *
+ * DiscoveryPlugins use the OSGi WhiteBoard pattern. To add one to the system, register an instance under this interface
+ * with the OSGi Service Registry. All registered DiscoveryPlugin instances are visited and given a chance to
+ * process the information before it is pushed into ZooKeeper. <p/>
+ *
+ * Note that the changes made using this plugin do not modify the local service registration.
+ *
+ */
+public interface DiscoveryPlugin {
+
+    /**
+     * Process service registration information. Plugins can change this information before it is published into the
+     * ZooKeeper discovery system.
+     *
+     * @param mutableProperties A map of service registration properties. The map is mutable and any changes to the map
+     * will be reflected in the ZooKeeper registration.
+     * @param endpointKey The key under which the service is registered in ZooKeeper. This key typically has the
+     * following format: hostname#port##context. While the actual value of this key is not actually used by the
+     * system (people can use it as a hint to understand where the service is located), the value <i>must</i> be
+     * unique for all services of a given type.
+     * @return The <tt>endpointKey</tt> value to be used. If there is no need to change this simply return the value
+     * of the <tt>endpointKey</tt> parameter.
+     */
+    String process(Map<String, Object> mutableProperties, String endpointKey);
+}
diff --git a/trunk/discovery/distributed/cxf-discovery/src/main/java/org/apache/cxf/dosgi/discovery/zookeeper/publish/PublishingEndpointListener.java b/trunk/discovery/distributed/cxf-discovery/src/main/java/org/apache/cxf/dosgi/discovery/zookeeper/publish/PublishingEndpointListener.java
new file mode 100644
index 0000000..c703b9f
--- /dev/null
+++ b/trunk/discovery/distributed/cxf-discovery/src/main/java/org/apache/cxf/dosgi/discovery/zookeeper/publish/PublishingEndpointListener.java
@@ -0,0 +1,216 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.cxf.dosgi.discovery.zookeeper.publish;
+
+import java.io.IOException;
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.net.UnknownHostException;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.cxf.dosgi.discovery.zookeeper.util.Utils;
+import org.apache.cxf.dosgi.endpointdesc.EndpointDescriptionParser;
+import org.apache.cxf.dosgi.endpointdesc.PropertiesMapper;
+import org.apache.zookeeper.CreateMode;
+import org.apache.zookeeper.KeeperException;
+import org.apache.zookeeper.KeeperException.NoNodeException;
+import org.apache.zookeeper.KeeperException.NodeExistsException;
+import org.apache.zookeeper.ZooDefs.Ids;
+import org.apache.zookeeper.ZooKeeper;
+import org.osgi.framework.BundleContext;
+import org.osgi.service.remoteserviceadmin.EndpointDescription;
+import org.osgi.service.remoteserviceadmin.EndpointListener;
+import org.osgi.util.tracker.ServiceTracker;
+import org.osgi.xmlns.rsa.v1_0.EndpointDescriptionType;
+import org.osgi.xmlns.rsa.v1_0.PropertyType;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Listens for local Endpoints and publishes them to ZooKeeper.
+ */
+public class PublishingEndpointListener implements EndpointListener {
+
+    private static final Logger LOG = LoggerFactory.getLogger(PublishingEndpointListener.class);
+
+    private final ZooKeeper zk;
+    private final ServiceTracker<DiscoveryPlugin, DiscoveryPlugin> discoveryPluginTracker;
+    private final List<EndpointDescription> endpoints = new ArrayList<EndpointDescription>();
+    private boolean closed;
+
+    private final EndpointDescriptionParser endpointDescriptionParser;
+
+    public PublishingEndpointListener(ZooKeeper zk, BundleContext bctx) {
+        this.zk = zk;
+        discoveryPluginTracker = new ServiceTracker<DiscoveryPlugin, DiscoveryPlugin>(bctx, 
+            DiscoveryPlugin.class, null);
+        discoveryPluginTracker.open();
+        endpointDescriptionParser = new EndpointDescriptionParser();
+    }
+
+    public void endpointAdded(EndpointDescription endpoint, String matchedFilter) {
+        LOG.info("Local EndpointDescription added: {}", endpoint);
+
+        synchronized (endpoints) {
+            if (closed) {
+                return;
+            }
+            if (endpoints.contains(endpoint)) {
+                // TODO -> Should the published endpoint be updated here?
+                return;
+            }
+
+            try {
+                addEndpoint(endpoint);
+                endpoints.add(endpoint);
+            } catch (Exception ex) {
+                LOG.error("Exception while processing the addition of an endpoint.", ex);
+            }
+        }
+    }
+
+    private void addEndpoint(EndpointDescription endpoint) throws URISyntaxException, KeeperException,
+                                                                  InterruptedException, IOException {
+        Collection<String> interfaces = endpoint.getInterfaces();
+        String endpointKey = getKey(endpoint.getId());
+        Map<String, Object> props = new HashMap<String, Object>(endpoint.getProperties());
+
+        // process plugins
+        Object[] plugins = discoveryPluginTracker.getServices();
+        if (plugins != null) {
+            for (Object plugin : plugins) {
+                if (plugin instanceof DiscoveryPlugin) {
+                    endpointKey = ((DiscoveryPlugin)plugin).process(props, endpointKey);
+                }
+            }
+        }
+
+        for (String name : interfaces) {
+            String path = Utils.getZooKeeperPath(name);
+            String fullPath = path + '/' + endpointKey;
+            LOG.debug("Creating ZooKeeper node: {}", fullPath);
+            ensurePath(path, zk);
+            List<PropertyType> propsOut = new PropertiesMapper().fromProps(props);
+            EndpointDescriptionType epd = new EndpointDescriptionType();
+            epd.getProperty().addAll(propsOut);
+            byte[] epData = endpointDescriptionParser.getData(epd);
+            createEphemeralNode(fullPath, epData);
+        }
+    }
+
+    private void createEphemeralNode(String fullPath, byte[] data) throws KeeperException, InterruptedException {
+        try {
+            zk.create(fullPath, data, Ids.OPEN_ACL_UNSAFE, CreateMode.EPHEMERAL);
+        } catch (NodeExistsException nee) {
+            // this sometimes happens after a ZooKeeper node dies and the ephemeral node
+            // that belonged to the old session was not yet deleted. We need to make our
+            // session the owner of the node so it won't get deleted automatically -
+            // we do this by deleting and recreating it ourselves.
+            LOG.info("node for endpoint already exists, recreating: {}", fullPath);
+            try {
+                zk.delete(fullPath, -1);
+            } catch (NoNodeException nne) {
+                // it's a race condition, but as long as it got deleted - it's ok
+            }
+            zk.create(fullPath, data, Ids.OPEN_ACL_UNSAFE, CreateMode.EPHEMERAL);
+        }
+    }
+
+    public void endpointRemoved(EndpointDescription endpoint, String matchedFilter) {
+        LOG.info("Local EndpointDescription removed: {}", endpoint);
+
+        synchronized (endpoints) {
+            if (closed) {
+                return;
+            }
+            if (!endpoints.contains(endpoint)) {
+                return;
+            }
+
+            try {
+                removeEndpoint(endpoint);
+                endpoints.remove(endpoint);
+            } catch (Exception ex) {
+                LOG.error("Exception while processing the removal of an endpoint", ex);
+            }
+        }
+    }
+
+    private void removeEndpoint(EndpointDescription endpoint) throws UnknownHostException, URISyntaxException {
+        Collection<String> interfaces = endpoint.getInterfaces();
+        String endpointKey = getKey(endpoint.getId());
+
+        for (String name : interfaces) {
+            String path = Utils.getZooKeeperPath(name);
+            String fullPath = path + '/' + endpointKey;
+            LOG.debug("Removing ZooKeeper node: {}", fullPath);
+            try {
+                zk.delete(fullPath, -1);
+            } catch (Exception ex) {
+                LOG.debug("Error while removing endpoint: {}", ex); // e.g. session expired
+            }
+        }
+    }
+
+    private static void ensurePath(String path, ZooKeeper zk) throws KeeperException, InterruptedException {
+        StringBuilder current = new StringBuilder();
+        String[] parts = Utils.removeEmpty(path.split("/"));
+        for (String part : parts) {
+            current.append('/');
+            current.append(part);
+            try {
+                zk.create(current.toString(), new byte[0], Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);
+            } catch (NodeExistsException nee) {
+                // it's not the first node with this path to ever exist - that's normal
+            }
+        }
+    }
+
+    static String getKey(String endpoint) throws URISyntaxException {
+        URI uri = new URI(endpoint);
+
+        StringBuilder sb = new StringBuilder();
+        sb.append(uri.getHost());
+        sb.append("#");
+        sb.append(uri.getPort());
+        sb.append("#");
+        sb.append(uri.getPath().replace('/', '#'));
+        return sb.toString();
+    }
+
+    public void close() {
+        LOG.debug("closing - removing all endpoints");
+        synchronized (endpoints) {
+            closed = true;
+            for (EndpointDescription endpoint : endpoints) {
+                try {
+                    removeEndpoint(endpoint);
+                } catch (Exception ex) {
+                    LOG.error("Exception while removing endpoint during close", ex);
+                }
+            }
+            endpoints.clear();
+        }
+        discoveryPluginTracker.close();
+    }
+}
diff --git a/trunk/discovery/distributed/cxf-discovery/src/main/java/org/apache/cxf/dosgi/discovery/zookeeper/publish/PublishingEndpointListenerFactory.java b/trunk/discovery/distributed/cxf-discovery/src/main/java/org/apache/cxf/dosgi/discovery/zookeeper/publish/PublishingEndpointListenerFactory.java
new file mode 100644
index 0000000..c505bb4
--- /dev/null
+++ b/trunk/discovery/distributed/cxf-discovery/src/main/java/org/apache/cxf/dosgi/discovery/zookeeper/publish/PublishingEndpointListenerFactory.java
@@ -0,0 +1,105 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.cxf.dosgi.discovery.zookeeper.publish;
+
+import java.util.ArrayList;
+import java.util.Dictionary;
+import java.util.Hashtable;
+import java.util.List;
+
+import org.apache.cxf.dosgi.discovery.zookeeper.ZooKeeperDiscovery;
+import org.apache.cxf.dosgi.discovery.zookeeper.util.Utils;
+import org.apache.zookeeper.ZooKeeper;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.Constants;
+import org.osgi.framework.ServiceFactory;
+import org.osgi.framework.ServiceRegistration;
+import org.osgi.service.remoteserviceadmin.EndpointListener;
+import org.osgi.service.remoteserviceadmin.RemoteConstants;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Creates local EndpointListeners that publish to ZooKeeper.
+ */
+public class PublishingEndpointListenerFactory implements ServiceFactory<PublishingEndpointListener> {
+
+    private static final Logger LOG = LoggerFactory.getLogger(PublishingEndpointListenerFactory.class);
+
+    private final BundleContext bctx;
+    private final ZooKeeper zk;
+    private final List<PublishingEndpointListener> listeners = new ArrayList<PublishingEndpointListener>();
+    private ServiceRegistration serviceRegistration;
+
+    public PublishingEndpointListenerFactory(ZooKeeper zk, BundleContext bctx) {
+        this.bctx = bctx;
+        this.zk = zk;
+    }
+
+    public PublishingEndpointListener getService(Bundle b, ServiceRegistration<PublishingEndpointListener> sr) {
+        LOG.debug("new EndpointListener from factory");
+        synchronized (listeners) {
+            PublishingEndpointListener pel = new PublishingEndpointListener(zk, bctx);
+            listeners.add(pel);
+            return pel;
+        }
+    }
+
+    public void ungetService(Bundle b, ServiceRegistration<PublishingEndpointListener> sr, 
+                             PublishingEndpointListener pel) {
+        LOG.debug("remove EndpointListener");
+        synchronized (listeners) {
+            if (listeners.remove(pel)) {
+                pel.close();
+            }
+        }
+    }
+
+    public synchronized void start() {
+        Dictionary<String, String> props = new Hashtable<String, String>();
+        props.put(EndpointListener.ENDPOINT_LISTENER_SCOPE,
+                  "(&(" + Constants.OBJECTCLASS + "=*)(" + RemoteConstants.ENDPOINT_FRAMEWORK_UUID
+                  + "=" + Utils.getUUID(bctx) + "))");
+        props.put(ZooKeeperDiscovery.DISCOVERY_ZOOKEEPER_ID, "true");
+        serviceRegistration = bctx.registerService(EndpointListener.class.getName(), this, props);
+    }
+
+    public synchronized void stop() {
+        if (serviceRegistration != null) {
+            serviceRegistration.unregister();
+            serviceRegistration = null;
+        }
+        synchronized (listeners) {
+            for (PublishingEndpointListener pel : listeners) {
+                pel.close();
+            }
+            listeners.clear();
+        }
+    }
+
+    /**
+     * Only for the test case!
+     */
+    protected List<PublishingEndpointListener> getListeners() {
+        synchronized (listeners) {
+            return listeners;
+        }
+    }
+}
diff --git a/trunk/discovery/distributed/cxf-discovery/src/main/java/org/apache/cxf/dosgi/discovery/zookeeper/subscribe/EndpointListenerTracker.java b/trunk/discovery/distributed/cxf-discovery/src/main/java/org/apache/cxf/dosgi/discovery/zookeeper/subscribe/EndpointListenerTracker.java
new file mode 100644
index 0000000..59e8c66
--- /dev/null
+++ b/trunk/discovery/distributed/cxf-discovery/src/main/java/org/apache/cxf/dosgi/discovery/zookeeper/subscribe/EndpointListenerTracker.java
@@ -0,0 +1,53 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.cxf.dosgi.discovery.zookeeper.subscribe;
+
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.ServiceReference;
+import org.osgi.service.remoteserviceadmin.EndpointListener;
+import org.osgi.util.tracker.ServiceTracker;
+
+/**
+ * Tracks interest in EndpointListeners. Delegates to InterfaceMonitorManager to manage
+ * interest in the scopes of each EndpointListener.
+ */
+public class EndpointListenerTracker extends ServiceTracker<EndpointListener, EndpointListener> {
+    private final InterfaceMonitorManager imManager;
+
+    public EndpointListenerTracker(BundleContext bctx, InterfaceMonitorManager imManager) {
+        super(bctx, EndpointListener.class, null);
+        this.imManager = imManager;
+    }
+
+    public EndpointListener addingService(ServiceReference<EndpointListener> endpointListener) {
+        imManager.addInterest(endpointListener);
+        return null;
+    }
+
+    public void modifiedService(ServiceReference<EndpointListener> endpointListener, EndpointListener service) {
+        // called when an EndpointListener updates its service properties,
+        // e.g. when its interest scope is expanded/reduced
+        imManager.addInterest(endpointListener);
+    }
+
+    public void removedService(ServiceReference<EndpointListener> endpointListener, EndpointListener service) {
+        imManager.removeInterest(endpointListener);
+    }
+
+}
diff --git a/trunk/discovery/distributed/cxf-discovery/src/main/java/org/apache/cxf/dosgi/discovery/zookeeper/subscribe/InterfaceMonitor.java b/trunk/discovery/distributed/cxf-discovery/src/main/java/org/apache/cxf/dosgi/discovery/zookeeper/subscribe/InterfaceMonitor.java
new file mode 100644
index 0000000..95277d3
--- /dev/null
+++ b/trunk/discovery/distributed/cxf-discovery/src/main/java/org/apache/cxf/dosgi/discovery/zookeeper/subscribe/InterfaceMonitor.java
@@ -0,0 +1,262 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.cxf.dosgi.discovery.zookeeper.subscribe;
+
+import java.io.ByteArrayInputStream;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.cxf.dosgi.discovery.zookeeper.util.Utils;
+import org.apache.cxf.dosgi.endpointdesc.EndpointDescriptionParser;
+import org.apache.cxf.dosgi.endpointdesc.PropertiesMapper;
+import org.apache.zookeeper.AsyncCallback.StatCallback;
+import org.apache.zookeeper.KeeperException;
+import org.apache.zookeeper.KeeperException.Code;
+import org.apache.zookeeper.WatchedEvent;
+import org.apache.zookeeper.Watcher;
+import org.apache.zookeeper.ZooKeeper;
+import org.apache.zookeeper.data.Stat;
+import org.osgi.service.remoteserviceadmin.EndpointDescription;
+import org.osgi.service.remoteserviceadmin.EndpointListener;
+import org.osgi.xmlns.rsa.v1_0.EndpointDescriptionType;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Monitors ZooKeeper for changes in published endpoints.
+ * <p>
+ * Specifically, it monitors the node path associated with a given interface class,
+ * whose data is a serialized version of an EndpointDescription, and notifies an
+ * EndpointListener when changes are detected (which can then propagate the
+ * notification to other EndpointListeners with a matching scope).
+ * <p>
+ * Note that the EndpointListener is used here as a decoupling interface for
+ * convenience, and is not necessarily used according to its documented contract.
+ */
+public class InterfaceMonitor implements Watcher, StatCallback {
+
+    private static final Logger LOG = LoggerFactory.getLogger(InterfaceMonitor.class);
+
+    private final String znode;
+    private final ZooKeeper zk;
+    private final EndpointListener endpointListener;
+    private final boolean recursive;
+    private volatile boolean closed;
+
+    // This map reference changes, so don't synchronize on it
+    private Map<String, EndpointDescription> nodes = new HashMap<String, EndpointDescription>();
+
+    private EndpointDescriptionParser parser;
+
+    public InterfaceMonitor(ZooKeeper zk, String objClass, EndpointListener endpointListener, String scope) {
+        this.zk = zk;
+        this.znode = Utils.getZooKeeperPath(objClass);
+        this.recursive = objClass == null || objClass.isEmpty();
+        this.endpointListener = endpointListener;
+        this.parser = new EndpointDescriptionParser();
+        LOG.debug("Creating new InterfaceMonitor {} for scope [{}] and objectClass [{}]",
+                new Object[] {recursive ? "(recursive)" : "", scope, objClass});
+    }
+
+    /**
+     * Returns all endpoints that are currently known to this monitor.
+     *
+     * @return all endpoints that are currently known to this monitor
+     */
+    public synchronized List<EndpointDescription> getEndpoints() {
+        return new ArrayList<EndpointDescription>(nodes.values());
+    }
+
+    public void start() {
+        watch();
+    }
+
+    private void watch() {
+        LOG.debug("registering a ZooKeeper.exists({}) callback", znode);
+        zk.exists(znode, this, this, null);
+    }
+
+    /**
+     * Zookeeper Watcher interface callback.
+     */
+    public void process(WatchedEvent event) {
+        LOG.debug("ZooKeeper watcher callback on node {} for event {}", znode, event);
+        processDelta();
+    }
+
+    /**
+     * Zookeeper StatCallback interface callback.
+     */
+    @SuppressWarnings("deprecation")
+    public void processResult(int rc, String path, Object ctx, Stat stat) {
+        LOG.debug("ZooKeeper callback on node: {} code: {}", znode, rc);
+
+        switch (rc) {
+        case Code.Ok:
+        case Code.NoNode:
+            processDelta();
+            return;
+
+        case Code.SessionExpired:
+        case Code.NoAuth:
+        case Code.ConnectionLoss:
+            return;
+
+        default:
+            watch();
+        }
+    }
+
+    private void processDelta() {
+        if (closed) {
+            return;
+        }
+
+        if (zk.getState() != ZooKeeper.States.CONNECTED) {
+            LOG.debug("ZooKeeper connection was already closed! Not processing changed event.");
+            return;
+        }
+
+        try {
+            if (zk.exists(znode, false) != null) {
+                zk.getChildren(znode, this);
+                refreshNodes();
+            } else {
+                LOG.debug("znode {} doesn't exist -> not processing any changes", znode);
+            }
+        } catch (Exception e) {
+            if (zk.getState() != ZooKeeper.States.CONNECTED) {
+                LOG.debug("Error getting Zookeeper data: " + e); // e.g. session expired, handled by ZooKeeperDiscovery
+            } else {
+                LOG.error("Error getting ZooKeeper data.", e);
+            }
+        }
+    }
+
+    public synchronized void close() {
+        closed = true;
+        for (EndpointDescription endpoint : nodes.values()) {
+            endpointListener.endpointRemoved(endpoint, null);
+        }
+        nodes.clear();
+    }
+
+    private synchronized void refreshNodes() {
+        if (closed) {
+            return;
+        }
+        LOG.info("Processing change on node: {}", znode);
+
+        Map<String, EndpointDescription> newNodes = new HashMap<String, EndpointDescription>();
+        Map<String, EndpointDescription> prevNodes = new HashMap<String, EndpointDescription>(nodes);
+        processChildren(znode, newNodes, prevNodes);
+
+        // whatever is left in prevNodes now has been removed from Discovery
+        LOG.debug("processChildren done. Nodes that are missing now and need to be removed: {}", prevNodes.values());
+        for (EndpointDescription endpoint : prevNodes.values()) {
+            endpointListener.endpointRemoved(endpoint, null);
+        }
+        nodes = newNodes;
+    }
+
+    /**
+     * Iterates through all child nodes of the given node and tries to find
+     * endpoints. If the recursive flag is set it also traverses into the child
+     * nodes.
+     *
+     * @return true if an endpoint was found and if the node therefore needs to
+     *         be monitored for changes
+     */
+    private boolean processChildren(String zn, Map<String, EndpointDescription> newNodes,
+            Map<String, EndpointDescription> prevNodes) {
+        List<String> children;
+        try {
+            LOG.debug("Processing the children of {}", zn);
+            children = zk.getChildren(zn, false);
+
+            boolean foundANode = false;
+            for (String child : children) {
+                String childZNode = zn + '/' + child;
+                EndpointDescription endpoint = getEndpointDescriptionFromNode(childZNode);
+                if (endpoint != null) {
+                    EndpointDescription prevEndpoint = prevNodes.get(child);
+                    LOG.info("found new node " + zn + "/[" + child + "]   ( []->child )  props: "
+                            + endpoint.getProperties().values());
+                    newNodes.put(child, endpoint);
+                    prevNodes.remove(child);
+                    foundANode = true;
+                    LOG.debug("Properties: {}", endpoint.getProperties());
+                    if (prevEndpoint == null) {
+                        // This guy is new
+                        endpointListener.endpointAdded(endpoint, null);
+                    } else if (!prevEndpoint.getProperties().equals(endpoint.getProperties())) {
+                        // TODO
+                    }
+                }
+                if (recursive && processChildren(childZNode, newNodes, prevNodes)) {
+                    zk.getChildren(childZNode, this);
+                }
+            }
+
+            return foundANode;
+        } catch (KeeperException e) {
+            LOG.error("Problem processing ZooKeeper node", e);
+        } catch (InterruptedException e) {
+            LOG.error("Problem processing ZooKeeper node", e);
+        }
+        return false;
+    }
+
+    /**
+     * Retrieves data from the given node and parses it into an EndpointDescription.
+     *
+     * @param node a node path
+     * @return endpoint found in the node or null if no endpoint was found
+     */
+    private EndpointDescription getEndpointDescriptionFromNode(String node) {
+        try {
+            Stat stat = zk.exists(node, false);
+            if (stat == null || stat.getDataLength() <= 0) {
+                return null;
+            }
+            byte[] data = zk.getData(node, false, null);
+            LOG.debug("Got data for node: {}", node);
+
+            EndpointDescription endpoint = getFirstEnpointDescription(data);
+            if (endpoint != null) {
+                return endpoint;
+            }
+            LOG.warn("No Discovery information found for node: {}", node);
+        } catch (Exception e) {
+            LOG.error("Problem getting EndpointDescription from node " + node, e);
+        }
+        return null;
+    }
+
+    public EndpointDescription getFirstEnpointDescription(byte[] data) {
+        List<EndpointDescriptionType> elements = parser.getEndpointDescriptions(new ByteArrayInputStream(data));
+        if (elements.isEmpty()) {
+            return null;
+        }
+        Map<String, Object> props = new PropertiesMapper().toProps(elements.get(0).getProperty());
+        return new EndpointDescription(props);
+    }
+}
diff --git a/trunk/discovery/distributed/cxf-discovery/src/main/java/org/apache/cxf/dosgi/discovery/zookeeper/subscribe/InterfaceMonitorManager.java b/trunk/discovery/distributed/cxf-discovery/src/main/java/org/apache/cxf/dosgi/discovery/zookeeper/subscribe/InterfaceMonitorManager.java
new file mode 100644
index 0000000..240e5ea
--- /dev/null
+++ b/trunk/discovery/distributed/cxf-discovery/src/main/java/org/apache/cxf/dosgi/discovery/zookeeper/subscribe/InterfaceMonitorManager.java
@@ -0,0 +1,218 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.cxf.dosgi.discovery.zookeeper.subscribe;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.CopyOnWriteArrayList;
+
+import org.apache.cxf.dosgi.discovery.zookeeper.ZooKeeperDiscovery;
+import org.apache.cxf.dosgi.discovery.zookeeper.util.Utils;
+import org.apache.zookeeper.ZooKeeper;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.ServiceReference;
+import org.osgi.service.remoteserviceadmin.EndpointDescription;
+import org.osgi.service.remoteserviceadmin.EndpointListener;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import static org.apache.cxf.dosgi.discovery.local.util.Utils.matchFilter;
+
+/**
+ * Manages the EndpointListeners and the scopes they are interested in.
+ * For each scope with interested EndpointListeners an InterfaceMonitor is created.
+ * The InterfaceMonitor calls back when it detects added or removed external Endpoints.
+ * These events are then forwarded to all interested EndpointListeners.
+ */
+public class InterfaceMonitorManager {
+
+    private static final Logger LOG = LoggerFactory.getLogger(InterfaceMonitorManager.class);
+
+    private final BundleContext bctx;
+    private final ZooKeeper zk;
+    // map of EndpointListeners and the scopes they are interested in
+    private final Map<ServiceReference<EndpointListener>, List<String>> endpointListenerScopes =
+            new HashMap<ServiceReference<EndpointListener>, List<String>>();
+    // map of scopes and their interest data
+    private final Map<String, Interest> interests = new HashMap<String, Interest>();
+
+    protected static class Interest {
+        List<ServiceReference<EndpointListener>> endpointListeners = 
+            new CopyOnWriteArrayList<ServiceReference<EndpointListener>>();
+        InterfaceMonitor monitor;
+    }
+
+    public InterfaceMonitorManager(BundleContext bctx, ZooKeeper zk) {
+        this.bctx = bctx;
+        this.zk = zk;
+    }
+
+    public void addInterest(ServiceReference<EndpointListener> endpointListener) {
+        if (isOurOwnEndpointListener(endpointListener)) {
+            LOG.debug("Skipping our own EndpointListener");
+            return;
+        }
+
+        LOG.info("updating EndpointListener interests: {}", endpointListener);
+        if (LOG.isDebugEnabled()) {
+            LOG.debug("updated EndpointListener properties: {}", Utils.getProperties(endpointListener));
+        }
+        for (String scope : Utils.getScopes(endpointListener)) {
+            String objClass = Utils.getObjectClass(scope);
+            LOG.debug("Adding interest in scope {}, objectClass {}", scope, objClass);
+            addInterest(endpointListener, scope, objClass);
+        }
+    }
+
+    private static boolean isOurOwnEndpointListener(ServiceReference<EndpointListener> endpointListener) {
+        return Boolean.parseBoolean(String.valueOf(
+                endpointListener.getProperty(ZooKeeperDiscovery.DISCOVERY_ZOOKEEPER_ID)));
+    }
+
+    @SuppressWarnings("unchecked")
+    public synchronized void addInterest(ServiceReference<EndpointListener> endpointListener, 
+                                         String scope, String objClass) {
+        // get or create interest for given scope and add listener to it
+        Interest interest = interests.get(scope);
+        if (interest == null) {
+            // create interest, add listener and start monitor
+            interest = new Interest();
+            interests.put(scope, interest);
+            interest.endpointListeners.add(endpointListener); // add it before monitor starts so we don't miss events
+            interest.monitor = createInterfaceMonitor(scope, objClass, interest);
+            interest.monitor.start();
+        } else {
+            // interest already exists, so just add listener to it
+            if (!interest.endpointListeners.contains(endpointListener)) {
+                interest.endpointListeners.add(endpointListener);
+            }
+            // notify listener of all known endpoints for given scope
+            // (as EndpointListener contract requires of all added/modified listeners)
+            for (EndpointDescription endpoint : interest.monitor.getEndpoints()) {
+                notifyListeners(endpoint, scope, true, Arrays.asList(endpointListener));
+            }
+        }
+
+        // add scope to listener's scopes list
+        List<String> scopes = endpointListenerScopes.get(endpointListener);
+        if (scopes == null) {
+            scopes = new ArrayList<String>(1);
+            endpointListenerScopes.put(endpointListener, scopes);
+        }
+        if (!scopes.contains(scope)) {
+            scopes.add(scope);
+        }
+    }
+
+    public synchronized void removeInterest(ServiceReference<EndpointListener> endpointListener) {
+        LOG.info("removing EndpointListener interests: {}", endpointListener);
+        List<String> scopes = endpointListenerScopes.get(endpointListener);
+        if (scopes == null) {
+            return;
+        }
+
+        for (String scope : scopes) {
+            Interest interest = interests.get(scope);
+            if (interest != null) {
+                interest.endpointListeners.remove(endpointListener);
+                if (interest.endpointListeners.isEmpty()) {
+                    interest.monitor.close();
+                    interests.remove(scope);
+                }
+            }
+        }
+        endpointListenerScopes.remove(endpointListener);
+    }
+
+    protected InterfaceMonitor createInterfaceMonitor(final String scope, String objClass, final Interest interest) {
+        // holding this object's lock in the callbacks can lead to a deadlock with InterfaceMonitor
+        EndpointListener endpointListener = new EndpointListener() {
+
+            public void endpointRemoved(EndpointDescription endpoint, String matchedFilter) {
+                notifyListeners(endpoint, scope, false, interest.endpointListeners);
+            }
+
+            public void endpointAdded(EndpointDescription endpoint, String matchedFilter) {
+                notifyListeners(endpoint, scope, true, interest.endpointListeners);
+            }
+        };
+        return new InterfaceMonitor(zk, objClass, endpointListener, scope);
+    }
+
+    private void notifyListeners(EndpointDescription endpoint, String currentScope, boolean isAdded,
+            List<ServiceReference<EndpointListener>> endpointListeners) {
+        for (ServiceReference<EndpointListener> endpointListenerRef : endpointListeners) {
+            EndpointListener service = bctx.getService(endpointListenerRef);
+            try {
+                EndpointListener endpointListener = (EndpointListener)service;
+                LOG.trace("matching {} against {}", endpoint, currentScope);
+                if (matchFilter(bctx, currentScope, endpoint)) {
+                    LOG.debug("Matched {} against {}", endpoint, currentScope);
+                    notifyListener(endpoint, currentScope, isAdded, endpointListenerRef.getBundle(),
+                                   endpointListener);
+                }
+            } finally {
+                if (service != null) {
+                    bctx.ungetService(endpointListenerRef);
+                }
+            }
+        }
+    }
+
+    private void notifyListener(EndpointDescription endpoint, String currentScope, boolean isAdded,
+                                Bundle endpointListenerBundle, EndpointListener endpointListener) {
+        if (endpointListenerBundle == null) {
+            LOG.info("listening service was unregistered, ignoring");
+        } else if (isAdded) {
+            LOG.info("calling EndpointListener.endpointAdded: " + endpointListener + " from bundle "
+                    + endpointListenerBundle.getSymbolicName() + " for endpoint: " + endpoint);
+            endpointListener.endpointAdded(endpoint, currentScope);
+        } else {
+            LOG.info("calling EndpointListener.endpointRemoved: " + endpointListener + " from bundle "
+                    + endpointListenerBundle.getSymbolicName() + " for endpoint: " + endpoint);
+            endpointListener.endpointRemoved(endpoint, currentScope);
+        }
+    }
+
+    public synchronized void close() {
+        for (Interest interest : interests.values()) {
+            interest.monitor.close();
+        }
+        interests.clear();
+        endpointListenerScopes.clear();
+    }
+
+    /**
+     * Only for test case!
+     */
+    protected synchronized Map<String, Interest> getInterests() {
+        return interests;
+    }
+
+    /**
+     * Only for test case!
+     */
+    protected synchronized Map<ServiceReference<EndpointListener>, List<String>> getEndpointListenerScopes() {
+        return endpointListenerScopes;
+    }
+}
diff --git a/trunk/discovery/distributed/cxf-discovery/src/main/java/org/apache/cxf/dosgi/discovery/zookeeper/util/Utils.java b/trunk/discovery/distributed/cxf-discovery/src/main/java/org/apache/cxf/dosgi/discovery/zookeeper/util/Utils.java
new file mode 100644
index 0000000..121546e
--- /dev/null
+++ b/trunk/discovery/distributed/cxf-discovery/src/main/java/org/apache/cxf/dosgi/discovery/zookeeper/util/Utils.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.discovery.zookeeper.util;
+
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Dictionary;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.UUID;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.ServiceReference;
+import org.osgi.service.remoteserviceadmin.EndpointListener;
+
+public final class Utils {
+
+    static final String PATH_PREFIX = "/osgi/service_registry";
+    static final Pattern OBJECTCLASS_PATTERN = Pattern.compile(".*\\(objectClass=([^)]+)\\).*");
+
+    private Utils() {
+        // never constructed
+    }
+
+    public static String getZooKeeperPath(String name) {
+        return name == null || name.isEmpty() ? PATH_PREFIX : PATH_PREFIX + '/' + name.replace('.', '/');
+    }
+
+    /**
+     * Returns the value of a "string+" property as an array of strings.
+     * <p>
+     * A "string+" property can have a value which is either a string,
+     * an array of strings, or a collection of strings.
+     * <p>
+     * If the given value is not of one of the valid types, or is null,
+     * an empty array is returned.
+     *
+     * @param property a "string+" property value
+     * @return the property value as an array of strings, or an empty array
+     */
+    public static String[] getStringPlusProperty(Object property) {
+        if (property instanceof String) {
+            return new String[] {(String)property};
+        } else if (property instanceof String[]) {
+            return (String[])property;
+        } else if (property instanceof Collection) {
+            try {
+                @SuppressWarnings("unchecked")
+                Collection<String> strings = (Collection<String>)property;
+                return strings.toArray(new String[strings.size()]);
+            } catch (ArrayStoreException ase) {
+                // ignore collections with wrong type
+            }
+        }
+        return new String[0];
+    }
+
+    /**
+     * Removes nulls and empty strings from the given string array.
+     *
+     * @param strings an array of strings
+     * @return a new array containing the non-null and non-empty
+     *         elements of the original array in the same order
+     */
+    public static String[] removeEmpty(String[] strings) {
+        String[] result = new String[strings.length];
+        int copied = 0;
+        for (String s : strings) {
+            if (s != null && !s.isEmpty()) {
+                result[copied++] = s;
+            }
+        }
+        return copied == result.length ? result : Arrays.copyOf(result, copied);
+    }
+
+    public static String[] getScopes(ServiceReference<?> sref) {
+        return removeEmpty(getStringPlusProperty(sref.getProperty(EndpointListener.ENDPOINT_LISTENER_SCOPE)));
+    }
+
+    // copied from the DSW OSGiUtils class
+    public static String getUUID(BundleContext bc) {
+        synchronized ("org.osgi.framework.uuid") {
+            String uuid = bc.getProperty("org.osgi.framework.uuid");
+            if (uuid == null) {
+                uuid = UUID.randomUUID().toString();
+                System.setProperty("org.osgi.framework.uuid", uuid);
+            }
+            return uuid;
+        }
+    }
+
+    public static <K, V> String getProp(Dictionary<K, V> props, String key, String def) {
+        V val = props.get(key);
+        return val == null ? def : val.toString();
+    }
+
+    public static <K, V> int getProp(Dictionary<K, V> props, String key, int def) {
+        V val = props.get(key);
+        return val == null ? def : Integer.parseInt(val.toString());
+    }
+
+    public static String getObjectClass(String scope) {
+        Matcher m = OBJECTCLASS_PATTERN.matcher(scope);
+        return m.matches() ? m.group(1) : null;
+    }
+
+    /**
+     * Returns a service's properties as a map.
+     *
+     * @param serviceReference a service reference
+     * @return the service's properties as a map
+     */
+    public static Map<String, Object> getProperties(ServiceReference<?> serviceReference) {
+        String[] keys = serviceReference.getPropertyKeys();
+        Map<String, Object> props = new HashMap<String, Object>(keys.length);
+        for (String key : keys) {
+            Object val = serviceReference.getProperty(key);
+            props.put(key, val);
+        }
+        return props;
+    }
+}
diff --git a/trunk/discovery/distributed/cxf-discovery/src/test/java/org/apache/cxf/dosgi/discovery/zookeeper/DiscoveryDriverTest.java b/trunk/discovery/distributed/cxf-discovery/src/test/java/org/apache/cxf/dosgi/discovery/zookeeper/DiscoveryDriverTest.java
new file mode 100644
index 0000000..84470c2
--- /dev/null
+++ b/trunk/discovery/distributed/cxf-discovery/src/test/java/org/apache/cxf/dosgi/discovery/zookeeper/DiscoveryDriverTest.java
@@ -0,0 +1,135 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.cxf.dosgi.discovery.zookeeper;
+
+import junit.framework.TestCase;
+
+public class DiscoveryDriverTest extends TestCase {
+
+    public void testDUMMY() {
+        assertTrue(true);
+    }
+
+//    public void testDiscoveryDriver() throws Exception {
+//        BundleContext bc = getDefaultBundleContext();
+//        Dictionary<String, String> props = getDefaultProps();
+//
+//        final StringBuilder sb = new StringBuilder();
+//        DiscoveryDriver dd = new DiscoveryDriver(bc, props) {
+//            @Override
+//            ZooKeeper createZooKeeper() throws IOException {
+//                sb.append(zkHost + ":" + zkPort);
+//                ZooKeeper zk = EasyMock.createMock(ZooKeeper.class);
+//                EasyMock.replay(zk);
+//                return zk;
+//            }
+//        };
+//        EasyMock.verify(bc);
+//        assertEquals("somehost:1910", sb.toString());
+//
+//        EasyMock.verify(dd.zooKeeper);
+//        EasyMock.reset(dd.zooKeeper);
+//        dd.zooKeeper.close();
+//        EasyMock.expectLastCall();
+//        EasyMock.replay(dd.zooKeeper);
+//
+//        ServiceTracker st1 = EasyMock.createMock(ServiceTracker.class);
+//        st1.close();
+//        EasyMock.expectLastCall();
+//        EasyMock.replay(st1);
+//        ServiceTracker st2 = EasyMock.createMock(ServiceTracker.class);
+//        st2.close();
+//        EasyMock.expectLastCall();
+//        EasyMock.replay(st2);
+//
+//        dd.lookupTracker = st1;
+//        dd.publicationTracker = st2;
+//
+//        dd.destroy();
+//    }
+//
+//    private void expectServiceTrackerCalls(BundleContext bc, String objectClass)
+//            throws InvalidSyntaxException {
+//        Filter filter = EasyMock.createNiceMock(Filter.class);
+//        EasyMock.replay(filter);
+//
+//        EasyMock.expect(bc.createFilter("(objectClass=" + objectClass + ")"))
+//            .andReturn(filter).anyTimes();
+//        bc.addServiceListener((ServiceListener) EasyMock.anyObject(),
+//            EasyMock.eq("(objectClass=" + objectClass + ")"));
+//        EasyMock.expectLastCall().anyTimes();
+//        EasyMock.expect(bc.getServiceReferences(objectClass, null))
+//            .andReturn(new ServiceReference [0]).anyTimes();
+//    }
+//
+//    public void testProcessEvent() throws Exception {
+//        DiscoveryDriver db = new DiscoveryDriver(getDefaultBundleContext(), getDefaultProps()) {
+//            @Override
+//            ZooKeeper createZooKeeper() throws IOException {
+//                return null;
+//            }
+//        };
+//
+//        FindInZooKeeperCustomizer fc = new FindInZooKeeperCustomizer(null, null);
+//        List<InterfaceMonitor> l1 = new ArrayList<InterfaceMonitor>();
+//        InterfaceMonitor dm1a = EasyMock.createMock(InterfaceMonitor.class);
+//        dm1a.process();
+//        EasyMock.expectLastCall();
+//        EasyMock.replay(dm1a);
+//        InterfaceMonitor dm1b = EasyMock.createMock(InterfaceMonitor.class);
+//        dm1b.process();
+//        EasyMock.expectLastCall();
+//        EasyMock.replay(dm1b);
+//        l1.add(dm1a);
+//        l1.add(dm1b);
+//
+//        List<InterfaceMonitor> l2 = new ArrayList<InterfaceMonitor>();
+//        InterfaceMonitor dm2 = EasyMock.createMock(InterfaceMonitor.class);
+//        dm2.process();
+//        EasyMock.expectLastCall();
+//        EasyMock.replay(dm2);
+//        l2.add(dm2);
+//
+//        fc.watchers.put(EasyMock.createMock(DiscoveredServiceTracker.class), l1);
+//        fc.watchers.put(EasyMock.createMock(DiscoveredServiceTracker.class), l2);
+//
+//        db.finderCustomizer = fc;
+//        db.process(null);
+//
+//        EasyMock.verify(dm1a);
+//        EasyMock.verify(dm1b);
+//        EasyMock.verify(dm2);
+//    }
+//
+//    private BundleContext getDefaultBundleContext() throws InvalidSyntaxException {
+//        BundleContext bc = EasyMock.createMock(BundleContext.class);
+//        expectServiceTrackerCalls(bc, ServicePublication.class.getName());
+//        expectServiceTrackerCalls(bc, DiscoveredServiceTracker.class.getName());
+//        EasyMock.replay(bc);
+//        return bc;
+//    }
+//
+//    private Dictionary<String, String> getDefaultProps() {
+//        Dictionary<String, String> props = new Hashtable<String, String>();
+//        props.put("zookeeper.host", "somehost");
+//        props.put("zookeeper.port", "1910");
+//        props.put("zookeeper.timeout", "1500");
+//        return props;
+//    }
+}
diff --git a/trunk/discovery/distributed/cxf-discovery/src/test/java/org/apache/cxf/dosgi/discovery/zookeeper/FindInZooKeeperCustomizerTest.java b/trunk/discovery/distributed/cxf-discovery/src/test/java/org/apache/cxf/dosgi/discovery/zookeeper/FindInZooKeeperCustomizerTest.java
new file mode 100644
index 0000000..cb2180b
--- /dev/null
+++ b/trunk/discovery/distributed/cxf-discovery/src/test/java/org/apache/cxf/dosgi/discovery/zookeeper/FindInZooKeeperCustomizerTest.java
@@ -0,0 +1,301 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.cxf.dosgi.discovery.zookeeper;
+
+import junit.framework.TestCase;
+
+public class FindInZooKeeperCustomizerTest extends TestCase {
+
+    public void testDUMMY() {
+        assertTrue(true);
+    }
+
+//    public void testAddingServiceInterface() {
+//        DiscoveredServiceTracker dst = new DiscoveredServiceTracker() {
+//            public void serviceChanged(DiscoveredServiceNotification dsn) {}
+//        };
+//
+//        ServiceReference sr = EasyMock.createMock(ServiceReference.class);
+//        EasyMock.expect(sr.getProperty(DiscoveredServiceTracker.INTERFACE_MATCH_CRITERIA))
+//            .andReturn(Collections.singleton(String.class.getName()));
+//        EasyMock.expect(sr.getProperty(DiscoveredServiceTracker.FILTER_MATCH_CRITERIA))
+//            .andReturn(null);
+//        EasyMock.replay(sr);
+//
+//        DiscoveredServiceTracker dst2 = new DiscoveredServiceTracker() {
+//            public void serviceChanged(DiscoveredServiceNotification dsn) {}
+//        };
+//
+//        ServiceReference sr2 = EasyMock.createMock(ServiceReference.class);
+//        EasyMock.expect(sr2.getProperty(DiscoveredServiceTracker.INTERFACE_MATCH_CRITERIA))
+//            .andReturn(Arrays.asList(Integer.class.getName(), Comparable.class.getName()));
+//        EasyMock.expect(sr2.getProperty(DiscoveredServiceTracker.FILTER_MATCH_CRITERIA))
+//            .andReturn(null);
+//        EasyMock.replay(sr2);
+//
+//        BundleContext bc = EasyMock.createMock(BundleContext.class);
+//        EasyMock.expect(bc.getService(sr)).andReturn(dst);
+//        EasyMock.expect(bc.getService(sr2)).andReturn(dst2);
+//        EasyMock.replay(bc);
+//
+//        ZooKeeper zk = EasyMock.createMock(ZooKeeper.class);
+//        zkExpectExists(zk, String.class.getName());
+//        zkExpectExists(zk, Integer.class.getName());
+//        zkExpectExists(zk, Comparable.class.getName());
+//        EasyMock.expectLastCall();
+//        EasyMock.replay(zk);
+//
+//        FindInZooKeeperCustomizer fc = new FindInZooKeeperCustomizer(bc, zk);
+//
+//        // ---------------------------------------------------------------
+//        // Test the addingService APIs
+//        // ---------------------------------------------------------------
+//
+//        assertEquals("Precondition failed", 0, fc.watchers.size());
+//        fc.addingService(sr);
+//        assertEquals(1, fc.watchers.size());
+//
+//        DiscoveredServiceTracker key = fc.watchers.keySet().iterator().next();
+//        assertSame(dst, key);
+//        List<InterfaceMonitor> dmList = fc.watchers.get(key);
+//        assertEquals(1, dmList.size());
+//        InterfaceMonitor dm = dmList.iterator().next();
+//        assertNotNull(dm.listener);
+//        assertSame(zk, dm.zookeeper);
+//        assertEquals(Utils.getZooKeeperPath(String.class.getName()), dm.znode);
+//
+//        assertEquals("Precondition failed", 1, fc.watchers.size());
+//        fc.addingService(sr2);
+//        assertEquals(2, fc.watchers.size());
+//
+//        assertTrue(fc.watchers.containsKey(dst));
+//        assertTrue(fc.watchers.containsKey(dst2));
+//        assertEquals(dmList, fc.watchers.get(dst));
+//        List<InterfaceMonitor> dmList2 = fc.watchers.get(dst2);
+//        assertEquals(2, dmList2.size());
+//
+//        Set<String> actual = new HashSet<String>();
+//        for (InterfaceMonitor im : dmList2) {
+//            actual.add(im.znode);
+//        }
+//        Set<String> expected = new HashSet<String>(Arrays.asList(
+//                Utils.getZooKeeperPath(Integer.class.getName()),
+//                Utils.getZooKeeperPath(Comparable.class.getName())));
+//        assertEquals(expected, actual);
+//
+//        EasyMock.verify(zk);
+//
+//        // ---------------------------------------------------------------
+//        // Test the modifiedService APIs
+//        // ---------------------------------------------------------------
+//        EasyMock.reset(zk);
+//        zkExpectExists(zk, List.class.getName());
+//        EasyMock.replay(zk);
+//
+//        EasyMock.reset(sr);
+//        EasyMock.expect(sr.getProperty(DiscoveredServiceTracker.INTERFACE_MATCH_CRITERIA))
+//            .andReturn(Collections.singleton(List.class.getName()));
+//        EasyMock.expect(sr.getProperty(DiscoveredServiceTracker.FILTER_MATCH_CRITERIA))
+//            .andReturn(null);
+//        EasyMock.replay(sr);
+//
+//        assertEquals("Precondition failed", 2, fc.watchers.size());
+//        fc.modifiedService(sr, dst);
+//        assertEquals("Precondition failed", 2, fc.watchers.size());
+//
+//        assertTrue(fc.watchers.containsKey(dst));
+//        assertTrue(fc.watchers.containsKey(dst2));
+//        assertEquals(dmList2, fc.watchers.get(dst2));
+//        List<InterfaceMonitor> dmList3 = fc.watchers.get(dst);
+//        assertEquals(1, dmList3.size());
+//        assertEquals(Utils.getZooKeeperPath(List.class.getName()), dmList3.iterator().next().znode);
+//
+//        EasyMock.verify(zk);
+//
+//        // ---------------------------------------------------------------
+//        // Test the removedService APIs
+//        // ---------------------------------------------------------------
+//        EasyMock.reset(zk);
+//        EasyMock.replay(zk);
+//
+//        assertEquals("Precondition failed", 2, fc.watchers.size());
+//        fc.removedService(sr2, dst2);
+//        assertEquals("Precondition failed", 1, fc.watchers.size());
+//
+//        assertEquals(dmList3, fc.watchers.get(dst));
+//        assertNull(fc.watchers.get(dst2));
+//
+//        EasyMock.verify(zk);
+//    }
+//
+//    public void testAddingServiceFilter() {
+//        DiscoveredServiceTracker dst = new DiscoveredServiceTracker() {
+//            public void serviceChanged(DiscoveredServiceNotification dsn) {}
+//        };
+//
+//        ServiceReference sr = EasyMock.createMock(ServiceReference.class);
+//        EasyMock.expect(sr.getProperty(DiscoveredServiceTracker.INTERFACE_MATCH_CRITERIA))
+//            .andReturn(null);
+//        Set<String> stringFilter = Collections.singleton("(objectClass=java.lang.String)");
+//        EasyMock.expect(sr.getProperty(DiscoveredServiceTracker.FILTER_MATCH_CRITERIA))
+//            .andReturn(stringFilter);
+//        EasyMock.replay(sr);
+//
+//        DiscoveredServiceTracker dst2 = new DiscoveredServiceTracker() {
+//            public void serviceChanged(DiscoveredServiceNotification dsn) {}
+//        };
+//
+//        ServiceReference sr2 = EasyMock.createMock(ServiceReference.class);
+//        EasyMock.expect(sr2.getProperty(DiscoveredServiceTracker.INTERFACE_MATCH_CRITERIA))
+//            .andReturn(null);
+//        List<String> combinedFilter =
+//            Arrays.asList("(objectClass=java.lang.Integer)", "(objectClass=java.lang.Comparable)");
+//        EasyMock.expect(sr2.getProperty(DiscoveredServiceTracker.FILTER_MATCH_CRITERIA))
+//            .andReturn(combinedFilter);
+//        EasyMock.replay(sr2);
+//
+//        BundleContext bc = EasyMock.createMock(BundleContext.class);
+//        EasyMock.expect(bc.getService(sr)).andReturn(dst);
+//        EasyMock.expect(bc.getService(sr2)).andReturn(dst2);
+//        EasyMock.replay(bc);
+//
+//        ZooKeeper zk = EasyMock.createMock(ZooKeeper.class);
+//        zkExpectExists(zk, String.class.getName());
+//        zkExpectExists(zk, Integer.class.getName());
+//        zkExpectExists(zk, Comparable.class.getName());
+//        EasyMock.expectLastCall();
+//        EasyMock.replay(zk);
+//
+//        FindInZooKeeperCustomizer fc = new FindInZooKeeperCustomizer(bc, zk);
+//
+//        // ---------------------------------------------------------------
+//        // Test the addingService APIs
+//        // ---------------------------------------------------------------
+//
+//        assertEquals("Precondition failed", 0, fc.watchers.size());
+//        fc.addingService(sr);
+//        assertEquals(1, fc.watchers.size());
+//
+//        DiscoveredServiceTracker key = fc.watchers.keySet().iterator().next();
+//        assertSame(dst, key);
+//        List<InterfaceMonitor> dmList = fc.watchers.get(key);
+//        assertEquals(1, dmList.size());
+//        InterfaceMonitor dm = dmList.iterator().next();
+//        assertNotNull(dm.listener);
+//        assertSame(zk, dm.zookeeper);
+//        assertEquals(Utils.getZooKeeperPath(String.class.getName()), dm.znode);
+//
+//        assertEquals("Precondition failed", 1, fc.watchers.size());
+//        fc.addingService(sr2);
+//        assertEquals(2, fc.watchers.size());
+//
+//        assertTrue(fc.watchers.containsKey(dst));
+//        assertTrue(fc.watchers.containsKey(dst2));
+//        assertEquals(dmList, fc.watchers.get(dst));
+//        List<InterfaceMonitor> dmList2 = fc.watchers.get(dst2);
+//        assertEquals(2, dmList2.size());
+//        Set<String> actual = new HashSet<String>();
+//        for (InterfaceMonitor im : dmList2) {
+//            actual.add(im.znode);
+//        }
+//        Set<String> expected = new HashSet<String>(Arrays.asList(
+//                Utils.getZooKeeperPath(Integer.class.getName()),
+//                Utils.getZooKeeperPath(Comparable.class.getName())));
+//        assertEquals(expected, actual);
+//
+//        EasyMock.verify(zk);
+//
+//        // ---------------------------------------------------------------
+//        // Test the modifiedService APIs
+//        // ---------------------------------------------------------------
+//        EasyMock.reset(zk);
+//        zkExpectExists(zk, List.class.getName());
+//        EasyMock.replay(zk);
+//
+//        EasyMock.reset(sr);
+//        Set<String> listFilter = Collections.singleton("(objectClass=java.util.List)");
+//        EasyMock.expect(sr.getProperty(DiscoveredServiceTracker.INTERFACE_MATCH_CRITERIA))
+//            .andReturn(null);
+//        EasyMock.expect(sr.getProperty(DiscoveredServiceTracker.FILTER_MATCH_CRITERIA))
+//            .andReturn(listFilter);
+//        EasyMock.replay(sr);
+//
+//        assertEquals("Precondition failed", 2, fc.watchers.size());
+//        fc.modifiedService(sr, dst);
+//        assertEquals("Precondition failed", 2, fc.watchers.size());
+//
+//        assertTrue(fc.watchers.containsKey(dst));
+//        assertTrue(fc.watchers.containsKey(dst2));
+//        assertEquals(dmList2, fc.watchers.get(dst2));
+//        List<InterfaceMonitor> dmList3 = fc.watchers.get(dst);
+//        assertEquals(1, dmList3.size());
+//        assertEquals(Utils.getZooKeeperPath(List.class.getName()), dmList3.iterator().next().znode);
+//
+//        EasyMock.verify(zk);
+//
+//        // ---------------------------------------------------------------
+//        // Test the removedService APIs
+//        // ---------------------------------------------------------------
+//        EasyMock.reset(zk);
+//        EasyMock.replay(zk);
+//
+//        assertEquals("Precondition failed", 2, fc.watchers.size());
+//        fc.removedService(sr2, dst2);
+//        assertEquals("Precondition failed", 1, fc.watchers.size());
+//
+//        assertEquals(dmList3, fc.watchers.get(dst));
+//        assertNull(fc.watchers.get(dst2));
+//
+//        EasyMock.verify(zk);
+//    }
+//
+//    public void testGetInterfacesFromFilter() {
+//        testGetInterfacesFromFilter("objectClass=org.apache_2.Some$FunnyClass",
+//                "org.apache_2.Some$FunnyClass");
+//        testGetInterfacesFromFilter("(&(a=b)(objectClass = org.acme.Q)",
+//                "org.acme.Q");
+//        testGetInterfacesFromFilter("(&(objectClassIdentifier=b)(objectClass = org.acme.Q)",
+//                "org.acme.Q");
+//        testGetInterfacesFromFilter("(|(OBJECTCLASS=   X  )(objectclass = Y)",
+//                "X", "Y");
+//        testGetInterfacesFromFilter(new String[] {"(objectClass=X)", "(objectClass=Y)"},
+//                "X", "Y");
+//    }
+//
+//    private void testGetInterfacesFromFilter(String filter, String ... interfaces) {
+//        testGetInterfacesFromFilter(new String[] {filter}, interfaces);
+//    }
+//
+//    private void testGetInterfacesFromFilter(String[] filters, String ... interfaces) {
+//        FindInZooKeeperCustomizer.getInterfacesFromFilter(Arrays.asList(filters));
+//    }
+//
+//    private void zkExpectExists(ZooKeeper zk, String className) {
+//        zk.exists(EasyMock.eq(Utils.getZooKeeperPath(className)),
+//                (Watcher) EasyMock.anyObject(),
+//                (StatCallback) EasyMock.anyObject(), EasyMock.isNull());
+//        EasyMock.expectLastCall().andAnswer(new IAnswer<Object>() {
+//            public Object answer() throws Throwable {
+//                assertEquals(EasyMock.getCurrentArguments()[1],
+//                        EasyMock.getCurrentArguments()[2]);
+//                return null;
+//            }
+//        });
+//    }
+}
diff --git a/trunk/discovery/distributed/cxf-discovery/src/test/java/org/apache/cxf/dosgi/discovery/zookeeper/InterfaceDataMonitorListenerImplTest.java b/trunk/discovery/distributed/cxf-discovery/src/test/java/org/apache/cxf/dosgi/discovery/zookeeper/InterfaceDataMonitorListenerImplTest.java
new file mode 100644
index 0000000..53b6139
--- /dev/null
+++ b/trunk/discovery/distributed/cxf-discovery/src/test/java/org/apache/cxf/dosgi/discovery/zookeeper/InterfaceDataMonitorListenerImplTest.java
@@ -0,0 +1,183 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.cxf.dosgi.discovery.zookeeper;
+
+import junit.framework.TestCase;
+
+public class InterfaceDataMonitorListenerImplTest extends TestCase {
+
+    public void testDUMMY() {
+        assertTrue(true);
+    }
+
+//    public void testChange() throws Exception {
+//        final List<DiscoveredServiceNotification> dsnCallbacks = new ArrayList<DiscoveredServiceNotification>();
+//        DiscoveredServiceTracker dst = new DiscoveredServiceTracker() {
+//            public void serviceChanged(DiscoveredServiceNotification dsn) {
+//                dsnCallbacks.add(dsn);
+//            }
+//        };
+//
+//        //----------------------------------------------------------------
+//        // Test DiscoveredServiceNotification.AVAILABLE
+//        //----------------------------------------------------------------
+//        Properties initial = new Properties();
+//        initial.put("a", "b");
+//        initial.put(ServicePublication.ENDPOINT_LOCATION, "http://somehost:12345/some/context");
+//        ByteArrayOutputStream propBytes = new ByteArrayOutputStream();
+//        initial.store(propBytes, "");
+//
+//        ZooKeeper zk = EasyMock.createMock(ZooKeeper.class);
+//        EasyMock.expect(zk.getChildren(Utils.getZooKeeperPath(String.class.getName()), false))
+//            .andReturn(Arrays.asList("x#y#z"));
+//        EasyMock.expect(zk.getData(Utils.getZooKeeperPath(String.class.getName()) + "/x#y#z", false, null))
+//            .andReturn(propBytes.toByteArray());
+//        EasyMock.replay(zk);
+//
+//        InterfaceDataMonitorListenerImpl dml = new InterfaceDataMonitorListenerImpl(zk, String.class.getName(), dst);
+//
+//        assertEquals("Precondition failed", 0, dsnCallbacks.size());
+//        dml.change();
+//        assertEquals(1, dsnCallbacks.size());
+//        DiscoveredServiceNotification dsn = dsnCallbacks.iterator().next();
+//        assertEquals(Collections.singleton(String.class.getName()), dsn.getInterfaces());
+//        assertEquals(DiscoveredServiceNotification.AVAILABLE, dsn.getType());
+//        assertEquals(0, dsn.getFilters().size());
+//        ServiceEndpointDescription sed = dsn.getServiceEndpointDescription();
+//        assertEquals(Collections.singleton(String.class.getName()), sed.getProvidedInterfaces());
+//
+//        Properties expected = new Properties();
+//        expected.load(new ByteArrayInputStream(propBytes.toByteArray()));
+//        expected.put("service.exported.configs", "org.apache.cxf.ws");
+//        expected.put("org.apache.cxf.ws.address", "http://somehost:12345/some/context");
+//
+//        assertEquals(expected, sed.getProperties());
+//        EasyMock.verify(zk);
+//
+//        // Again with the same data
+//        EasyMock.reset(zk);
+//        EasyMock.expect(zk.getChildren(Utils.getZooKeeperPath(String.class.getName()), false))
+//            .andReturn(Arrays.asList("x#y#z"));
+//        EasyMock.expect(zk.getData(Utils.getZooKeeperPath(String.class.getName()) + "/x#y#z", false, null))
+//            .andReturn(propBytes.toByteArray());
+//        EasyMock.replay(zk);
+//
+//        dsnCallbacks.clear();
+//        assertEquals("Precondition failed", 0, dsnCallbacks.size());
+//        dml.change();
+//        assertEquals(0, dsnCallbacks.size());
+//
+//        EasyMock.verify(zk);
+//        //----------------------------------------------------------------
+//        // Test DiscoveredServiceNotification.MODIFIED
+//        //----------------------------------------------------------------
+//        Properties modified = new Properties();
+//        modified.put("c", "d");
+//        modified.put(ServicePublication.ENDPOINT_LOCATION, "http://somehost:999/some/context");
+//        modified.put("service.exported.configs", "org.apache.cxf.rs");
+//        ByteArrayOutputStream modBytes = new ByteArrayOutputStream();
+//        modified.store(modBytes, "");
+//
+//        EasyMock.reset(zk);
+//        EasyMock.expect(zk.getChildren(Utils.getZooKeeperPath(String.class.getName()), false))
+//            .andReturn(Arrays.asList("x#y#z"));
+//        EasyMock.expect(zk.getData(Utils.getZooKeeperPath(String.class.getName()) + "/x#y#z", false, null))
+//            .andReturn(modBytes.toByteArray());
+//        EasyMock.replay(zk);
+//
+//        dsnCallbacks.clear();
+//        assertEquals("Precondition failed", 0, dsnCallbacks.size());
+//        dml.change();
+//        assertEquals(1, dsnCallbacks.size());
+//        DiscoveredServiceNotification dsn2 = dsnCallbacks.iterator().next();
+//        assertEquals(Collections.singleton(String.class.getName()), dsn2.getInterfaces());
+//        assertEquals(DiscoveredServiceNotification.MODIFIED, dsn2.getType());
+//        assertEquals(0, dsn2.getFilters().size());
+//        ServiceEndpointDescription sed2 = dsn2.getServiceEndpointDescription();
+//        assertEquals(Collections.singleton(String.class.getName()), sed2.getProvidedInterfaces());
+//        assertEquals(modified, sed2.getProperties());
+//
+//        EasyMock.verify(zk);
+//
+//        //----------------------------------------------------------------
+//        // Test DiscoveredServiceNotification.MODIFIED2
+//        //----------------------------------------------------------------
+//        Properties modified2 = new Properties();
+//        modified2.put("c", "d2");
+//        modified2.put(ServicePublication.ENDPOINT_LOCATION, "http://somehost:112/some/context");
+//        modified2.put("service.exported.configs", "org.apache.cxf.ws");
+//        modified2.put("org.apache.cxf.ws.address", "http://somewhereelse/123");
+//        ByteArrayOutputStream modBytes2 = new ByteArrayOutputStream();
+//        modified2.store(modBytes2, "");
+//
+//        EasyMock.reset(zk);
+//        EasyMock.expect(zk.getChildren(Utils.getZooKeeperPath(String.class.getName()), false))
+//            .andReturn(Arrays.asList("x#y#z"));
+//        EasyMock.expect(zk.getData(Utils.getZooKeeperPath(String.class.getName()) + "/x#y#z", false, null))
+//            .andReturn(modBytes2.toByteArray());
+//        EasyMock.replay(zk);
+//
+//        dsnCallbacks.clear();
+//        assertEquals("Precondition failed", 0, dsnCallbacks.size());
+//        dml.change();
+//        assertEquals(1, dsnCallbacks.size());
+//        DiscoveredServiceNotification dsn3 = dsnCallbacks.iterator().next();
+//        assertEquals(Collections.singleton(String.class.getName()), dsn3.getInterfaces());
+//        assertEquals(DiscoveredServiceNotification.MODIFIED, dsn3.getType());
+//        assertEquals(0, dsn3.getFilters().size());
+//        ServiceEndpointDescription sed3 = dsn3.getServiceEndpointDescription();
+//        assertEquals(Collections.singleton(String.class.getName()), sed3.getProvidedInterfaces());
+//        assertEquals(modified2, sed3.getProperties());
+//
+//        EasyMock.verify(zk);
+//        //----------------------------------------------------------------
+//        // Test DiscoveredServiceNotification.UNAVAILABLE
+//        //----------------------------------------------------------------
+//        EasyMock.reset(zk);
+//        EasyMock.expect(zk.getChildren(Utils.getZooKeeperPath(String.class.getName()), false))
+//            .andReturn(Collections.<String>emptyList());
+//        EasyMock.replay(zk);
+//
+//        dsnCallbacks.clear();
+//        assertEquals("Precondition failed", 0, dsnCallbacks.size());
+//        dml.change();
+//        assertEquals(1, dsnCallbacks.size());
+//        DiscoveredServiceNotification dsn4 = dsnCallbacks.iterator().next();
+//        assertEquals(Collections.singleton(String.class.getName()), dsn4.getInterfaces());
+//        assertEquals(DiscoveredServiceNotification.UNAVAILABLE, dsn4.getType());
+//        assertEquals(0, dsn4.getFilters().size());
+//        ServiceEndpointDescription sed4 = dsn4.getServiceEndpointDescription();
+//        assertEquals(Collections.singleton(String.class.getName()), sed4.getProvidedInterfaces());
+//        assertEquals(modified2, sed4.getProperties());
+//
+//        EasyMock.verify(zk);
+//
+//        // Try the same again...
+//        EasyMock.reset(zk);
+//        EasyMock.expect(zk.getChildren(Utils.getZooKeeperPath(String.class.getName()), false))
+//            .andReturn(Collections.<String>emptyList());
+//        EasyMock.replay(zk);
+//
+//        dsnCallbacks.clear();
+//        assertEquals("Precondition failed", 0, dsnCallbacks.size());
+//        dml.change();
+//        assertEquals("Should not receive a callback again...", 0, dsnCallbacks.size());
+//        EasyMock.verify(zk);
+//    }
+}
diff --git a/trunk/discovery/distributed/cxf-discovery/src/test/java/org/apache/cxf/dosgi/discovery/zookeeper/publish/PublishingEndpointListenerFactoryTest.java b/trunk/discovery/distributed/cxf-discovery/src/test/java/org/apache/cxf/dosgi/discovery/zookeeper/publish/PublishingEndpointListenerFactoryTest.java
new file mode 100644
index 0000000..e63b805
--- /dev/null
+++ b/trunk/discovery/distributed/cxf-discovery/src/test/java/org/apache/cxf/dosgi/discovery/zookeeper/publish/PublishingEndpointListenerFactoryTest.java
@@ -0,0 +1,100 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.cxf.dosgi.discovery.zookeeper.publish;
+
+import java.util.Dictionary;
+import java.util.List;
+
+import junit.framework.TestCase;
+
+import org.apache.zookeeper.ZooKeeper;
+import org.easymock.classextension.EasyMock;
+import org.easymock.classextension.IMocksControl;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.ServiceRegistration;
+import org.osgi.service.remoteserviceadmin.EndpointListener;
+
+public class PublishingEndpointListenerFactoryTest extends TestCase {
+
+    @SuppressWarnings("unchecked")
+    public void testScope() {
+        IMocksControl c = EasyMock.createNiceControl();
+
+        BundleContext ctx = c.createMock(BundleContext.class);
+        ZooKeeper zk = c.createMock(ZooKeeper.class);
+        @SuppressWarnings("rawtypes")
+        ServiceRegistration sreg = c.createMock(ServiceRegistration.class);
+
+        PublishingEndpointListenerFactory eplf = new PublishingEndpointListenerFactory(zk, ctx);
+
+        EasyMock.expect(ctx.registerService(EasyMock.eq(EndpointListener.class.getName()), EasyMock.eq(eplf),
+                                            (Dictionary<String, String>)EasyMock.anyObject())).andReturn(sreg).once();
+
+        EasyMock.expect(ctx.getProperty(EasyMock.eq("org.osgi.framework.uuid"))).andReturn("myUUID").anyTimes();
+
+        c.replay();
+        eplf.start();
+        c.verify();
+
+    }
+
+    @SuppressWarnings("unchecked")
+    public void testServiceFactory() {
+        IMocksControl c = EasyMock.createNiceControl();
+
+        BundleContext ctx = c.createMock(BundleContext.class);
+        ZooKeeper zk = c.createMock(ZooKeeper.class);
+        @SuppressWarnings("rawtypes")
+        ServiceRegistration sreg = c.createMock(ServiceRegistration.class);
+
+        PublishingEndpointListenerFactory eplf = new PublishingEndpointListenerFactory(zk, ctx);
+
+        EasyMock.expect(ctx.registerService(EasyMock.eq(EndpointListener.class.getName()), EasyMock.eq(eplf),
+                                (Dictionary<String, String>)EasyMock.anyObject())).andReturn(sreg).once();
+
+        EasyMock.expect(ctx.getProperty(EasyMock.eq("org.osgi.framework.uuid"))).andReturn("myUUID").anyTimes();
+
+        PublishingEndpointListener eli = c.createMock(PublishingEndpointListener.class);
+        eli.close();
+        EasyMock.expectLastCall().once();
+
+        c.replay();
+        eplf.start();
+
+        PublishingEndpointListener service = eplf.getService(null, null);
+        assertNotNull(service);
+        assertTrue(service instanceof EndpointListener);
+
+        List<PublishingEndpointListener> listeners = eplf.getListeners();
+        assertEquals(1, listeners.size());
+        assertEquals(service, listeners.get(0));
+
+        eplf.ungetService(null, null, service);
+        listeners = eplf.getListeners();
+        assertEquals(0, listeners.size());
+
+        eplf.ungetService(null, null, eli); // no call to close
+        listeners.add(eli);
+        eplf.ungetService(null, null, eli); // call to close
+        listeners = eplf.getListeners();
+        assertEquals(0, listeners.size());
+
+        c.verify();
+    }
+}
diff --git a/trunk/discovery/distributed/cxf-discovery/src/test/java/org/apache/cxf/dosgi/discovery/zookeeper/publish/PublishingEndpointListenerTest.java b/trunk/discovery/distributed/cxf-discovery/src/test/java/org/apache/cxf/dosgi/discovery/zookeeper/publish/PublishingEndpointListenerTest.java
new file mode 100644
index 0000000..c61fc9d
--- /dev/null
+++ b/trunk/discovery/distributed/cxf-discovery/src/test/java/org/apache/cxf/dosgi/discovery/zookeeper/publish/PublishingEndpointListenerTest.java
@@ -0,0 +1,200 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.cxf.dosgi.discovery.zookeeper.publish;
+
+import java.lang.reflect.Field;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import junit.framework.TestCase;
+
+import org.apache.cxf.dosgi.endpointdesc.EndpointDescriptionParser;
+import org.apache.cxf.dosgi.endpointdesc.PropertiesMapper;
+import org.apache.zookeeper.CreateMode;
+import org.apache.zookeeper.KeeperException;
+import org.apache.zookeeper.ZooDefs.Ids;
+import org.apache.zookeeper.ZooKeeper;
+import org.easymock.IAnswer;
+import org.easymock.classextension.EasyMock;
+import org.easymock.classextension.IMocksControl;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.Constants;
+import org.osgi.framework.Filter;
+import org.osgi.framework.FrameworkUtil;
+import org.osgi.framework.ServiceListener;
+import org.osgi.framework.ServiceReference;
+import org.osgi.service.remoteserviceadmin.EndpointDescription;
+import org.osgi.service.remoteserviceadmin.RemoteConstants;
+import org.osgi.xmlns.rsa.v1_0.EndpointDescriptionType;
+import org.osgi.xmlns.rsa.v1_0.PropertyType;
+
+public class PublishingEndpointListenerTest extends TestCase {
+
+    public void testEndpointRemovalAdding() throws KeeperException, InterruptedException {
+        IMocksControl c = EasyMock.createNiceControl();
+
+        BundleContext ctx = c.createMock(BundleContext.class);
+        ZooKeeper zk = c.createMock(ZooKeeper.class);
+
+        String path = "/osgi/service_registry/myClass/google.de#80##test";
+        EasyMock.expect(zk.create(EasyMock.eq(path),
+                (byte[])EasyMock.anyObject(), EasyMock.eq(Ids.OPEN_ACL_UNSAFE),
+                EasyMock.eq(CreateMode.EPHEMERAL))).andReturn("").once();
+
+        zk.delete(EasyMock.eq("/osgi/service_registry/myClass/google.de#80##test"), EasyMock.eq(-1));
+        EasyMock.expectLastCall().once();
+
+        c.replay();
+
+        PublishingEndpointListener eli = new PublishingEndpointListener(zk, ctx);
+
+        Map<String, Object> props = new HashMap<String, Object>();
+        props.put(Constants.OBJECTCLASS, new String[] {
+            "myClass"
+        });
+        props.put(RemoteConstants.ENDPOINT_ID, "http://google.de:80/test");
+        props.put(RemoteConstants.SERVICE_IMPORTED_CONFIGS, "myConfig");
+
+        EndpointDescription endpoint = new EndpointDescription(props);
+
+        eli.endpointAdded(endpoint, null);
+        eli.endpointAdded(endpoint, null); // should do nothing
+
+        eli.endpointRemoved(endpoint, null);
+        eli.endpointRemoved(endpoint, null); // should do nothing
+
+        c.verify();
+    }
+
+    public void testDiscoveryPlugin() throws Exception {
+        DiscoveryPlugin plugin1 = new DiscoveryPlugin() {
+            public String process(Map<String, Object> mutableProperties, String endpointKey) {
+                String eid = (String) mutableProperties.get("endpoint.id");
+                mutableProperties.put("endpoint.id", eid + "/appended");
+                return endpointKey;
+            }
+        };
+        @SuppressWarnings("unchecked")
+        ServiceReference<DiscoveryPlugin> sr1 = EasyMock.createMock(ServiceReference.class);
+
+        DiscoveryPlugin plugin2 = new DiscoveryPlugin() {
+            public String process(Map<String, Object> mutableProperties, String endpointKey) {
+                mutableProperties.put("foo", "bar");
+                return endpointKey.replaceAll("localhost", "some.machine");
+            }
+        };
+        @SuppressWarnings("unchecked")
+        ServiceReference<DiscoveryPlugin> sr2 = EasyMock.createMock(ServiceReference.class);
+
+        BundleContext ctx = EasyMock.createMock(BundleContext.class);
+        EasyMock.expect(ctx.createFilter(EasyMock.isA(String.class))).andAnswer(new IAnswer<Filter>() {
+            public Filter answer() throws Throwable {
+                return FrameworkUtil.createFilter((String) EasyMock.getCurrentArguments()[0]);
+            }
+        }).anyTimes();
+        ctx.addServiceListener(EasyMock.isA(ServiceListener.class),
+                EasyMock.eq("(objectClass=" + DiscoveryPlugin.class.getName() + ")"));
+        EasyMock.expect(ctx.getService(sr1)).andReturn(plugin1).anyTimes();
+        EasyMock.expect(ctx.getService(sr2)).andReturn(plugin2).anyTimes();
+        EasyMock.expect(ctx.getServiceReferences(DiscoveryPlugin.class.getName(), null))
+                .andReturn(new ServiceReference[]{sr1, sr2}).anyTimes();
+        EasyMock.replay(ctx);
+
+        Map<String, Object> props = new HashMap<String, Object>();
+        props.put(Constants.OBJECTCLASS, new String[] {"org.foo.myClass"});
+        props.put(RemoteConstants.ENDPOINT_ID, "http://localhost:9876/test");
+        props.put(RemoteConstants.SERVICE_IMPORTED_CONFIGS, "myConfig");
+        EndpointDescription endpoint = new EndpointDescription(props);
+
+        Map<String, Object> expectedProps = new HashMap<String, Object>(props);
+        expectedProps.put("endpoint.id", "http://localhost:9876/test/appended");
+        expectedProps.put("foo", "bar");
+        expectedProps.put("service.imported", "true");
+
+        final ZooKeeper zk = EasyMock.createNiceMock(ZooKeeper.class);
+        String expectedFullPath = "/osgi/service_registry/org/foo/myClass/some.machine#9876##test";
+        
+        List<PropertyType> props2 = new PropertiesMapper().fromProps(expectedProps);
+        EndpointDescriptionType epd = new EndpointDescriptionType();
+        epd.getProperty().addAll(props2);
+        byte[] data = new EndpointDescriptionParser().getData(epd);
+        EasyMock.expect(zk.create(
+                EasyMock.eq(expectedFullPath),
+                EasyMock.aryEq(data),
+                EasyMock.eq(Ids.OPEN_ACL_UNSAFE),
+                EasyMock.eq(CreateMode.EPHEMERAL))).andReturn("");
+        EasyMock.replay(zk);
+
+        PublishingEndpointListener eli = new PublishingEndpointListener(zk, ctx);
+
+        List<EndpointDescription> endpoints = getEndpoints(eli);
+        assertEquals("Precondition", 0, endpoints.size());
+        eli.endpointAdded(endpoint, null);
+        assertEquals(1, endpoints.size());
+
+        EasyMock.verify(zk);
+    }
+
+    @SuppressWarnings("unchecked")
+    private List<EndpointDescription> getEndpoints(PublishingEndpointListener eli) throws Exception {
+        Field field = eli.getClass().getDeclaredField("endpoints");
+        field.setAccessible(true);
+        return (List<EndpointDescription>) field.get(eli);
+    }
+
+    public void testClose() throws KeeperException, InterruptedException {
+        IMocksControl c = EasyMock.createNiceControl();
+
+        BundleContext ctx = c.createMock(BundleContext.class);
+        ZooKeeper zk = c.createMock(ZooKeeper.class);
+
+        String path = "/osgi/service_registry/myClass/google.de#80##test";
+        EasyMock.expect(zk.create(EasyMock.eq(path),
+                (byte[])EasyMock.anyObject(), EasyMock.eq(Ids.OPEN_ACL_UNSAFE),
+                EasyMock.eq(CreateMode.EPHEMERAL))).andReturn("").once();
+
+        zk.delete(EasyMock.eq("/osgi/service_registry/myClass/google.de#80##test"), EasyMock.eq(-1));
+        EasyMock.expectLastCall().once();
+
+        c.replay();
+
+        PublishingEndpointListener eli = new PublishingEndpointListener(zk, ctx);
+
+        Map<String, Object> props = new HashMap<String, Object>();
+        props.put(Constants.OBJECTCLASS, new String[] {
+            "myClass"
+        });
+        props.put(RemoteConstants.ENDPOINT_ID, "http://google.de:80/test");
+        props.put(RemoteConstants.SERVICE_IMPORTED_CONFIGS, "myConfig");
+
+        EndpointDescription endpoint = new EndpointDescription(props);
+
+        eli.endpointAdded(endpoint, null);
+
+        eli.close(); // should result in zk.delete(...)
+
+        c.verify();
+    }
+
+    public void testGetKey() throws Exception {
+        assertEquals("somehost#9090##org#example#TestEndpoint",
+            PublishingEndpointListener.getKey("http://somehost:9090/org/example/TestEndpoint"));
+    }
+}
diff --git a/trunk/discovery/distributed/cxf-discovery/src/test/java/org/apache/cxf/dosgi/discovery/zookeeper/subscribe/InterfaceMonitorManagerTest.java b/trunk/discovery/distributed/cxf-discovery/src/test/java/org/apache/cxf/dosgi/discovery/zookeeper/subscribe/InterfaceMonitorManagerTest.java
new file mode 100644
index 0000000..7d6f67f
--- /dev/null
+++ b/trunk/discovery/distributed/cxf-discovery/src/test/java/org/apache/cxf/dosgi/discovery/zookeeper/subscribe/InterfaceMonitorManagerTest.java
@@ -0,0 +1,139 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.cxf.dosgi.discovery.zookeeper.subscribe;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.zookeeper.ZooKeeper;
+import org.easymock.IAnswer;
+import org.easymock.classextension.EasyMock;
+import org.easymock.classextension.IMocksControl;
+import org.junit.Test;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.ServiceReference;
+import org.osgi.service.remoteserviceadmin.EndpointListener;
+
+import static org.junit.Assert.assertEquals;
+
+public class InterfaceMonitorManagerTest {
+
+    @Test
+    public void testEndpointListenerTrackerCustomizer() {
+        IMocksControl c = EasyMock.createNiceControl();
+
+        BundleContext ctx = c.createMock(BundleContext.class);
+        ZooKeeper zk = c.createMock(ZooKeeper.class);
+
+        @SuppressWarnings("unchecked")
+        ServiceReference<EndpointListener> sref = c.createMock(ServiceReference.class);
+        @SuppressWarnings("unchecked")
+        ServiceReference<EndpointListener> sref2 = c.createMock(ServiceReference.class);
+
+        final Map<String, ?> p = new HashMap<String, Object>();
+
+        EasyMock.expect(sref.getPropertyKeys()).andAnswer(new IAnswer<String[]>() {
+            public String[] answer() throws Throwable {
+                return p.keySet().toArray(new String[p.size()]);
+            }
+        }).anyTimes();
+
+        EasyMock.expect(sref.getProperty((String)EasyMock.anyObject())).andAnswer(new IAnswer<Object>() {
+            public Object answer() throws Throwable {
+                String key = (String)(EasyMock.getCurrentArguments()[0]);
+                return p.get(key);
+            }
+        }).anyTimes();
+
+        EasyMock.expect(sref2.getPropertyKeys()).andAnswer(new IAnswer<String[]>() {
+            public String[] answer() throws Throwable {
+                return p.keySet().toArray(new String[p.size()]);
+            }
+        }).anyTimes();
+
+        EasyMock.expect(sref2.getProperty((String)EasyMock.anyObject())).andAnswer(new IAnswer<Object>() {
+            public Object answer() throws Throwable {
+                String key = (String)(EasyMock.getCurrentArguments()[0]);
+                return p.get(key);
+            }
+        }).anyTimes();
+
+        final List<IMocksControl> controls = new ArrayList<IMocksControl>();
+
+        InterfaceMonitorManager eltc = new InterfaceMonitorManager(ctx, zk);
+
+        c.replay();
+
+        // sref has no scope -> nothing should happen
+
+        assertEquals(0, eltc.getEndpointListenerScopes().size());
+        assertEquals(0, eltc.getInterests().size());
+
+        //p.put(EndpointListener.ENDPOINT_LISTENER_SCOPE, );
+
+        eltc.addInterest(sref, "(objectClass=mine)", "mine");
+
+        assertEquals(1, eltc.getEndpointListenerScopes().size());
+        assertEquals(1, eltc.getEndpointListenerScopes().get(sref).size());
+        assertEquals("(objectClass=mine)", eltc.getEndpointListenerScopes().get(sref).get(0));
+        assertEquals(1, eltc.getInterests().size());
+
+        eltc.addInterest(sref, "(objectClass=mine)", "mine");
+
+        assertEquals(1, eltc.getEndpointListenerScopes().size());
+        assertEquals(1, eltc.getEndpointListenerScopes().get(sref).size());
+        assertEquals("(objectClass=mine)", eltc.getEndpointListenerScopes().get(sref).get(0));
+        assertEquals(1, eltc.getInterests().size());
+
+        eltc.addInterest(sref2, "(objectClass=mine)", "mine");
+
+        assertEquals(2, eltc.getEndpointListenerScopes().size());
+        assertEquals(1, eltc.getEndpointListenerScopes().get(sref).size());
+        assertEquals(1, eltc.getEndpointListenerScopes().get(sref2).size());
+        assertEquals("(objectClass=mine)", eltc.getEndpointListenerScopes().get(sref).get(0));
+        assertEquals("(objectClass=mine)", eltc.getEndpointListenerScopes().get(sref2).get(0));
+        assertEquals(1, eltc.getInterests().size());
+
+        eltc.removeInterest(sref);
+
+        assertEquals(1, eltc.getEndpointListenerScopes().size());
+        assertEquals(1, eltc.getEndpointListenerScopes().get(sref2).size());
+        assertEquals("(objectClass=mine)", eltc.getEndpointListenerScopes().get(sref2).get(0));
+        assertEquals(1, eltc.getInterests().size());
+
+        eltc.removeInterest(sref);
+
+        assertEquals(1, eltc.getEndpointListenerScopes().size());
+        assertEquals(1, eltc.getEndpointListenerScopes().get(sref2).size());
+        assertEquals("(objectClass=mine)", eltc.getEndpointListenerScopes().get(sref2).get(0));
+        assertEquals(1, eltc.getInterests().size());
+
+        eltc.removeInterest(sref2);
+
+        assertEquals(0, eltc.getEndpointListenerScopes().size());
+        assertEquals(0, eltc.getInterests().size());
+
+        c.verify();
+        for (IMocksControl control : controls) {
+            control.verify();
+        }
+    }
+}
diff --git a/trunk/discovery/distributed/cxf-discovery/src/test/java/org/apache/cxf/dosgi/discovery/zookeeper/subscribe/InterfaceMonitorTest.java b/trunk/discovery/distributed/cxf-discovery/src/test/java/org/apache/cxf/dosgi/discovery/zookeeper/subscribe/InterfaceMonitorTest.java
new file mode 100644
index 0000000..67afb16
--- /dev/null
+++ b/trunk/discovery/distributed/cxf-discovery/src/test/java/org/apache/cxf/dosgi/discovery/zookeeper/subscribe/InterfaceMonitorTest.java
@@ -0,0 +1,67 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.cxf.dosgi.discovery.zookeeper.subscribe;
+
+import java.util.Collections;
+
+import junit.framework.TestCase;
+
+import org.apache.cxf.dosgi.discovery.zookeeper.util.Utils;
+import org.apache.zookeeper.KeeperException;
+import org.apache.zookeeper.WatchedEvent;
+import org.apache.zookeeper.Watcher.Event.EventType;
+import org.apache.zookeeper.Watcher.Event.KeeperState;
+import org.apache.zookeeper.ZooKeeper;
+import org.apache.zookeeper.data.Stat;
+import org.easymock.classextension.EasyMock;
+import org.easymock.classextension.IMocksControl;
+import org.osgi.service.remoteserviceadmin.EndpointListener;
+
+import static org.easymock.EasyMock.eq;
+import static org.easymock.EasyMock.expect;
+
+public class InterfaceMonitorTest extends TestCase {
+
+    public void testInterfaceMonitor() throws KeeperException, InterruptedException {
+        IMocksControl c = EasyMock.createControl();
+
+        ZooKeeper zk = c.createMock(ZooKeeper.class);
+        expect(zk.getState()).andReturn(ZooKeeper.States.CONNECTED).anyTimes();
+
+        String scope = "(myProp=test)";
+        String interf = "es.schaaf.test";
+        String node = Utils.getZooKeeperPath(interf);
+
+        EndpointListener endpointListener = c.createMock(EndpointListener.class);
+        InterfaceMonitor im = new InterfaceMonitor(zk, interf, endpointListener, scope);
+        zk.exists(eq(node), eq(im), eq(im), EasyMock.anyObject());
+        EasyMock.expectLastCall().once();
+
+        expect(zk.exists(eq(node), eq(false))).andReturn(new Stat()).anyTimes();
+        expect(zk.getChildren(eq(node), eq(false))).andReturn(Collections.<String> emptyList()).once();
+        expect(zk.getChildren(eq(node), eq(im))).andReturn(Collections.<String> emptyList()).once();
+
+        c.replay();
+        im.start();
+        // simulate a zk callback
+        WatchedEvent we = new WatchedEvent(EventType.NodeCreated, KeeperState.SyncConnected, node);
+        im.process(we);
+        c.verify();
+    }
+}
diff --git a/trunk/discovery/distributed/cxf-discovery/src/test/java/org/apache/cxf/dosgi/discovery/zookeeper/util/UtilsTest.java b/trunk/discovery/distributed/cxf-discovery/src/test/java/org/apache/cxf/dosgi/discovery/zookeeper/util/UtilsTest.java
new file mode 100644
index 0000000..08c830c
--- /dev/null
+++ b/trunk/discovery/distributed/cxf-discovery/src/test/java/org/apache/cxf/dosgi/discovery/zookeeper/util/UtilsTest.java
@@ -0,0 +1,110 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.cxf.dosgi.discovery.zookeeper.util;
+
+import java.util.Arrays;
+
+import junit.framework.TestCase;
+
+import org.easymock.classextension.EasyMock;
+import org.easymock.classextension.IMocksControl;
+import org.osgi.framework.ServiceReference;
+import org.osgi.service.remoteserviceadmin.EndpointListener;
+
+public class UtilsTest extends TestCase {
+
+    public void testGetZooKeeperPath() {
+        assertEquals(Utils.PATH_PREFIX + '/' + "org/example/Test",
+            Utils.getZooKeeperPath("org.example.Test"));
+
+        // used for the recursive discovery
+        assertEquals(Utils.PATH_PREFIX, Utils.getZooKeeperPath(null));
+        assertEquals(Utils.PATH_PREFIX, Utils.getZooKeeperPath(""));
+    }
+
+    public void testGetStringPlusProperty() {
+        String[] out = Utils.getStringPlusProperty("MyString");
+        assertEquals(1, out.length);
+        assertEquals("MyString", out[0]);
+
+        out = Utils.getStringPlusProperty(new String[]{"MyString"});
+        assertEquals(1, out.length);
+        assertEquals("MyString", out[0]);
+
+        out = Utils.getStringPlusProperty(Arrays.asList("MyString"));
+        assertEquals(1, out.length);
+        assertEquals("MyString", out[0]);
+
+        out = Utils.getStringPlusProperty(Arrays.asList(1));
+        assertEquals(0, out.length);
+
+        out = Utils.getStringPlusProperty(new Object());
+        assertEquals(0, out.length);
+
+        out = Utils.getStringPlusProperty(null);
+        assertEquals(0, out.length);
+    }
+
+    public void testRemoveEmpty() {
+        String[] out = Utils.removeEmpty(new String[0]);
+        assertEquals(0, out.length);
+
+        out = Utils.removeEmpty(new String[]{null});
+        assertEquals(0, out.length);
+
+        out = Utils.removeEmpty(new String[]{""});
+        assertEquals(0, out.length);
+
+        out = Utils.removeEmpty(new String[]{"hi"});
+        assertEquals(1, out.length);
+        assertEquals("hi", out[0]);
+
+        out = Utils.removeEmpty(new String[]{"", "hi", null});
+        assertEquals(1, out.length);
+        assertEquals("hi", out[0]);
+
+        out = Utils.removeEmpty(new String[]{"hi", null, "", ""});
+        assertEquals(1, out.length);
+        assertEquals("hi", out[0]);
+
+        out = Utils.removeEmpty(new String[]{"", "hi", null, "", "", "bye", null});
+        assertEquals(2, out.length);
+        assertEquals("hi", out[0]);
+        assertEquals("bye", out[1]);
+    }
+
+    public void testGetScopes() {
+        IMocksControl c = EasyMock.createNiceControl();
+
+        String[] scopes = new String[]{"myScope=test", ""};
+
+        @SuppressWarnings("unchecked")
+        ServiceReference<EndpointListener> sref = c.createMock(ServiceReference.class);
+        EasyMock.expect(sref.getProperty(EasyMock.eq(EndpointListener.ENDPOINT_LISTENER_SCOPE)))
+            .andReturn(scopes).anyTimes();
+
+        c.replay();
+
+        String[] ret = Utils.getScopes(sref);
+
+        c.verify();
+        assertEquals(1, ret.length);
+        assertEquals(scopes[0], ret[0]);
+    }
+}
diff --git a/trunk/discovery/distributed/pom.xml b/trunk/discovery/distributed/pom.xml
new file mode 100644
index 0000000..61f06f0
--- /dev/null
+++ b/trunk/discovery/distributed/pom.xml
@@ -0,0 +1,42 @@
+<?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>
+    <groupId>org.apache.cxf.dosgi</groupId>
+    <artifactId>cxf-dosgi-ri-discovery-distributed-parent</artifactId>
+    <version>1.6.0</version>
+    <packaging>pom</packaging>
+    <name>Distributed OSGI Distributed Discovery Parent</name>
+    <url>http://cxf.apache.org</url>
+
+    <parent>
+      <groupId>org.apache.cxf.dosgi</groupId>
+      <artifactId>cxf-dosgi-ri-parent</artifactId>
+      <version>1.6.0</version>
+      <relativePath>../../parent/pom.xml</relativePath>
+    </parent>
+
+    <modules>
+      <module>zookeeper-server</module>
+      <module>zookeeper-server-config</module>
+      <module>cxf-discovery</module>
+    </modules>
+</project>
diff --git a/trunk/discovery/distributed/zookeeper-server-config/pom.xml b/trunk/discovery/distributed/zookeeper-server-config/pom.xml
new file mode 100644
index 0000000..0b3fbfc
--- /dev/null
+++ b/trunk/discovery/distributed/zookeeper-server-config/pom.xml
@@ -0,0 +1,76 @@
+<?xml version='1.0' encoding='UTF-8' ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements. See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership. The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License. You may obtain a copy of the License at
+
+  http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied. See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+
+    <modelVersion>4.0.0</modelVersion>
+    <groupId>org.apache.cxf.dosgi</groupId>
+    <artifactId>cxf-dosgi-ri-discovery-distributed-zookeeper-server-config</artifactId>
+    <packaging>bundle</packaging>
+    <name>Distributed OSGI Distributed Discovery ZooKeeper Server Control Configuration Bundle</name>
+    <description>This bundle provides some default OSGi Configuration Admin data and is only useful for use in the OSGi CT suite</description>
+    <version>1.6.0</version>
+
+    <parent>
+      <groupId>org.apache.cxf.dosgi</groupId>
+      <artifactId>cxf-dosgi-ri-parent</artifactId>
+      <version>1.6.0</version>
+      <relativePath>../../../parent/pom.xml</relativePath>
+    </parent>
+
+    <properties>
+        <topDirectoryLocation>../../..</topDirectoryLocation>
+    </properties>
+
+    <dependencies>
+        <dependency>
+            <groupId>org.osgi</groupId>
+            <artifactId>org.osgi.core</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.osgi</groupId>
+            <artifactId>org.osgi.compendium</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>org.slf4j</groupId>
+            <artifactId>slf4j-api</artifactId>
+        </dependency>
+    </dependencies>
+
+    <build>
+        <plugins>
+            <plugin>
+                <groupId>org.apache.felix</groupId>
+                <artifactId>maven-bundle-plugin</artifactId>
+                <configuration>
+                    <instructions>
+                        <Bundle-Name>ZooKeeper server configuration bundle</Bundle-Name>
+                        <Bundle-Description>Configures the ZooKeeper server in an OSGi Framework</Bundle-Description>
+                        <Bundle-SymbolicName>${project.artifactId}</Bundle-SymbolicName>
+                        <Bundle-Activator>org.apache.cxf.dosgi.discovery.zookeeper.server.config.Activator</Bundle-Activator>
+                        <Import-Package>*</Import-Package>
+                        <Private-Package>org.apache.cxf.dosgi.discovery.zookeeper.server.config</Private-Package>
+                        <Export-Package />
+                    </instructions>
+                </configuration>
+            </plugin>
+        </plugins>
+    </build>
+</project>
diff --git a/trunk/discovery/distributed/zookeeper-server-config/src/main/java/org/apache/cxf/dosgi/discovery/zookeeper/server/config/Activator.java b/trunk/discovery/distributed/zookeeper-server-config/src/main/java/org/apache/cxf/dosgi/discovery/zookeeper/server/config/Activator.java
new file mode 100644
index 0000000..cbe0e79
--- /dev/null
+++ b/trunk/discovery/distributed/zookeeper-server-config/src/main/java/org/apache/cxf/dosgi/discovery/zookeeper/server/config/Activator.java
@@ -0,0 +1,113 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.cxf.dosgi.discovery.zookeeper.server.config;
+
+import java.io.IOException;
+import java.net.ServerSocket;
+import java.util.Dictionary;
+import java.util.Hashtable;
+
+import org.osgi.framework.BundleActivator;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.ServiceReference;
+import org.osgi.service.cm.Configuration;
+import org.osgi.service.cm.ConfigurationAdmin;
+import org.osgi.service.cm.ManagedService;
+import org.osgi.util.tracker.ServiceTracker;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class Activator implements BundleActivator {
+
+    private static final Logger LOG = LoggerFactory.getLogger(Activator.class);
+    private static final String ZOOKEEPER_PORT = "org.apache.cxf.dosgi.discovery.zookeeper.port";
+    private static final String PID = "org.apache.cxf.dosgi.discovery.zookeeper.server";
+    private ServiceTracker st;
+
+    public void start(BundleContext context) throws Exception {
+        synchronized (Activator.class) {
+            // Only one thread gets to set the port number
+            if (System.getProperty(ZOOKEEPER_PORT) == null) {
+                String port = getFreePort();
+                System.setProperty(ZOOKEEPER_PORT, port);
+                LOG.info("Global ZooKeeper port: {}", port);
+            }
+        }
+
+        st = new ServiceTracker(context, ConfigurationAdmin.class.getName(), null) {
+            @Override
+            public Object addingService(ServiceReference reference) {
+                Object svc = super.addingService(reference);
+                if (svc instanceof ConfigurationAdmin) {
+                    try {
+                        ConfigurationAdmin cadmin = (ConfigurationAdmin) svc;
+                        Configuration cfg = cadmin.getConfiguration(PID, null);
+                        Dictionary<String, Object> props = new Hashtable<String, Object>();
+                        String zp = System.getProperty(ZOOKEEPER_PORT);
+                        props.put("clientPort", zp);
+                        cfg.update(props);
+                        LOG.debug("Set ZooKeeper client port to {}", zp);
+                    } catch (IOException e) {
+                        LOG.error("Failed to configure ZooKeeper server!", e);
+                    }
+                }
+                return svc;
+            }
+        };
+        st.open();
+
+        // The following section is done synchronously otherwise it doesn't happen in time for the CT
+        ServiceReference[] refs = context.getServiceReferences(ManagedService.class.getName(),
+                "(service.pid=org.apache.cxf.dosgi.discovery.zookeeper)");
+        if (refs == null || refs.length == 0) {
+            throw new RuntimeException("This bundle must be started after the bundle with the ZooKeeper "
+                                       + "Discovery Managed Service was started.");
+        }
+
+        Dictionary<String, Object> props = new Hashtable<String, Object>();
+        props.put("zookeeper.host", "127.0.0.1");
+        props.put("zookeeper.port", System.getProperty(ZOOKEEPER_PORT));
+
+        ManagedService ms = (ManagedService) context.getService(refs[0]);
+        try {
+            ms.updated(props);
+        } finally {
+            if (ms != null) {
+                context.ungetService(refs[0]);
+            }
+        }
+        LOG.debug("Passed the zookeeper.host property to the ZooKeeper Client managed service.");
+    }
+
+    private String getFreePort() {
+        try {
+            ServerSocket ss = new ServerSocket(0);
+            String port = "" + ss.getLocalPort();
+            ss.close();
+            return port;
+        } catch (IOException e) {
+            LOG.error("Failed to find a free port!", e);
+            return null;
+        }
+    }
+
+    public void stop(BundleContext context) throws Exception {
+        st.close();
+    }
+}
diff --git a/trunk/discovery/distributed/zookeeper-server/pom.xml b/trunk/discovery/distributed/zookeeper-server/pom.xml
new file mode 100644
index 0000000..a37706b
--- /dev/null
+++ b/trunk/discovery/distributed/zookeeper-server/pom.xml
@@ -0,0 +1,101 @@
+<?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>
+    <artifactId>cxf-dosgi-ri-discovery-distributed-zookeeper-server</artifactId>
+    <packaging>bundle</packaging>
+    <name>CXF DOSGi ZooKeeper Server Control Bundle</name>
+    <description>Runs the ZooKeeper server</description>
+
+    <parent>
+      <groupId>org.apache.cxf.dosgi</groupId>
+      <artifactId>cxf-dosgi-ri-parent</artifactId>
+      <version>1.6.0</version>
+      <relativePath>../../../parent/pom.xml</relativePath>
+    </parent>
+
+    <properties>
+        <topDirectoryLocation>../../..</topDirectoryLocation>
+    </properties>
+
+    <dependencies>
+        <dependency>
+            <groupId>org.osgi</groupId>
+            <artifactId>org.osgi.core</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.osgi</groupId>
+            <artifactId>org.osgi.compendium</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>org.apache.zookeeper</groupId>
+            <artifactId>zookeeper</artifactId>
+            <version>${zookeeper.version}</version>
+            <exclusions>
+                <exclusion>
+                   <groupId>com.sun.jdmk</groupId>
+                   <artifactId>jmxtools</artifactId>
+                </exclusion>
+                <exclusion>
+                   <groupId>com.sun.jmx</groupId>
+                   <artifactId>jmxri</artifactId>
+                </exclusion>
+            </exclusions>
+        </dependency>
+
+        <!--  We need the newer log4j as the one from ZooKeeper has some ugly dependencies -->
+        <dependency>
+            <groupId>log4j</groupId>
+            <artifactId>log4j</artifactId>
+            <version>${log4j.version}</version>
+        </dependency>
+
+        <dependency>
+            <groupId>junit</groupId>
+            <artifactId>junit</artifactId>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.easymock</groupId>
+            <artifactId>easymockclassextension</artifactId>
+            <scope>test</scope>
+        </dependency>
+    </dependencies>
+
+    <build>
+        <plugins>
+            <plugin>
+                <groupId>org.apache.felix</groupId>
+                <artifactId>maven-bundle-plugin</artifactId>
+                <configuration>
+                    <instructions>
+                        <Bundle-SymbolicName>${project.artifactId}</Bundle-SymbolicName>
+                        <Bundle-Activator>org.apache.cxf.dosgi.discovery.zookeeper.server.Activator</Bundle-Activator>
+                        <Export-Package>
+                            !*
+                        </Export-Package>
+                    </instructions>
+                </configuration>
+            </plugin>
+        </plugins>
+    </build>
+</project>
diff --git a/trunk/discovery/distributed/zookeeper-server/src/main/java/org/apache/cxf/dosgi/discovery/zookeeper/server/Activator.java b/trunk/discovery/distributed/zookeeper-server/src/main/java/org/apache/cxf/dosgi/discovery/zookeeper/server/Activator.java
new file mode 100644
index 0000000..6adf700
--- /dev/null
+++ b/trunk/discovery/distributed/zookeeper-server/src/main/java/org/apache/cxf/dosgi/discovery/zookeeper/server/Activator.java
@@ -0,0 +1,44 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.cxf.dosgi.discovery.zookeeper.server;
+
+import java.util.Dictionary;
+import java.util.Hashtable;
+
+import org.osgi.framework.BundleActivator;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.Constants;
+
+public class Activator implements BundleActivator {
+
+    ZookeeperStarter zkStarter;
+
+    public void start(BundleContext context) throws Exception {
+        zkStarter = new ZookeeperStarter(context);
+        Dictionary<String, Object> props = new Hashtable<String, Object>();
+        props.put(Constants.SERVICE_PID, "org.apache.cxf.dosgi.discovery.zookeeper.server");
+        context.registerService(org.osgi.service.cm.ManagedService.class.getName(), zkStarter, props);
+    }
+
+    public void stop(BundleContext context) throws Exception {
+        if (zkStarter != null) {
+            zkStarter.shutdown();
+        }
+    }
+}
diff --git a/trunk/discovery/distributed/zookeeper-server/src/main/java/org/apache/cxf/dosgi/discovery/zookeeper/server/ZookeeperStarter.java b/trunk/discovery/distributed/zookeeper-server/src/main/java/org/apache/cxf/dosgi/discovery/zookeeper/server/ZookeeperStarter.java
new file mode 100644
index 0000000..4bf772a
--- /dev/null
+++ b/trunk/discovery/distributed/zookeeper-server/src/main/java/org/apache/cxf/dosgi/discovery/zookeeper/server/ZookeeperStarter.java
@@ -0,0 +1,156 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.cxf.dosgi.discovery.zookeeper.server;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.Dictionary;
+
+import org.apache.cxf.dosgi.discovery.zookeeper.server.util.Utils;
+import org.apache.log4j.Level;
+import org.apache.log4j.Logger;
+import org.apache.zookeeper.server.ServerConfig;
+import org.apache.zookeeper.server.ZooKeeperServerMain;
+import org.apache.zookeeper.server.quorum.QuorumPeerConfig;
+import org.apache.zookeeper.server.quorum.QuorumPeerConfig.ConfigException;
+import org.apache.zookeeper.server.quorum.QuorumPeerMain;
+import org.osgi.framework.BundleContext;
+import org.osgi.service.cm.ConfigurationException;
+
+public class ZookeeperStarter implements org.osgi.service.cm.ManagedService {
+
+    private static final Logger LOG = Logger.getLogger(ZookeeperStarter.class); //NOPMD - using log4j here
+
+    protected ZookeeperServer main;
+    private final BundleContext bundleContext;
+    private Thread zkMainThread;
+
+    public ZookeeperStarter(BundleContext ctx) {
+        bundleContext = ctx;
+    }
+
+    synchronized void shutdown() {
+        if (main != null) {
+            LOG.info("Shutting down ZooKeeper server");
+            try {
+                main.shutdown();
+                if (zkMainThread != null) {
+                    zkMainThread.join();
+                }
+            } catch (Throwable e) {
+                LOG.log(Level.ERROR, e.getMessage(), e);
+            }
+            main = null;
+            zkMainThread = null;
+        }
+    }
+
+    private void setDefaults(Dictionary<String, String> dict) throws IOException {
+        Utils.removeEmptyValues(dict); // to avoid NumberFormatExceptions
+        Utils.setDefault(dict, "tickTime", "2000");
+        Utils.setDefault(dict, "initLimit", "10");
+        Utils.setDefault(dict, "syncLimit", "5");
+        Utils.setDefault(dict, "clientPort", "2181");
+        Utils.setDefault(dict, "dataDir", new File(bundleContext.getDataFile(""), "zkdata").getCanonicalPath());
+    }
+
+    @SuppressWarnings("unchecked")
+    public synchronized void updated(Dictionary<String, ?> dict) throws ConfigurationException {
+        shutdown();
+        if (dict == null) {
+            return;
+        }
+        try {
+            setDefaults((Dictionary<String, String>)dict);
+            QuorumPeerConfig config = parseConfig(dict);
+            startFromConfig(config);
+            LOG.info("Applied configuration update: " + dict);
+        } catch (Exception th) {
+            LOG.error("Problem applying configuration update: " + dict, th);
+        }
+    }
+
+    private QuorumPeerConfig parseConfig(Dictionary<String, ?> dict) throws IOException, ConfigException {
+        QuorumPeerConfig config = new QuorumPeerConfig();
+        config.parseProperties(Utils.toProperties(dict));
+        return config;
+    }
+
+    protected void startFromConfig(final QuorumPeerConfig config) {
+        int numServers = config.getServers().size();
+        main = numServers > 1 ? new MyQuorumPeerMain(config) : new MyZooKeeperServerMain(config);
+        zkMainThread = new Thread(new Runnable() {
+            public void run() {
+                try {
+                    main.startup();
+                } catch (Throwable e) {
+                    LOG.error("Problem running ZooKeeper server.", e);
+                }
+            }
+        });
+        zkMainThread.start();
+    }
+
+    interface ZookeeperServer {
+        void startup() throws IOException;
+        void shutdown();
+    }
+
+    static class MyQuorumPeerMain extends QuorumPeerMain implements ZookeeperServer {
+
+        private QuorumPeerConfig config;
+
+        public MyQuorumPeerMain(QuorumPeerConfig config) {
+            this.config = config;
+        }
+
+        public void startup() throws IOException {
+            runFromConfig(config);
+        }
+
+        public void shutdown() {
+            if (null != quorumPeer) {
+                quorumPeer.shutdown();
+            }
+        }
+    }
+
+    static class MyZooKeeperServerMain extends ZooKeeperServerMain implements ZookeeperServer {
+
+        private QuorumPeerConfig config;
+
+        public MyZooKeeperServerMain(QuorumPeerConfig config) {
+            this.config = config;
+        }
+
+        public void startup() throws IOException {
+            ServerConfig serverConfig = new ServerConfig();
+            serverConfig.readFrom(config);
+            runFromConfig(serverConfig);
+        }
+
+        public void shutdown() {
+            try {
+                super.shutdown();
+            } catch (Exception e) {
+                LOG.error("Error shutting down ZooKeeper", e);
+            }
+        }
+    }
+}
diff --git a/trunk/discovery/distributed/zookeeper-server/src/main/java/org/apache/cxf/dosgi/discovery/zookeeper/server/util/Utils.java b/trunk/discovery/distributed/zookeeper-server/src/main/java/org/apache/cxf/dosgi/discovery/zookeeper/server/util/Utils.java
new file mode 100644
index 0000000..7359199
--- /dev/null
+++ b/trunk/discovery/distributed/zookeeper-server/src/main/java/org/apache/cxf/dosgi/discovery/zookeeper/server/util/Utils.java
@@ -0,0 +1,86 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.cxf.dosgi.discovery.zookeeper.server.util;
+
+import java.util.ArrayList;
+import java.util.Dictionary;
+import java.util.Enumeration;
+import java.util.List;
+import java.util.Properties;
+
+/**
+ * General purpose utility methods.
+ */
+public final class Utils {
+
+    private Utils() {
+        // prevent instantiation
+    }
+
+    /**
+     * Remove entries whose values are empty from the given dictionary.
+     *
+     * @param dict a dictionary
+     */
+    public static void removeEmptyValues(Dictionary<String, ?> dict) {
+        List<String> keysToRemove = new ArrayList<String>();
+        Enumeration<String> keys = dict.keys();
+        while (keys.hasMoreElements()) {
+            String key = keys.nextElement();
+            Object value = dict.get(key);
+            if (value instanceof String && "".equals(value)) {
+                keysToRemove.add(key);
+            }
+        }
+        for (String key : keysToRemove) {
+            dict.remove(key);
+        }
+    }
+
+    /**
+     * Puts the given key-value pair in the given dictionary if the key does not
+     * already exist in it or if its existing value is null.
+     *
+     * @param dict a dictionary
+     * @param key the key
+     * @param value the default value to set
+     */
+    public static void setDefault(Dictionary<String, String> dict, String key, String value) {
+        if (dict.get(key) == null) {
+            dict.put(key, value);
+        }
+    }
+
+    /**
+     * Converts a Dictionary into a Properties instance.
+     *
+     * @param dict a dictionary
+     * @param <K> the key type
+     * @param <V> the value type
+     * @return the properties
+     */
+    public static <K, V> Properties toProperties(Dictionary<K, V> dict) {
+        Properties props = new Properties();
+        for (Enumeration<K> e = dict.keys(); e.hasMoreElements();) {
+            K key = e.nextElement();
+            props.put(key, dict.get(key));
+        }
+        return props;
+    }
+}
diff --git a/trunk/discovery/distributed/zookeeper-server/src/main/resources/OSGI-INF/metatype/zookeeper.xml b/trunk/discovery/distributed/zookeeper-server/src/main/resources/OSGI-INF/metatype/zookeeper.xml
new file mode 100644
index 0000000..efd9403
--- /dev/null
+++ b/trunk/discovery/distributed/zookeeper-server/src/main/resources/OSGI-INF/metatype/zookeeper.xml
@@ -0,0 +1,34 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements. See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership. The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License. You may obtain a copy of the License at
+
+  http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied. See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<MetaData xmlns="http://www.osgi.org/xmlns/metadata/v1.0.0"
+	 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+	 xsi:schemaLocation="
+		 http://www.osgi.org/xmlns/metadata/v1.0.0 http://www.osgi.org/xmlns/metatype/v1.1.0/metatype.xsd
+	 ">
+	 <OCD description="" name="Zookeeper server config" id="org.apache.cxf.dosgi.discovery.zookeeper.server">
+        <AD id="clientPort" required="false" type="String" default="2181" description=""/>
+	 	<AD id="tickTime" required="false" type="String" default="2000" description=""/>
+        <AD id="initLimit" required="false" type="String" default="10" description=""/>
+        <AD id="syncLimit" required="false" type="String" default="5" description=""/>
+	 </OCD>
+	 <Designate pid="org.apache.cxf.dosgi.discovery.zookeeper.server">
+	 	<Object ocdref="org.apache.cxf.dosgi.discovery.zookeeper.server"/>
+	 </Designate>
+</MetaData>
\ No newline at end of file
diff --git a/trunk/discovery/distributed/zookeeper-server/src/test/java/org/apache/cxf/dosgi/discovery/zookeeper/server/ZookeeperStarterTest.java b/trunk/discovery/distributed/zookeeper-server/src/test/java/org/apache/cxf/dosgi/discovery/zookeeper/server/ZookeeperStarterTest.java
new file mode 100644
index 0000000..17ca117
--- /dev/null
+++ b/trunk/discovery/distributed/zookeeper-server/src/test/java/org/apache/cxf/dosgi/discovery/zookeeper/server/ZookeeperStarterTest.java
@@ -0,0 +1,81 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.cxf.dosgi.discovery.zookeeper.server;
+
+import java.io.File;
+import java.util.Dictionary;
+import java.util.Hashtable;
+
+import junit.framework.TestCase;
+
+import org.apache.cxf.dosgi.discovery.zookeeper.server.ZookeeperStarter.MyZooKeeperServerMain;
+import org.apache.zookeeper.server.quorum.QuorumPeerConfig;
+import org.easymock.classextension.EasyMock;
+import org.easymock.classextension.IMocksControl;
+import org.osgi.framework.BundleContext;
+
+import static org.easymock.EasyMock.expect;
+import static org.easymock.classextension.EasyMock.replay;
+import static org.easymock.classextension.EasyMock.verify;
+
+public class ZookeeperStarterTest extends TestCase {
+
+    public void testUpdateConfig() throws Exception {
+        final File tempDir = new File("target");
+        IMocksControl control = EasyMock.createControl();
+        BundleContext bc = control.createMock(BundleContext.class);
+        expect(bc.getDataFile("")).andReturn(tempDir);
+        final MyZooKeeperServerMain mockServer = control.createMock(MyZooKeeperServerMain.class);
+        control.replay();
+
+        ZookeeperStarter starter = new ZookeeperStarter(bc) {
+            @Override
+            protected void startFromConfig(QuorumPeerConfig config) {
+                assertEquals(1234, config.getClientPortAddress().getPort());
+                assertTrue(config.getDataDir().contains(tempDir + File.separator + "zkdata"));
+                assertEquals(2000, config.getTickTime());
+                assertEquals(10, config.getInitLimit());
+                assertEquals(5, config.getSyncLimit());
+                this.main = mockServer;
+            }
+        };
+        Dictionary<String, Object> props = new Hashtable<String, Object>();
+        props.put("clientPort", "1234");
+        starter.updated(props);
+        assertNotNull(starter.main);
+
+        control.verify();
+    }
+
+    public void testRemoveConfiguration() throws Exception {
+        BundleContext bc = EasyMock.createMock(BundleContext.class);
+        MyZooKeeperServerMain zkServer = EasyMock.createMock(MyZooKeeperServerMain.class);
+        zkServer.shutdown();
+        EasyMock.expectLastCall();
+
+        replay(zkServer);
+
+        ZookeeperStarter starter = new ZookeeperStarter(bc);
+        starter.main = zkServer;
+        starter.updated(null);
+
+        verify(zkServer);
+        assertNull("main should be null", starter.main);
+    }
+}
diff --git a/trunk/discovery/local/pom.xml b/trunk/discovery/local/pom.xml
new file mode 100644
index 0000000..e96bbc4
--- /dev/null
+++ b/trunk/discovery/local/pom.xml
@@ -0,0 +1,96 @@
+<?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>
+    <artifactId>cxf-dosgi-ri-discovery-local</artifactId>
+    <packaging>bundle</packaging>
+    <name>CXF Local Discovery Service Bundle</name>
+    <description>The CXF Local Discovery Service Implementation</description>
+
+    <parent>
+        <groupId>org.apache.cxf.dosgi</groupId>
+        <artifactId>cxf-dosgi-ri-parent</artifactId>
+        <version>1.6.0</version>
+        <relativePath>../../parent/pom.xml</relativePath>
+    </parent>
+
+    <properties>
+        <topDirectoryLocation>../..</topDirectoryLocation>
+    </properties>
+
+    <dependencies>
+        <dependency>
+            <groupId>org.osgi</groupId>
+            <artifactId>org.osgi.core</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.osgi</groupId>
+            <artifactId>org.osgi.compendium</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>org.slf4j</groupId>
+            <artifactId>slf4j-api</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>junit</groupId>
+            <artifactId>junit</artifactId>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>xmlunit</groupId>
+            <artifactId>xmlunit</artifactId>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.easymock</groupId>
+            <artifactId>easymockclassextension</artifactId>
+            <scope>test</scope>
+        </dependency>
+    </dependencies>
+
+    <build>
+        <plugins>
+            <plugin>
+                <groupId>org.jvnet.jaxb2.maven2</groupId>
+                <artifactId>maven-jaxb2-plugin</artifactId>
+                <executions>
+                    <execution>
+                        <goals>
+                            <goal>generate</goal>
+                        </goals>
+                    </execution>
+                </executions>
+            </plugin>
+            <plugin>
+                <groupId>org.apache.felix</groupId>
+                <artifactId>maven-bundle-plugin</artifactId>
+                <configuration>
+                    <instructions>
+                        <Bundle-SymbolicName>${project.artifactId}</Bundle-SymbolicName>
+                        <Bundle-Activator>org.apache.cxf.dosgi.discovery.local.internal.Activator</Bundle-Activator>
+                    </instructions>
+                </configuration>
+            </plugin>
+        </plugins>
+    </build>
+</project>
diff --git a/trunk/discovery/local/src/main/java/org/apache/cxf/dosgi/discovery/local/internal/Activator.java b/trunk/discovery/local/src/main/java/org/apache/cxf/dosgi/discovery/local/internal/Activator.java
new file mode 100644
index 0000000..918f009
--- /dev/null
+++ b/trunk/discovery/local/src/main/java/org/apache/cxf/dosgi/discovery/local/internal/Activator.java
@@ -0,0 +1,41 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.cxf.dosgi.discovery.local.internal;
+
+import org.osgi.framework.BundleActivator;
+import org.osgi.framework.BundleContext;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class Activator implements BundleActivator {
+
+    private static final Logger LOG = LoggerFactory.getLogger(Activator.class);
+
+    LocalDiscovery localDiscovery;
+
+    public synchronized void start(BundleContext context) {
+        localDiscovery = new LocalDiscovery(context);
+        LOG.info("Local D-OSGi service discovery started");
+    }
+
+    public synchronized void stop(BundleContext context) {
+        localDiscovery.shutDown();
+        LOG.info("Local D-OSGi service discovery stopped");
+    }
+}
diff --git a/trunk/discovery/local/src/main/java/org/apache/cxf/dosgi/discovery/local/internal/LocalDiscovery.java b/trunk/discovery/local/src/main/java/org/apache/cxf/dosgi/discovery/local/internal/LocalDiscovery.java
new file mode 100644
index 0000000..ebfaefe
--- /dev/null
+++ b/trunk/discovery/local/src/main/java/org/apache/cxf/dosgi/discovery/local/internal/LocalDiscovery.java
@@ -0,0 +1,242 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.cxf.dosgi.discovery.local.internal;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.concurrent.ConcurrentHashMap;
+
+import org.apache.cxf.dosgi.discovery.local.util.Utils;
+import org.apache.cxf.dosgi.endpointdesc.EndpointDescriptionBundleParser;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.BundleEvent;
+import org.osgi.framework.BundleListener;
+import org.osgi.framework.ServiceReference;
+import org.osgi.service.remoteserviceadmin.EndpointDescription;
+import org.osgi.service.remoteserviceadmin.EndpointListener;
+import org.osgi.util.tracker.ServiceTracker;
+
+public class LocalDiscovery implements BundleListener {
+
+    // this is effectively a set which allows for multiple service descriptions with the
+    // same interface name but different properties and takes care of itself with respect to concurrency
+    ConcurrentHashMap<EndpointDescription, Bundle> endpointDescriptions =
+        new ConcurrentHashMap<EndpointDescription, Bundle>();
+    Map<EndpointListener, Collection<String>> listenerToFilters =
+        new HashMap<EndpointListener, Collection<String>>();
+    Map<String, Collection<EndpointListener>> filterToListeners =
+        new HashMap<String, Collection<EndpointListener>>();
+    final BundleContext bundleContext;
+
+    EndpointDescriptionBundleParser bundleParser;
+    ServiceTracker<EndpointListener, EndpointListener> listenerTracker;
+
+    public LocalDiscovery(BundleContext bc) {
+        this.bundleParser = new EndpointDescriptionBundleParser();
+        bundleContext = bc;
+
+        listenerTracker = new ServiceTracker<EndpointListener, EndpointListener>(bundleContext, 
+            EndpointListener.class, null) {
+
+            @Override
+            public EndpointListener addingService(ServiceReference<EndpointListener> reference) {
+                EndpointListener svc = super.addingService(reference);
+                addListener(reference, svc);
+                return svc;
+            }
+
+            @Override
+            public void modifiedService(ServiceReference<EndpointListener> reference, EndpointListener service) {
+                super.modifiedService(reference, service);
+                removeListener(service);
+
+                // This may cause duplicate registrations of remote services,
+                // but that's fine and should be filtered out on another level.
+                // See Remote Service Admin spec section 122.6.3
+                addListener(reference, service);
+            }
+
+            @Override
+            public void removedService(ServiceReference<EndpointListener> reference, EndpointListener service) {
+                super.removedService(reference, service);
+                removeListener(service);
+            }
+        };
+        listenerTracker.open();
+
+        bundleContext.addBundleListener(this);
+        processExistingBundles();
+    }
+
+    private void processExistingBundles() {
+        Bundle[] bundles = bundleContext.getBundles();
+        if (bundles == null) {
+            return;
+        }
+
+        for (Bundle b : bundles) {
+            if (b.getState() == Bundle.ACTIVE) {
+                findDeclaredRemoteServices(b);
+            }
+        }
+    }
+
+    void addListener(ServiceReference<EndpointListener> endpointListenerRef, EndpointListener endpointListener) {
+        List<String> filters = Utils.getStringPlusProperty(endpointListenerRef,
+                EndpointListener.ENDPOINT_LISTENER_SCOPE);
+        if (filters.isEmpty()) {
+            return;
+        }
+
+        synchronized (listenerToFilters) {
+            listenerToFilters.put(endpointListener, filters);
+            for (String filter : filters) {
+                Collection<EndpointListener> listeners = filterToListeners.get(filter);
+                if (listeners == null) {
+                    listeners = new ArrayList<EndpointListener>();
+                    filterToListeners.put(filter, listeners);
+                }
+                listeners.add(endpointListener);
+            }
+        }
+
+        triggerCallbacks(filters, endpointListener);
+    }
+
+    /**
+     * If the tracker was removed or the scope was changed this doesn't require
+     * additional callbacks on the tracker. Its the responsibility of the tracker
+     * itself to clean up any orphans. See Remote Service Admin spec 122.6.3
+     * @param endpointListener
+     */
+    void removeListener(EndpointListener endpointListener) {
+        synchronized (listenerToFilters) {
+            Collection<String> filters = listenerToFilters.remove(endpointListener);
+            if (filters == null) {
+                return;
+            }
+
+            for (String filter : filters) {
+                Collection<EndpointListener> listeners = filterToListeners.get(filter);
+                if (listeners != null) {
+                    listeners.remove(endpointListener);
+                    if (listeners.isEmpty()) {
+                        filterToListeners.remove(filter);
+                    }
+                }
+            }
+        }
+    }
+
+    private Map<String, Collection<EndpointListener>> getMatchingListeners(EndpointDescription endpoint) {
+        // return a copy of matched filters/listeners so that caller doesn't need to hold locks while triggering events
+        Map<String, Collection<EndpointListener>> matched = new HashMap<String, Collection<EndpointListener>>();
+        synchronized (listenerToFilters) {
+            for (Entry<String, Collection<EndpointListener>> entry : filterToListeners.entrySet()) {
+                String filter = entry.getKey();
+                if (Utils.matchFilter(bundleContext, filter, endpoint)) {
+                    matched.put(filter, new ArrayList<EndpointListener>(entry.getValue()));
+                }
+            }
+        }
+        return matched;
+    }
+
+    public void shutDown() {
+        bundleContext.removeBundleListener(this);
+        listenerTracker.close();
+    }
+
+    // BundleListener method
+    public void bundleChanged(BundleEvent be) {
+        switch (be.getType()) {
+        case BundleEvent.STARTED:
+            findDeclaredRemoteServices(be.getBundle());
+            break;
+        case BundleEvent.STOPPED:
+            removeServicesDeclaredInBundle(be.getBundle());
+            break;
+        default:
+        }
+    }
+
+    private void findDeclaredRemoteServices(Bundle bundle) {
+        List<EndpointDescription> endpoints = bundleParser.getAllEndpointDescriptions(bundle);
+        for (EndpointDescription endpoint : endpoints) {
+            endpointDescriptions.put(endpoint, bundle);
+            addedEndpointDescription(endpoint);
+        }
+    }
+
+    private void removeServicesDeclaredInBundle(Bundle bundle) {
+        for (Iterator<Entry<EndpointDescription, Bundle>> i = endpointDescriptions.entrySet().iterator();
+            i.hasNext();) {
+            Entry<EndpointDescription, Bundle> entry = i.next();
+            if (bundle.equals(entry.getValue())) {
+                removedEndpointDescription(entry.getKey());
+                i.remove();
+            }
+        }
+    }
+
+    private void addedEndpointDescription(EndpointDescription endpoint) {
+        triggerCallbacks(endpoint, true);
+    }
+
+    private void removedEndpointDescription(EndpointDescription endpoint) {
+        triggerCallbacks(endpoint, false);
+    }
+
+    private void triggerCallbacks(EndpointDescription endpoint, boolean added) {
+        for (Map.Entry<String, Collection<EndpointListener>> entry : getMatchingListeners(endpoint).entrySet()) {
+            String filter = entry.getKey();
+            for (EndpointListener listener : entry.getValue()) {
+                triggerCallbacks(listener, filter, endpoint, added);
+            }
+        }
+    }
+
+    private void triggerCallbacks(EndpointListener endpointListener, String filter,
+            EndpointDescription endpoint, boolean added) {
+        if (!Utils.matchFilter(bundleContext, filter, endpoint)) {
+            return;
+        }
+
+        if (added) {
+            endpointListener.endpointAdded(endpoint, filter);
+        } else {
+            endpointListener.endpointRemoved(endpoint, filter);
+        }
+    }
+
+    private void triggerCallbacks(Collection<String> filters, EndpointListener endpointListener) {
+        for (String filter : filters) {
+            for (EndpointDescription endpoint : endpointDescriptions.keySet()) {
+                triggerCallbacks(endpointListener, filter, endpoint, true);
+            }
+        }
+    }
+
+}
diff --git a/trunk/discovery/local/src/main/java/org/apache/cxf/dosgi/discovery/local/util/Utils.java b/trunk/discovery/local/src/main/java/org/apache/cxf/dosgi/discovery/local/util/Utils.java
new file mode 100644
index 0000000..990ae9f
--- /dev/null
+++ b/trunk/discovery/local/src/main/java/org/apache/cxf/dosgi/discovery/local/util/Utils.java
@@ -0,0 +1,125 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.cxf.dosgi.discovery.local.util;
+
+import java.io.StringReader;
+import java.io.StringWriter;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Dictionary;
+import java.util.Hashtable;
+import java.util.List;
+import java.util.regex.Pattern;
+
+import javax.xml.transform.OutputKeys;
+import javax.xml.transform.Transformer;
+import javax.xml.transform.TransformerFactory;
+import javax.xml.transform.stream.StreamResult;
+import javax.xml.transform.stream.StreamSource;
+
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.Filter;
+import org.osgi.framework.ServiceReference;
+import org.osgi.service.remoteserviceadmin.EndpointDescription;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public final class Utils {
+
+    private static final Logger LOG = LoggerFactory.getLogger(Utils.class);
+
+    private Utils() {
+        // prevent instantiation
+    }
+
+    public static List<String> getStringPlusProperty(ServiceReference<?> sr, String key) {
+        Object value = sr.getProperty(key);
+        if (value == null) {
+            return Collections.emptyList();
+        }
+
+        if (value instanceof String) {
+            return Collections.singletonList((String) value);
+        }
+
+        if (value instanceof String[]) {
+            String[] values = (String[]) value;
+            List<String> result = new ArrayList<String>(values.length);
+            for (String v : values) {
+                if (v != null) {
+                    result.add(v);
+                }
+            }
+            return Collections.unmodifiableList(result);
+        }
+
+        if (value instanceof Collection<?>) {
+            Collection<?> values = (Collection<?>) value;
+            List<String> result = new ArrayList<String>(values.size());
+            for (Object v : values) {
+                if (v instanceof String) {
+                    result.add((String) v);
+                }
+            }
+            return Collections.unmodifiableList(result);
+        }
+
+        return Collections.emptyList();
+    }
+
+    public static boolean matchFilter(BundleContext bctx, String filter, EndpointDescription endpoint) {
+        if (filter == null) {
+            return false;
+        }
+
+        try {
+            Filter f = bctx.createFilter(filter);
+            Dictionary<String, Object> dict = new Hashtable<String, Object>(endpoint.getProperties());
+            return f.match(dict);
+        } catch (Exception e) {
+            LOG.error("Problem creating a Filter from " + filter, e);
+            return false;
+        }
+    }
+    
+    public static String normXML(String s) {
+        String s2 = stripComment(s);
+        String s3 = stripProlog(s2);
+        try {
+            TransformerFactory transFactory = TransformerFactory.newInstance();
+            Transformer transformer = transFactory.newTransformer();
+            StringWriter buffer = new StringWriter();
+            transformer.setOutputProperty(OutputKeys.INDENT, "yes");
+            transformer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "yes");
+            transformer.transform(new StreamSource(new StringReader(s3)), new StreamResult(buffer));
+            return buffer.toString();
+        } catch (Exception e) {
+            return "";
+        }
+    }
+
+    private static String stripComment(String s) {
+        return Pattern.compile("<!--(.*?)-->", Pattern.DOTALL).matcher(s).replaceAll("");
+    }
+
+    private static String stripProlog(String s) {
+        return s.replaceAll("<\\?(.*?)\\?>", "");
+    }
+}
diff --git a/trunk/discovery/local/src/main/java/org/apache/cxf/dosgi/endpointdesc/EndpointDescriptionBundleParser.java b/trunk/discovery/local/src/main/java/org/apache/cxf/dosgi/endpointdesc/EndpointDescriptionBundleParser.java
new file mode 100644
index 0000000..edeaeac
--- /dev/null
+++ b/trunk/discovery/local/src/main/java/org/apache/cxf/dosgi/endpointdesc/EndpointDescriptionBundleParser.java
@@ -0,0 +1,104 @@
+/**
+ * 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.endpointdesc;
+
+import java.net.URL;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Dictionary;
+import java.util.Enumeration;
+import java.util.List;
+import java.util.Map;
+
+import org.osgi.framework.Bundle;
+import org.osgi.service.remoteserviceadmin.EndpointDescription;
+import org.osgi.xmlns.rsa.v1_0.EndpointDescriptionType;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public final class EndpointDescriptionBundleParser {
+    private static final Logger LOG = LoggerFactory.getLogger(EndpointDescriptionBundleParser.class);
+
+    private static final String REMOTE_SERVICES_HEADER_NAME = "Remote-Service";
+    private static final String REMOTE_SERVICES_DIRECTORY = "OSGI-INF/remote-service/";
+
+    private EndpointDescriptionParser parser;
+
+    public EndpointDescriptionBundleParser() {
+        parser = new EndpointDescriptionParser();
+    }
+
+    public List<EndpointDescription> getAllEndpointDescriptions(Bundle b) {
+        List<EndpointDescriptionType> elements = getAllDescriptionElements(b);
+
+        List<EndpointDescription> endpoints = new ArrayList<EndpointDescription>(elements.size());
+        for (EndpointDescriptionType epd : elements) {
+            Map<String, Object> props = new PropertiesMapper().toProps(epd.getProperty());
+            endpoints.add(new EndpointDescription(props));
+        }
+        return endpoints;
+    }
+
+    List<EndpointDescriptionType> getAllDescriptionElements(Bundle b) {
+        Enumeration<URL> urls = getEndpointDescriptionURLs(b);
+        List<EndpointDescriptionType> elements = new ArrayList<EndpointDescriptionType>();
+        while (urls.hasMoreElements()) {
+            URL resourceURL = (URL) urls.nextElement();
+            try {
+                elements.addAll(parser.getEndpointDescriptions(resourceURL.openStream()));
+            } catch (Exception ex) {
+                LOG.warn("Problem parsing: " + resourceURL, ex);
+            }
+        }
+        return elements;
+    }
+    
+    Enumeration<URL> getEndpointDescriptionURLs(Bundle b) {
+        String origDir = getRemoteServicesDir(b);
+        
+        // Split origDir into dir and file pattern
+        String filePattern = "*.xml";
+        String dir;
+        if (origDir.endsWith("/")) {
+            dir = origDir.substring(0, origDir.length() - 1);
+        } else {
+            int idx = origDir.lastIndexOf('/');
+            if (idx >= 0 & origDir.length() > idx) {
+                filePattern = origDir.substring(idx + 1);
+                dir = origDir.substring(0, idx);
+            } else {
+                filePattern = origDir;
+                dir = "";
+            }
+        }
+
+        Enumeration<URL> urls = b.findEntries(dir, filePattern, false);
+        return (urls == null) ? Collections.enumeration(new ArrayList<URL>()) : urls;
+    }
+
+    private static String getRemoteServicesDir(Bundle b) {
+        Dictionary<?, ?> headers = b.getHeaders();
+        Object header = null;
+        if (headers != null) {
+            header = headers.get(REMOTE_SERVICES_HEADER_NAME);
+        }
+        return (header == null) ? REMOTE_SERVICES_DIRECTORY : header.toString();
+    }
+
+}
diff --git a/trunk/discovery/local/src/main/java/org/apache/cxf/dosgi/endpointdesc/EndpointDescriptionParser.java b/trunk/discovery/local/src/main/java/org/apache/cxf/dosgi/endpointdesc/EndpointDescriptionParser.java
new file mode 100644
index 0000000..fb502c8
--- /dev/null
+++ b/trunk/discovery/local/src/main/java/org/apache/cxf/dosgi/endpointdesc/EndpointDescriptionParser.java
@@ -0,0 +1,90 @@
+/**
+ * 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.endpointdesc;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.util.List;
+
+import javax.xml.bind.JAXBContext;
+import javax.xml.bind.JAXBElement;
+import javax.xml.bind.JAXBException;
+import javax.xml.bind.Marshaller;
+import javax.xml.bind.Unmarshaller;
+import javax.xml.namespace.QName;
+import javax.xml.transform.Source;
+import javax.xml.transform.stream.StreamSource;
+
+import org.osgi.xmlns.rsa.v1_0.EndpointDescriptionType;
+import org.osgi.xmlns.rsa.v1_0.EndpointDescriptionsType;
+
+public class EndpointDescriptionParser {
+    private JAXBContext jaxbContext;
+
+    public EndpointDescriptionParser() {
+        try {
+            jaxbContext = JAXBContext.newInstance(EndpointDescriptionsType.class.getPackage().getName(),
+                                                  this.getClass().getClassLoader());
+        } catch (JAXBException e) {
+            throw new RuntimeException(e.getMessage(), e);
+        }
+    }
+
+    public List<EndpointDescriptionType> getEndpointDescriptions(InputStream is) {
+        try {
+            Unmarshaller unmarshaller = jaxbContext.createUnmarshaller();
+            Source source = new StreamSource(is);
+            JAXBElement<EndpointDescriptionsType> jaxb = unmarshaller.unmarshal(source, EndpointDescriptionsType.class);
+            EndpointDescriptionsType decorations = jaxb.getValue();
+            return decorations.getEndpointDescription();
+        } catch (Exception ex) {
+            throw new RuntimeException(ex.getMessage(), ex);
+        }
+    }
+
+    public void writeTo(EndpointDescriptionsType endpointDescriptions, OutputStream os) {
+        try {
+            Marshaller marshaller = jaxbContext.createMarshaller();
+            marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
+            QName name = new QName("http://www.osgi.org/xmlns/rsa/v1.0.0", "endpoint-descriptions");
+            JAXBElement<EndpointDescriptionsType> el = 
+                new JAXBElement<EndpointDescriptionsType>(name, EndpointDescriptionsType.class, 
+                    endpointDescriptions);
+            marshaller.marshal(el, os);
+        } catch (Exception ex) {
+            throw new RuntimeException(ex.getMessage(), ex);
+        } finally {
+            try {
+                os.close();
+            } catch (IOException e) {
+                // Ignore
+            }
+        }
+    }
+    
+    public byte[] getData(EndpointDescriptionType endpointDescription) {
+        EndpointDescriptionsType endpointDescriptions = new EndpointDescriptionsType();
+        endpointDescriptions.getEndpointDescription().add(endpointDescription);
+        ByteArrayOutputStream bos = new ByteArrayOutputStream();
+        writeTo(endpointDescriptions, bos);
+        return bos.toByteArray();
+    }
+}
diff --git a/trunk/discovery/local/src/main/java/org/apache/cxf/dosgi/endpointdesc/PropertiesMapper.java b/trunk/discovery/local/src/main/java/org/apache/cxf/dosgi/endpointdesc/PropertiesMapper.java
new file mode 100644
index 0000000..a7ed445
--- /dev/null
+++ b/trunk/discovery/local/src/main/java/org/apache/cxf/dosgi/endpointdesc/PropertiesMapper.java
@@ -0,0 +1,345 @@
+/**
+ * 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.endpointdesc;
+
+import java.io.Serializable;
+import java.io.StringWriter;
+import java.lang.reflect.Array;
+import java.lang.reflect.Constructor;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import javax.xml.bind.JAXBElement;
+import javax.xml.transform.OutputKeys;
+import javax.xml.transform.Transformer;
+import javax.xml.transform.TransformerFactory;
+import javax.xml.transform.dom.DOMSource;
+import javax.xml.transform.stream.StreamResult;
+
+import org.w3c.dom.Node;
+import org.osgi.xmlns.rsa.v1_0.ArrayType;
+import org.osgi.xmlns.rsa.v1_0.ObjectFactory;
+import org.osgi.xmlns.rsa.v1_0.PropertyType;
+import org.osgi.xmlns.rsa.v1_0.ValueType;
+import org.osgi.xmlns.rsa.v1_0.XmlType;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class PropertiesMapper {
+    private static final Logger LOG = LoggerFactory.getLogger(PropertiesMapper.class);
+
+    public Map<String, Object> toProps(List<PropertyType> properties) {
+        Map<String, Object> map = new HashMap<String, Object>();
+        for (PropertyType prop : properties) {
+            map.put(prop.getName(), getValue(prop));
+        }
+        return map;
+    }
+
+    private Object getValue(PropertyType prop) {
+        Object value = null;
+        String type = getTypeName(prop);
+        Object content = getFirstNonText(prop.getContent());
+        if (content instanceof JAXBElement<?>) {
+            JAXBElement<?> el = (JAXBElement<?>)content;
+            if (el.getDeclaredType() == ArrayType.class) {
+                String elName = el.getName().getLocalPart();
+                ArrayType inValue = (ArrayType)el.getValue();
+                if ("array".equals(elName)) {
+                    value = getArray(inValue, type);
+                } else if ("set".equals(elName)) {
+                    value = handleCollection(inValue, new HashSet<Object>(), type);
+                } else if ("list".equals(elName)) {
+                    value = handleCollection(inValue, new ArrayList<Object>(), type);
+                }
+            } else if (el.getDeclaredType() == XmlType.class) {
+                value = readXML((XmlType)el.getValue(), type);
+            }
+        } else {
+            if (prop.getValue() != null) {
+                value = instantiate(type, prop.getValue());
+            } else {
+                if (prop.getContent().size() > 0) {
+                    value = instantiate(type, prop.getContent().get(0).toString());
+                }
+            }
+        }
+        return value;
+    }
+
+    private Object getFirstNonText(List<Serializable> contentList) {
+        for (Object content : contentList) {
+            if (content instanceof JAXBElement<?>) {
+                return content;
+            }
+        }
+        return null;
+    }
+
+    private static String getTypeName(PropertyType prop) {
+        String type = prop.getValueType();
+        return type == null ? "String" : type;
+    }
+
+    private Object getArray(ArrayType arrayEl, String type) {
+        List<ValueType> values = arrayEl.getValue();
+        Class<?> cls = null;
+        if ("long".equals(type)) {
+            cls = long.class;
+        } else if ("double".equals(type)) {
+            cls = double.class;
+        } else if ("float".equals(type)) {
+            cls = float.class;
+        } else if ("int".equals(type)) {
+            cls = int.class;
+        } else if ("byte".equals(type)) {
+            cls = byte.class;
+        } else if ("boolean".equals(type)) {
+            cls = boolean.class;
+        } else if ("short".equals(type)) {
+            cls = short.class;
+        }
+
+        try {
+            if (cls == null) {
+                cls = ClassLoader.getSystemClassLoader().loadClass("java.lang." + type);
+            }
+            Object array = Array.newInstance(cls, values.size());
+
+            for (int i = 0; i < values.size(); i++) {
+                Object val = getValue(values.get(i), type);
+                Array.set(array, i, val);
+            }
+
+            return array;
+        } catch (Exception e) {
+            LOG.warn("Could not create array for Endpoint Description", e);
+            return null;
+        }
+    }
+
+    @SuppressWarnings({ "rawtypes", "unchecked" })
+    private Collection handleCollection(ArrayType el, Collection value, String type) {
+        List<ValueType> values = el.getValue();
+        for (ValueType val : values) {
+            Object obj = getValue(val, type);
+            value.add(obj);
+        }
+        return value;
+    }
+    
+    private Object getValue(ValueType value, String type) {
+        if (value.getContent().size() == 1 && value.getContent().get(0) instanceof String) {
+            return handleValue((String)value.getContent().get(0), type);
+        }
+        JAXBElement<?> valueContent = (JAXBElement<?>)getFirstNonText(value.getContent());
+        if (valueContent.getDeclaredType() == XmlType.class) {
+            return readXML((XmlType)valueContent.getValue(), type);
+        }
+        return "";
+    }
+
+    private String readXML(XmlType el, String type) {
+        if (el == null) {
+            return null;
+        }
+        if (!"String".equals(type)) {
+            LOG.warn("Embedded XML must be of type String, found: " + type);
+            return null;
+        }
+        Node xmlContent = (Node)el.getAny();
+        xmlContent.normalize();
+        try {
+            TransformerFactory transFactory = TransformerFactory.newInstance();
+            Transformer transformer = transFactory.newTransformer();
+            StringWriter buffer = new StringWriter();
+            transformer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "yes");
+            transformer.transform(new DOMSource(xmlContent), new StreamResult(buffer));
+            return buffer.toString();
+        } catch (Exception e) {
+            return "";
+        }
+    }
+
+    private static Object handleValue(String val, String type) {
+        return instantiate(type, val);
+    }
+
+    private static Object instantiate(String type, String value) {
+        if ("String".equals(type)) {
+            return value;
+        }
+
+        value = value.trim();
+        String boxedType = null;
+        if ("long".equals(type)) {
+            boxedType = "Long";
+        } else if ("double".equals(type)) {
+            boxedType = "Double";
+        } else if ("float".equals(type)) {
+            boxedType = "Float";
+        } else if ("int".equals(type)) {
+            boxedType = "Integer";
+        } else if ("byte".equals(type)) {
+            boxedType = "Byte";
+        } else if ("char".equals(type)) {
+            boxedType = "Character";
+        } else if ("boolean".equals(type)) {
+            boxedType = "Boolean";
+        } else if ("short".equals(type)) {
+            boxedType = "Short";
+        }
+
+        if (boxedType == null) {
+            boxedType = type;
+        }
+        String javaType = "java.lang." + boxedType;
+
+        try {
+            if ("Character".equals(boxedType)) {
+                return new Character(value.charAt(0));
+            } else {
+                Class<?> cls = ClassLoader.getSystemClassLoader().loadClass(javaType);
+                Constructor<?> ctor = cls.getConstructor(String.class);
+                return ctor.newInstance(value);
+            }
+        } catch (Exception e) {
+            LOG.warn("Could not create Endpoint Property of type " + type + " and value " + value);
+            return null;
+        }
+    }
+    
+    public List<PropertyType> fromProps(Map<String, Object> m) {
+        List<PropertyType> props = new ArrayList<PropertyType>();
+        for (Map.Entry<String, Object> entry : m.entrySet()) {
+            String key = entry.getKey();
+            Object val = entry.getValue();
+
+            PropertyType propEl = new PropertyType();
+            propEl.setName(key);
+            ObjectFactory factory = new ObjectFactory();
+            if (val.getClass().isArray()) {
+                ArrayType arrayEl = new ArrayType();
+                propEl.getContent().add(factory.createArray(arrayEl));
+                for (Object o : normalizeArray(val)) {
+                    setValueType(propEl, o);
+                    ValueType valueType =  new ValueType();
+                    valueType.getContent().add(o.toString());
+                    arrayEl.getValue().add(valueType);
+                }
+            } else if (val instanceof List) {
+                ArrayType listEl = new ArrayType();
+                propEl.getContent().add(factory.createList(listEl));
+                handleCollectionValue((Collection<?>) val, propEl, listEl);
+            } else if (val instanceof Set) {
+                ArrayType setEl = new ArrayType();
+                propEl.getContent().add(factory.createSet(setEl));
+                handleCollectionValue((Collection<?>) val, propEl, setEl);
+            } else if (val instanceof String
+                    || val instanceof Character
+                    || val instanceof Boolean
+                    || val instanceof Byte) {
+                setValueType(propEl, val);
+                propEl.setValue(val.toString());
+            } else if (val instanceof Long
+                    || val instanceof Double
+                    || val instanceof Float
+                    || val instanceof Integer
+                    || val instanceof Short) {
+                // various numbers..   maybe "val instanceof Number"?
+                setValueType(propEl, val);
+                propEl.setValue(val.toString());
+            } else {
+                // Don't add this property as the value type is not supported
+                continue;
+            }
+            props.add(propEl);
+        }
+        return props;
+    }
+
+    private static Object[] normalizeArray(Object val) {
+        List<Object> l = new ArrayList<Object>();
+        if (val instanceof int[]) {
+            int[] ia = (int[]) val;
+            for (int i : ia) {
+                l.add(i);
+            }
+        } else if (val instanceof long[]) {
+            long[] la = (long[]) val;
+            for (long i : la) {
+                l.add(i);
+            }
+        } else if (val instanceof float[]) {
+            float[] fa = (float[]) val;
+            for (float f : fa) {
+                l.add(f);
+            }
+        } else if (val instanceof byte[]) {
+            byte[] ba = (byte[]) val;
+            for (byte b : ba) {
+                l.add(b);
+            }
+        } else if (val instanceof boolean[]) {
+            boolean[] ba = (boolean[]) val;
+            for (boolean b : ba) {
+                l.add(b);
+            }
+        } else if (val instanceof short[]) {
+            short[] sa = (short[]) val;
+            for (short s : sa) {
+                l.add(s);
+            }
+        } else if (val instanceof char[]) {
+            char[] ca = (char[]) val;
+            for (char c : ca) {
+                l.add(c);
+            }
+        } else {
+            return (Object[]) val;
+        }
+        return l.toArray();
+    }
+
+    private static void handleCollectionValue(Collection<?> val, PropertyType propEl, ArrayType listEl) {
+        for (Object o : val) {
+            setValueType(propEl, o);
+            ValueType valueType = new ValueType();
+            valueType.getContent().add(o.toString());
+            listEl.getValue().add(valueType);
+        }
+    }
+
+    private static void setValueType(PropertyType propEl, Object val) {
+        if (val instanceof String) {
+            return;
+        }
+
+        String dataType = val.getClass().getName();
+        if (dataType.startsWith("java.lang.")) {
+            dataType = dataType.substring("java.lang.".length());
+        }
+        propEl.setValueType(dataType);
+    }
+}
diff --git a/trunk/discovery/local/src/main/resources/endpoint-description.xsd b/trunk/discovery/local/src/main/resources/endpoint-description.xsd
new file mode 100644
index 0000000..b3254c1
--- /dev/null
+++ b/trunk/discovery/local/src/main/resources/endpoint-description.xsd
@@ -0,0 +1,61 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<schema xmlns="http://www.w3.org/2001/XMLSchema" xmlns:tns="http://www.osgi.org/xmlns/rsa/v1.0.0" targetNamespace="http://www.osgi.org/xmlns/rsa/v1.0.0">
+    <element name="endpoint-descriptions"
+        type="tns:EndpointDescriptionsType">
+    </element>
+    
+    <complexType name="EndpointDescriptionsType">
+        <sequence>
+            <element maxOccurs="unbounded" minOccurs="0"
+                ref="tns:endpoint-description">
+            </element>
+        </sequence>
+    </complexType>
+
+    <complexType name="EndpointDescriptionType">
+        <sequence>
+            <element ref="tns:property" maxOccurs="unbounded" minOccurs="0"></element>
+        </sequence>
+    </complexType>
+
+    <complexType name="PropertyType" mixed="true">
+        <choice>
+            <element ref="tns:array"></element>
+            <element ref="tns:list"></element>
+            <element ref="tns:set"></element>
+            <element ref="tns:xml"></element>
+        </choice>
+        <attribute name="name" type="string"></attribute>
+        <attribute name="value-type" type="string"></attribute>
+        <attribute name="value" type="string"></attribute>
+    </complexType>
+
+    <complexType name="ArrayType">
+        <sequence>
+            <element maxOccurs="unbounded" minOccurs="0"
+                ref="tns:value">
+            </element>
+        </sequence>
+    </complexType>
+    <element name="endpoint-description"
+        type="tns:EndpointDescriptionType">
+    </element>
+    <element name="property" type="tns:PropertyType"></element>
+    <element name="array" type="tns:ArrayType"></element>
+    <element name="list" type="tns:ArrayType"></element>
+    <element name="set" type="tns:ArrayType"></element>
+
+    <complexType name="XmlType">
+        <sequence>
+            <any></any>
+        </sequence>
+    </complexType>
+    <element name="value" type="tns:ValueType"></element>
+    <element name="xml" type="tns:XmlType"></element>
+
+    <complexType name="ValueType" mixed="true">
+        <sequence>
+            <element ref="tns:xml"></element>
+        </sequence>
+    </complexType>
+</schema>
\ No newline at end of file
diff --git a/trunk/discovery/local/src/test/java/org/apache/cxf/dosgi/discovery/local/internal/ActivatorTest.java b/trunk/discovery/local/src/test/java/org/apache/cxf/dosgi/discovery/local/internal/ActivatorTest.java
new file mode 100644
index 0000000..a0bdc87
--- /dev/null
+++ b/trunk/discovery/local/src/test/java/org/apache/cxf/dosgi/discovery/local/internal/ActivatorTest.java
@@ -0,0 +1,52 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.cxf.dosgi.discovery.local.internal;
+
+import junit.framework.TestCase;
+
+import org.easymock.IAnswer;
+import org.easymock.classextension.EasyMock;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.Filter;
+import org.osgi.framework.FrameworkUtil;
+
+public class ActivatorTest extends TestCase {
+
+    public void testActivator() throws Exception {
+        BundleContext bc = EasyMock.createNiceMock(BundleContext.class);
+        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.replay(bc);
+
+        Activator a = new Activator();
+        a.start(bc);
+        assertNotNull(a.localDiscovery);
+
+        a.localDiscovery = EasyMock.createMock(LocalDiscovery.class);
+        a.localDiscovery.shutDown();
+        EasyMock.expectLastCall();
+        EasyMock.replay(a.localDiscovery);
+        a.stop(bc);
+
+        EasyMock.verify(a.localDiscovery);
+    }
+}
diff --git a/trunk/discovery/local/src/test/java/org/apache/cxf/dosgi/discovery/local/internal/LocalDiscoveryTest.java b/trunk/discovery/local/src/test/java/org/apache/cxf/dosgi/discovery/local/internal/LocalDiscoveryTest.java
new file mode 100644
index 0000000..ccbaca7
--- /dev/null
+++ b/trunk/discovery/local/src/test/java/org/apache/cxf/dosgi/discovery/local/internal/LocalDiscoveryTest.java
@@ -0,0 +1,409 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.cxf.dosgi.discovery.local.internal;
+
+import java.net.URL;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+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 junit.framework.TestCase;
+
+import org.easymock.EasyMock;
+import org.easymock.IAnswer;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.BundleEvent;
+import org.osgi.framework.BundleListener;
+import org.osgi.framework.Filter;
+import org.osgi.framework.FrameworkUtil;
+import org.osgi.framework.InvalidSyntaxException;
+import org.osgi.framework.ServiceListener;
+import org.osgi.framework.ServiceReference;
+import org.osgi.service.remoteserviceadmin.EndpointDescription;
+import org.osgi.service.remoteserviceadmin.EndpointListener;
+
+public class LocalDiscoveryTest extends TestCase {
+
+    public void testLocalDiscovery() throws Exception {
+        Filter filter = EasyMock.createMock(Filter.class);
+        EasyMock.replay(filter);
+
+        BundleContext bc = EasyMock.createMock(BundleContext.class);
+        EasyMock.expect(bc.createFilter("(objectClass=org.osgi.service.remoteserviceadmin.EndpointListener)"))
+            .andReturn(filter);
+        bc.addServiceListener((ServiceListener) EasyMock.anyObject(),
+            EasyMock.eq("(objectClass=org.osgi.service.remoteserviceadmin.EndpointListener)"));
+        EasyMock.expectLastCall();
+        EasyMock.expect(bc.getServiceReferences("org.osgi.service.remoteserviceadmin.EndpointListener", null))
+            .andReturn(null);
+        bc.addBundleListener((BundleListener) EasyMock.anyObject());
+        EasyMock.expectLastCall().andAnswer(new IAnswer<Object>() {
+            public Object answer() throws Throwable {
+                assertEquals(LocalDiscovery.class, EasyMock.getCurrentArguments()[0].getClass());
+                return null;
+            }
+        });
+        EasyMock.expect(bc.getBundles()).andReturn(null);
+        EasyMock.replay(bc);
+
+        LocalDiscovery ld = new LocalDiscovery(bc);
+        assertSame(bc, ld.bundleContext);
+        assertNotNull(ld.listenerTracker);
+
+        EasyMock.verify(bc);
+
+        EasyMock.reset(bc);
+        bc.removeBundleListener(ld);
+        EasyMock.expectLastCall();
+        bc.removeServiceListener((ServiceListener) EasyMock.anyObject());
+        EasyMock.expectLastCall();
+        EasyMock.replay(bc);
+
+        ld.shutDown();
+        EasyMock.verify(bc);
+    }
+
+    public void testPreExistingBundles() throws Exception {
+        Filter filter = EasyMock.createMock(Filter.class);
+        EasyMock.replay(filter);
+
+        BundleContext bc = EasyMock.createMock(BundleContext.class);
+        EasyMock.expect(bc.createFilter("(objectClass=org.osgi.service.remoteserviceadmin.EndpointListener)"))
+            .andReturn(filter);
+        bc.addServiceListener((ServiceListener) EasyMock.anyObject(),
+            EasyMock.eq("(objectClass=org.osgi.service.remoteserviceadmin.EndpointListener)"));
+        EasyMock.expectLastCall();
+        EasyMock.expect(bc.getServiceReferences("org.osgi.service.remoteserviceadmin.EndpointListener", null))
+            .andReturn(null);
+        bc.addBundleListener((BundleListener) EasyMock.anyObject());
+        EasyMock.expectLastCall();
+
+        Bundle b1 = EasyMock.createMock(Bundle.class);
+        EasyMock.expect(b1.getState()).andReturn(Bundle.RESOLVED);
+        EasyMock.replay(b1);
+        Bundle b2 = EasyMock.createMock(Bundle.class);
+        EasyMock.expect(b2.getState()).andReturn(Bundle.ACTIVE);
+        Dictionary<String, String> headers = new Hashtable<String, String>();
+        headers.put("Remote-Service", "OSGI-INF/remote-service/");
+        EasyMock.expect(b2.getHeaders()).andReturn(headers);
+
+        URL rs3URL = getClass().getResource("/ed3.xml");
+        URL rs4URL = getClass().getResource("/ed4.xml");
+        List<URL> urls = Arrays.asList(rs3URL, rs4URL);
+        EasyMock.expect(b2.findEntries("OSGI-INF/remote-service", "*.xml", false))
+            .andReturn(Collections.enumeration(urls));
+        EasyMock.replay(b2);
+
+        EasyMock.expect(bc.getBundles()).andReturn(new Bundle[] {b1, b2});
+        EasyMock.replay(bc);
+
+        LocalDiscovery ld = new LocalDiscovery(bc);
+
+        assertEquals(3, ld.endpointDescriptions.size());
+        Set<String> expected = new HashSet<String>(
+                Arrays.asList("http://somewhere:12345", "http://somewhere:1", "http://somewhere"));
+        Set<String> actual = new HashSet<String>();
+        for (Map.Entry<EndpointDescription, Bundle> entry : ld.endpointDescriptions.entrySet()) {
+            assertSame(b2, entry.getValue());
+            actual.add(entry.getKey().getId());
+        }
+        assertEquals(expected, actual);
+    }
+
+    public void testBundleChanged() throws Exception {
+        LocalDiscovery ld = getLocalDiscovery();
+
+        Bundle bundle = EasyMock.createMock(Bundle.class);
+        EasyMock.expect(bundle.getSymbolicName()).andReturn("testing.bundle").anyTimes();
+        EasyMock.expect(bundle.getState()).andReturn(Bundle.ACTIVE);
+        Dictionary<String, String> headers = new Hashtable<String, String>();
+        headers.put("Remote-Service", "OSGI-INF/rsa/");
+        EasyMock.expect(bundle.getHeaders()).andReturn(headers);
+        EasyMock.expect(bundle.findEntries("OSGI-INF/rsa", "*.xml", false))
+            .andReturn(Collections.enumeration(
+                Collections.singleton(getClass().getResource("/ed3.xml"))));
+        EasyMock.replay(bundle);
+
+        BundleEvent be0 = new BundleEvent(BundleEvent.INSTALLED, bundle);
+        ld.bundleChanged(be0);
+        assertEquals(0, ld.endpointDescriptions.size());
+
+        // Create an EndpointListener
+        final Map<String, Object> props = new Hashtable<String, Object>();
+        props.put(EndpointListener.ENDPOINT_LISTENER_SCOPE, "(objectClass=*)");
+        @SuppressWarnings("unchecked")
+        ServiceReference<EndpointListener> sr = EasyMock.createMock(ServiceReference.class);
+        EasyMock.expect(sr.getPropertyKeys()).andReturn(props.keySet().toArray(new String[] {})).anyTimes();
+        EasyMock.expect(sr.getProperty((String) EasyMock.anyObject())).andAnswer(new IAnswer<Object>() {
+            public Object answer() throws Throwable {
+                return props.get(EasyMock.getCurrentArguments()[0]);
+            }
+        }).anyTimes();
+        EasyMock.replay(sr);
+
+        EndpointListener endpointListener = EasyMock.createMock(EndpointListener.class);
+        endpointListener.endpointAdded((EndpointDescription) EasyMock.anyObject(), EasyMock.eq("(objectClass=*)"));
+        EasyMock.expectLastCall();
+        EasyMock.replay(endpointListener);
+        ld.addListener(sr, endpointListener);
+
+        // Start the bundle
+        BundleEvent be = new BundleEvent(BundleEvent.STARTED, bundle);
+        ld.bundleChanged(be);
+        assertEquals(1, ld.endpointDescriptions.size());
+        EndpointDescription endpoint = ld.endpointDescriptions.keySet().iterator().next();
+        assertEquals("http://somewhere:12345", endpoint.getId());
+        assertSame(bundle, ld.endpointDescriptions.get(endpoint));
+
+        EasyMock.verify(endpointListener);
+
+        // Stop the bundle
+        EasyMock.reset(endpointListener);
+        endpointListener.endpointRemoved((EndpointDescription) EasyMock.anyObject(), EasyMock.eq("(objectClass=*)"));
+        EasyMock.expectLastCall();
+        EasyMock.replay(endpointListener);
+
+        BundleEvent be1 = new BundleEvent(BundleEvent.STOPPED, bundle);
+        ld.bundleChanged(be1);
+        assertEquals(0, ld.endpointDescriptions.size());
+
+        EasyMock.verify(endpointListener);
+    }
+
+    public void testEndpointListenerService() throws Exception {
+        LocalDiscovery ld = getLocalDiscovery();
+
+        Bundle bundle = EasyMock.createMock(Bundle.class);
+        EasyMock.expect(bundle.getState()).andReturn(Bundle.ACTIVE);
+        Dictionary<String, String> headers = new Hashtable<String, String>();
+        headers.put("Remote-Service", "OSGI-INF/rsa/ed4.xml");
+        EasyMock.expect(bundle.getHeaders()).andReturn(headers);
+        EasyMock.expect(bundle.findEntries("OSGI-INF/rsa", "ed4.xml", false))
+            .andReturn(Collections.enumeration(
+                Collections.singleton(getClass().getResource("/ed4.xml"))));
+        EasyMock.replay(bundle);
+
+        BundleEvent be = new BundleEvent(BundleEvent.STARTED, bundle);
+        ld.bundleChanged(be);
+        assertEquals(2, ld.endpointDescriptions.size());
+
+        final Map<String, Object> props = new Hashtable<String, Object>();
+        props.put(EndpointListener.ENDPOINT_LISTENER_SCOPE, new String[] {"(objectClass=org.example.ClassA)"});
+        @SuppressWarnings("unchecked")
+        ServiceReference<EndpointListener> sr = EasyMock.createMock(ServiceReference.class);
+        EasyMock.expect(sr.getPropertyKeys()).andReturn(props.keySet().toArray(new String[] {})).anyTimes();
+        EasyMock.expect(sr.getProperty((String) EasyMock.anyObject())).andAnswer(new IAnswer<Object>() {
+            public Object answer() throws Throwable {
+                return props.get(EasyMock.getCurrentArguments()[0]);
+            }
+        }).anyTimes();
+
+        EasyMock.replay(sr);
+
+        EasyMock.reset(ld.bundleContext);
+        EndpointListener el = EasyMock.createMock(EndpointListener.class);
+        EasyMock.expect(ld.bundleContext.getService(sr)).andReturn(el);
+        EasyMock.expect(ld.bundleContext.ungetService(sr)).andReturn(true);
+        EasyMock.expect(ld.bundleContext.createFilter((String) EasyMock.anyObject())).andAnswer(new IAnswer<Filter>() {
+            public Filter answer() throws Throwable {
+                return FrameworkUtil.createFilter((String) EasyMock.getCurrentArguments()[0]);
+            }
+        }).anyTimes();
+        EasyMock.replay(ld.bundleContext);
+
+        el.endpointAdded((EndpointDescription) EasyMock.anyObject(),
+                EasyMock.eq("(objectClass=org.example.ClassA)"));
+        EasyMock.expectLastCall();
+        EasyMock.replay(el);
+
+        // Add the EndpointListener Service
+        assertEquals("Precondition failed", 0, ld.listenerToFilters.size());
+        assertEquals("Precondition failed", 0, ld.filterToListeners.size());
+        assertSame(el, ld.listenerTracker.addingService(sr));
+
+        assertEquals(1, ld.listenerToFilters.size());
+        assertEquals(Collections.singletonList("(objectClass=org.example.ClassA)"), ld.listenerToFilters.get(el));
+        assertEquals(1, ld.filterToListeners.size());
+        assertEquals(Collections.singletonList(el), ld.filterToListeners.get("(objectClass=org.example.ClassA)"));
+
+        EasyMock.verify(el);
+
+        // Modify the EndpointListener Service
+        // no need to reset the mock for this...
+        props.put(EndpointListener.ENDPOINT_LISTENER_SCOPE,
+                  "(|(objectClass=org.example.ClassA)(objectClass=org.example.ClassB))");
+
+        EasyMock.reset(el);
+        final Set<String> actualEndpoints = new HashSet<String>();
+        el.endpointAdded((EndpointDescription) EasyMock.anyObject(),
+                EasyMock.eq("(|(objectClass=org.example.ClassA)(objectClass=org.example.ClassB))"));
+        EasyMock.expectLastCall().andAnswer(new IAnswer<Object>() {
+            public Object answer() throws Throwable {
+                EndpointDescription endpoint = (EndpointDescription) EasyMock.getCurrentArguments()[0];
+                actualEndpoints.addAll(endpoint.getInterfaces());
+                return null;
+            }
+        }).times(2);
+        EasyMock.replay(el);
+
+        ld.listenerTracker.modifiedService(sr, el);
+        assertEquals(1, ld.listenerToFilters.size());
+        assertEquals(Arrays.asList("(|(objectClass=org.example.ClassA)(objectClass=org.example.ClassB))"),
+            ld.listenerToFilters.get(el));
+        assertEquals(1, ld.filterToListeners.size());
+        assertEquals(Collections.singletonList(el),
+            ld.filterToListeners.get("(|(objectClass=org.example.ClassA)(objectClass=org.example.ClassB))"));
+
+        EasyMock.verify(el);
+        Set<String> expectedEndpoints = new HashSet<String>(Arrays.asList("org.example.ClassA", "org.example.ClassB"));
+        assertEquals(expectedEndpoints, actualEndpoints);
+
+        // Remove the EndpointListener Service
+        ld.listenerTracker.removedService(sr, el);
+        assertEquals(0, ld.listenerToFilters.size());
+        assertEquals(0, ld.filterToListeners.size());
+    }
+
+    public void testRegisterTracker() throws Exception {
+        LocalDiscovery ld = getLocalDiscovery();
+
+        final Map<String, Object> props = new Hashtable<String, Object>();
+        props.put(EndpointListener.ENDPOINT_LISTENER_SCOPE, "(objectClass=Aaaa)");
+        @SuppressWarnings("unchecked")
+        ServiceReference<EndpointListener> sr = EasyMock.createMock(ServiceReference.class);
+        EasyMock.expect(sr.getPropertyKeys()).andReturn(props.keySet().toArray(new String[] {})).anyTimes();
+        EasyMock.expect(sr.getProperty((String) EasyMock.anyObject())).andAnswer(new IAnswer<Object>() {
+            public Object answer() throws Throwable {
+                return props.get(EasyMock.getCurrentArguments()[0]);
+            }
+        }).anyTimes();
+        EasyMock.replay(sr);
+
+        EndpointListener endpointListener = EasyMock.createMock(EndpointListener.class);
+        EasyMock.replay(endpointListener);
+
+        assertEquals("Precondition failed", 0, ld.listenerToFilters.size());
+        assertEquals("Precondition failed", 0, ld.filterToListeners.size());
+        ld.addListener(sr, endpointListener);
+
+        assertEquals(1, ld.listenerToFilters.size());
+        assertEquals(Collections.singletonList("(objectClass=Aaaa)"), ld.listenerToFilters.get(endpointListener));
+        assertEquals(1, ld.filterToListeners.size());
+        assertEquals(Collections.singletonList(endpointListener), ld.filterToListeners.get("(objectClass=Aaaa)"));
+
+        // Add another one with the same scope filter
+        @SuppressWarnings("unchecked")
+        ServiceReference<EndpointListener> sr2 = EasyMock.createMock(ServiceReference.class);
+        EasyMock.expect(sr2.getPropertyKeys()).andReturn(props.keySet().toArray(new String[] {})).anyTimes();
+        EasyMock.expect(sr2.getProperty((String) EasyMock.anyObject())).andAnswer(new IAnswer<Object>() {
+            public Object answer() throws Throwable {
+                return props.get(EasyMock.getCurrentArguments()[0]);
+            }
+        }).anyTimes();
+        EasyMock.replay(sr2);
+
+        EndpointListener endpointListener2 = EasyMock.createMock(EndpointListener.class);
+        EasyMock.replay(endpointListener2);
+        ld.addListener(sr2, endpointListener2);
+
+        assertEquals(2, ld.listenerToFilters.size());
+        assertEquals(Collections.singletonList("(objectClass=Aaaa)"), ld.listenerToFilters.get(endpointListener));
+        assertEquals(Collections.singletonList("(objectClass=Aaaa)"), ld.listenerToFilters.get(endpointListener2));
+
+        assertEquals(1, ld.filterToListeners.size());
+        List<EndpointListener> endpointListeners12 = Arrays.asList(endpointListener, endpointListener2);
+        assertEquals(endpointListeners12, ld.filterToListeners.get("(objectClass=Aaaa)"));
+
+        // Add another listener with a multi-value scope
+        final Map<String, Object> props2 = new Hashtable<String, Object>();
+        props2.put(EndpointListener.ENDPOINT_LISTENER_SCOPE, Arrays.asList("(objectClass=X)", "(objectClass=Y)"));
+        @SuppressWarnings("unchecked")
+        ServiceReference<EndpointListener> sr3 = EasyMock.createMock(ServiceReference.class);
+        EasyMock.expect(sr3.getPropertyKeys()).andReturn(props2.keySet().toArray(new String[] {})).anyTimes();
+        EasyMock.expect(sr3.getProperty((String) EasyMock.anyObject())).andAnswer(new IAnswer<Object>() {
+            public Object answer() throws Throwable {
+                return props2.get(EasyMock.getCurrentArguments()[0]);
+            }
+        }).anyTimes();
+        EasyMock.replay(sr3);
+
+        EndpointListener endpointListener3 = EasyMock.createMock(EndpointListener.class);
+        EasyMock.replay(endpointListener3);
+        ld.addListener(sr3, endpointListener3);
+
+        assertEquals(3, ld.listenerToFilters.size());
+        assertEquals(Collections.singletonList("(objectClass=Aaaa)"), ld.listenerToFilters.get(endpointListener));
+        assertEquals(Collections.singletonList("(objectClass=Aaaa)"), ld.listenerToFilters.get(endpointListener2));
+        assertEquals(Arrays.asList("(objectClass=X)", "(objectClass=Y)"), ld.listenerToFilters.get(endpointListener3));
+
+        assertEquals(3, ld.filterToListeners.size());
+        assertEquals(endpointListeners12, ld.filterToListeners.get("(objectClass=Aaaa)"));
+        assertEquals(Collections.singletonList(endpointListener3), ld.filterToListeners.get("(objectClass=X)"));
+        assertEquals(Collections.singletonList(endpointListener3), ld.filterToListeners.get("(objectClass=Y)"));
+    }
+
+    public void testClearTracker() throws Exception {
+        LocalDiscovery ld = getLocalDiscovery();
+
+        EndpointListener endpointListener = EasyMock.createMock(EndpointListener.class);
+        ld.listenerToFilters.put(endpointListener,
+                new ArrayList<String>(Arrays.asList("(a=b)", "(objectClass=foo.bar.Bheuaark)")));
+        ld.filterToListeners.put("(a=b)", new ArrayList<EndpointListener>(Arrays.asList(endpointListener)));
+        ld.filterToListeners.put("(objectClass=foo.bar.Bheuaark)",
+                new ArrayList<EndpointListener>(Arrays.asList(endpointListener)));
+
+        assertEquals(1, ld.listenerToFilters.size());
+        assertEquals(2, ld.filterToListeners.size());
+        assertEquals(1, ld.filterToListeners.values().iterator().next().size());
+        ld.removeListener(EasyMock.createMock(EndpointListener.class));
+        assertEquals(1, ld.listenerToFilters.size());
+        assertEquals(2, ld.filterToListeners.size());
+        assertEquals(1, ld.filterToListeners.values().iterator().next().size());
+        ld.removeListener(endpointListener);
+        assertEquals(0, ld.listenerToFilters.size());
+        assertEquals(0, ld.filterToListeners.size());
+    }
+
+    private LocalDiscovery getLocalDiscovery() throws InvalidSyntaxException {
+        BundleContext bc = EasyMock.createMock(BundleContext.class);
+        EasyMock.expect(bc.createFilter((String) EasyMock.anyObject())).andAnswer(new IAnswer<Filter>() {
+            public Filter answer() throws Throwable {
+                return FrameworkUtil.createFilter((String) EasyMock.getCurrentArguments()[0]);
+            }
+        }).anyTimes();
+        bc.addServiceListener((ServiceListener) EasyMock.anyObject(),
+            EasyMock.eq("(objectClass=org.osgi.service.remoteserviceadmin.EndpointListener)"));
+        EasyMock.expectLastCall();
+        EasyMock.expect(bc.getServiceReferences("org.osgi.service.remoteserviceadmin.EndpointListener", null))
+            .andReturn(null);
+        bc.addBundleListener((BundleListener) EasyMock.anyObject());
+        EasyMock.expectLastCall();
+        EasyMock.expect(bc.getBundles()).andReturn(null);
+        EasyMock.replay(bc);
+
+        return new LocalDiscovery(bc);
+    }
+}
diff --git a/trunk/discovery/local/src/test/java/org/apache/cxf/dosgi/endpointdesc/EndpointDescriptionBundleParserTest.java b/trunk/discovery/local/src/test/java/org/apache/cxf/dosgi/endpointdesc/EndpointDescriptionBundleParserTest.java
new file mode 100644
index 0000000..4884c50
--- /dev/null
+++ b/trunk/discovery/local/src/test/java/org/apache/cxf/dosgi/endpointdesc/EndpointDescriptionBundleParserTest.java
@@ -0,0 +1,138 @@
+/**
+ * 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.endpointdesc;
+
+import java.net.URL;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import junit.framework.TestCase;
+
+import org.apache.cxf.dosgi.discovery.local.util.Utils;
+import org.easymock.EasyMock;
+import org.osgi.framework.Bundle;
+import org.osgi.service.remoteserviceadmin.EndpointDescription;
+
+public class EndpointDescriptionBundleParserTest extends TestCase {
+
+    private Bundle createBundleContaining(URL ed1URL) {
+        Bundle b = EasyMock.createNiceMock(Bundle.class);
+        EasyMock.expect(b.findEntries(
+            EasyMock.eq("OSGI-INF/remote-service"),
+            EasyMock.eq("*.xml"), EasyMock.anyBoolean())).andReturn(
+                Collections.enumeration(Arrays.asList(ed1URL))).anyTimes();
+        EasyMock.replay(b);
+        return b;
+    }
+
+    public void testAllEndpoints1() {
+        URL ed1URL = getClass().getResource("/ed1.xml");
+
+        Bundle b = createBundleContaining(ed1URL);
+
+        List<EndpointDescription> endpoints = new EndpointDescriptionBundleParser().getAllEndpointDescriptions(b);
+        assertEquals(4, endpoints.size());
+        EndpointDescription endpoint0 = endpoints.get(0);
+        assertEquals("http://somewhere:12345", endpoint0.getId());
+        assertEquals(Arrays.asList("SomeService"), endpoint0.getInterfaces());
+        assertEquals(Arrays.asList("confidentiality"),
+            endpoint0.getProperties().get("osgi.remote.requires.intents"));
+        assertEquals("testValue", endpoint0.getProperties().get("testKey"));
+
+        EndpointDescription endpoint1 = endpoints.get(1);
+        assertEquals("myScheme://somewhere:12345", endpoint1.getId());
+        assertEquals(Arrays.asList("SomeOtherService", "WithSomeSecondInterface"), endpoint1.getInterfaces());
+
+        EndpointDescription endpoint2 = endpoints.get(2);
+        assertEquals("http://somewhere", endpoint2.getId());
+        assertEquals(Arrays.asList("SomeOtherService", "WithSomeSecondInterface"), endpoint2.getInterfaces());
+
+        EndpointDescription endpoint3 = endpoints.get(3);
+        assertEquals("http://somewhere:1/2/3/4?5", endpoint3.getId());
+        assertEquals(Arrays.asList("SomeOtherService", "WithSomeSecondInterface"), endpoint3.getInterfaces());
+    }
+
+    public void testAllEndpoints2() throws Exception {
+        URL ed2URL = getClass().getResource("/ed2.xml");
+
+        Bundle b = createBundleContaining(ed2URL);
+
+        List<EndpointDescription> endpoints = new EndpointDescriptionBundleParser().getAllEndpointDescriptions(b);
+        assertEquals(2, endpoints.size());
+        EndpointDescription endpoint0 = endpoints.get(0);
+        assertEquals("foo:bar", endpoint0.getId());
+        assertEquals(Arrays.asList("com.acme.HelloService"), endpoint0.getInterfaces());
+        assertEquals(Arrays.asList("SOAP"), endpoint0.getIntents());
+        // changed from exported to imported
+        assertEquals("org.apache.cxf.ws", endpoint0.getProperties().get("service.imported.configs"));
+
+        EndpointDescription endpoint1 = endpoints.get(1);
+        Map<String, Object> props = endpoint1.getProperties();
+        assertEquals(Arrays.asList("com.acme.HelloService", "some.other.Service"), endpoint1.getInterfaces());
+        assertEquals("org.apache.cxf.ws", props.get("service.imported.configs"));
+        // exports should have been removed
+        assertNull(props.get("service.exported.configs"));
+
+        assertEquals(Utils.normXML("<other:t1 xmlns:other='http://www.acme.org/xmlns/other/v1.0.0' "
+            + "xmlns='http://www.acme.org/xmlns/other/v1.0.0'><foo type='bar'>haha</foo>\n"
+            + "        </other:t1>"),
+            Utils.normXML((String) props.get("someXML")));
+        assertEquals(Long.MAX_VALUE, props.get("long"));
+        assertEquals(-1L, props.get("long2"));
+        assertEquals(Double.MAX_VALUE, props.get("double"));
+        assertEquals(1.0d, props.get("Double2"));
+        assertEquals(42.24f, props.get("float"));
+        assertEquals(1.0f, props.get("Float2"));
+        assertEquals(17, props.get("int"));
+        assertEquals(42, props.get("Integer2"));
+        assertEquals((byte) 127, props.get("byte"));
+        assertEquals((byte) -128, props.get("Byte2"));
+        assertEquals(Boolean.TRUE, props.get("boolean"));
+        assertEquals(Boolean.TRUE, props.get("Boolean2"));
+        assertEquals((short) 99, props.get("short"));
+        assertEquals((short) -99, props.get("Short2"));
+        assertEquals('@', props.get("char"));
+        assertEquals('X', props.get("Character2"));
+
+        int[] intArray = (int[]) props.get("int-array");
+        assertTrue(Arrays.equals(new int[] {1, 2}, intArray));
+
+        Integer[] integerArray = (Integer[]) props.get("Integer-array");
+        assertTrue(Arrays.equals(new Integer[] {2, 1}, integerArray));
+
+        assertEquals(Arrays.asList(true, false), props.get("bool-list"));
+        assertEquals(new HashSet<Object>(), props.get("long-set"));
+        Set<String> stringSet = new HashSet<String>();
+        stringSet.add("Hello there");
+        stringSet.add("How are you?");
+        assertEquals(stringSet, props.get("string-set"));
+        assertEquals("Hello", props.get("other1").toString().trim());
+
+        List<?> l = (List<?>) props.get("other2");
+        assertEquals(1, l.size());
+        assertEquals(Utils.normXML("<other:t2 xmlns:other='http://www.acme.org/xmlns/other/v1.0.0' " 
+                                   + "xmlns='http://www.osgi.org/xmlns/rsa/v1.0.0'/>"),
+                                   Utils.normXML((String) l.get(0)));
+    }
+
+}
diff --git a/trunk/discovery/local/src/test/java/org/apache/cxf/dosgi/endpointdesc/EndpointDescriptionParserTest.java b/trunk/discovery/local/src/test/java/org/apache/cxf/dosgi/endpointdesc/EndpointDescriptionParserTest.java
new file mode 100644
index 0000000..97e4b45
--- /dev/null
+++ b/trunk/discovery/local/src/test/java/org/apache/cxf/dosgi/endpointdesc/EndpointDescriptionParserTest.java
@@ -0,0 +1,49 @@
+/**
+ * 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.endpointdesc;
+
+import java.io.IOException;
+import java.net.URL;
+import java.util.List;
+
+import org.easymock.EasyMock;
+import org.junit.Assert;
+import org.junit.Test;
+import org.osgi.framework.Bundle;
+import org.osgi.xmlns.rsa.v1_0.EndpointDescriptionType;
+
+public class EndpointDescriptionParserTest {
+
+    @Test
+    public void testNoRemoteServicesXMLFiles() {
+        Bundle b = EasyMock.createNiceMock(Bundle.class);
+        EasyMock.replay(b);
+
+        List<EndpointDescriptionType> rsElements = new EndpointDescriptionBundleParser().getAllDescriptionElements(b);
+        Assert.assertEquals(0, rsElements.size());
+    }
+
+    @Test
+    public void testEndpointDescriptionsFromURL() throws IOException {
+        URL ed1URL = getClass().getResource("/ed1.xml");
+        List<EndpointDescriptionType> edElements = new EndpointDescriptionParser().
+            getEndpointDescriptions(ed1URL.openStream());
+        Assert.assertEquals(4, edElements.size());
+    }
+}
diff --git a/trunk/discovery/local/src/test/java/org/apache/cxf/dosgi/endpointdesc/PropertiesMapperTest.java b/trunk/discovery/local/src/test/java/org/apache/cxf/dosgi/endpointdesc/PropertiesMapperTest.java
new file mode 100644
index 0000000..bc21198
--- /dev/null
+++ b/trunk/discovery/local/src/test/java/org/apache/cxf/dosgi/endpointdesc/PropertiesMapperTest.java
@@ -0,0 +1,97 @@
+/**
+ * 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.endpointdesc;
+
+import java.io.ByteArrayInputStream;
+import java.net.URL;
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.LinkedHashMap;
+import java.util.LinkedHashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import org.xml.sax.InputSource;
+
+import org.custommonkey.xmlunit.XMLAssert;
+import org.junit.Test;
+import org.osgi.xmlns.rsa.v1_0.EndpointDescriptionType;
+import org.osgi.xmlns.rsa.v1_0.PropertyType;
+
+public class PropertiesMapperTest {
+    private static final String LF = "\n";
+
+    @Test
+    public void testCreateXML() throws Exception {
+        Map<String, Object> m = new LinkedHashMap<String, Object>();
+        m.put("service.imported.configs", "org.apache.cxf.ws");
+        m.put("endpoint.id", "foo:bar");
+        m.put("objectClass", new String[] {"com.acme.HelloService", "some.other.Service"});
+        m.put("SomeObject", new Object());
+        m.put("long", 9223372036854775807L);
+        m.put("Long2", -1L);
+        m.put("double", 1.7976931348623157E308);
+        m.put("Double2", 1.0d);
+        m.put("float", 42.24f);
+        m.put("Float2", 1.0f);
+        m.put("int", 17);
+        m.put("Integer2", 42);
+        m.put("byte", (byte) 127);
+        m.put("Byte2", (byte) -128);
+        m.put("boolean", true);
+        m.put("Boolean2", false);
+        m.put("short", (short) 99);
+        m.put("Short2", (short) -99);
+        m.put("char", '@');
+        m.put("Character2", 'X');
+
+        List<Boolean> boolList = new ArrayList<Boolean>();
+        boolList.add(true);
+        boolList.add(false);
+        m.put("bool-list", boolList);
+        m.put("empty-set", new HashSet<Object>());
+
+        Set<String> stringSet = new LinkedHashSet<String>();
+        stringSet.add("Hello there");
+        stringSet.add("How are you?");
+        m.put("string-set", stringSet);
+
+        int[] intArray = new int[] {1, 2};
+        m.put("int-array", intArray);
+
+        String xml = "<xml>" + LF
+            + "<t1 xmlns=\"http://www.acme.org/xmlns/other/v1.0.0\">" + LF
+            + "<foo type='bar'>haha</foo>" + LF
+            + "</t1>" + LF
+            + "</xml>";
+        m.put("someXML", xml);
+
+        List<PropertyType> props = new PropertiesMapper().fromProps(m);
+        EndpointDescriptionType epd = new EndpointDescriptionType();
+        epd.getProperty().addAll(props);
+        byte[] epData = new EndpointDescriptionParser().getData(epd);
+
+        URL edURL = getClass().getResource("/ed2-generated.xml");
+        InputSource expectedXml = new InputSource(edURL.openStream());
+        InputSource actualXml = new InputSource(new ByteArrayInputStream(epData)); 
+        XMLAssert.assertXMLEqual(expectedXml, actualXml);
+    }
+
+}
diff --git a/trunk/discovery/local/src/test/resources/ed1.xml b/trunk/discovery/local/src/test/resources/ed1.xml
new file mode 100644
index 0000000..95b1994
--- /dev/null
+++ b/trunk/discovery/local/src/test/resources/ed1.xml
@@ -0,0 +1,72 @@
+<?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.
+-->
+
+<endpoint-descriptions xmlns="http://www.osgi.org/xmlns/rsa/v1.0.0"
+  xmlns:other="http://www.acme.org/xmlns/other/v1.0.0">
+  <endpoint-description>
+    <property name="objectClass">
+      <array>
+        <value>SomeService</value>
+      </array>
+    </property>
+    <property name="osgi.remote.requires.intents">
+      <list>
+        <value>confidentiality</value>
+      </list>
+    </property>
+    <property name="testKey" value="testValue"/>
+    <property name="endpoint.id">http://somewhere:12345</property>
+    <property name="service.imported.configs" value="org.apache.cxf.ws"/>
+  </endpoint-description>
+
+  <endpoint-description>
+    <property name="objectClass">
+      <array>
+        <value>SomeOtherService</value>
+        <value>WithSomeSecondInterface</value>
+      </array>
+    </property>
+    <property name="endpoint.id" value-type="String" value="myScheme://somewhere:12345" />
+    <property name="service.imported.configs" value="org.apache.cxf.ws"/>
+  </endpoint-description>
+
+  <endpoint-description>
+    <property name="objectClass" value-type="String">
+      <array>
+        <value>SomeOtherService</value>
+        <value>WithSomeSecondInterface</value>
+      </array>
+    </property>
+    <property name="endpoint.id" value="http://somewhere" />
+    <property name="service.imported.configs" value="org.apache.cxf.ws"/>
+  </endpoint-description>
+
+  <endpoint-description>
+    <property name="objectClass">
+      <array>
+        <value>SomeOtherService</value>
+        <value>WithSomeSecondInterface</value>
+      </array>
+    </property>
+    <property name="endpoint.id" value-type="String">http://somewhere:1/2/3/4?5</property>
+    <property name="service.imported.configs" value="org.apache.cxf.ws"/>
+  </endpoint-description>
+</endpoint-descriptions>
diff --git a/trunk/discovery/local/src/test/resources/ed2-generated.xml b/trunk/discovery/local/src/test/resources/ed2-generated.xml
new file mode 100644
index 0000000..5e2a5ef
--- /dev/null
+++ b/trunk/discovery/local/src/test/resources/ed2-generated.xml
@@ -0,0 +1,54 @@
+<?xml version="1.0" encoding="UTF-8"?>

+<endpoint-descriptions xmlns="http://www.osgi.org/xmlns/rsa/v1.0.0">

+    <endpoint-description>

+        <property name="service.imported.configs" value="org.apache.cxf.ws" />

+        <property name="endpoint.id" value="foo:bar" />

+        <property name="objectClass">

+            <array>

+                <value>com.acme.HelloService</value>

+                <value>some.other.Service</value>

+            </array>

+        </property>

+        <property name="long" value-type="Long" value="9223372036854775807" />

+        <property name="Long2" value-type="Long" value="-1" />

+        <property name="double" value-type="Double"

+            value="1.7976931348623157E308" />

+        <property name="Double2" value-type="Double" value="1.0" />

+        <property name="float" value-type="Float" value="42.24" />

+        <property name="Float2" value-type="Float" value="1.0" />

+        <property name="int" value-type="Integer" value="17" />

+        <property name="Integer2" value-type="Integer" value="42" />

+        <property name="byte" value-type="Byte" value="127" />

+        <property name="Byte2" value-type="Byte" value="-128" />

+        <property name="boolean" value-type="Boolean" value="true" />

+        <property name="Boolean2" value-type="Boolean" value="false" />

+        <property name="short" value-type="Short" value="99" />

+        <property name="Short2" value-type="Short" value="-99" />

+        <property name="char" value-type="Character" value="@" />

+        <property name="Character2" value-type="Character"

+            value="X" />

+        <property name="bool-list" value-type="Boolean">

+            <list>

+                <value>true</value>

+                <value>false</value>

+            </list>

+        </property>

+        <property name="empty-set">

+            <set />

+        </property>

+        <property name="string-set">

+            <set>

+                <value>Hello there</value>

+                <value>How are you?</value>

+            </set>

+        </property>

+        <property name="int-array" value-type="Integer">

+            <array>

+                <value>1</value>

+                <value>2</value>

+            </array>

+        </property>

+        <property name="someXML"

+            value="&lt;xml&gt;&#xA;&lt;t1 xmlns=&quot;http://www.acme.org/xmlns/other/v1.0.0&quot;&gt;&#xA;&lt;foo type='bar'&gt;haha&lt;/foo&gt;&#xA;&lt;/t1&gt;&#xA;&lt;/xml&gt;" />

+    </endpoint-description>

+</endpoint-descriptions>

diff --git a/trunk/discovery/local/src/test/resources/ed2.xml b/trunk/discovery/local/src/test/resources/ed2.xml
new file mode 100644
index 0000000..e3c42b9
--- /dev/null
+++ b/trunk/discovery/local/src/test/resources/ed2.xml
@@ -0,0 +1,99 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<endpoint-descriptions xmlns="http://www.osgi.org/xmlns/rsa/v1.0.0"
+  xmlns:other="http://www.acme.org/xmlns/other/v1.0.0">
+  <endpoint-description>
+    <property name="objectClass">
+      <array>
+        <value>com.acme.HelloService</value>
+      </array>
+    </property>
+    <property name="service.intents">SOAP</property>
+    <property name="service.imported.configs" value="org.apache.cxf.ws"/>
+    <property name="endpoint.id">foo:bar</property>
+  </endpoint-description>
+  <endpoint-description>
+    <property name="service.imported.configs" value="org.apache.cxf.ws"/>
+    <property name="endpoint.id">foo:bar</property>
+    <property name="objectClass" value-type="String">
+      <array>
+        <value>com.acme.HelloService</value>
+        <value>some.other.Service</value>
+      </array>
+    </property>
+
+    <property name="someXML" value-type="String">
+      <!-- Literal XML to be parsed into the String -->
+      <xml>
+        <other:t1 xmlns="http://www.acme.org/xmlns/other/v1.0.0">
+          <foo type="bar">haha</foo>
+        </other:t1>
+      </xml>
+    </property>
+
+    <property name="long" value-type="long">9223372036854775807</property>
+    <property name="Long2" value-type="Long" value="-1"/>
+    <property name="double" value-type="double">1.7976931348623157E308</property>
+    <property name="Double2" value-type="Double">1.0</property>
+    <property name="float" value-type="float">42.24</property>
+    <property name="Float2" value-type="Float" value="1.0"/>
+    <property name="int" value-type="int">17</property>
+    <property name="Integer2" value-type="Integer" value="42"/>
+    <property name="byte" value-type="byte">127</property>
+    <property name="Byte2" value-type="Byte" value="-128"/>
+    <property name="boolean" value-type="boolean">true</property>
+    <property name="Boolean2" value-type="Boolean" value="true"/>
+    <property name="short" value-type="short">99</property>
+    <property name="Short2" value-type="Short" value="-99"/>
+    <property name="char" value-type="char">@</property>
+    <property name="Character2" value-type="Character" value="X"/>
+
+    <property name="bool-list" value-type="boolean">
+      <list>
+        <value>true</value>
+        <value>false</value>
+      </list>
+    </property>
+    <property name="long-set" value-type="long">
+      <set/> <!-- empty set -->
+    </property>
+    <property name="string-set">
+      <set>
+        <value>Hello there</value>
+        <value>How are you?</value>
+      </set>
+    </property>
+    <property name="int-array" value-type="int">
+      <array>
+        <value>1</value>
+        <value>2</value>
+      </array>
+    </property>
+    <property name="Integer-array" value-type="Integer">
+      <array>
+        <value>2</value>
+        <value>1</value>
+      </array>
+    </property>
+    <property name="service.exported.configs">
+      org.apache.cxf.ws
+    </property>
+
+    <property name="other1">
+        Hello
+      <other:t1/>
+      <!-- the above tag is a custom extension -->
+    </property>
+    <property name="other2">
+      <list>
+        <value>
+          <!-- A value specified as literal XML -->
+          <xml>
+            <other:t2/>
+          </xml>
+        </value>
+      </list>
+      <!-- This is a custom extension -->
+      <other:t1/>
+    </property>
+  </endpoint-description>
+</endpoint-descriptions>
diff --git a/trunk/discovery/local/src/test/resources/ed3.xml b/trunk/discovery/local/src/test/resources/ed3.xml
new file mode 100644
index 0000000..7d4d681
--- /dev/null
+++ b/trunk/discovery/local/src/test/resources/ed3.xml
@@ -0,0 +1,32 @@
+<?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.
+-->
+
+<endpoint-descriptions xmlns="http://www.osgi.org/xmlns/rsa/v1.0.0">
+  <endpoint-description>
+    <property name="objectClass">
+      <array>
+        <value>SomeService</value>
+      </array>
+    </property>
+    <property name="endpoint.id">http://somewhere:12345</property>
+    <property name="service.imported.configs" value="org.apache.cxf.ws"/>
+  </endpoint-description>
+</endpoint-descriptions>
diff --git a/trunk/discovery/local/src/test/resources/ed4.xml b/trunk/discovery/local/src/test/resources/ed4.xml
new file mode 100644
index 0000000..cef5d18
--- /dev/null
+++ b/trunk/discovery/local/src/test/resources/ed4.xml
@@ -0,0 +1,43 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements. See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership. The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License. You may obtain a copy of the License at
+
+  http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied. See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+
+<endpoint-descriptions xmlns="http://www.osgi.org/xmlns/rsa/v1.0.0"
+  xmlns:other="http://www.acme.org/xmlns/other/v1.0.0">
+  <endpoint-description>
+    <property name="objectClass">
+      <array>
+        <value>org.example.ClassA</value>
+      </array>
+    </property>
+    <property name="endpoint.id">http://somewhere</property>
+    <property name="service.imported.configs" value="org.apache.cxf.ws"/>
+  </endpoint-description>
+
+  <endpoint-description>
+    <property name="objectClass">
+      <array>
+        <value>org.example.ClassB</value>
+      </array>
+    </property>
+    <property name="endpoint.id">http://somewhere:1</property>
+    <property name="service.imported.configs" value="org.apache.cxf.ws"/>
+  </endpoint-description>
+</endpoint-descriptions>
diff --git a/trunk/discovery/local/src/test/resources/sd.xml b/trunk/discovery/local/src/test/resources/sd.xml
new file mode 100644
index 0000000..c476116
--- /dev/null
+++ b/trunk/discovery/local/src/test/resources/sd.xml
@@ -0,0 +1,23 @@
+<?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.
+  -->
+<service-descriptions xmlns="http://www.osgi.org/xmlns/sd/v1.0.0">
+  <service-description>
+    <provide interface="org.apache.cxf.dosgi.samples.greeter.GreeterService" />
+    <property name="service.exported.interfaces">*</property>
+    <property name="service.exported.configs">org.apache.cxf.ws</property>
+    <property name="org.apache.cxf.ws.address">http://localhost:9090/greeter</property>
+  </service-description>
+</service-descriptions>
diff --git a/trunk/discovery/local/src/test/resources/sd2.xml b/trunk/discovery/local/src/test/resources/sd2.xml
new file mode 100644
index 0000000..5a156ea
--- /dev/null
+++ b/trunk/discovery/local/src/test/resources/sd2.xml
@@ -0,0 +1,32 @@
+<?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.
+-->
+
+<service-descriptions xmlns="http://www.osgi.org/xmlns/sd/v1.0.0">
+  <service-description>
+    <provide interface="org.example.SomeService" />
+    <property name="service.intents">confidentiality</property>
+  </service-description>
+  <service-description>
+    <provide interface="SomeOtherService" />
+    <provide interface="WithSomeSecondInterface" />
+    <property name="blah">5</property>
+  </service-description>
+</service-descriptions>
diff --git a/trunk/discovery/pom.xml b/trunk/discovery/pom.xml
new file mode 100644
index 0000000..659afd1
--- /dev/null
+++ b/trunk/discovery/pom.xml
@@ -0,0 +1,41 @@
+<?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>
+    <groupId>org.apache.cxf.dosgi</groupId>
+    <artifactId>cxf-dosgi-ri-discovery</artifactId>
+    <packaging>pom</packaging>
+    <name>Distributed OSGI Discovery Service Modules</name>
+    <version>1.6.0</version>
+
+    <parent>
+      <groupId>org.apache.cxf.dosgi</groupId>
+      <artifactId>cxf-dosgi-ri-parent</artifactId>
+      <version>1.6.0</version>
+      <relativePath>../parent/pom.xml</relativePath>
+    </parent>
+
+    <modules>
+      <module>local</module>
+      <module>distributed</module>
+    </modules>
+
+</project>
diff --git a/trunk/distribution/features/pom.xml b/trunk/distribution/features/pom.xml
new file mode 100644
index 0000000..aa02f51
--- /dev/null
+++ b/trunk/distribution/features/pom.xml
@@ -0,0 +1,90 @@
+<?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>
+  <artifactId>cxf-dosgi</artifactId>
+  <packaging>pom</packaging>
+  <name>CXF DOSGI Karaf Features</name>
+  <url>http://cxf.apache.org</url>
+
+  <parent>
+    <groupId>org.apache.cxf.dosgi</groupId>
+    <artifactId>cxf-dosgi-ri-distribution-parent</artifactId>
+    <version>1.6.0</version>
+    <relativePath>../pom.xml</relativePath>
+  </parent>
+
+  <properties>
+    <dosgi.version>${project.version}</dosgi.version>
+    <topDirectoryLocation>../..</topDirectoryLocation>
+  </properties>
+
+  <build>
+		<resources>
+			<resource>
+				<directory>${project.basedir}/src/main/resources</directory>
+				<filtering>true</filtering>
+				<includes>
+					<include>**/features.xml</include>
+			                <include>**/*.cfg</include>
+			                <include>**/*.properties</include>
+				</includes>
+			</resource>
+		</resources>
+		<plugins>
+			<plugin>
+				<groupId>org.apache.maven.plugins</groupId>
+				<artifactId>maven-resources-plugin</artifactId>
+				<executions>
+					<execution>
+						<id>filter</id>
+						<phase>generate-resources</phase>
+						<goals>
+							<goal>resources</goal>
+						</goals>
+					</execution>
+				</executions>
+			</plugin>
+			<plugin>
+				<groupId>org.codehaus.mojo</groupId>
+				<artifactId>build-helper-maven-plugin</artifactId>
+				<executions>
+					<execution>
+						<id>attach-artifacts</id>
+						<phase>package</phase>
+						<goals>
+							<goal>attach-artifact</goal>
+						</goals>
+						<configuration>
+							<artifacts>
+								<artifact>
+									<file>target/classes/features.xml</file>
+									<type>xml</type>
+                                    <classifier>features</classifier>
+								</artifact>
+							</artifacts>
+						</configuration>
+					</execution>
+				</executions>
+			</plugin>
+		</plugins>
+	</build>
+</project>
diff --git a/trunk/distribution/features/src/main/resources/features.xml b/trunk/distribution/features/src/main/resources/features.xml
new file mode 100644
index 0000000..66eda10
--- /dev/null
+++ b/trunk/distribution/features/src/main/resources/features.xml
@@ -0,0 +1,47 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<features xmlns="http://karaf.apache.org/xmlns/features/v1.0.0" name="cxf-dosgi-${project.version}">
+    <repository>mvn:org.apache.cxf.karaf/apache-cxf/${cxf.version}/xml/features</repository>
+
+	<feature name="cxf-dosgi-base" description="base libs needed outside karaf" version="${project.version}" resolver="(obr)">
+        <bundle start-level="8">mvn:org.ops4j.base/ops4j-base-lang/1.4.0</bundle>
+        <bundle start-level="8">mvn:org.ops4j.pax.logging/pax-logging-api/1.7.0</bundle>
+        <bundle start-level="8">mvn:org.ops4j.pax.logging/pax-logging-service/1.7.0</bundle>
+        <bundle start-level="10">mvn:org.apache.felix/org.apache.felix.configadmin/1.6.0</bundle>
+        <bundle start-level="11">mvn:org.apache.felix/org.apache.felix.fileinstall/3.2.6</bundle>
+        <bundle start-level="20">mvn:org.apache.aries/org.apache.aries.util/1.1.0</bundle>
+        <bundle start-level="20">mvn:org.apache.aries.proxy/org.apache.aries.proxy.api/1.0.0</bundle>
+        <bundle start-level="20">mvn:org.apache.aries.proxy/org.apache.aries.proxy.impl/1.0.1</bundle>
+        <bundle start-level="20">mvn:org.apache.aries.blueprint/org.apache.aries.blueprint.api/1.0.0</bundle>
+        <bundle start-level="20">mvn:org.apache.aries.blueprint/org.apache.aries.blueprint.core/1.1.0</bundle>
+        <bundle start-level="20">mvn:org.apache.aries.blueprint/org.apache.aries.blueprint.cm/1.0.1</bundle>
+    </feature>
+
+    <feature name="cxf-dosgi-core" version="${project.version}">
+        <feature>cxf-specs</feature>
+        <feature>cxf-jaxws</feature>
+        <feature>cxf-jaxrs</feature>
+        <feature>cxf-databinding-aegis</feature>
+        <feature>cxf-http-jetty</feature>
+        <feature>cxf-http</feature>
+        <bundle start-level="8">mvn:${project.groupId}/cxf-dosgi-ri-osgi-api/${project.version}</bundle>
+        <bundle>mvn:${project.groupId}/cxf-dosgi-ri-topology-manager/${project.version}</bundle>
+        <bundle>mvn:${project.groupId}/cxf-dosgi-ri-dsw-cxf/${project.version}</bundle>
+    </feature>
+
+    <feature name="cxf-dosgi-discovery-local" version="${project.version}">
+        <feature>cxf-dosgi-core</feature>
+        <bundle>mvn:${project.groupId}/cxf-dosgi-ri-discovery-local/${project.version}</bundle>
+    </feature>
+
+    <feature name="cxf-dosgi-discovery-distributed" version="${project.version}">
+        <feature>cxf-dosgi-core</feature>
+        <bundle>mvn:org.apache.zookeeper/zookeeper/${zookeeper.version}</bundle>
+        <bundle>mvn:${project.groupId}/cxf-dosgi-ri-discovery-local/${project.version}</bundle>
+        <bundle>mvn:${project.groupId}/cxf-dosgi-ri-discovery-distributed/${project.version}</bundle>
+    </feature>
+
+    <feature name="cxf-dosgi-zookeeper-server">
+        <bundle>mvn:org.apache.zookeeper/zookeeper/${zookeeper.version}</bundle>
+        <bundle>mvn:${project.groupId}/cxf-dosgi-ri-discovery-distributed-zookeeper-server/${project.version}</bundle>
+    </feature>
+</features>
diff --git a/trunk/distribution/multi-bundle/pom.xml b/trunk/distribution/multi-bundle/pom.xml
new file mode 100644
index 0000000..a76a1dc
--- /dev/null
+++ b/trunk/distribution/multi-bundle/pom.xml
@@ -0,0 +1,121 @@
+<?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>
+  <artifactId>cxf-dosgi-ri-multibundle-distribution</artifactId>
+  <name>Distributed OSGI Multi-Bundle Distribution</name>
+  <url>http://cxf.apache.org</url>
+
+  <parent>
+    <groupId>org.apache.cxf.dosgi</groupId>
+    <artifactId>cxf-dosgi-ri-distribution-parent</artifactId>
+    <version>1.6.0</version>
+    <relativePath>../pom.xml</relativePath>
+  </parent>
+
+  <properties>
+    <dosgi.version>${project.version}</dosgi.version>
+    <topDirectoryLocation>../..</topDirectoryLocation>
+  </properties>
+
+  <build>
+    <resources>
+      <resource>
+        <directory>src/main/resources</directory>
+        <filtering>true</filtering>
+      </resource>
+    </resources>
+
+    <plugins>
+    <plugin>
+        <groupId>org.apache.karaf.tooling</groupId>
+        <artifactId>karaf-maven-plugin</artifactId>
+        <version>3.0.0</version>
+
+        <executions>
+          <execution>
+            <id>features-add-to-repository</id>
+            <phase>generate-resources</phase>
+            <goals>
+              <goal>features-export-meta-data</goal>
+              <goal>features-add-to-repository</goal>
+            </goals>
+            <configuration>
+              <descriptors>
+                <descriptor>mvn:org.apache.karaf.assemblies.features/standard/2.3.3/xml/features</descriptor>
+                <descriptor>mvn:org.apache.cxf.dosgi/cxf-dosgi/${project.version}/xml/features</descriptor>
+              </descriptors>
+              <features>
+                <feature>cxf-dosgi-base</feature>
+                <feature>cxf-dosgi-discovery-distributed</feature>
+                <feature>cxf-dosgi-zookeeper-server</feature>
+              </features>
+              <repository>target/distribution_bundles</repository>
+              <resolveDefinedRepositoriesRecursively>true</resolveDefinedRepositoriesRecursively>
+              <flatRepoLayout>true</flatRepoLayout>
+              <mergedFeature>true</mergedFeature>
+              <karafVersion>2.3.2</karafVersion>
+            </configuration>
+          </execution>
+        </executions>
+      </plugin>
+      
+      <plugin>
+        <artifactId>maven-antrun-plugin</artifactId>
+        <executions>
+          <execution>
+            <phase>package</phase>
+            <configuration>
+              <target>
+                <xslt processor="trax" in="target/features.xml" out="target/filtered-features.xml" style="src/main/xsl/filter_features.xslt" />
+                <xslt processor="trax" in="target/filtered-features.xml" out="target/distribution_configs/felix.config.properties.append" style="src/main/xsl/felix_distro_config.xslt" />
+                <xslt processor="trax" in="target/filtered-features.xml" out="target/distribution_configs/config.ini" style="src/main/xsl/equinox_distro_config.xslt" />
+              </target>
+            </configuration>
+            <goals>
+              <goal>run</goal>
+            </goals>
+          </execution>
+        </executions>
+      </plugin>
+
+      <plugin>
+        <artifactId>maven-assembly-plugin</artifactId>
+        <executions>
+          <execution>
+            <id>make-assembly</id>
+            <phase>package</phase>
+            <goals>
+              <goal>single</goal>
+            </goals>
+            <configuration>
+              <descriptors>
+                <descriptor>./src/main/assembly/assembly.xml</descriptor>
+              </descriptors>
+            </configuration>
+
+          </execution>
+        </executions>
+      </plugin>
+
+    </plugins>
+  </build>
+</project>
diff --git a/trunk/distribution/multi-bundle/src/main/appended-resources/META-INF/LICENSE.vm b/trunk/distribution/multi-bundle/src/main/appended-resources/META-INF/LICENSE.vm
new file mode 100644
index 0000000..8569572
--- /dev/null
+++ b/trunk/distribution/multi-bundle/src/main/appended-resources/META-INF/LICENSE.vm
@@ -0,0 +1,39 @@
+##
+## 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.
+##
+## $Date: 2008-03-09 23:17:06 -0700 (Sun, 09 Mar 2008) $ $Rev: 635446 $
+##
+
+
+The $projectName
+includes a number of components and libraries with separate
+copyright notices and license terms. Your use of those components are
+subject to the terms and conditions of the following licenses.
+#set ( $apacheTxt = "The Apache Software License, Version 2.0" )
+
+#foreach ( $project in $projects )
+#foreach ( $license in $project.licenses)
+#if ( ! ($apacheTxt == $license.name) )
+
+$project.name #if ($project.url)($project.url)#end $project.artifact
+    License: $license.name #if ($license.url) ($license.url)#end
+
+#end
+#end
+#end
+
diff --git a/trunk/distribution/multi-bundle/src/main/appended-resources/META-INF/NOTICE b/trunk/distribution/multi-bundle/src/main/appended-resources/META-INF/NOTICE
new file mode 100644
index 0000000..f380729
--- /dev/null
+++ b/trunk/distribution/multi-bundle/src/main/appended-resources/META-INF/NOTICE
@@ -0,0 +1,42 @@
+This product contains interfaces and specifications Copyright The OSGi Alliance.

+

+

+This product also includes schemas and specification developed by:

+      - the W3C consortium (http://www.w3c.org)

+      (http://www.w3.org/XML/1998/namespace)

+

+

+This product also includes WS-* schemas developed by International

+   Business Machines Corporation, Microsoft Corporation, BEA Systems,

+   TIBCO Software, SAP AG, Sonic Software, and VeriSign

+   (http://schemas.xmlsoap.org/wsdl/2003-02-11.xsd)

+   (http://schemas.xmlsoap.org/ws/2004/08/addressing/)

+   (http://schemas.xmlsoap.org/wsdl/http)

+   (http://schemas.xmlsoap.org/ws/2005/02/rm/wsrm.xsd)

+   (http://www.w3.org/2005/08/addressing/ws-addr.xsd)

+

+The product contains code (StaxBuilder.java) that is

+  Copyright (C) 2000-2004 Jason Hunter & Brett McLaughlin.

+  All rights reserved.

+

+Java classes (source and binary) under org.apache.cxf.jaxws.javaee

+are generated from schema available here:

+(http://java.sun.com/xml/ns/javaee/javaee_5.xsd)

+

+

+Portions of the included XmlSchema library are Copyright 2006 International Business Machines Corp.

+

+

+Portions of the included xml-apis library were originally based on the following:

+   - software copyright (c) 1999, IBM Corporation., http://www.ibm.com.

+   - software copyright (c) 1999, Sun Microsystems., http://www.sun.com.

+   - software copyright (c) 2000 World Wide Web Consortium, http://www.w3.org

+

+

+Portions of the included xmlbeans library were originally based on the following:

+   - software copyright (c) 2000-2003, BEA Systems, <http://www.bea.com/>.

+

+This product includes xmlunit

+Copyright (c) 2001-2007, Jeff Martin, Tim Bacon

+All rights reserved. 

+

diff --git a/trunk/distribution/multi-bundle/src/main/assembly/assembly.xml b/trunk/distribution/multi-bundle/src/main/assembly/assembly.xml
new file mode 100644
index 0000000..2844317
--- /dev/null
+++ b/trunk/distribution/multi-bundle/src/main/assembly/assembly.xml
@@ -0,0 +1,54 @@
+<assembly xmlns="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.2"
+          xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+          xsi:schemaLocation="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.2 http://maven.apache.org/xsd/component-1.1.2.xsd">
+<!--
+  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.
+-->
+  <id>dir</id>
+  <formats>
+    <format>tar.gz</format>
+    <format>zip</format>
+    <format>dir</format>
+  </formats>
+  <includeBaseDirectory>false</includeBaseDirectory>
+  <fileSets>
+    <fileSet>
+      <directory>target/distribution_bundles</directory>
+      <outputDirectory>apache-cxf-dosgi-ri-${dosgi.version}/dosgi_bundles</outputDirectory>
+    </fileSet>
+    <fileSet>
+      <directory>target/distribution_configs</directory>
+      <outputDirectory>apache-cxf-dosgi-ri-${dosgi.version}/conf</outputDirectory>
+    </fileSet>
+    <fileSet>
+      <directory>target/maven-shared-archive-resources/META-INF</directory>
+      <excludes>
+          <exclude>DEPENDENCIES</exclude>
+      </excludes>
+      <outputDirectory>apache-cxf-dosgi-ri-${dosgi.version}</outputDirectory>
+    </fileSet>
+    <fileSet>
+      <directory>src/main/release</directory>
+      <includes>
+        <include>README</include>
+        <include>release_notes.txt</include>
+      </includes>
+      <outputDirectory>apache-cxf-dosgi-ri-${dosgi.version}</outputDirectory>
+    </fileSet>
+  </fileSets>
+</assembly>
diff --git a/trunk/distribution/multi-bundle/src/main/release/README b/trunk/distribution/multi-bundle/src/main/release/README
new file mode 100644
index 0000000..40d7b0d
--- /dev/null
+++ b/trunk/distribution/multi-bundle/src/main/release/README
@@ -0,0 +1,63 @@
+Welcome to the Apache CXF Distributed OSGi DSW Reference Implementation
+=======================================================================
+
+
+The dOSGi subproject of Apache CXF provides the Reference Implementation
+of the Remote Services Specification version 1.0, Chapter 13 in the OSGi
+Compendium Specification, and OSGi Remote Service Admin Specification
+version 1.0, Chapter 122 in the OSGi Enterprise Specification[1].
+
+
+This release is provided for your convenience in three different
+distribution formats:
+
+1. Multi-bundle distro: cxf-dosgi-ri-multibundle-distribution-1.2.{tar.gaz|zip}
+
+Contains the dOSGi implementation and all 3rd party dependencies as
+separate bundles within an archive. The current distribution is an
+instance of this type. The easiest way to get started is to explode
+this archive into your Felix or Equinox installation tree. Then
+append the contents of the felix.config.properties.append or
+equinox.config.ini.append snippets found in the conf directory to
+your felix.config.properties or equinox.config.ini. This will cause
+all the required bundles to be loaded on start-up. The bundles required
+for the Zookeeper-based Discovery Service implementation are also provided
+in this distribution, and similarly may be automatically loaded by
+appending the felix.discovery.config.properties.append or
+equinox.discovery.config.ini.append snippets as appropriate.
+
+
+2. Single-bundle distro: cxf-dosgi-ri-singlebundle-distribution-1.2.jar
+
+Contains the dOSGi implementation and all 3rd party dependencies wrapped
+in a single OSGi bundle so as to allow direct installation in your favourite
+OSGi container in one fell swoop.
+
+
+3. Source distro: cxf-dosgi-ri-source-distribution-1.2.{tar.gz|zip}
+
+Contains the entire source tree for dOSGi.
+
+
+The best starting point for using dOSGi is the Getting Started Guide[2].
+
+Also note the very detailed walk-through of the greeter demo[3].
+
+If you need more help, or want to provide any feedback, please feel free
+to drop us a note on the CXF dev or users list[4].
+
+If you trip over any problems with dOSGi, don't hesitate to submit an issue
+to the CXF JIRA[5] with the component set to "Distributed-OSGi".
+
+
+Thanks for using dOSGi!
+
+Regards,
+The CXF dOSGi team.
+
+
+[1] see chapter 122 http://www.osgi.org/Download/Release4V42
+[2] http://cxf.apache.org/distributed-osgi.html#DistributedOSGi-GettingStarted
+[3] http://cxf.apache.org/distributed-osgi-greeter-demo-walkthrough.htm
+[4] http://cxf.apache.org/mailing-lists.html
+[5] https://issues.apache.org/jira/browse/CXF
diff --git a/trunk/distribution/multi-bundle/src/main/release/release_notes.txt b/trunk/distribution/multi-bundle/src/main/release/release_notes.txt
new file mode 100644
index 0000000..889952e
--- /dev/null
+++ b/trunk/distribution/multi-bundle/src/main/release/release_notes.txt
@@ -0,0 +1,295 @@
+
+Release Notes - CXF Distributed OSGi - Version 1.6.0
+====================================================
+
+** Bug
+    * [DOSGI-11] - dOSGi creates new databinding instance instead of using a spring-loaded databinding if available
+    * [DOSGI-196] - Greeter demo does not work in standalone Felix
+    * [DOSGI-198] - Imported service is gone after client bundle is restarted
+    * [DOSGI-206] - Parse errors for xml files in discovery local and dsw
+    * [DOSGI-207] - Update karaf maven plugin to release version
+    * [DOSGI-208] - OSGi compendium bundle installed by feature causes problems
+    * [DOSGI-210] - Service registration and memory leaks
+
+** Improvement
+    * [DOSGI-201] - Create DSOGi distro from karaf feature file
+    * [DOSGI-202] - Make DOSGi independent of jdom
+    * [DOSGI-203] - Upgrade to cxf 2.7.6
+    * [DOSGI-204] - Update osgi spec version to 4.3.1 and felix to 4.2.1
+    * [DOSGI-205] - Upgrade to pax exam 3.2
+
+** Task
+    * [DOSGI-212] - Update CXF version to 2.7.8
+
+
+Release Notes - CXF Distributed OSGi - Version 1.5.0
+====================================================
+
+** Bug
+    * [DOSGI-158] - NPE on shutdown of DOSGi service
+    * [DOSGI-160] - RemoteServiceAdmin shuts itself down during startup
+    * [DOSGI-161] - services sometimes don't get exported
+    * [DOSGI-162] - Compilation errors when using OSGi core
+    * 4.3.0/4.3.1/5.0.0
+    * [DOSGI-164] - NullPointerException on export
+    * [DOSGI-165] - exported service is not properly closed and cannot be
+    * restarted
+    * [DOSGI-166] - List can not be used to register CXF providers with DSW
+    * [DOSGI-168] - RemoteServiceAdminCore service parameters handling bugs
+    * [DOSGI-172] - o.a.c.d.discovery.zookeeper package classes are not
+    * properly synchronized
+    * [DOSGI-173] - unregistering an exported service does not remove it
+    * from zookeeper (and remote clients)
+    * [DOSGI-174] - synchronization issues and resource leaks in
+    * TopologyManagerImport and related classes
+    * [DOSGI-175] - TopologyManagerImport's reference counter doesn't count
+    * [DOSGI-176] - zookeeper discovery sending multiple duplicate endpoint
+    * notifications
+    * [DOSGI-177] - stopped services still appear as available to clients
+    * [DOSGI-180] - CXF service does not disappear if exporting bundle is
+    * stopped
+    * [DOSGI-188] - services aren't re-imported after RemoteServiceAdmin
+    * restart
+    * [DOSGI-190] - NodeExistsException and missing endpoint after ZooKeeper
+    * is restarted
+    * [DOSGI-191] - ZooKeeperDiscovery instance reconnects to ZooKeeper
+    * after bundle is stopped
+    * [DOSGI-192] - Upgrade to zookeeper 3.3.2 to fix bug with zk event
+    * thread shutdown
+    * [DOSGI-195] - Exceptions in tests: ClassCastException on
+    * SpringBusFactory
+
+** Improvement
+    * [DOSGI-167] - Upgrade Aries to the 1.x version for distro
+    * [DOSGI-170] - Remove single bundle distro
+    * [DOSGI-181] - Reactivate or delete old systests
+    * [DOSGI-184] - Split Endpoint repository from TopologyManagerExport
+    * [DOSGI-193] - Split discovery.zookeeper package into subpackages
+
+
+Release Notes - CXF Distributed OSGi - Version 1.4.0
+====================================================
+
+** Bug
+    * [DOSGI-10] - Spring schema handling (intents) doesn't work properly
+    * for the single-bundle case
+    * [DOSGI-18] - RESTful Proxies can not be created in multibundle DOSGI
+    * distributions 
+    * [DOSGI-63] - The discovery can be used be used before the connection
+    * to the server is completely established
+    * [DOSGI-69] - CXF-DOSGi requires internet access when reading XML
+    * [DOSGI-90] - Do not use/assume that endpoint.id is an address
+    * [DOSGI-92] - Exception : Applying intent: SOAP via binding config
+    * [DOSGI-109] - NullPointerException in ToloplogyManager during bundle
+    * stop
+    * [DOSGI-110] - Unable to export multiple services
+    * [DOSGI-111] - DOSGi bundle attempts to load WSDL using wrong bundle in
+    * WSDL-first configuration 
+    * [DOSGI-113] - Integration with pax-logging not possible
+    * [DOSGI-114] - RemoteServiceAdmin is not available warnings in DOSGi
+    * 1.3
+    * [DOSGI-116] - Build fails when downloading Zookeeper artifacts
+    * [DOSGI-119] - Single bundle activator fails to stop all the bundles if
+    * one of the activators throws an exception
+    * [DOSGI-120] - NullPointerException on export
+    * [DOSGI-121] - Fix logging: System.out prints, printStackTrace, verbose
+    * logs
+    * [DOSGI-123] - ZooKeeper registrations are not recreated on ZooKeeper
+    * server restart
+    * [DOSGI-125] - The dead lock in TopologyManagerImport
+    * [DOSGI-129] - NPE when stopping a bundle that exports a DOSGI service
+    * [DOSGI-135] - Switch logging api to slf4j
+    * [DOSGI-136] - Refactor zookeeper server and add metatype config
+    * [DOSGI-137] - Possible bug in TopologyManagerImport when checking if
+    * an Endpoint is already imported
+    * [DOSGI-142] - Upgrade CXF to 2.7.0
+    * [DOSGI-145] - Multiple services using HTTP Service and published from
+    * the same bundle do not work 
+    * [DOSGI-150] - Update to Java 1.6
+    * [DOSGI-153] - Error starting greeter sample in karaf 2.3.0 in aegis
+    * setup: ExceptionInInitializerError ... failed to create an
+    * XPathFactory for the default object model:
+    * http://java.sun.com/jaxp/xpath/dom
+    * [DOSGI-154] - Problems with api packages since update to cxf 2.7.2
+
+** Improvement
+    * [DOSGI-70] - Reconnect automatically to Zookeeper after a connection
+    * loss / timeout
+    * [DOSGI-86] - Decouple DOSGi DSW from Spring DM.
+    * [DOSGI-126] - Allow to use the servlet transport with automatic
+    * discovery
+    * [DOSGI-127] - Default address for services should use the servlet
+    * transport
+    * [DOSGI-128] - Allow to use JAXWS/JAXB service without frontend and
+    * databinding properties
+    * [DOSGI-130] - Clean up unused code and fix warnings, use interfaces
+    * where possible in DSW
+    * [DOSGI-131] - Switch slf4j from springsource bundles to org.slf4j,
+    * update slf4j version
+    * [DOSGI-132] - Switch logging at runtime to pax logging
+    * [DOSGI-133] - Create a Karaf feature file for CXF DOSGi
+    * [DOSGI-134] - Refactoring of TopologyManager
+    * [DOSGI-138] - Refactoring of discovery distributed
+    * [DOSGI-139] - Refactor dsw-cxf to remove dep cycles
+    * [DOSGI-141] - ZooKeeper is not support cluster (ensemble) mode
+    * [DOSGI-143] - Remove all repos except for apache snapshot and central
+    * [DOSGI-146] - Allow to define intents as OSGi services
+    * [DOSGI-147] - Deprecate some Constants that are defined in the spec
+    * [DOSGI-148] - Refactoring of dsw ConfigTypeHandlers
+    * [DOSGI-149] - Optimize distributions and karaf feature
+
+** New Feature
+    * [DOSGI-115] - Use Spring DM and Eclipse Gemini Blueprint with DOSGi
+
+Apache CXF Distributed OSGi 1.3.1 Release Notes
+===============================================
+
+Fixes needed in order to pass the OSGi 4.3 Remote Service Admin TCK.
+* Fixed exports from Single Bundle Distro
+* Fixed deadlock
+* Fixed cleanup
+* Fixed ExportReferenceImpl.equals() and hashCode()
+* Fixed RemoteServiceAdminCore.exportService()
+
+Apache CXF Distributed OSGi 1.3 Release Notes
+=============================================
+
+The following modules have been removed from the destribution:
+
+* org.apache.cxf.dosgi:cxf-dosgi-ri-discovery-distributed-zookeeper-wrapper
+
+  Zookeeper 3.3.1 bundle is now available. See DOSGI-100 for more information.
+
+* org.apache.cxf.dosgi:cxf-dosgi-remote-service-admin-interfaces
+
+  org.osgi:org.osgi.enterprize:4.2.0 artifact is now available. See DOSGI-104 for more information.
+
+Many dependencies have been updated, including the update to CXF 2.5.1. See also DOSGI-96.
+
+Additionally, a number of bugs has been fixed including:
+
+DOSGI-108   service.exported.interfaces doesn't support comma-seperated String value
+DOSGI-107   Support for a 'wsdl' configuration type
+DOSGI-105   Update greeter_rest demo to use OSGI HttpService
+DOSGI-103   Improve multi-bundle distro configuration for Felix
+DOSGI-102   DOSGI RI can not map invocation exceptions to custom exceptions on the client side
+DOSGI-97    Automatically unregister HTTP servlets/resources if exported service goes down
+DOSGI-94    Enhancement to deal with registered services that might have been proxied
+DOSGI-91    DOSGI RS Proxies ignore ResponseExceptionMapper providers
+DOSGI-85    Unable to export services started after Topology manager
+DOSGI-82    Populate custom servicename, portname and targetnamespace for jax-ws
+DOSGI-79    RemoteServiceAdmin.getImportedEndpoints() returns collection of incorrect type
+DOSGI-77    NullPointerException from Distributed OSGI when bundle with wanted properties is started.
+DOSGI-76    EndpointListener.endpointRemoved
+DOSGI-75    CXF Distributed OSGi isn't using org.apache.cxf.common.logging.LogUtils
+
+
+Apache CXF Distributed OSGi 1.2 Release Notes
+=============================================
+
+In addition to providing the Reference Implementation to the OSGi Remote
+Services Specification, the CXF Distributed OSGi 1.2 release now also
+provides the Reference Implementation of the OSGi Remote Service Admin
+Specification version 1.0, Chapter 122 in the OSGi Enterprise
+Specification.
+
+To achieve compliance with the RSA specification a major refactoring has
+been done on the code base.
+
+For the new features applicable to the RSA specification, see chapter
+122 in the OSGi Enterprise Spec (http://www.osgi.org/Download/Release4V42).
+
+The following new features have been introduced:
+
+* org.apache.cxf.ws.port=[port number]
+  This configuration property can be used to change the default port
+  at which a remote service appears. When setting this property the
+  default context will still be used.
+
+* Servlet Filters (javax.servlet.Filter) can now be registered as OSGi
+  services with the "org.apache.cxf.httpservice.filter" boolean
+  property set to true and used to secure DOSGi server endpoints.
+  Endpoints can enforce the registration of the filters by setting an
+  "org.apache.cxf.httpservice.requirefilter" boolean property to true
+
+Additionally, a number of bugs has been fixed including:
+
+[DOSGI-13] - The CXF DOSGi implementation needs to be updated to support the
+             latest OSGi Remote Services Admin spec.
+[DOSGI-24] - org.apache.cxf.dosgi.dsw.ClassUtils#getInterfaceClass() method
+             should search through super class interfaces too
+[DOSGI-25] - FileNotFoundException when client-side proxy is being created
+             [META-INF/cxf/cxf.xml]
+[DOSGI-27] - Discovery problem when two dependent bundles export interfaces
+[DOSGI-28] - Consuming more than 1 service using Spring-DM doesn't work
+[DOSGI-29] - Exception when stopping DOSGi bundle
+[DOSGI-30] - ClassNotFoundException when exposing service.
+[DOSGI-31] - Distributed OSGi having a problem with a custom type method
+             argument
+[DOSGI-32] - The default amount of logging should be significantly reduced
+[DOSGI-33] - Exception when exposing remote service using DOSGi
+[DOSGI-34] - org.apache.servicemix.specs.locator-1.1.1.jar useless?
+[DOSGI-35] - ServicePublication.PROP_KEY_ENDPOINT_LOCATION is now a URI,
+             instead of a URL
+[DOSGI-37] - Fix the dependency on Equinox for the DOSGi system tests
+[DOSGI-38] - single-bundle distribution has incorrect Import-Package and
+             Export-Package declaration in the manifest
+[DOSGI-40] - Remoted service fails to register endpoint after framework is
+             restarted
+[DOSGI-41] - Remove simple-pojo demo (temporarily) as its currently not
+             supported
+[DOSGI-43] - ClassCastException with Declarative Services
+[DOSGI-44] - Existing OSGi Services are not remoted when CXF-DOSGi is started
+[DOSGI-50] - Need to automatically infer SOAP/HTTP transport intents if not
+             explicily set via osgi.remote.requires.intents
+[DOSGI-54] - RemoteServiceAdmin interfaces/classes out of sync with official
+             version
+[DOSGI-61] - The Zookeeper Discovery only supports primitive types as service
+             properties
+[DOSGI-62] - The DSW creates endpoints with localhost URLs
+[DOSGI-66] - The DSW only loads the intent map when certain spring bundles
+             are loaded and started upfront
+[DOSGI-67] - Enable filters on DOSGi endpoints
+[DOSGI-72] - DOSGI not working with HTTP Service
+[DOSGI-74] - Update CXF version to 2.2.9
+
+
+Apache CXF Distributed OSGi 1.1 Release Notes
+=============================================
+
+Specific issues, features, and improvements fixed in this version
+-----------------------------------------------------------------
+
+The Distributed OSGi 1.1 release provides the Reference Implementation
+of the Remote Services Specification version 1.0. Chapter 13 in the OSGi
+Compendium Specification (http://www.osgi.org/Download/Release4V42).
+
+New features in this release include:
+
+* A live Discovery System is now supported. The CXF-DOSGi implementation
+  makes use of Apache Zookeeper (http://hadoop.apache.org/zookeeper) as
+  the Discovery Server and provides client-side bundles for transparent
+  interaction with Zookeeper. See the Discovery Documentation pages
+  (http://cxf.apache.org/dosgi-discovery.html) for more details.
+
+* REST support for JAX-RS-based Remoted Services and Consumers through
+  the org.apache.cxf.rs configuration type.
+
+* Many user issues have been addressed. In addition the following bugs
+  have been fixed:
+
+[CXF-2182] - Exceptions when remoting pre-existing service
+[CXF-2337] - org.apache.cxf.dosgi.dsw.ClassUtils#getInterfaceClass() method
+             should search through super class interfaces too
+[CXF-2435] - Distributed OSGi having a problem with a custom type method
+             argument
+[CXF-2288] - Bundle cannot be restarted
+[CXF-2385] - Discovery doesn't fully translate 'localhost' into a proper
+             machine name
+[CXF-2200] - Consuming more than 1 service using Spring-DM doesn't work
+
+
+Known limitations :
+
+* Schema validation can not be done for JAX-RS-based endpoints which use
+  Aegis databinding
diff --git a/trunk/distribution/multi-bundle/src/main/xsl/equinox_distro_config.xslt b/trunk/distribution/multi-bundle/src/main/xsl/equinox_distro_config.xslt
new file mode 100644
index 0000000..d7db137
--- /dev/null
+++ b/trunk/distribution/multi-bundle/src/main/xsl/equinox_distro_config.xslt
@@ -0,0 +1,17 @@
+<?xml version="1.0" encoding="UTF-8"?>

+<xsl:transform version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

+  <xsl:output method="text" version="1.0" encoding="UTF-8" indent="yes"/>

+<xsl:template match="/">

+# equinox config

+org.ops4j.pax.web.session.timeout=30

+

+osgi.bundles=org.eclipse.osgi.services@start, \

+../plugins/org.eclipse.equinox.console_1.0.0.v20120522-1841.jar@start, \

+../plugins/org.apache.felix.gogo.shell_0.8.0.v201110170705.jar@start, \

+../plugins/org.apache.felix.gogo.command_0.8.0.v201108120515.jar@start, \

+../plugins/org.apache.felix.gogo.runtime_0.8.0.v201108120515.jar@start, \

+<xsl:for-each select="//bundle"><xsl:sort select="@start-level" data-type="number" order="ascending"/>../dosgi_bundles/<xsl:value-of select="@name"/>@start,\

+</xsl:for-each>

+  </xsl:template>

+</xsl:transform>

+

diff --git a/trunk/distribution/multi-bundle/src/main/xsl/felix_distro_config.xslt b/trunk/distribution/multi-bundle/src/main/xsl/felix_distro_config.xslt
new file mode 100644
index 0000000..eeb88b5
--- /dev/null
+++ b/trunk/distribution/multi-bundle/src/main/xsl/felix_distro_config.xslt
@@ -0,0 +1,75 @@
+<?xml version="1.0" encoding="UTF-8"?>

+<xsl:transform version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

+  <xsl:output method="text" version="1.0" encoding="UTF-8" indent="yes"/>

+  <xsl:template match="/">

+org.ops4j.pax.web.session.timeout=30

+org.osgi.framework.startlevel.beginning=200

+

+<xsl:for-each select="//bundle">

+<xsl:sort select="@start-level" data-type="number" order="ascending"/>

+<xsl:variable name="i" select="position() + count(//bundles/felix_deps) + 50"/>

+felix.auto.start.<xsl:value-of select="$i"/>=file:dosgi_bundles/<xsl:value-of select="@name"/>

+</xsl:for-each>

+

+org.osgi.framework.system.packages=org.osgi.framework; version=1.5.0, \

+ org.osgi.framework.launch; version=1.0.0, \

+ org.osgi.framework.hooks.service; version=1.0.0, \

+ org.osgi.framework.wiring; version=1.0.0 , \

+ org.osgi.service.packageadmin; version=1.2.0, \

+ org.osgi.service.startlevel; version=1.1.0, \

+ org.osgi.service.url; version=1.0.0, \

+ org.osgi.util.tracker; version=1.4.0, \

+ org.apache.karaf.jaas.boot; version=2.2.9, \

+ org.apache.karaf.version; version=2.2.9, \

+ javax.annotation.processing, \

+ javax.crypto, \

+ javax.crypto.spec, \

+ javax.imageio, \

+ javax.imageio.stream, \

+ javax.lang.model, \

+ javax.lang.model.element, \

+ javax.lang.model.type, \

+ javax.lang.model.util, \

+ javax.naming, \

+ javax.xml.bind.annotation, \

+ javax.xml.datatype, \

+ javax.xml.parsers, \

+ javax.xml.namespace, \

+ javax.xml.transform, \

+ javax.xml.transform.dom, \

+ javax.xml.transform.sax, \

+ javax.xml.transform.stream, \

+ javax.xml.validation, \

+ javax.xml.xpath, \

+ javax.management, \

+ javax.management.modelmbean, \

+ javax.management.remote, \

+ javax.naming.directory, \

+ javax.naming.spi, \

+ javax.net, \

+ javax.net.ssl, \

+ javax.security.auth, \

+ javax.security.auth.callback, \

+ javax.security.auth.login, \

+ javax.security.auth.spi, \

+ javax.security.auth.x500, \

+ javax.security.cert, \

+ javax.sql, \

+ javax.swing, \

+ javax.swing.border, \

+ javax.swing.tree, \

+ javax.tools, \

+ javax.transaction; javax.transaction.xa; partial=true; mandatory:=partial, \

+ javax.xml.transform.stax, \

+ javax.wsdl, \

+ javax.wsdl.extensions, \

+ org.ietf.jgss, \

+ org.xml.sax, \

+ org.xml.sax.ext, \

+ org.xml.sax.helpers, \

+ org.w3c.dom, \

+ org.w3c.dom.bootstrap, \

+ org.w3c.dom.ls

+

+  </xsl:template>

+</xsl:transform>

diff --git a/trunk/distribution/multi-bundle/src/main/xsl/filter_features.xslt b/trunk/distribution/multi-bundle/src/main/xsl/filter_features.xslt
new file mode 100644
index 0000000..3044a55
--- /dev/null
+++ b/trunk/distribution/multi-bundle/src/main/xsl/filter_features.xslt
@@ -0,0 +1,17 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<xsl:transform version="1.0"
+    xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
+    <xsl:output method="xml" version="1.0" encoding="UTF-8"
+        indent="yes" />
+
+    <!-- Filter out undesired bundles -->
+    <xsl:template match="bundle[@artifactId='cxf-karaf-commands']"></xsl:template>
+
+    <!-- Copy the rest unachanged -->
+    <xsl:template match="@* | node()">
+        <xsl:copy>
+          <xsl:apply-templates select="@* | node()" />
+        </xsl:copy>
+    </xsl:template>
+
+</xsl:transform>
diff --git a/trunk/distribution/pom.xml b/trunk/distribution/pom.xml
new file mode 100644
index 0000000..320fc8a
--- /dev/null
+++ b/trunk/distribution/pom.xml
@@ -0,0 +1,45 @@
+<?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>
+    <groupId>org.apache.cxf.dosgi</groupId>
+    <artifactId>cxf-dosgi-ri-distribution-parent</artifactId>
+    <version>1.6.0</version>
+    <packaging>pom</packaging>
+    <name>Distributed OSGI Distribution Parent</name>
+    <url>http://cxf.apache.org</url>
+
+    <parent>
+      <groupId>org.apache.cxf.dosgi</groupId>
+      <artifactId>cxf-dosgi-ri-parent</artifactId>
+      <version>1.6.0</version>
+      <relativePath>../parent/pom.xml</relativePath>
+    </parent>
+
+    <properties>
+        <topDirectoryLocation>..</topDirectoryLocation>
+    </properties>
+
+    <modules>
+      <module>features</module>
+      <module>multi-bundle</module>
+      <module>sources</module>
+    </modules>
+</project>
diff --git a/trunk/distribution/sources/pom.xml b/trunk/distribution/sources/pom.xml
new file mode 100644
index 0000000..8b82857
--- /dev/null
+++ b/trunk/distribution/sources/pom.xml
@@ -0,0 +1,66 @@
+<?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>
+    <groupId>org.apache.cxf.dosgi</groupId>
+    <artifactId>cxf-dosgi-ri-source-distribution</artifactId>
+    <version>1.6.0</version>
+    <name>Distributed OSGI Source Distribution</name>
+    <url>http://cxf.apache.org</url>
+
+    <parent>
+        <groupId>org.apache.cxf.dosgi</groupId>
+        <artifactId>cxf-dosgi-ri-distribution-parent</artifactId>
+        <version>1.6.0</version>
+        <relativePath>../pom.xml</relativePath>
+    </parent>
+
+    <properties>
+        <maven.test.skip>true</maven.test.skip>
+        <dosgi.version>${project.version}</dosgi.version>
+        <topDirectoryLocation>../..</topDirectoryLocation>
+    </properties>
+
+    <build>
+        <plugins>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-assembly-plugin</artifactId>
+                <executions>
+                    <execution>
+                        <id>distribution-package</id>
+                        <phase>package</phase>
+                        <goals>
+                            <goal>single</goal>
+                        </goals>
+                        <configuration>
+                            <descriptors>
+                                <descriptor>src/main/assembly/src.xml</descriptor>
+                            </descriptors>
+                            <tarLongFileMode>gnu</tarLongFileMode>
+                        </configuration>
+                    </execution>
+                </executions>
+            </plugin>
+        </plugins>
+    </build>
+
+</project>
diff --git a/trunk/distribution/sources/src/main/assembly/src.xml b/trunk/distribution/sources/src/main/assembly/src.xml
new file mode 100644
index 0000000..493e414
--- /dev/null
+++ b/trunk/distribution/sources/src/main/assembly/src.xml
@@ -0,0 +1,68 @@
+<?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.
+-->
+<assembly>
+    <id>dist</id>
+    <includeBaseDirectory>false</includeBaseDirectory>
+    <formats>
+        <format>tar.gz</format>
+        <format>zip</format>
+    </formats>
+
+    <fileSets>
+        <fileSet>
+            <directory>../..</directory>
+            <outputDirectory>apache-cxf-dosgi-ri-${dosgi.version}</outputDirectory>
+            <includes>
+                <include>**/*</include>
+            </includes>
+            <excludes>
+                <exclude>**/target</exclude>
+                <exclude>**/target/**/*</exclude>
+                <exclude>**/build</exclude>
+                <exclude>**/build/**/*</exclude>
+                <exclude>**/.settings</exclude>
+                <exclude>**/.pmd</exclude>
+                <exclude>**/.checkstyle</exclude>
+                <exclude>**/.ruleset</exclude>
+                <exclude>**/pmd-eclipse.log</exclude>
+                <exclude>**/.classpath</exclude>
+                <exclude>**/.project</exclude>
+                <exclude>**/.wtpmodules</exclude>
+                <exclude>**/surefire*</exclude>
+                <exclude>**/cobertura.ser</exclude>
+                <exclude>**/velocity.log</exclude>
+                <exclude>**/var/journal</exclude>
+                <exclude>**/build.out*</exclude>
+                <exclude>**/*.swp</exclude>
+                <exclude>**/org.eclipse.jdt.core.prefs</exclude>
+            </excludes>
+        </fileSet>
+        <fileSet>
+            <directory>src/main/release</directory>
+            <includes>
+                <include>LICENSE</include>
+                <include>NOTICE</include>
+                <include>README</include>
+                <include>release_notes.txt</include>
+            </includes>
+            <outputDirectory>apache-cxf-dosgi-ri-${dosgi.version}</outputDirectory>
+        </fileSet>
+    </fileSets>
+</assembly>
diff --git a/trunk/distribution/sources/src/main/release/LICENSE b/trunk/distribution/sources/src/main/release/LICENSE
new file mode 100644
index 0000000..172feda
--- /dev/null
+++ b/trunk/distribution/sources/src/main/release/LICENSE
@@ -0,0 +1,262 @@
+
+                                 Apache License
+                           Version 2.0, January 2004
+                        http://www.apache.org/licenses/
+
+   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+   1. Definitions.
+
+      "License" shall mean the terms and conditions for use, reproduction,
+      and distribution as defined by Sections 1 through 9 of this document.
+
+      "Licensor" shall mean the copyright owner or entity authorized by
+      the copyright owner that is granting the License.
+
+      "Legal Entity" shall mean the union of the acting entity and all
+      other entities that control, are controlled by, or are under common
+      control with that entity. For the purposes of this definition,
+      "control" means (i) the power, direct or indirect, to cause the
+      direction or management of such entity, whether by contract or
+      otherwise, or (ii) ownership of fifty percent (50%) or more of the
+      outstanding shares, or (iii) beneficial ownership of such entity.
+
+      "You" (or "Your") shall mean an individual or Legal Entity
+      exercising permissions granted by this License.
+
+      "Source" form shall mean the preferred form for making modifications,
+      including but not limited to software source code, documentation
+      source, and configuration files.
+
+      "Object" form shall mean any form resulting from mechanical
+      transformation or translation of a Source form, including but
+      not limited to compiled object code, generated documentation,
+      and conversions to other media types.
+
+      "Work" shall mean the work of authorship, whether in Source or
+      Object form, made available under the License, as indicated by a
+      copyright notice that is included in or attached to the work
+      (an example is provided in the Appendix below).
+
+      "Derivative Works" shall mean any work, whether in Source or Object
+      form, that is based on (or derived from) the Work and for which the
+      editorial revisions, annotations, elaborations, or other modifications
+      represent, as a whole, an original work of authorship. For the purposes
+      of this License, Derivative Works shall not include works that remain
+      separable from, or merely link (or bind by name) to the interfaces of,
+      the Work and Derivative Works thereof.
+
+      "Contribution" shall mean any work of authorship, including
+      the original version of the Work and any modifications or additions
+      to that Work or Derivative Works thereof, that is intentionally
+      submitted to Licensor for inclusion in the Work by the copyright owner
+      or by an individual or Legal Entity authorized to submit on behalf of
+      the copyright owner. For the purposes of this definition, "submitted"
+      means any form of electronic, verbal, or written communication sent
+      to the Licensor or its representatives, including but not limited to
+      communication on electronic mailing lists, source code control systems,
+      and issue tracking systems that are managed by, or on behalf of, the
+      Licensor for the purpose of discussing and improving the Work, but
+      excluding communication that is conspicuously marked or otherwise
+      designated in writing by the copyright owner as "Not a Contribution."
+
+      "Contributor" shall mean Licensor and any individual or Legal Entity
+      on behalf of whom a Contribution has been received by Licensor and
+      subsequently incorporated within the Work.
+
+   2. Grant of Copyright License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      copyright license to reproduce, prepare Derivative Works of,
+      publicly display, publicly perform, sublicense, and distribute the
+      Work and such Derivative Works in Source or Object form.
+
+   3. Grant of Patent License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      (except as stated in this section) patent license to make, have made,
+      use, offer to sell, sell, import, and otherwise transfer the Work,
+      where such license applies only to those patent claims licensable
+      by such Contributor that are necessarily infringed by their
+      Contribution(s) alone or by combination of their Contribution(s)
+      with the Work to which such Contribution(s) was submitted. If You
+      institute patent litigation against any entity (including a
+      cross-claim or counterclaim in a lawsuit) alleging that the Work
+      or a Contribution incorporated within the Work constitutes direct
+      or contributory patent infringement, then any patent licenses
+      granted to You under this License for that Work shall terminate
+      as of the date such litigation is filed.
+
+   4. Redistribution. You may reproduce and distribute copies of the
+      Work or Derivative Works thereof in any medium, with or without
+      modifications, and in Source or Object form, provided that You
+      meet the following conditions:
+
+      (a) You must give any other recipients of the Work or
+          Derivative Works a copy of this License; and
+
+      (b) You must cause any modified files to carry prominent notices
+          stating that You changed the files; and
+
+      (c) You must retain, in the Source form of any Derivative Works
+          that You distribute, all copyright, patent, trademark, and
+          attribution notices from the Source form of the Work,
+          excluding those notices that do not pertain to any part of
+          the Derivative Works; and
+
+      (d) If the Work includes a "NOTICE" text file as part of its
+          distribution, then any Derivative Works that You distribute must
+          include a readable copy of the attribution notices contained
+          within such NOTICE file, excluding those notices that do not
+          pertain to any part of the Derivative Works, in at least one
+          of the following places: within a NOTICE text file distributed
+          as part of the Derivative Works; within the Source form or
+          documentation, if provided along with the Derivative Works; or,
+          within a display generated by the Derivative Works, if and
+          wherever such third-party notices normally appear. The contents
+          of the NOTICE file are for informational purposes only and
+          do not modify the License. You may add Your own attribution
+          notices within Derivative Works that You distribute, alongside
+          or as an addendum to the NOTICE text from the Work, provided
+          that such additional attribution notices cannot be construed
+          as modifying the License.
+
+      You may add Your own copyright statement to Your modifications and
+      may provide additional or different license terms and conditions
+      for use, reproduction, or distribution of Your modifications, or
+      for any such Derivative Works as a whole, provided Your use,
+      reproduction, and distribution of the Work otherwise complies with
+      the conditions stated in this License.
+
+   5. Submission of Contributions. Unless You explicitly state otherwise,
+      any Contribution intentionally submitted for inclusion in the Work
+      by You to the Licensor shall be under the terms and conditions of
+      this License, without any additional terms or conditions.
+      Notwithstanding the above, nothing herein shall supersede or modify
+      the terms of any separate license agreement you may have executed
+      with Licensor regarding such Contributions.
+
+   6. Trademarks. This License does not grant permission to use the trade
+      names, trademarks, service marks, or product names of the Licensor,
+      except as required for reasonable and customary use in describing the
+      origin of the Work and reproducing the content of the NOTICE file.
+
+   7. Disclaimer of Warranty. Unless required by applicable law or
+      agreed to in writing, Licensor provides the Work (and each
+      Contributor provides its Contributions) on an "AS IS" BASIS,
+      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+      implied, including, without limitation, any warranties or conditions
+      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+      PARTICULAR PURPOSE. You are solely responsible for determining the
+      appropriateness of using or redistributing the Work and assume any
+      risks associated with Your exercise of permissions under this License.
+
+   8. Limitation of Liability. In no event and under no legal theory,
+      whether in tort (including negligence), contract, or otherwise,
+      unless required by applicable law (such as deliberate and grossly
+      negligent acts) or agreed to in writing, shall any Contributor be
+      liable to You for damages, including any direct, indirect, special,
+      incidental, or consequential damages of any character arising as a
+      result of this License or out of the use or inability to use the
+      Work (including but not limited to damages for loss of goodwill,
+      work stoppage, computer failure or malfunction, or any and all
+      other commercial damages or losses), even if such Contributor
+      has been advised of the possibility of such damages.
+
+   9. Accepting Warranty or Additional Liability. While redistributing
+      the Work or Derivative Works thereof, You may choose to offer,
+      and charge a fee for, acceptance of support, warranty, indemnity,
+      or other liability obligations and/or rights consistent with this
+      License. However, in accepting such obligations, You may act only
+      on Your own behalf and on Your sole responsibility, not on behalf
+      of any other Contributor, and only if You agree to indemnify,
+      defend, and hold each Contributor harmless for any liability
+      incurred by, or claims asserted against, such Contributor by reason
+      of your accepting any such warranty or additional liability.
+
+   END OF TERMS AND CONDITIONS
+
+   APPENDIX: How to apply the Apache License to your work.
+
+      To apply the Apache License to your work, attach the following
+      boilerplate notice, with the fields enclosed by brackets "[]"
+      replaced with your own identifying information. (Don't include
+      the brackets!)  The text should be enclosed in the appropriate
+      comment syntax for the file format. We also recommend that a
+      file or class name and description of purpose be included on the
+      same "printed page" as the copyright notice for easier
+      identification within third-party archives.
+
+   Copyright [yyyy] [name of copyright owner]
+
+   Licensed 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.
+
+
+The Apache CXF Distributed OSGi DSW Reference Implementation
+includes a number of components and libraries with separate
+copyright notices and license terms. Your use of those components are
+subject to the terms and conditions of the following licenses.
+
+
+AOP alliance (http://aopalliance.sourceforge.net) aopalliance:aopalliance:jar:1.0
+    License: Public Domain
+
+Unnamed - asm:asm:jar:2.2.3 (http://asm.objectweb.org/asm/asm) asm:asm:jar:2.2.3:compile
+    License: BSD  (http://asm.objectweb.org/license.html)
+
+Legion of the Bouncy Castle Java Cryptography APIs (http://www.bouncycastle.org/java.html) bouncycastle:bcprov-jdk15:jar:140
+    License: Bouncy Castle License  (http://www.bouncycastle.org/licence.html)
+
+Sun JAXB Reference Implementation Runtime  com.sun.xml.bind:jaxb-impl:jar:2.1.9:compile
+    License: COMMON DEVELOPMENT AND DISTRIBUTION LICENSE (CDDL) Version 1.0  (http://www.sun.com/cddl/cddl.html)
+
+Sun JAXB Reference Implementation Tools  com.sun.xml.bind:jaxb-xjc:jar:2.1.9:compile
+    License: COMMON DEVELOPMENT AND DISTRIBUTION LICENSE (CDDL) Version 1.0  (http://www.sun.com/cddl/cddl.html)
+
+Sun SAAJ Reference Implementation  com.sun.xml.messaging.saaj:saaj-impl:jar:1.3.2:compile
+    License: COMMON DEVELOPMENT AND DISTRIBUTION LICENSE (CDDL) Version 1.0  (http://www.sun.com/cddl/cddl.html)
+
+JavaBeans Activation Framework (JAF) (http://java.sun.com/products/javabeans/jaf/index.jsp) javax.activation:activation:jar:1.1
+    License: Common Development and Distribution License (CDDL) v1.0  (https://glassfish.dev.java.net/public/CDDLv1.0.html)
+
+Java Architecture for XML Binding (JAXB API)  javax.xml.bind:jaxb-api:jar:2.1:compile
+    License: COMMON DEVELOPMENT AND DISTRIBUTION LICENSE (CDDL) Version 1.0  (http://www.sun.com/cddl/cddl.html)
+
+Sun SAAJ API (http://java.sun.com/webservices/saaj/index.jsp/saaj-api) javax.xml.soap:saaj-api:jar:1.3:compile
+    License: COMMON DEVELOPMENT AND DISTRIBUTION LICENSE (CDDL) Version 1.0  (http://www.sun.com/cddl/cddl.html)
+
+Streaming API for XML  javax.xml.stream:stax-api:jar:1.0-2
+    License: GNU General Public Library  (http://www.gnu.org/licenses/gpl.txt)
+
+Streaming API for XML  javax.xml.stream:stax-api:jar:1.0-2
+    License: COMMON DEVELOPMENT AND DISTRIBUTION LICENSE (CDDL) Version 1.0  (http://www.sun.com/cddl/cddl.html)
+
+Jetty Server (http://jetty.mortbay.org/project/modules/jetty) org.mortbay.jetty:jetty:jar:6.1.16
+    License: Apache License Version 2.0  (http://www.apache.org/licenses/LICENSE-2.0)
+
+Jetty Utilities (http://jetty.mortbay.org/project/jetty-util) org.mortbay.jetty:jetty-util:jar:6.1.16
+    License: Apache License Version 2.0  (http://www.apache.org/licenses/LICENSE-2.0)
+
+OPS4J Pax Web - Service (http://www.ops4j.org/projects/pax/web/pax-web-service) org.ops4j.pax.web:pax-web-service:bundle:0.5.1
+    License: ALv2  (http://www.apache.org/licenses/LICENSE-2.0.html)
+
+Unnamed - org.slf4j:slf4j-api:jar:1.5.6 (http://www.slf4j.org/slf4j-api) org.slf4j:slf4j-api:jar:1.5.6:runtime
+    License: MIT License  (http://www.slf4j.org/license.html)
+
+Unnamed - org.slf4j:slf4j-jdk14:jar:1.5.6 (http://www.slf4j.org/slf4j-jdk14) org.slf4j:slf4j-jdk14:jar:1.5.6:runtime
+    License: MIT License  (http://www.slf4j.org/license.html)
+
+WSDL4J (http://sf.net/projects/wsdl4j) wsdl4j:wsdl4j:jar:1.6.2
+    License: CPL  (http://www.opensource.org/licenses/cpl1.0.txt)
+
+
diff --git a/trunk/distribution/sources/src/main/release/NOTICE b/trunk/distribution/sources/src/main/release/NOTICE
new file mode 100644
index 0000000..51527cd
--- /dev/null
+++ b/trunk/distribution/sources/src/main/release/NOTICE
@@ -0,0 +1,9 @@
+
+Apache CXF Distributed OSGi DSW Reference Implementation
+Copyright 2008-2012 The Apache Software Foundation
+
+This product includes software developed at
+The Apache Software Foundation (http://www.apache.org/).
+
+This product contains interfaces and specifications Copyright The OSGi Alliance.
+
diff --git a/trunk/distribution/sources/src/main/release/README b/trunk/distribution/sources/src/main/release/README
new file mode 100644
index 0000000..f2f7ffe
--- /dev/null
+++ b/trunk/distribution/sources/src/main/release/README
@@ -0,0 +1,57 @@
+Welcome to the Apache CXF Distributed OSGi DSW Reference Implementation
+=======================================================================
+
+
+The dOSGi subproject of Apache CXF provides the Reference Implementation
+of the Remote Services Specification version 1.0, Chapter 13 in the OSGi
+Compendium Specification, and OSGi Remote Service Admin Specification
+version 1.0, Chapter 122 in the OSGi Enterprise Specification[1].
+
+
+This release is provided for your convenience in three different
+distribution formats:
+
+1. Multi-bundle distro: cxf-dosgi-ri-multibundle-distribution-1.3.{tar.gaz|zip}
+
+Contains the dOSGi implementation and all 3rd party dependencies as
+separate bundles within an archive. The current distribution is an
+instance of this type.
+
+
+2. Single-bundle distro: cxf-dosgi-ri-singlebundle-distribution-1.3.jar
+
+Contains the dOSGi implementation and all 3rd party dependencies wrapped
+in a single OSGi bundle so as to allow direct installation in your favourite
+OSGi container in one fell swoop.
+
+3. Source distro: cxf-dosgi-ri-source-distribution-1.3.{tar.gz|zip}
+
+Contains the entire source tree for dOSGi. The current distribution is
+an instance of this type. It may be built by running "mvn install" from
+the top level directory. Ensure you have maven installed, version 2.0.9
+or higher is recommended. Also a JDK of version 1.5.0_13 or higher is
+required.
+
+
+The best starting point for using dOSGi is the Getting Started Guide[2].
+
+Also note the very detailed walk-through of the greeter demo[3].
+
+If you need more help, or want to provide any feedback, please feel free
+to drop us a note on the CXF dev or users list[4].
+
+If you trip over any problems with dOSGi, don't hesitate to submit an issue
+to the CXF Distributed OSGI JIRA[5].
+
+
+Thanks for using dOSGi!
+
+Regards,
+The CXF dOSGi team.
+
+
+[1] see chapter 122 http://www.osgi.org/Download/Release4V42
+[2] http://cxf.apache.org/distributed-osgi.html#DistributedOSGi-GettingStarted
+[3] http://cxf.apache.org/distributed-osgi-greeter-demo-walkthrough.htm
+[4] http://cxf.apache.org/mailing-lists.html
+[5] https://issues.apache.org/jira/browse/DOSGI
diff --git a/trunk/distribution/sources/src/main/release/release_notes.txt b/trunk/distribution/sources/src/main/release/release_notes.txt
new file mode 100644
index 0000000..889952e
--- /dev/null
+++ b/trunk/distribution/sources/src/main/release/release_notes.txt
@@ -0,0 +1,295 @@
+
+Release Notes - CXF Distributed OSGi - Version 1.6.0
+====================================================
+
+** Bug
+    * [DOSGI-11] - dOSGi creates new databinding instance instead of using a spring-loaded databinding if available
+    * [DOSGI-196] - Greeter demo does not work in standalone Felix
+    * [DOSGI-198] - Imported service is gone after client bundle is restarted
+    * [DOSGI-206] - Parse errors for xml files in discovery local and dsw
+    * [DOSGI-207] - Update karaf maven plugin to release version
+    * [DOSGI-208] - OSGi compendium bundle installed by feature causes problems
+    * [DOSGI-210] - Service registration and memory leaks
+
+** Improvement
+    * [DOSGI-201] - Create DSOGi distro from karaf feature file
+    * [DOSGI-202] - Make DOSGi independent of jdom
+    * [DOSGI-203] - Upgrade to cxf 2.7.6
+    * [DOSGI-204] - Update osgi spec version to 4.3.1 and felix to 4.2.1
+    * [DOSGI-205] - Upgrade to pax exam 3.2
+
+** Task
+    * [DOSGI-212] - Update CXF version to 2.7.8
+
+
+Release Notes - CXF Distributed OSGi - Version 1.5.0
+====================================================
+
+** Bug
+    * [DOSGI-158] - NPE on shutdown of DOSGi service
+    * [DOSGI-160] - RemoteServiceAdmin shuts itself down during startup
+    * [DOSGI-161] - services sometimes don't get exported
+    * [DOSGI-162] - Compilation errors when using OSGi core
+    * 4.3.0/4.3.1/5.0.0
+    * [DOSGI-164] - NullPointerException on export
+    * [DOSGI-165] - exported service is not properly closed and cannot be
+    * restarted
+    * [DOSGI-166] - List can not be used to register CXF providers with DSW
+    * [DOSGI-168] - RemoteServiceAdminCore service parameters handling bugs
+    * [DOSGI-172] - o.a.c.d.discovery.zookeeper package classes are not
+    * properly synchronized
+    * [DOSGI-173] - unregistering an exported service does not remove it
+    * from zookeeper (and remote clients)
+    * [DOSGI-174] - synchronization issues and resource leaks in
+    * TopologyManagerImport and related classes
+    * [DOSGI-175] - TopologyManagerImport's reference counter doesn't count
+    * [DOSGI-176] - zookeeper discovery sending multiple duplicate endpoint
+    * notifications
+    * [DOSGI-177] - stopped services still appear as available to clients
+    * [DOSGI-180] - CXF service does not disappear if exporting bundle is
+    * stopped
+    * [DOSGI-188] - services aren't re-imported after RemoteServiceAdmin
+    * restart
+    * [DOSGI-190] - NodeExistsException and missing endpoint after ZooKeeper
+    * is restarted
+    * [DOSGI-191] - ZooKeeperDiscovery instance reconnects to ZooKeeper
+    * after bundle is stopped
+    * [DOSGI-192] - Upgrade to zookeeper 3.3.2 to fix bug with zk event
+    * thread shutdown
+    * [DOSGI-195] - Exceptions in tests: ClassCastException on
+    * SpringBusFactory
+
+** Improvement
+    * [DOSGI-167] - Upgrade Aries to the 1.x version for distro
+    * [DOSGI-170] - Remove single bundle distro
+    * [DOSGI-181] - Reactivate or delete old systests
+    * [DOSGI-184] - Split Endpoint repository from TopologyManagerExport
+    * [DOSGI-193] - Split discovery.zookeeper package into subpackages
+
+
+Release Notes - CXF Distributed OSGi - Version 1.4.0
+====================================================
+
+** Bug
+    * [DOSGI-10] - Spring schema handling (intents) doesn't work properly
+    * for the single-bundle case
+    * [DOSGI-18] - RESTful Proxies can not be created in multibundle DOSGI
+    * distributions 
+    * [DOSGI-63] - The discovery can be used be used before the connection
+    * to the server is completely established
+    * [DOSGI-69] - CXF-DOSGi requires internet access when reading XML
+    * [DOSGI-90] - Do not use/assume that endpoint.id is an address
+    * [DOSGI-92] - Exception : Applying intent: SOAP via binding config
+    * [DOSGI-109] - NullPointerException in ToloplogyManager during bundle
+    * stop
+    * [DOSGI-110] - Unable to export multiple services
+    * [DOSGI-111] - DOSGi bundle attempts to load WSDL using wrong bundle in
+    * WSDL-first configuration 
+    * [DOSGI-113] - Integration with pax-logging not possible
+    * [DOSGI-114] - RemoteServiceAdmin is not available warnings in DOSGi
+    * 1.3
+    * [DOSGI-116] - Build fails when downloading Zookeeper artifacts
+    * [DOSGI-119] - Single bundle activator fails to stop all the bundles if
+    * one of the activators throws an exception
+    * [DOSGI-120] - NullPointerException on export
+    * [DOSGI-121] - Fix logging: System.out prints, printStackTrace, verbose
+    * logs
+    * [DOSGI-123] - ZooKeeper registrations are not recreated on ZooKeeper
+    * server restart
+    * [DOSGI-125] - The dead lock in TopologyManagerImport
+    * [DOSGI-129] - NPE when stopping a bundle that exports a DOSGI service
+    * [DOSGI-135] - Switch logging api to slf4j
+    * [DOSGI-136] - Refactor zookeeper server and add metatype config
+    * [DOSGI-137] - Possible bug in TopologyManagerImport when checking if
+    * an Endpoint is already imported
+    * [DOSGI-142] - Upgrade CXF to 2.7.0
+    * [DOSGI-145] - Multiple services using HTTP Service and published from
+    * the same bundle do not work 
+    * [DOSGI-150] - Update to Java 1.6
+    * [DOSGI-153] - Error starting greeter sample in karaf 2.3.0 in aegis
+    * setup: ExceptionInInitializerError ... failed to create an
+    * XPathFactory for the default object model:
+    * http://java.sun.com/jaxp/xpath/dom
+    * [DOSGI-154] - Problems with api packages since update to cxf 2.7.2
+
+** Improvement
+    * [DOSGI-70] - Reconnect automatically to Zookeeper after a connection
+    * loss / timeout
+    * [DOSGI-86] - Decouple DOSGi DSW from Spring DM.
+    * [DOSGI-126] - Allow to use the servlet transport with automatic
+    * discovery
+    * [DOSGI-127] - Default address for services should use the servlet
+    * transport
+    * [DOSGI-128] - Allow to use JAXWS/JAXB service without frontend and
+    * databinding properties
+    * [DOSGI-130] - Clean up unused code and fix warnings, use interfaces
+    * where possible in DSW
+    * [DOSGI-131] - Switch slf4j from springsource bundles to org.slf4j,
+    * update slf4j version
+    * [DOSGI-132] - Switch logging at runtime to pax logging
+    * [DOSGI-133] - Create a Karaf feature file for CXF DOSGi
+    * [DOSGI-134] - Refactoring of TopologyManager
+    * [DOSGI-138] - Refactoring of discovery distributed
+    * [DOSGI-139] - Refactor dsw-cxf to remove dep cycles
+    * [DOSGI-141] - ZooKeeper is not support cluster (ensemble) mode
+    * [DOSGI-143] - Remove all repos except for apache snapshot and central
+    * [DOSGI-146] - Allow to define intents as OSGi services
+    * [DOSGI-147] - Deprecate some Constants that are defined in the spec
+    * [DOSGI-148] - Refactoring of dsw ConfigTypeHandlers
+    * [DOSGI-149] - Optimize distributions and karaf feature
+
+** New Feature
+    * [DOSGI-115] - Use Spring DM and Eclipse Gemini Blueprint with DOSGi
+
+Apache CXF Distributed OSGi 1.3.1 Release Notes
+===============================================
+
+Fixes needed in order to pass the OSGi 4.3 Remote Service Admin TCK.
+* Fixed exports from Single Bundle Distro
+* Fixed deadlock
+* Fixed cleanup
+* Fixed ExportReferenceImpl.equals() and hashCode()
+* Fixed RemoteServiceAdminCore.exportService()
+
+Apache CXF Distributed OSGi 1.3 Release Notes
+=============================================
+
+The following modules have been removed from the destribution:
+
+* org.apache.cxf.dosgi:cxf-dosgi-ri-discovery-distributed-zookeeper-wrapper
+
+  Zookeeper 3.3.1 bundle is now available. See DOSGI-100 for more information.
+
+* org.apache.cxf.dosgi:cxf-dosgi-remote-service-admin-interfaces
+
+  org.osgi:org.osgi.enterprize:4.2.0 artifact is now available. See DOSGI-104 for more information.
+
+Many dependencies have been updated, including the update to CXF 2.5.1. See also DOSGI-96.
+
+Additionally, a number of bugs has been fixed including:
+
+DOSGI-108   service.exported.interfaces doesn't support comma-seperated String value
+DOSGI-107   Support for a 'wsdl' configuration type
+DOSGI-105   Update greeter_rest demo to use OSGI HttpService
+DOSGI-103   Improve multi-bundle distro configuration for Felix
+DOSGI-102   DOSGI RI can not map invocation exceptions to custom exceptions on the client side
+DOSGI-97    Automatically unregister HTTP servlets/resources if exported service goes down
+DOSGI-94    Enhancement to deal with registered services that might have been proxied
+DOSGI-91    DOSGI RS Proxies ignore ResponseExceptionMapper providers
+DOSGI-85    Unable to export services started after Topology manager
+DOSGI-82    Populate custom servicename, portname and targetnamespace for jax-ws
+DOSGI-79    RemoteServiceAdmin.getImportedEndpoints() returns collection of incorrect type
+DOSGI-77    NullPointerException from Distributed OSGI when bundle with wanted properties is started.
+DOSGI-76    EndpointListener.endpointRemoved
+DOSGI-75    CXF Distributed OSGi isn't using org.apache.cxf.common.logging.LogUtils
+
+
+Apache CXF Distributed OSGi 1.2 Release Notes
+=============================================
+
+In addition to providing the Reference Implementation to the OSGi Remote
+Services Specification, the CXF Distributed OSGi 1.2 release now also
+provides the Reference Implementation of the OSGi Remote Service Admin
+Specification version 1.0, Chapter 122 in the OSGi Enterprise
+Specification.
+
+To achieve compliance with the RSA specification a major refactoring has
+been done on the code base.
+
+For the new features applicable to the RSA specification, see chapter
+122 in the OSGi Enterprise Spec (http://www.osgi.org/Download/Release4V42).
+
+The following new features have been introduced:
+
+* org.apache.cxf.ws.port=[port number]
+  This configuration property can be used to change the default port
+  at which a remote service appears. When setting this property the
+  default context will still be used.
+
+* Servlet Filters (javax.servlet.Filter) can now be registered as OSGi
+  services with the "org.apache.cxf.httpservice.filter" boolean
+  property set to true and used to secure DOSGi server endpoints.
+  Endpoints can enforce the registration of the filters by setting an
+  "org.apache.cxf.httpservice.requirefilter" boolean property to true
+
+Additionally, a number of bugs has been fixed including:
+
+[DOSGI-13] - The CXF DOSGi implementation needs to be updated to support the
+             latest OSGi Remote Services Admin spec.
+[DOSGI-24] - org.apache.cxf.dosgi.dsw.ClassUtils#getInterfaceClass() method
+             should search through super class interfaces too
+[DOSGI-25] - FileNotFoundException when client-side proxy is being created
+             [META-INF/cxf/cxf.xml]
+[DOSGI-27] - Discovery problem when two dependent bundles export interfaces
+[DOSGI-28] - Consuming more than 1 service using Spring-DM doesn't work
+[DOSGI-29] - Exception when stopping DOSGi bundle
+[DOSGI-30] - ClassNotFoundException when exposing service.
+[DOSGI-31] - Distributed OSGi having a problem with a custom type method
+             argument
+[DOSGI-32] - The default amount of logging should be significantly reduced
+[DOSGI-33] - Exception when exposing remote service using DOSGi
+[DOSGI-34] - org.apache.servicemix.specs.locator-1.1.1.jar useless?
+[DOSGI-35] - ServicePublication.PROP_KEY_ENDPOINT_LOCATION is now a URI,
+             instead of a URL
+[DOSGI-37] - Fix the dependency on Equinox for the DOSGi system tests
+[DOSGI-38] - single-bundle distribution has incorrect Import-Package and
+             Export-Package declaration in the manifest
+[DOSGI-40] - Remoted service fails to register endpoint after framework is
+             restarted
+[DOSGI-41] - Remove simple-pojo demo (temporarily) as its currently not
+             supported
+[DOSGI-43] - ClassCastException with Declarative Services
+[DOSGI-44] - Existing OSGi Services are not remoted when CXF-DOSGi is started
+[DOSGI-50] - Need to automatically infer SOAP/HTTP transport intents if not
+             explicily set via osgi.remote.requires.intents
+[DOSGI-54] - RemoteServiceAdmin interfaces/classes out of sync with official
+             version
+[DOSGI-61] - The Zookeeper Discovery only supports primitive types as service
+             properties
+[DOSGI-62] - The DSW creates endpoints with localhost URLs
+[DOSGI-66] - The DSW only loads the intent map when certain spring bundles
+             are loaded and started upfront
+[DOSGI-67] - Enable filters on DOSGi endpoints
+[DOSGI-72] - DOSGI not working with HTTP Service
+[DOSGI-74] - Update CXF version to 2.2.9
+
+
+Apache CXF Distributed OSGi 1.1 Release Notes
+=============================================
+
+Specific issues, features, and improvements fixed in this version
+-----------------------------------------------------------------
+
+The Distributed OSGi 1.1 release provides the Reference Implementation
+of the Remote Services Specification version 1.0. Chapter 13 in the OSGi
+Compendium Specification (http://www.osgi.org/Download/Release4V42).
+
+New features in this release include:
+
+* A live Discovery System is now supported. The CXF-DOSGi implementation
+  makes use of Apache Zookeeper (http://hadoop.apache.org/zookeeper) as
+  the Discovery Server and provides client-side bundles for transparent
+  interaction with Zookeeper. See the Discovery Documentation pages
+  (http://cxf.apache.org/dosgi-discovery.html) for more details.
+
+* REST support for JAX-RS-based Remoted Services and Consumers through
+  the org.apache.cxf.rs configuration type.
+
+* Many user issues have been addressed. In addition the following bugs
+  have been fixed:
+
+[CXF-2182] - Exceptions when remoting pre-existing service
+[CXF-2337] - org.apache.cxf.dosgi.dsw.ClassUtils#getInterfaceClass() method
+             should search through super class interfaces too
+[CXF-2435] - Distributed OSGi having a problem with a custom type method
+             argument
+[CXF-2288] - Bundle cannot be restarted
+[CXF-2385] - Discovery doesn't fully translate 'localhost' into a proper
+             machine name
+[CXF-2200] - Consuming more than 1 service using Spring-DM doesn't work
+
+
+Known limitations :
+
+* Schema validation can not be done for JAX-RS-based endpoints which use
+  Aegis databinding
diff --git a/trunk/distribution/subsystem/pom.xml b/trunk/distribution/subsystem/pom.xml
new file mode 100644
index 0000000..bade03c
--- /dev/null
+++ b/trunk/distribution/subsystem/pom.xml
@@ -0,0 +1,393 @@
+<?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>
+  <groupId>org.apache.cxf.dosgi</groupId>
+  <artifactId>cxf-dosgi-ri-subsystem-distribution</artifactId>
+  <name>Distributed OSGi Subsystem Distribution</name>
+  <url>http://cxf.apache.org</url>
+
+  <parent>
+    <groupId>org.apache.cxf.dosgi</groupId>
+    <artifactId>cxf-dosgi-ri-distribution-parent</artifactId>
+    <version>1.4-SNAPSHOT</version>
+    <relativePath>../pom.xml</relativePath>
+  </parent>
+
+  <properties>
+    <dosgi.version>${project.version}</dosgi.version>
+    <topDirectoryLocation>../..</topDirectoryLocation>
+  </properties>
+
+  <dependencies>
+    <dependency>
+      <groupId>org.apache.geronimo.specs</groupId>
+      <artifactId>geronimo-annotation_1.0_spec</artifactId>
+      <version>1.1.1</version>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.geronimo.specs</groupId>
+      <artifactId>geronimo-activation_1.1_spec</artifactId>
+      <version>1.1</version>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.geronimo.specs</groupId>
+      <artifactId>geronimo-javamail_1.4_spec</artifactId>
+      <version>1.2</version>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.geronimo.specs</groupId>
+      <artifactId>geronimo-ws-metadata_2.0_spec</artifactId>
+      <version>1.1.3</version>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.geronimo.specs</groupId>
+      <artifactId>geronimo-servlet_${servlet.version}_spec</artifactId>
+      <version>1.0</version>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.commons</groupId>
+      <artifactId>com.springsource.org.apache.commons.logging</artifactId>
+      <version>1.1.1</version>
+    </dependency>
+    <dependency>
+	  <groupId>org.osgi</groupId>
+	  <artifactId>org.osgi.enterprise</artifactId>
+    </dependency>
+    <dependency>
+        <groupId>org.slf4j</groupId>
+        <artifactId>slf4j-api</artifactId>
+    </dependency>
+    <dependency>
+        <groupId>org.slf4j</groupId>
+        <artifactId>slf4j-jcl</artifactId>
+    </dependency>
+
+    <dependency>
+      <groupId>org.jdom</groupId>
+      <artifactId>com.springsource.org.jdom</artifactId>
+      <version>1.1.0</version>
+    </dependency>
+    <dependency>
+      <groupId>org.springframework</groupId>
+      <artifactId>spring-core</artifactId>
+      <version>${spring.version}</version>
+    </dependency>
+    <dependency>
+      <groupId>org.springframework</groupId>
+      <artifactId>spring-beans</artifactId>
+      <version>${spring.version}</version>
+    </dependency>
+    <dependency>
+      <groupId>org.springframework</groupId>
+      <artifactId>spring-context</artifactId>
+      <version>${spring.version}</version>
+    </dependency>
+    <dependency>
+      <groupId>org.aopalliance</groupId>
+      <artifactId>com.springsource.org.aopalliance</artifactId>
+      <version>1.0.0</version>
+    </dependency>
+    <dependency>
+      <groupId>org.springframework</groupId>
+      <artifactId>spring-aop</artifactId>
+      <version>${spring.version}</version>
+    </dependency>
+    <dependency>
+      <groupId>org.springframework</groupId>
+      <artifactId>spring-asm</artifactId>
+      <version>${spring.version}</version>
+    </dependency>
+    <dependency>
+      <groupId>org.springframework</groupId>
+      <artifactId>spring-expression</artifactId>
+      <version>${spring.version}</version>
+    </dependency>
+    <dependency>
+      <groupId>org.springframework.osgi</groupId>
+      <artifactId>spring-osgi-io</artifactId>
+      <version>${spring.osgi.version}</version>
+    </dependency>
+    <dependency>
+      <groupId>org.springframework.osgi</groupId>
+      <artifactId>spring-osgi-core</artifactId>
+      <version>${spring.osgi.version}</version>
+    </dependency>
+    <dependency>
+      <groupId>org.springframework.osgi</groupId>
+      <artifactId>spring-osgi-extender</artifactId>
+      <version>${spring.osgi.version}</version>
+    </dependency>
+    <dependency>
+      <groupId>org.eclipse.jetty.aggregate</groupId>
+      <artifactId>jetty-all-server</artifactId>
+      <version>${jetty.version}</version>
+    </dependency>
+    <dependency>
+      <groupId>org.ops4j.pax.web</groupId>
+      <artifactId>pax-web-spi</artifactId>
+      <version>${pax.web.version}</version>
+    </dependency>
+    <dependency>
+      <groupId>org.ops4j.pax.web</groupId>
+      <artifactId>pax-web-runtime</artifactId>
+      <version>${pax.web.version}</version>
+    </dependency>
+    <dependency>
+      <groupId>org.ops4j.pax.web</groupId>
+      <artifactId>pax-web-jetty</artifactId>
+      <version>${pax.web.version}</version>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.servicemix.specs</groupId>
+      <artifactId>org.apache.servicemix.specs.saaj-api-1.3</artifactId>
+      <version>${servicemix.specs.version}</version>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.servicemix.specs</groupId>
+      <artifactId>org.apache.servicemix.specs.stax-api-1.0</artifactId>
+      <version>${servicemix.specs.version}</version>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.servicemix.specs</groupId>
+      <artifactId>org.apache.servicemix.specs.jaxb-api-2.1</artifactId>
+      <version>${servicemix.specs.version}</version>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.servicemix.specs</groupId>
+      <artifactId>org.apache.servicemix.specs.jaxws-api-2.1</artifactId>
+      <version>${servicemix.specs.version}</version>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.servicemix.specs</groupId>
+      <artifactId>org.apache.servicemix.specs.jsr311-api-1.1.1</artifactId>
+      <version>${servicemix.specs.version}</version>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.ws.xmlschema</groupId>
+      <artifactId>xmlschema-core</artifactId>
+      <version>${xmlschema.bundle.version}</version>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.servicemix.bundles</groupId>
+      <artifactId>org.apache.servicemix.bundles.xmlresolver</artifactId>
+      <version>${xmlresolver.bundle.version}</version>
+    </dependency>
+    <dependency>
+       <groupId>org.apache.neethi</groupId>
+       <artifactId>neethi</artifactId>
+       <version>${neethi.bundle.version}</version>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.servicemix.bundles</groupId>
+      <artifactId>org.apache.servicemix.bundles.wsdl4j</artifactId>
+      <version>${wsdl4j.bundle.version}</version>
+    </dependency>
+    <dependency>
+       <groupId>org.apache.servicemix.bundles</groupId>
+       <artifactId>org.apache.servicemix.bundles.xmlsec</artifactId>
+       <version>${xmlsec.bundle.version}</version>
+    </dependency>
+    <dependency>
+       <groupId>org.apache.servicemix.bundles</groupId>
+       <artifactId>org.apache.servicemix.bundles.jaxb-impl</artifactId>
+       <version>${jaxbimpl.bundle.version}</version>
+    </dependency>
+
+    <dependency>
+       <groupId>org.apache.servicemix.bundles</groupId>
+       <artifactId>org.apache.servicemix.bundles.asm</artifactId>
+       <version>${asm.bundle.version}</version>
+    </dependency>
+
+    <dependency>
+       <groupId>org.codehaus.woodstox</groupId>
+       <artifactId>stax2-api</artifactId>
+       <version>3.1.1</version>
+    </dependency>
+    <dependency>
+       <groupId>org.codehaus.woodstox</groupId>
+       <artifactId>woodstox-core-asl</artifactId>
+       <version>${woodstox.bundle.version}</version>
+    </dependency>
+    <dependency>
+       <groupId>org.apache.servicemix.bundles</groupId>
+       <artifactId>org.apache.servicemix.bundles.commons-pool</artifactId>
+       <version>${commons.pool.bundle.version}</version>
+    </dependency>
+    <dependency>
+       <groupId>org.apache.servicemix.bundles</groupId>
+       <artifactId>org.apache.servicemix.bundles.joda-time</artifactId>
+       <version>1.5.2_4</version>
+    </dependency>
+    <dependency>
+       <groupId>org.apache.servicemix.bundles</groupId>
+       <artifactId>org.apache.servicemix.bundles.opensaml</artifactId>
+       <version>2.4.1_1</version>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.cxf</groupId>
+      <artifactId>cxf-bundle-minimal</artifactId>
+      <version>${cxf.version}</version>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.cxf.dosgi</groupId>
+      <artifactId>cxf-dosgi-ri-discovery-local</artifactId>
+      <version>${project.version}</version>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.cxf.dosgi</groupId>
+      <artifactId>cxf-dosgi-ri-dsw-cxf</artifactId>
+      <version>${project.version}</version>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.cxf.dosgi</groupId>
+      <artifactId>cxf-dosgi-ri-topology-manager</artifactId>
+      <version>${project.version}</version>
+    </dependency>
+
+    <!-- Discovery dependencies -->
+    <dependency>
+      <groupId>org.apache.felix</groupId>
+      <artifactId>org.apache.felix.configadmin</artifactId>
+      <version>1.2.8</version>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.felix</groupId>
+      <artifactId>org.apache.felix.fileinstall</artifactId>
+      <version>3.1.10</version>
+    </dependency>
+
+    <dependency>
+      <groupId>org.apache.log4j</groupId>
+      <artifactId>com.springsource.org.apache.log4j</artifactId>
+      <version>${log4j.version}</version>
+    </dependency>
+    <dependency>
+            <groupId>org.apache.hadoop</groupId>
+            <artifactId>zookeeper</artifactId>
+            <version>${zookeeper.version}</version>
+            <exclusions>
+                <exclusion>
+                   <groupId>com.sun.jdmk</groupId>
+                   <artifactId>jmxtools</artifactId>
+                </exclusion>
+                <exclusion>
+                   <groupId>com.sun.jmx</groupId>
+                   <artifactId>jmxri</artifactId>
+                </exclusion>
+                <exclusion>
+                   <groupId>log4j</groupId>
+                   <artifactId>log4j</artifactId>
+                </exclusion>
+            </exclusions>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.cxf.dosgi</groupId>
+      <artifactId>cxf-dosgi-ri-discovery-distributed</artifactId>
+      <version>${project.version}</version>
+    </dependency>
+    <dependency>
+        <groupId>org.apache.cxf.dosgi</groupId>
+        <artifactId>cxf-dosgi-ri-discovery-distributed-zookeeper-server</artifactId>
+        <version>${project.version}</version>
+    </dependency>
+    <dependency>
+        <groupId>org.apache.cxf.dosgi</groupId>
+        <artifactId>cxf-dosgi-ri-discovery-distributed-zookeeper-server-config</artifactId>
+        <version>${project.version}</version>
+    </dependency>
+
+  </dependencies>
+
+  <build>
+    <resources>
+      <resource>
+        <directory>src/main/resources</directory>
+        <filtering>true</filtering>
+      </resource>
+    </resources>
+
+    <plugins>
+      <!-- The assembly plugin is used to actually build the subsystem archive -->
+      <plugin>
+        <artifactId>maven-assembly-plugin</artifactId>
+        <executions>
+          <execution>
+            <id>make-assembly</id>
+            <phase>prepare-package</phase>
+            <goals>
+              <goal>single</goal>
+            </goals>
+            <configuration>
+              <appendAssemblyId>false</appendAssemblyId>
+              <descriptors>
+                <descriptor>./src/main/assembly/subsystem-assembly.xml</descriptor>
+              </descriptors>
+            </configuration>
+          </execution>
+        </executions>
+      </plugin>
+      <!-- Since the assembly plugin has no way to output to an .esa file extension use the antrun
+           plugin to copy the file to one with the proper extension -->
+      <plugin>
+        <artifactId>maven-antrun-plugin</artifactId>
+        <executions>
+          <execution>
+            <phase>package</phase>
+            <configuration>
+              <target>
+                <copy file="${project.build.directory}/${project.build.finalName}.zip"
+                    tofile="${project.build.directory}/${project.build.finalName}.esa" />
+              </target>
+            </configuration>
+            <goals>
+              <goal>run</goal>
+            </goals>
+          </execution>
+        </executions>
+      </plugin>
+      <!-- Attach the .esa file to the project so that it ends up in the repo -->
+      <plugin>
+        <groupId>org.codehaus.mojo</groupId>
+        <artifactId>build-helper-maven-plugin</artifactId>
+        <version>1.7</version>
+        <executions>
+          <execution>
+            <id>attach-instrumented-jar</id>
+            <phase>verify</phase>
+            <goals>
+              <goal>attach-artifact</goal>
+            </goals>
+            <configuration>
+              <artifacts>
+                <artifact>
+                  <file>${project.build.directory}/${project.build.finalName}.esa</file>
+                  <type>esa</type>
+                </artifact>
+              </artifacts>
+            </configuration>
+          </execution>
+        </executions>
+      </plugin>
+    </plugins>
+  </build>
+</project>
diff --git a/trunk/distribution/subsystem/src/main/assembly/subsystem-assembly.xml b/trunk/distribution/subsystem/src/main/assembly/subsystem-assembly.xml
new file mode 100644
index 0000000..c0daf6c
--- /dev/null
+++ b/trunk/distribution/subsystem/src/main/assembly/subsystem-assembly.xml
@@ -0,0 +1,46 @@
+<assembly xmlns="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.2"
+          xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+          xsi:schemaLocation="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.2 http://maven.apache.org/xsd/component-1.1.2.xsd">
+<!--
+  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.
+-->
+  <id>subsystem-feature</id>
+  <formats>
+    <format>zip</format>
+  </formats>
+  <includeBaseDirectory>false</includeBaseDirectory>
+
+  <files>
+    <file>
+      <source>target/classes/OSGI-INF/SUBSYSTEM.MF</source>
+      <outputDirectory>OSGI-INF</outputDirectory>
+    </file>
+  </files>
+
+  <dependencySets>
+    <dependencySet>
+      <scope>runtime</scope>
+      <useTransitiveDependencies>false</useTransitiveDependencies>
+      <excludes>
+        <!-- Exclude the current artifact as it doesn't contribute anything other than the
+             logic to build the subsystem. -->
+        <exclude>org.apache.cxf.dosgi:cxf-dosgi-ri-subsystem-distribution</exclude>
+      </excludes>
+    </dependencySet>
+  </dependencySets>
+</assembly>
diff --git a/trunk/distribution/subsystem/src/main/resources/OSGI-INF/SUBSYSTEM.MF b/trunk/distribution/subsystem/src/main/resources/OSGI-INF/SUBSYSTEM.MF
new file mode 100644
index 0000000..e2631e0
--- /dev/null
+++ b/trunk/distribution/subsystem/src/main/resources/OSGI-INF/SUBSYSTEM.MF
@@ -0,0 +1,51 @@
+Manifest-Version: 2.0
+Subsystem-ManifestVersion: 1.0
+Subsystem-SymbolicName: ${project.artifactId}
+Subsystem-Version: 1.4.0
+Subsystem-Name: ${project.name}
+Subsystem-Content: org.apache.geronimo.specs.geronimo-annotation_1.0_spec;start-order:=1,
+ org.apache.geronimo.specs.geronimo-activation_1.1_spec;start-order:=2,
+ org.apache.geronimo.specs.geronimo-javamail_1.4_spec;start-order:=3,
+ org.apache.geronimo.specs.geronimo-servlet_3.0_spec;start-order:=4,
+ org.apache.geronimo.specs.geronimo-ws-metadata_2.0_spec;start-order:=5,
+ com.springsource.org.apache.commons.logging;start-order:=6,
+ com.springsource.org.jdom;start-order:=7,
+ org.springframework.core;start-order:=8,
+ org.springframework.beans;start-order:=9,
+ org.springframework.context;start-order:=10,
+ com.springsource.org.aopalliance;start-order:=11,
+ slf4j-api;start-order:=11,
+ slf4j-jcl,
+ org.springframework.aop;start-order:=12,
+ org.springframework.asm;start-order:=13,
+ org.springframework.expression;start-order:=14,
+ org.springframework.osgi.io;start-order:=15,
+ org.springframework.osgi.core;start-order:=16,
+ org.springframework.osgi.extender;start-order:=17,
+ org.eclipse.jetty.aggregate.jetty-all-server;start-order:=18,
+ org.ops4j.pax.web.pax-web-spi;start-order:=19,
+ org.ops4j.pax.web.pax-web-runtime;start-order:=20,
+ org.ops4j.pax.web.pax-web-jetty;start-order:=21,
+ org.apache.servicemix.bundles.jaxb-impl;start-order:=22,
+ org.apache.servicemix.bundles.wsdl4j;start-order:=23,
+ org.apache.servicemix.bundles.xmlsec;start-order:=24,
+ org.apache.ws.xmlschema.core;start-order:=25,
+ org.apache.servicemix.bundles.asm;start-order:=26,
+ org.apache.servicemix.bundles.xmlresolver;start-order:=27,
+ org.apache.neethi;start-order:=28,
+ stax2-api;start-order:=29,
+ woodstox-core-asl;start-order:=30,
+ org.apache.servicemix.bundles.commons-pool;start-order:=31,
+ org.apache.servicemix.specs.saaj-api-1.3;start-order:=32,
+ org.apache.servicemix.specs.stax-api-1.0;start-order:=33,
+ org.apache.servicemix.specs.jaxb-api-2.1;start-order:=34,
+ org.apache.servicemix.specs.jaxws-api-2.1;start-order:=35,
+ org.apache.servicemix.specs.jsr311-api-1.1.1;start-order:=36,
+ org.apache.servicemix.bundles.joda-time;start-order:=37,
+ org.apache.servicemix.bundles.opensaml;start-order:=38,
+ org.apache.cxf.bundle-minimal;start-order:=39,
+ cxf-dosgi-ri-discovery-local;start-order:=40,
+ osgi.enterprise;start-order:=41,
+ cxf-dosgi-ri-dsw-cxf;start-order:=42,
+ cxf-dosgi-ri-topology-manager;start-order:=43
+Subsystem-Type: osgi.subsystem.feature
diff --git a/trunk/dsw/cxf-dsw/pom.xml b/trunk/dsw/cxf-dsw/pom.xml
new file mode 100644
index 0000000..eb81732
--- /dev/null
+++ b/trunk/dsw/cxf-dsw/pom.xml
@@ -0,0 +1,143 @@
+<?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>
+    <artifactId>cxf-dosgi-ri-dsw-cxf</artifactId>
+    <packaging>bundle</packaging>
+    <name>CXF dOSGi Remote Service Admin Implementation</name>
+    <description>The CXF Remote Service Admin as described in the OSGi Remote Service Admin specification</description>
+
+    <parent>
+        <groupId>org.apache.cxf.dosgi</groupId>
+        <artifactId>cxf-dosgi-ri-parent</artifactId>
+        <version>1.6.0</version>
+        <relativePath>../../parent/pom.xml</relativePath>
+    </parent>
+
+    <properties>
+        <topDirectoryLocation>../..</topDirectoryLocation>
+    </properties>
+
+    <dependencies>
+        <dependency>
+            <groupId>org.slf4j</groupId>
+            <artifactId>slf4j-api</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.osgi</groupId>
+            <artifactId>org.osgi.core</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.osgi</groupId>
+            <artifactId>org.osgi.compendium</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>org.apache.cxf</groupId>
+            <artifactId>cxf-rt-core</artifactId>
+            <version>${cxf.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.cxf</groupId>
+            <artifactId>cxf-rt-frontend-jaxws</artifactId>
+            <version>${cxf.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.cxf</groupId>
+            <artifactId>cxf-rt-frontend-jaxrs</artifactId>
+            <version>${cxf.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.cxf</groupId>
+            <artifactId>cxf-rt-databinding-aegis</artifactId>
+            <version>${cxf.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.cxf</groupId>
+            <artifactId>cxf-rt-rs-extension-providers</artifactId>
+            <version>${cxf.version}</version>
+        </dependency>
+
+        <dependency>
+            <groupId>org.apache.geronimo.specs</groupId>
+            <artifactId>geronimo-servlet_${servlet.version}_spec</artifactId>
+            <version>1.0</version>
+        </dependency>
+
+        <dependency>
+            <groupId>junit</groupId>
+            <artifactId>junit</artifactId>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.easymock</groupId>
+            <artifactId>easymockclassextension</artifactId>
+            <scope>test</scope>
+        </dependency>
+    </dependencies>
+
+    <build>
+        <plugins>
+            <plugin>
+                <groupId>org.jvnet.jaxb2.maven2</groupId>
+                <artifactId>maven-jaxb2-plugin</artifactId>
+                <executions>
+                    <execution>
+                        <goals>
+                            <goal>generate</goal>
+                        </goals>
+                    </execution>
+                </executions>
+            </plugin>
+            <plugin>
+                <groupId>org.apache.felix</groupId>
+                <artifactId>maven-bundle-plugin</artifactId>
+                <extensions>true</extensions>
+                <configuration>
+                    <instructions>
+                        <Bundle-SymbolicName>${project.artifactId}</Bundle-SymbolicName>
+                        <Import-Package>
+                            javax.servlet*;version="[0.0,4)",
+                            *
+                        </Import-Package>
+                        <Export-Package>
+                            !*
+                        </Export-Package>
+                        <Bundle-Activator>org.apache.cxf.dosgi.dsw.Activator</Bundle-Activator>
+                        
+                        <!-- Is currently needed to create a proxy of an interface given in String form -->
+                        <DynamicImport-Package>*</DynamicImport-Package>
+                    </instructions>
+                </configuration>
+            </plugin>
+
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-surefire-plugin</artifactId>
+                <configuration>
+                    <excludes>
+                        <exclude>**/TestUtils*</exclude>
+                    </excludes>
+                </configuration>
+            </plugin>
+        </plugins>
+    </build>
+</project>
diff --git a/trunk/dsw/cxf-dsw/src/main/java/org/apache/cxf/dosgi/dsw/Activator.java b/trunk/dsw/cxf-dsw/src/main/java/org/apache/cxf/dosgi/dsw/Activator.java
new file mode 100644
index 0000000..470ecc3
--- /dev/null
+++ b/trunk/dsw/cxf-dsw/src/main/java/org/apache/cxf/dosgi/dsw/Activator.java
@@ -0,0 +1,169 @@
+/**
+ * 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.dsw;
+
+import java.util.ArrayList;
+import java.util.Dictionary;
+import java.util.Hashtable;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.cxf.Bus;
+import org.apache.cxf.BusFactory;
+import org.apache.cxf.dosgi.dsw.decorator.ServiceDecorator;
+import org.apache.cxf.dosgi.dsw.decorator.ServiceDecoratorBundleListener;
+import org.apache.cxf.dosgi.dsw.decorator.ServiceDecoratorImpl;
+import org.apache.cxf.dosgi.dsw.handlers.ConfigTypeHandlerFactory;
+import org.apache.cxf.dosgi.dsw.handlers.HttpServiceManager;
+import org.apache.cxf.dosgi.dsw.qos.DefaultIntentMapFactory;
+import org.apache.cxf.dosgi.dsw.qos.IntentManager;
+import org.apache.cxf.dosgi.dsw.qos.IntentManagerImpl;
+import org.apache.cxf.dosgi.dsw.qos.IntentMap;
+import org.apache.cxf.dosgi.dsw.qos.IntentTracker;
+import org.apache.cxf.dosgi.dsw.service.RemoteServiceAdminCore;
+import org.apache.cxf.dosgi.dsw.service.RemoteServiceadminFactory;
+import org.apache.cxf.dosgi.dsw.util.Utils;
+import org.osgi.framework.BundleActivator;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.BundleListener;
+import org.osgi.framework.Constants;
+import org.osgi.framework.ServiceRegistration;
+import org.osgi.service.cm.ConfigurationException;
+import org.osgi.service.cm.ManagedService;
+import org.osgi.service.remoteserviceadmin.RemoteServiceAdmin;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+// registered as spring bean -> start / stop called accordingly
+public class Activator implements ManagedService, BundleActivator {
+
+    private static final Logger LOG = LoggerFactory.getLogger(Activator.class);
+    private static final int DEFAULT_INTENT_TIMEOUT = 30000;
+    private static final String CONFIG_SERVICE_PID = "cxf-dsw";
+    private ServiceRegistration rsaFactoryReg;
+    private ServiceRegistration decoratorReg;
+    private IntentTracker intentTracker;
+    private HttpServiceManager httpServiceManager;
+    private BundleContext bc;
+    private BundleListener bundleListener;
+
+    public void start(BundleContext bundlecontext) throws Exception {
+        LOG.debug("RemoteServiceAdmin Implementation is starting up");
+        this.bc = bundlecontext;
+        // Disable the fast infoset as it's not compatible (yet) with OSGi
+        System.setProperty("org.apache.cxf.nofastinfoset", "true");
+        init(new Hashtable<String, Object>());
+        registerManagedService(bc);
+    }
+
+    private synchronized void init(Map<String, Object> config) {
+        String httpBase = (String) config.get(org.apache.cxf.dosgi.dsw.Constants.HTTP_BASE);
+        String cxfServletAlias = (String) config.get(org.apache.cxf.dosgi.dsw.Constants.CXF_SERVLET_ALIAS);
+
+        IntentMap intentMap = new IntentMap(new DefaultIntentMapFactory().create());
+        intentTracker = new IntentTracker(bc, intentMap);
+        intentTracker.open();
+        IntentManager intentManager = new IntentManagerImpl(intentMap, DEFAULT_INTENT_TIMEOUT);
+        httpServiceManager = new HttpServiceManager(bc, httpBase, cxfServletAlias);
+        ConfigTypeHandlerFactory configTypeHandlerFactory
+            = new ConfigTypeHandlerFactory(bc, intentManager, httpServiceManager);
+        RemoteServiceAdminCore rsaCore = new RemoteServiceAdminCore(bc, configTypeHandlerFactory);
+        RemoteServiceadminFactory rsaf = new RemoteServiceadminFactory(rsaCore);
+        Dictionary<String, Object> props = new Hashtable<String, Object>();
+        String[] supportedIntents = intentMap.keySet().toArray(new String[] {});
+        props.put("remote.intents.supported", supportedIntents);
+        props.put("remote.configs.supported",
+                  obtainSupportedConfigTypes(configTypeHandlerFactory.getSupportedConfigurationTypes()));
+        LOG.info("Registering RemoteServiceAdminFactory...");
+        rsaFactoryReg = bc.registerService(RemoteServiceAdmin.class.getName(), rsaf, props);
+        ServiceDecoratorImpl serviceDecorator = new ServiceDecoratorImpl();
+        bundleListener = new ServiceDecoratorBundleListener(serviceDecorator);
+        bc.addBundleListener(bundleListener);
+        decoratorReg = bc.registerService(ServiceDecorator.class.getName(), serviceDecorator, null);
+    }
+
+    // The CT sometimes uses the first element returned to register a service, but
+    // does not provide any additional configuration.
+    // Return the configuration type that works without additional configuration as the first in the list.
+    private String[] obtainSupportedConfigTypes(List<String> types) {
+        List<String> l = new ArrayList<String>(types);
+        if (l.contains(org.apache.cxf.dosgi.dsw.Constants.WS_CONFIG_TYPE)) {
+            // make sure its the first element...
+            l.remove(org.apache.cxf.dosgi.dsw.Constants.WS_CONFIG_TYPE);
+            l.add(0, org.apache.cxf.dosgi.dsw.Constants.WS_CONFIG_TYPE);
+        }
+        return l.toArray(new String[] {});
+    }
+
+    private void registerManagedService(BundleContext bundlecontext) {
+        Dictionary<String, String> props = new Hashtable<String, String>();
+        props.put(Constants.SERVICE_PID, CONFIG_SERVICE_PID);
+        // No need to store the registration. Will be unregistered in stop by framework
+        bundlecontext.registerService(ManagedService.class.getName(), this, props);
+    }
+
+    public void stop(BundleContext context) throws Exception {
+        LOG.debug("RemoteServiceAdmin Implementation is shutting down now");
+        bc.removeBundleListener(bundleListener);
+        intentTracker.close();
+        // This also triggers the unimport and unexport of the remote services
+        rsaFactoryReg.unregister();
+        decoratorReg.unregister();
+        httpServiceManager.close();
+        httpServiceManager = null;
+        intentTracker = null;
+        rsaFactoryReg = null;
+        decoratorReg = null;
+        shutdownCXFBus();
+    }
+
+    /**
+     * Causes also the shutdown of the embedded HTTP server
+     */
+    private void shutdownCXFBus() {
+        Bus b = BusFactory.getDefaultBus();
+        if (b != null) {
+            LOG.debug("Shutting down the CXF Bus");
+            b.shutdown(true);
+        }
+    }
+
+    @SuppressWarnings({ "rawtypes", "unchecked" })
+    public synchronized void updated(Dictionary config) throws ConfigurationException {
+        LOG.debug("RemoteServiceAdmin Implementation configuration is updated with {}", config);
+        if (config != null) {
+            try {
+                bc.removeBundleListener(bundleListener);
+                intentTracker.close();
+                // This also triggers the unimport and unexport of the remote services
+                rsaFactoryReg.unregister();
+                decoratorReg.unregister();
+                httpServiceManager.close();
+                httpServiceManager = null;
+                intentTracker = null;
+                rsaFactoryReg = null;
+                decoratorReg = null;
+            } catch (Exception e) {
+                LOG.error(e.getMessage(), e);
+            }
+            init(Utils.toMap(config));
+        }
+    }
+
+}
diff --git a/trunk/dsw/cxf-dsw/src/main/java/org/apache/cxf/dosgi/dsw/Constants.java b/trunk/dsw/cxf-dsw/src/main/java/org/apache/cxf/dosgi/dsw/Constants.java
new file mode 100644
index 0000000..218bec6
--- /dev/null
+++ b/trunk/dsw/cxf-dsw/src/main/java/org/apache/cxf/dosgi/dsw/Constants.java
@@ -0,0 +1,146 @@
+/**
+ * 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.dsw;
+
+import org.osgi.service.remoteserviceadmin.RemoteConstants;
+
+public final class Constants {
+
+    // Constants from RFC 119, they should ultimately be picked up from an OSGi class.
+    @Deprecated
+    public static final String EXPORTED_INTERFACES = RemoteConstants.SERVICE_EXPORTED_INTERFACES;
+    @Deprecated
+    public static final String EXPORTED_INTERFACES_OLD = "osgi.remote.interfaces"; // for BW compatibility
+
+    @Deprecated
+    public static final String EXPORTED_CONFIGS = RemoteConstants.SERVICE_EXPORTED_CONFIGS;
+    @Deprecated
+    public static final String EXPORTED_CONFIGS_OLD = "osgi.remote.configuration.type"; // for BW compatibility
+
+    @Deprecated
+    public static final String EXPORTED_INTENTS = RemoteConstants.SERVICE_EXPORTED_INTENTS;
+    @Deprecated
+    public static final String EXPORTED_INTENTS_EXTRA = RemoteConstants.SERVICE_EXPORTED_INTENTS_EXTRA;
+    @Deprecated
+    public static final String EXPORTED_INTENTS_OLD = "osgi.remote.requires.intents";
+
+    @Deprecated
+    public static final String IMPORTED = RemoteConstants.SERVICE_IMPORTED;
+    @Deprecated
+    public static final String IMPORTD_CONFIGS = RemoteConstants.SERVICE_IMPORTED_CONFIGS;
+
+    @Deprecated
+    public static final String INTENTS = RemoteConstants.SERVICE_INTENTS;
+
+    // WSDL
+    public static final String WSDL_CONFIG_TYPE = "wsdl";
+    public static final String WSDL_CONFIG_PREFIX = "osgi.remote.configuration" + "." + WSDL_CONFIG_TYPE;
+    public static final String WSDL_SERVICE_NAMESPACE = WSDL_CONFIG_PREFIX + ".service.ns";
+    public static final String WSDL_SERVICE_NAME = WSDL_CONFIG_PREFIX + ".service.name";
+    public static final String WSDL_PORT_NAME = WSDL_CONFIG_PREFIX + ".port.name";
+    public static final String WSDL_LOCATION = WSDL_CONFIG_PREFIX + ".location";
+    public static final String WSDL_HTTP_SERVICE_CONTEXT = WSDL_CONFIG_PREFIX + ".httpservice.context";
+    // Provider prefix
+    public static final String PROVIDER_PREFIX = "org.apache.cxf";
+
+    // WS
+    public static final String WS_CONFIG_TYPE = PROVIDER_PREFIX + ".ws";
+    public static final String WS_ADDRESS_PROPERTY = WS_CONFIG_TYPE + ".address";
+    public static final String WS_PORT_PROPERTY = WS_CONFIG_TYPE + ".port";
+    public static final String WS_HTTP_SERVICE_CONTEXT = WS_CONFIG_TYPE + ".httpservice.context";
+
+    public static final String WS_FRONTEND_PROP_KEY = WS_CONFIG_TYPE + ".frontend";
+    public static final String WS_FRONTEND_JAXWS = "jaxws";
+    public static final String WS_FRONTEND_SIMPLE = "simple";
+
+    public static final String WS_IN_INTERCEPTORS_PROP_KEY = WS_CONFIG_TYPE + ".in.interceptors";
+    public static final String WS_OUT_INTERCEPTORS_PROP_KEY = WS_CONFIG_TYPE + ".out.interceptors";
+    public static final String WS_OUT_FAULT_INTERCEPTORS_PROP_KEY = WS_CONFIG_TYPE + ".out.fault.interceptors";
+    public static final String WS_IN_FAULT_INTERCEPTORS_PROP_KEY = WS_CONFIG_TYPE + ".in.fault.interceptors";
+    public static final String WS_CONTEXT_PROPS_PROP_KEY = WS_CONFIG_TYPE + ".context.properties";
+    public static final String WS_FEATURES_PROP_KEY = WS_CONFIG_TYPE + ".features";
+
+    public static final String WS_DATABINDING_PROP_KEY = WS_CONFIG_TYPE + ".databinding";
+    public static final String WS_DATABINDING_BEAN_PROP_KEY = WS_DATABINDING_PROP_KEY + ".bean";
+    public static final String WS_DATA_BINDING_JAXB = "jaxb";
+    public static final String WS_DATA_BINDING_AEGIS = "aegis";
+
+    public static final String WS_WSDL_SERVICE_NAMESPACE = WS_CONFIG_TYPE + ".service.ns";
+    public static final String WS_WSDL_SERVICE_NAME = WS_CONFIG_TYPE + ".service.name";
+    public static final String WS_WSDL_PORT_NAME = WS_CONFIG_TYPE + ".port.name";
+    public static final String WS_WSDL_LOCATION = WS_CONFIG_TYPE + ".wsdl.location";
+    // Rest
+    public static final String RS_CONFIG_TYPE = PROVIDER_PREFIX + ".rs";
+    public static final String RS_ADDRESS_PROPERTY = RS_CONFIG_TYPE + ".address";
+    public static final String RS_HTTP_SERVICE_CONTEXT = RS_CONFIG_TYPE + ".httpservice.context";
+    public static final String RS_DATABINDING_PROP_KEY = RS_CONFIG_TYPE + ".databinding";
+    public static final String RS_IN_INTERCEPTORS_PROP_KEY = RS_CONFIG_TYPE + ".in.interceptors";
+    public static final String RS_OUT_INTERCEPTORS_PROP_KEY = RS_CONFIG_TYPE + ".out.interceptors";
+    public static final String RS_IN_FAULT_INTERCEPTORS_PROP_KEY = RS_CONFIG_TYPE + ".in.fault.interceptors";
+    public static final String RS_OUT_FAULT_INTERCEPTORS_PROP_KEY = RS_CONFIG_TYPE + ".out.fault.interceptors";
+    public static final String RS_CONTEXT_PROPS_PROP_KEY = RS_CONFIG_TYPE + ".context.properties";
+    public static final String RS_FEATURES_PROP_KEY = RS_CONFIG_TYPE + ".features";
+    public static final String RS_PROVIDER_PROP_KEY = RS_CONFIG_TYPE + ".provider";
+    public static final String RS_PROVIDER_EXPECTED_PROP_KEY = RS_PROVIDER_PROP_KEY + ".expected";
+    public static final String RS_PROVIDER_GLOBAL_PROP_KEY = RS_PROVIDER_PROP_KEY + ".globalquery";
+    public static final String RS_WADL_LOCATION = RS_CONFIG_TYPE + ".wadl.location";
+    // POJO (old value for WS)
+    public static final String WS_CONFIG_TYPE_OLD = "pojo";
+    public static final String WS_CONFIG_OLD_PREFIX = "osgi.remote.configuration." + WS_CONFIG_TYPE_OLD;
+    public static final String WS_ADDRESS_PROPERTY_OLD = WS_CONFIG_OLD_PREFIX + ".address";
+    public static final String WS_HTTP_SERVICE_CONTEXT_OLD = WS_CONFIG_OLD_PREFIX + ".httpservice.context";
+
+    // Common Configuration Properties
+    public static final String CHECK_BUNDLE = "check.bundle";
+
+    // The following constants are not evaluated anymore
+    @Deprecated
+    public static final String DEFAULT_PORT_CONFIG = "default.port";
+    @Deprecated
+    public static final String DEFAULT_HOST_CONFIG = "default.host";
+    @Deprecated
+    public static final String DEFAULT_PORT_VALUE = "9000";
+    @Deprecated
+    public static final String DEFAULT_HOST_VALUE = "localhost";
+    @Deprecated
+    public static final String USE_MASTER_MAP = "use.master.map";
+
+    // DSW Identification - TODO do we really need this one?
+    public static final String DSW_CLIENT_ID = PROVIDER_PREFIX + ".remote.dsw.client";
+
+    public static final String INTENT_NAME_PROP = "org.apache.cxf.dosgi.IntentName";
+
+    /**
+     * Prefix to create an absolute URL from a relative URL.
+     * See HttpServiceManager.getAbsoluteAddress
+     *
+     * Defaults to: http://<host name>:8181
+     */
+    public static final String HTTP_BASE = "httpBase";
+
+    /**
+     * Name of the cxf servlet alias
+     */
+    public static final String CXF_SERVLET_ALIAS = "cxfServletAlias";
+    public static final String DEFAULT_CXF_SERVLET_ALIAS = "/cxf";
+
+    private Constants() {
+        // never constructed
+    }
+}
diff --git a/trunk/dsw/cxf-dsw/src/main/java/org/apache/cxf/dosgi/dsw/decorator/DecorationParser.java b/trunk/dsw/cxf-dsw/src/main/java/org/apache/cxf/dosgi/dsw/decorator/DecorationParser.java
new file mode 100644
index 0000000..c7a8f96
--- /dev/null
+++ b/trunk/dsw/cxf-dsw/src/main/java/org/apache/cxf/dosgi/dsw/decorator/DecorationParser.java
@@ -0,0 +1,79 @@
+/**
+ * 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.dsw.decorator;
+
+import java.io.InputStream;
+import java.net.URL;
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.xml.XMLConstants;
+import javax.xml.bind.JAXBContext;
+import javax.xml.bind.JAXBElement;
+import javax.xml.bind.JAXBException;
+import javax.xml.bind.Unmarshaller;
+import javax.xml.transform.Source;
+import javax.xml.transform.stream.StreamSource;
+import javax.xml.validation.Schema;
+import javax.xml.validation.SchemaFactory;
+
+import org.xml.sax.SAXException;
+import org.apache.cxf.xmlns.service_decoration._1_0.ServiceDecorationType;
+import org.apache.cxf.xmlns.service_decoration._1_0.ServiceDecorationsType;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+class DecorationParser {
+    private static final Logger LOG = LoggerFactory.getLogger(ServiceDecoratorImpl.class);
+    private JAXBContext jaxbContext;
+    private Schema schema;
+
+    DecorationParser() {
+        try {
+            jaxbContext = JAXBContext.newInstance(ServiceDecorationsType.class.getPackage().getName(),
+                                                  this.getClass().getClassLoader());
+            SchemaFactory schemaFactory = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);
+            URL resource = getClass().getResource("/service-decoration.xsd");
+            schema = schemaFactory.newSchema(resource);
+        } catch (JAXBException e) {
+            throw new RuntimeException(e.getMessage(), e);
+        } catch (SAXException e) {
+            throw new RuntimeException("Error loading decorations schema", e);
+        }
+
+    }
+
+    List<ServiceDecorationType> getDecorations(URL resourceURL) {
+        if (resourceURL == null) {
+            return new ArrayList<ServiceDecorationType>();
+        }
+        try {
+            Unmarshaller unmarshaller = jaxbContext.createUnmarshaller();
+            unmarshaller.setSchema(schema);
+            InputStream is = resourceURL.openStream();
+            Source source = new StreamSource(is);
+            JAXBElement<ServiceDecorationsType> jaxb = unmarshaller.unmarshal(source, ServiceDecorationsType.class);
+            ServiceDecorationsType decorations = jaxb.getValue();
+            return decorations.getServiceDecoration();
+        } catch (Exception ex) {
+            LOG.warn("Problem parsing: " + resourceURL, ex);
+            return new ArrayList<ServiceDecorationType>();
+        }
+    }
+}
diff --git a/trunk/dsw/cxf-dsw/src/main/java/org/apache/cxf/dosgi/dsw/decorator/InterfaceRule.java b/trunk/dsw/cxf-dsw/src/main/java/org/apache/cxf/dosgi/dsw/decorator/InterfaceRule.java
new file mode 100644
index 0000000..14b1ab8
--- /dev/null
+++ b/trunk/dsw/cxf-dsw/src/main/java/org/apache/cxf/dosgi/dsw/decorator/InterfaceRule.java
@@ -0,0 +1,96 @@
+/**
+ * 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.dsw.decorator;
+
+import java.lang.reflect.Constructor;
+import java.util.HashMap;
+import java.util.Map;
+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;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class InterfaceRule implements Rule {
+
+    private static final Logger LOG = LoggerFactory.getLogger(InterfaceRule.class);
+
+    private final Bundle bundle;
+    private final Pattern matchPattern;
+    private final Map<String, String> propMatches = new HashMap<String, String>();
+    private final Map<String, Object> addProps = new HashMap<String, Object>();
+
+    public InterfaceRule(Bundle b, String im) {
+        bundle = b;
+        matchPattern = Pattern.compile(im);
+    }
+
+    public synchronized void addPropMatch(String name, String value) {
+        propMatches.put(name, value);
+    }
+
+    public synchronized void addProperty(String name, String value, String type) {
+        Object obj = value;
+
+        if (type != null && !String.class.getName().equals(type)) {
+            try {
+                Class<?> cls = getClass().getClassLoader().loadClass(type);
+                Constructor<?> ctor = cls.getConstructor(new Class[] {String.class});
+                obj = ctor.newInstance(value);
+            } catch (Throwable th) {
+                LOG.warn("Could not handle property '" + name
+                         + "' with value '" + value + "' of type: " + type, th);
+                return;
+            }
+        }
+
+        addProps.put(name, obj);
+    }
+
+    public synchronized void apply(ServiceReference sref, Map<String, Object> target) {
+        String[] objectClass = (String[]) sref.getProperty(Constants.OBJECTCLASS);
+        boolean matches = false;
+        for (String cls : objectClass) {
+            Matcher m = matchPattern.matcher(cls);
+            if (m.matches()) {
+                for (Map.Entry<String, String> pm : propMatches.entrySet()) {
+                    Object value = sref.getProperty(pm.getKey());
+                    if (value == null || !Pattern.matches(pm.getValue(), value.toString())) {
+                        return;
+                    }
+                }
+                matches = true;
+                break;
+            }
+        }
+        if (!matches) {
+            return;
+        }
+
+        LOG.info("Adding the following properties to " + sref + ": " + addProps);
+        target.putAll(addProps);
+    }
+
+    public Bundle getBundle() {
+        return bundle;
+    }
+}
diff --git a/trunk/dsw/cxf-dsw/src/main/java/org/apache/cxf/dosgi/dsw/decorator/Rule.java b/trunk/dsw/cxf-dsw/src/main/java/org/apache/cxf/dosgi/dsw/decorator/Rule.java
new file mode 100644
index 0000000..a280442
--- /dev/null
+++ b/trunk/dsw/cxf-dsw/src/main/java/org/apache/cxf/dosgi/dsw/decorator/Rule.java
@@ -0,0 +1,41 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.cxf.dosgi.dsw.decorator;
+
+import java.util.Map;
+
+import org.osgi.framework.Bundle;
+import org.osgi.framework.ServiceReference;
+
+public interface Rule {
+
+    /**
+     * When the ServiceReference passed in matches the rule's condition,
+     * set the additional properties in the target.
+     * @param sref The Service Reference to be checked.
+     * @param target Any additional properties are to be set in this map.
+     */
+    void apply(ServiceReference sref, Map<String, Object> target);
+
+    /**
+     * Returns the bundle that provided this rule.
+     * @return The Bundle where the Rule was defined.
+     */
+    Bundle getBundle();
+}
diff --git a/trunk/dsw/cxf-dsw/src/main/java/org/apache/cxf/dosgi/dsw/decorator/ServiceDecorator.java b/trunk/dsw/cxf-dsw/src/main/java/org/apache/cxf/dosgi/dsw/decorator/ServiceDecorator.java
new file mode 100644
index 0000000..07a0b85
--- /dev/null
+++ b/trunk/dsw/cxf-dsw/src/main/java/org/apache/cxf/dosgi/dsw/decorator/ServiceDecorator.java
@@ -0,0 +1,28 @@
+/**
+ * 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.dsw.decorator;
+
+import java.util.Map;
+
+import org.osgi.framework.ServiceReference;
+
+public interface ServiceDecorator {
+
+    void decorate(ServiceReference sref, Map<String, Object> properties);
+}
diff --git a/trunk/dsw/cxf-dsw/src/main/java/org/apache/cxf/dosgi/dsw/decorator/ServiceDecoratorBundleListener.java b/trunk/dsw/cxf-dsw/src/main/java/org/apache/cxf/dosgi/dsw/decorator/ServiceDecoratorBundleListener.java
new file mode 100644
index 0000000..79c2908
--- /dev/null
+++ b/trunk/dsw/cxf-dsw/src/main/java/org/apache/cxf/dosgi/dsw/decorator/ServiceDecoratorBundleListener.java
@@ -0,0 +1,48 @@
+/**
+ * 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.dsw.decorator;
+
+import org.osgi.framework.BundleEvent;
+import org.osgi.framework.BundleListener;
+
+public class ServiceDecoratorBundleListener implements BundleListener {
+    /**
+     * 
+     */
+    private final ServiceDecoratorImpl serviceDecorator;
+
+    /**
+     * @param serviceDecorator
+     */
+    public ServiceDecoratorBundleListener(ServiceDecoratorImpl serviceDecorator) {
+        this.serviceDecorator = serviceDecorator;
+    }
+
+    public void bundleChanged(BundleEvent be) {
+        switch(be.getType()) {
+        case BundleEvent.STARTED:
+            this.serviceDecorator.addDecorations(be.getBundle());
+            break;
+        case BundleEvent.STOPPING:
+            this.serviceDecorator.removeDecorations(be.getBundle());
+            break;
+        default:
+        }
+    }
+}
\ No newline at end of file
diff --git a/trunk/dsw/cxf-dsw/src/main/java/org/apache/cxf/dosgi/dsw/decorator/ServiceDecoratorImpl.java b/trunk/dsw/cxf-dsw/src/main/java/org/apache/cxf/dosgi/dsw/decorator/ServiceDecoratorImpl.java
new file mode 100644
index 0000000..b67c1d6
--- /dev/null
+++ b/trunk/dsw/cxf-dsw/src/main/java/org/apache/cxf/dosgi/dsw/decorator/ServiceDecoratorImpl.java
@@ -0,0 +1,90 @@
+/**
+ * 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.dsw.decorator;
+
+import java.net.URL;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Enumeration;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.CopyOnWriteArrayList;
+
+import org.apache.cxf.xmlns.service_decoration._1_0.AddPropertyType;
+import org.apache.cxf.xmlns.service_decoration._1_0.MatchPropertyType;
+import org.apache.cxf.xmlns.service_decoration._1_0.MatchType;
+import org.apache.cxf.xmlns.service_decoration._1_0.ServiceDecorationType;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.ServiceReference;
+
+public class ServiceDecoratorImpl implements ServiceDecorator {
+    final List<Rule> decorations = new CopyOnWriteArrayList<Rule>();
+
+    private DecorationParser parser;
+
+    public ServiceDecoratorImpl() {
+        parser = new DecorationParser();
+    }
+    
+    public void decorate(ServiceReference sref, Map<String, Object> target) {
+        for (Rule matcher : decorations) {
+            matcher.apply(sref, target);
+        }
+    }
+
+    void addDecorations(Bundle bundle) {
+        for (ServiceDecorationType decoration : getDecorationElements(bundle)) {
+            for (MatchType match : decoration.getMatch()) {
+                decorations.add(getRule(bundle, match));
+            }
+        }
+    }
+
+    private Rule getRule(Bundle bundle, MatchType match) {
+        InterfaceRule m = new InterfaceRule(bundle, match.getInterface());
+        for (MatchPropertyType propMatch : match.getMatchProperty()) {
+            m.addPropMatch(propMatch.getName(), propMatch.getValue());
+        }
+        for (AddPropertyType addProp : match.getAddProperty()) {
+            m.addProperty(addProp.getName(), addProp.getValue(), addProp.getType());
+        }
+        return m;
+    }
+
+    List<ServiceDecorationType> getDecorationElements(Bundle bundle) {
+        @SuppressWarnings("rawtypes")
+        Enumeration entries = bundle.findEntries("OSGI-INF/remote-service", "*.xml", false);
+        if (entries == null) {
+            return Collections.emptyList();
+        }
+        List<ServiceDecorationType> elements = new ArrayList<ServiceDecorationType>();
+        while (entries.hasMoreElements()) {
+            elements.addAll(parser.getDecorations((URL)entries.nextElement()));
+        }
+        return elements;
+    }
+
+    void removeDecorations(Bundle bundle) {
+        for (Rule r : decorations) {
+            if (bundle.equals(r.getBundle())) {
+                decorations.remove(r); // the iterator doesn't support 'remove'
+            }
+        }
+    }
+}
diff --git a/trunk/dsw/cxf-dsw/src/main/java/org/apache/cxf/dosgi/dsw/handlers/AbstractPojoConfigurationTypeHandler.java b/trunk/dsw/cxf-dsw/src/main/java/org/apache/cxf/dosgi/dsw/handlers/AbstractPojoConfigurationTypeHandler.java
new file mode 100644
index 0000000..98308e7
--- /dev/null
+++ b/trunk/dsw/cxf-dsw/src/main/java/org/apache/cxf/dosgi/dsw/handlers/AbstractPojoConfigurationTypeHandler.java
@@ -0,0 +1,256 @@
+/**
+ * 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.dsw.handlers;
+
+import java.lang.reflect.Proxy;
+import java.net.URL;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import javax.xml.namespace.QName;
+
+import org.apache.cxf.common.util.PackageUtils;
+import org.apache.cxf.dosgi.dsw.Constants;
+import org.apache.cxf.dosgi.dsw.qos.IntentManager;
+import org.apache.cxf.dosgi.dsw.qos.IntentUtils;
+import org.apache.cxf.dosgi.dsw.util.ClassUtils;
+import org.apache.cxf.dosgi.dsw.util.OsgiUtils;
+import org.apache.cxf.endpoint.AbstractEndpointFactory;
+import org.apache.cxf.endpoint.Server;
+import org.apache.cxf.feature.AbstractFeature;
+import org.apache.cxf.frontend.AbstractWSDLBasedEndpointFactory;
+import org.apache.cxf.frontend.ClientFactoryBean;
+import org.apache.cxf.frontend.ServerFactoryBean;
+import org.apache.cxf.helpers.CastUtils;
+import org.apache.cxf.interceptor.Interceptor;
+import org.osgi.framework.BundleContext;
+import org.osgi.service.remoteserviceadmin.RemoteConstants;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public abstract class AbstractPojoConfigurationTypeHandler implements ConfigurationTypeHandler {
+
+    private static final Logger LOG = LoggerFactory.getLogger(AbstractPojoConfigurationTypeHandler.class);
+    protected BundleContext bundleContext;
+    protected IntentManager intentManager;
+    protected HttpServiceManager httpServiceManager;
+
+    public AbstractPojoConfigurationTypeHandler(BundleContext dswBC, IntentManager intentManager,
+                                                HttpServiceManager httpServiceManager) {
+        this.bundleContext = dswBC;
+        this.intentManager = intentManager;
+        this.httpServiceManager = httpServiceManager;
+    }
+
+    protected Object getProxy(Object serviceProxy, Class<?> iType) {
+        return Proxy.newProxyInstance(iType.getClassLoader(), new Class[] {
+            iType
+        }, new ServiceInvocationHandler(serviceProxy, iType));
+    }
+
+    protected Map<String, Object> createEndpointProps(Map<String, Object> sd, Class<?> iClass,
+                                                      String[] importedConfigs, String address, String[] intents) {
+        Map<String, Object> props = new HashMap<String, Object>();
+
+        copyEndpointProperties(sd, props);
+
+        String[] sa = new String[] {
+            iClass.getName()
+        };
+        String pkg = iClass.getPackage().getName();
+
+        props.remove(org.osgi.framework.Constants.SERVICE_ID);
+        props.put(org.osgi.framework.Constants.OBJECTCLASS, sa);
+        props.put(RemoteConstants.ENDPOINT_SERVICE_ID, sd.get(org.osgi.framework.Constants.SERVICE_ID));
+        props.put(RemoteConstants.ENDPOINT_FRAMEWORK_UUID, OsgiUtils.getUUID(bundleContext));
+        props.put(RemoteConstants.SERVICE_IMPORTED_CONFIGS, importedConfigs);
+        props.put(RemoteConstants.ENDPOINT_PACKAGE_VERSION_ + pkg, OsgiUtils.getVersion(iClass, bundleContext));
+
+        for (String configurationType : importedConfigs) {
+            if (Constants.WS_CONFIG_TYPE.equals(configurationType)) {
+                props.put(Constants.WS_ADDRESS_PROPERTY, address);
+            } else if (Constants.RS_CONFIG_TYPE.equals(configurationType)) {
+                props.put(Constants.RS_ADDRESS_PROPERTY, address);
+            } else if (Constants.WS_CONFIG_TYPE_OLD.equals(configurationType)) {
+                props.put(Constants.WS_ADDRESS_PROPERTY_OLD, address);
+                props.put(Constants.WS_ADDRESS_PROPERTY, address);
+            }
+        }
+
+        String[] allIntents = IntentUtils.mergeArrays(intents, IntentUtils.getIntentsImplementedByTheService(sd));
+        props.put(RemoteConstants.SERVICE_INTENTS, allIntents);
+        props.put(RemoteConstants.ENDPOINT_ID, address);
+        return props;
+    }
+
+    private void copyEndpointProperties(Map<String, Object> sd, Map<String, Object> endpointProps) {
+        Set<Map.Entry<String, Object>> keys = sd.entrySet();
+        for (Map.Entry<String, Object> entry : keys) {
+            try {
+                String skey = entry.getKey();
+                if (!skey.startsWith(".")) {
+                    endpointProps.put(skey, entry.getValue());
+                }
+            } catch (ClassCastException e) {
+                LOG.warn("ServiceProperties Map contained non String key. Skipped " + entry + "   "
+                         + e.getLocalizedMessage());
+            }
+        }
+    }
+
+    protected void setCommonWsdlProperties(AbstractWSDLBasedEndpointFactory factory, BundleContext context,
+                                           Map<String, Object> sd, boolean wsdlType) {
+        String location = OsgiUtils.getProperty(sd, wsdlType ? Constants.WSDL_LOCATION : Constants.WS_WSDL_LOCATION);
+        if (location != null) {
+            URL wsdlURL = context.getBundle().getResource(location);
+            if (wsdlURL != null) {
+                factory.setWsdlURL(wsdlURL.toString());
+            }
+            QName serviceName = getServiceQName(null, sd,
+                    wsdlType ? Constants.WSDL_SERVICE_NAMESPACE : Constants.WS_WSDL_SERVICE_NAMESPACE,
+                    wsdlType ? Constants.WSDL_SERVICE_NAME : Constants.WS_WSDL_SERVICE_NAME);
+            if (serviceName != null) {
+                factory.setServiceName(serviceName);
+                QName portName = getPortQName(serviceName.getNamespaceURI(), sd,
+                        wsdlType ? Constants.WSDL_PORT_NAME : Constants.WS_WSDL_PORT_NAME);
+                if (portName != null) {
+                    factory.setEndpointName(portName);
+                }
+            }
+        }
+    }
+
+    protected void setWsdlProperties(ServerFactoryBean factory, BundleContext callingContext, Map<String, Object> sd,
+                                     boolean wsdlType) {
+        setCommonWsdlProperties(factory, callingContext, sd, wsdlType);
+    }
+
+    protected void setClientWsdlProperties(ClientFactoryBean factory, BundleContext dswContext, Map<String, Object> sd,
+                                           boolean wsdlType) {
+        setCommonWsdlProperties(factory, dswContext, sd, wsdlType);
+    }
+
+    protected static QName getServiceQName(Class<?> iClass, Map<String, Object> sd, String nsPropName,
+                                           String namePropName) {
+        String serviceNs = OsgiUtils.getProperty(sd, nsPropName);
+        String serviceName = OsgiUtils.getProperty(sd, namePropName);
+        if (iClass == null && (serviceNs == null || serviceName == null)) {
+            return null;
+        }
+        if (serviceNs == null) {
+            serviceNs = PackageUtils.getNamespace(PackageUtils.getPackageName(iClass));
+        }
+        if (serviceName == null) {
+            serviceName = iClass.getSimpleName();
+        }
+        return new QName(serviceNs, serviceName);
+    }
+
+    protected static QName getPortQName(String ns, Map<String, Object> sd, String propName) {
+        String portName = OsgiUtils.getProperty(sd, propName);
+        if (portName == null) {
+            return null;
+        }
+        return new QName(ns, portName);
+    }
+
+    protected String getClientAddress(Map<String, Object> sd) {
+        return OsgiUtils.getFirstNonEmptyStringProperty(sd, RemoteConstants.ENDPOINT_ID,
+                                                        Constants.WS_ADDRESS_PROPERTY,
+                                                        Constants.WS_ADDRESS_PROPERTY_OLD,
+                                                        Constants.RS_ADDRESS_PROPERTY);
+    }
+
+    protected String getServerAddress(Map<String, Object> sd, Class<?> iClass) {
+        String address = getClientAddress(sd);
+        return address == null ? httpServiceManager.getDefaultAddress(iClass) : address;
+    }
+
+    protected ExportResult createServerFromFactory(ServerFactoryBean factory, Map<String, Object> endpointProps) {
+        ClassLoader oldClassLoader = Thread.currentThread().getContextClassLoader();
+        try {
+            Thread.currentThread().setContextClassLoader(ServerFactoryBean.class.getClassLoader());
+            Server server = factory.create();
+            return new ExportResult(endpointProps, server);
+        } catch (Exception e) {
+            return new ExportResult(endpointProps, e);
+        } finally {
+            Thread.currentThread().setContextClassLoader(oldClassLoader);
+        }
+    }
+
+    protected static void addWsInterceptorsFeaturesProps(AbstractEndpointFactory factory, BundleContext callingContext,
+                                                         Map<String, Object> sd) {
+        addInterceptors(factory, callingContext, sd, Constants.WS_IN_INTERCEPTORS_PROP_KEY);
+        addInterceptors(factory, callingContext, sd, Constants.WS_OUT_INTERCEPTORS_PROP_KEY);
+        addInterceptors(factory, callingContext, sd, Constants.WS_OUT_FAULT_INTERCEPTORS_PROP_KEY);
+        addInterceptors(factory, callingContext, sd, Constants.WS_IN_FAULT_INTERCEPTORS_PROP_KEY);
+        addFeatures(factory, callingContext, sd, Constants.WS_FEATURES_PROP_KEY);
+        addContextProperties(factory, sd, Constants.WS_CONTEXT_PROPS_PROP_KEY);
+    }
+
+    static void addRsInterceptorsFeaturesProps(AbstractEndpointFactory factory, BundleContext callingContext,
+                                               Map<String, Object> sd) {
+        addInterceptors(factory, callingContext, sd, Constants.RS_IN_INTERCEPTORS_PROP_KEY);
+        addInterceptors(factory, callingContext, sd, Constants.RS_OUT_INTERCEPTORS_PROP_KEY);
+        addInterceptors(factory, callingContext, sd, Constants.RS_OUT_FAULT_INTERCEPTORS_PROP_KEY);
+        addInterceptors(factory, callingContext, sd, Constants.RS_IN_FAULT_INTERCEPTORS_PROP_KEY);
+        addFeatures(factory, callingContext, sd, Constants.RS_FEATURES_PROP_KEY);
+        addContextProperties(factory, sd, Constants.RS_CONTEXT_PROPS_PROP_KEY);
+    }
+
+    private static void addInterceptors(AbstractEndpointFactory factory, BundleContext callingContext,
+                                        Map<String, Object> sd, String propName) {
+        List<Object> providers = ClassUtils.loadProviderClasses(callingContext, sd, propName);
+        boolean in = propName.contains("in.interceptors");
+        boolean out = propName.contains("out.interceptors");
+        boolean inFault = propName.contains("in.fault.interceptors");
+        boolean outFault = propName.contains("out.fault.interceptors");
+        for (Object provider : providers) {
+            Interceptor<?> interceptor = (Interceptor<?>) provider;
+            if (in) {
+                factory.getInInterceptors().add(interceptor);
+            } else if (out) {
+                factory.getOutInterceptors().add(interceptor);
+            } else if (inFault) {
+                factory.getInFaultInterceptors().add(interceptor);
+            } else if (outFault) {
+                factory.getOutFaultInterceptors().add(interceptor);
+            }
+        }
+    }
+
+    private static void addFeatures(AbstractEndpointFactory factory, BundleContext callingContext,
+                                    Map<String, Object> sd, String propName) {
+        List<Object> providers = ClassUtils.loadProviderClasses(callingContext, sd, propName);
+        if (!providers.isEmpty()) {
+            factory.getFeatures().addAll(CastUtils.cast(providers, AbstractFeature.class));
+        }
+    }
+
+    private static void addContextProperties(AbstractEndpointFactory factory, Map<String, Object> sd, String propName) {
+        @SuppressWarnings("unchecked")
+        Map<String, Object> props = (Map<String, Object>)sd.get(propName);
+        if (props != null) {
+            factory.getProperties(true).putAll(props);
+        }
+    }
+}
diff --git a/trunk/dsw/cxf-dsw/src/main/java/org/apache/cxf/dosgi/dsw/handlers/ConfigTypeHandlerFactory.java b/trunk/dsw/cxf-dsw/src/main/java/org/apache/cxf/dosgi/dsw/handlers/ConfigTypeHandlerFactory.java
new file mode 100644
index 0000000..b7380fb
--- /dev/null
+++ b/trunk/dsw/cxf-dsw/src/main/java/org/apache/cxf/dosgi/dsw/handlers/ConfigTypeHandlerFactory.java
@@ -0,0 +1,169 @@
+/**
+ * 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.dsw.handlers;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.cxf.dosgi.dsw.Constants;
+import org.apache.cxf.dosgi.dsw.qos.IntentManager;
+import org.apache.cxf.dosgi.dsw.util.OsgiUtils;
+import org.apache.cxf.dosgi.dsw.util.Utils;
+import org.osgi.framework.BundleContext;
+import org.osgi.service.remoteserviceadmin.EndpointDescription;
+import org.osgi.service.remoteserviceadmin.RemoteConstants;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class ConfigTypeHandlerFactory {
+
+    protected static final String DEFAULT_CONFIGURATION_TYPE = Constants.WS_CONFIG_TYPE;
+    private static final Logger LOG = LoggerFactory.getLogger(ConfigTypeHandlerFactory.class);
+
+    // protected because of tests
+    protected final List<String> supportedConfigurationTypes;
+
+    private IntentManager intentManager;
+    private PojoConfigurationTypeHandler pojoConfigurationTypeHandler;
+    private JaxRSPojoConfigurationTypeHandler jaxRsPojoConfigurationTypeHandler;
+    private WsdlConfigurationTypeHandler wsdlConfigurationTypeHandler;
+
+    public ConfigTypeHandlerFactory(BundleContext bc, IntentManager intentManager,
+                                    HttpServiceManager httpServiceManager) {
+        this.intentManager = intentManager;
+        this.pojoConfigurationTypeHandler = new PojoConfigurationTypeHandler(bc, intentManager, httpServiceManager);
+        this.jaxRsPojoConfigurationTypeHandler = new JaxRSPojoConfigurationTypeHandler(bc,
+                                                                                       intentManager,
+                                                                                       httpServiceManager);
+        this.wsdlConfigurationTypeHandler = new WsdlConfigurationTypeHandler(bc, intentManager, httpServiceManager);
+        supportedConfigurationTypes = new ArrayList<String>();
+        supportedConfigurationTypes.add(Constants.WSDL_CONFIG_TYPE);
+        supportedConfigurationTypes.add(Constants.RS_CONFIG_TYPE);
+        supportedConfigurationTypes.add(Constants.WS_CONFIG_TYPE);
+        supportedConfigurationTypes.add(Constants.WS_CONFIG_TYPE_OLD);
+    }
+
+    public ConfigurationTypeHandler getHandler(BundleContext dswBC,
+            Map<String, Object> serviceProperties) {
+        List<String> configurationTypes = determineConfigurationTypes(serviceProperties);
+        return getHandler(dswBC, configurationTypes, serviceProperties);
+    }
+
+    public ConfigurationTypeHandler getHandler(BundleContext dswBC, EndpointDescription endpoint) {
+        List<String> configurationTypes = determineConfigTypesForImport(endpoint);
+        return getHandler(dswBC, configurationTypes, endpoint.getProperties());
+    }
+
+    private ConfigurationTypeHandler getHandler(BundleContext dswBC,
+                                               List<String> configurationTypes,
+                                               Map<String, Object> serviceProperties) {
+        intentManager.assertAllIntentsSupported(serviceProperties);
+        if (configurationTypes.contains(Constants.WS_CONFIG_TYPE)
+            || configurationTypes.contains(Constants.WS_CONFIG_TYPE_OLD)
+            || configurationTypes.contains(Constants.RS_CONFIG_TYPE)) {
+            boolean jaxrs = isJaxrsRequested(configurationTypes, serviceProperties);
+            return jaxrs ? jaxRsPojoConfigurationTypeHandler : pojoConfigurationTypeHandler;
+        } else if (configurationTypes.contains(Constants.WSDL_CONFIG_TYPE)) {
+            return wsdlConfigurationTypeHandler;
+        }
+        throw new RuntimeException("None of the configuration types in " + configurationTypes + " is supported.");
+    }
+
+    private boolean isJaxrsRequested(Collection<String> types, Map<String, Object> serviceProperties) {
+        if (types == null) {
+            return false;
+        }
+
+        if (types.contains(Constants.RS_CONFIG_TYPE)) {
+            Collection<String> intentsProperty
+                = OsgiUtils.getMultiValueProperty(serviceProperties.get(RemoteConstants.SERVICE_EXPORTED_INTENTS));
+            boolean hasHttpIntent = false;
+            boolean hasSoapIntent = false;
+            if (intentsProperty != null) {
+                for (String intent : intentsProperty) {
+                    if (intent.contains("SOAP")) {
+                        hasSoapIntent = true;
+                        break;
+                    }
+
+                    if (intent.contains("HTTP")) {
+                        hasHttpIntent = true;
+                    }
+                }
+            }
+            if ((hasHttpIntent && !hasSoapIntent) || intentsProperty == null) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    /**
+     * determine which configuration types should be used / if the requested are
+     * supported
+     */
+    private List<String> determineConfigurationTypes(Map<String, Object> serviceProperties) {
+        String[] requestedConfigurationTypes = Utils.normalizeStringPlus(serviceProperties
+                .get(RemoteConstants.SERVICE_EXPORTED_CONFIGS));
+        if (requestedConfigurationTypes == null || requestedConfigurationTypes.length == 0) {
+            return Collections.singletonList(DEFAULT_CONFIGURATION_TYPE);
+        }
+
+        List<String> configurationTypes = new ArrayList<String>();
+        for (String rct : requestedConfigurationTypes) {
+            if (supportedConfigurationTypes.contains(rct)) {
+                configurationTypes.add(rct);
+            }
+        }
+        LOG.info("configuration types selected for export: " + configurationTypes);
+        if (configurationTypes.isEmpty()) {
+            throw new RuntimeException("the requested configuration types are not supported");
+        }
+        return configurationTypes;
+    }
+
+    private List<String> determineConfigTypesForImport(EndpointDescription endpoint) {
+        List<String> remoteConfigurationTypes = endpoint.getConfigurationTypes();
+
+        if (remoteConfigurationTypes == null) {
+            throw new RuntimeException("The supplied endpoint has no configuration type");
+        }
+
+        List<String> usableConfigurationTypes = new ArrayList<String>();
+        for (String ct : supportedConfigurationTypes) {
+            if (remoteConfigurationTypes.contains(ct)) {
+                usableConfigurationTypes.add(ct);
+            }
+        }
+
+        if (usableConfigurationTypes.isEmpty()) {
+            throw new RuntimeException("The supplied endpoint has no compatible configuration type. "
+                    + "Supported types are: " + supportedConfigurationTypes
+                    + "    Types needed by the endpoint: " + remoteConfigurationTypes);
+        }
+        return usableConfigurationTypes;
+    }
+
+    public List<String> getSupportedConfigurationTypes() {
+        return supportedConfigurationTypes;
+    }
+}
diff --git a/trunk/dsw/cxf-dsw/src/main/java/org/apache/cxf/dosgi/dsw/handlers/ConfigurationTypeHandler.java b/trunk/dsw/cxf-dsw/src/main/java/org/apache/cxf/dosgi/dsw/handlers/ConfigurationTypeHandler.java
new file mode 100644
index 0000000..a69c5e1
--- /dev/null
+++ b/trunk/dsw/cxf-dsw/src/main/java/org/apache/cxf/dosgi/dsw/handlers/ConfigurationTypeHandler.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.dsw.handlers;
+
+import java.util.Map;
+
+import org.apache.cxf.dosgi.dsw.qos.IntentUnsatisfiedException;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.ServiceReference;
+import org.osgi.service.remoteserviceadmin.EndpointDescription;
+
+public interface ConfigurationTypeHandler {
+
+    String[] getSupportedTypes();
+
+    ExportResult createServer(ServiceReference serviceReference,
+                        BundleContext dswContext,
+                        BundleContext callingContext,
+                        Map<String, Object> sd,
+                        Class<?> iClass,
+                        Object serviceBean);
+
+    Object createProxy(ServiceReference serviceReference,
+                       BundleContext dswContext,
+                       BundleContext callingContext,
+                       Class<?> iClass, EndpointDescription endpoint) throws IntentUnsatisfiedException;
+}
diff --git a/trunk/dsw/cxf-dsw/src/main/java/org/apache/cxf/dosgi/dsw/handlers/ExportResult.java b/trunk/dsw/cxf-dsw/src/main/java/org/apache/cxf/dosgi/dsw/handlers/ExportResult.java
new file mode 100644
index 0000000..47b7bf6
--- /dev/null
+++ b/trunk/dsw/cxf-dsw/src/main/java/org/apache/cxf/dosgi/dsw/handlers/ExportResult.java
@@ -0,0 +1,54 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.cxf.dosgi.dsw.handlers;
+
+import java.util.Map;
+
+import org.apache.cxf.endpoint.Server;
+
+public class ExportResult {
+
+    private final Map<String, Object> endpointProps;
+    private final Server server;
+    private final Exception exception;
+
+    public ExportResult(Map<String, Object> endpointProps, Server server) {
+        this.endpointProps = endpointProps;
+        this.server = server;
+        this.exception = null;
+    }
+
+    public ExportResult(Map<String, Object> endpointProps, Exception ex) {
+        this.endpointProps = endpointProps;
+        this.server = null;
+        this.exception = ex;
+    }
+
+    public Map<String, Object> getEndpointProps() {
+        return endpointProps;
+    }
+
+    public Server getServer() {
+        return server;
+    }
+
+    public Exception getException() {
+        return exception;
+    }
+}
diff --git a/trunk/dsw/cxf-dsw/src/main/java/org/apache/cxf/dosgi/dsw/handlers/HttpServiceManager.java b/trunk/dsw/cxf-dsw/src/main/java/org/apache/cxf/dosgi/dsw/handlers/HttpServiceManager.java
new file mode 100644
index 0000000..4aaf3ae
--- /dev/null
+++ b/trunk/dsw/cxf-dsw/src/main/java/org/apache/cxf/dosgi/dsw/handlers/HttpServiceManager.java
@@ -0,0 +1,183 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.cxf.dosgi.dsw.handlers;
+
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Hashtable;
+import java.util.Map;
+
+import org.apache.cxf.Bus;
+import org.apache.cxf.bus.CXFBusFactory;
+import org.apache.cxf.dosgi.dsw.Constants;
+import org.apache.cxf.dosgi.dsw.util.OsgiUtils;
+import org.apache.cxf.transport.http.DestinationRegistry;
+import org.apache.cxf.transport.http.DestinationRegistryImpl;
+import org.apache.cxf.transport.servlet.CXFNonSpringServlet;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.Filter;
+import org.osgi.framework.InvalidSyntaxException;
+import org.osgi.framework.ServiceEvent;
+import org.osgi.framework.ServiceException;
+import org.osgi.framework.ServiceListener;
+import org.osgi.framework.ServiceReference;
+import org.osgi.service.http.HttpContext;
+import org.osgi.service.http.HttpService;
+import org.osgi.util.tracker.ServiceTracker;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class HttpServiceManager {
+
+    private static final Logger LOG = LoggerFactory.getLogger(HttpServiceManager.class);
+    private ServiceTracker tracker;
+    private BundleContext bundleContext;
+    private Map<Long, String> exportedAliases = Collections.synchronizedMap(new HashMap<Long, String>());
+    private String httpBase;
+    private String cxfServletAlias;
+
+    public HttpServiceManager(BundleContext bundleContext, String httpBase, String cxfServletAlias) {
+        this(bundleContext, httpBase, cxfServletAlias,
+             new ServiceTracker(bundleContext, HttpService.class.getName(), null));
+        this.tracker.open();
+    }
+
+    // Only for tests
+    public HttpServiceManager(BundleContext bundleContext,
+                              String httpBase, String cxfServletAlias,
+                              ServiceTracker tracker) {
+        this.bundleContext = bundleContext;
+        this.tracker = tracker;
+        this.httpBase = getWithDefault(httpBase, "http://" + LocalHostUtil.getLocalIp() + ":8181");
+        this.cxfServletAlias = getWithDefault(cxfServletAlias, "/cxf");
+    }
+
+    private String getWithDefault(String value, String defaultValue) {
+        return value == null ? defaultValue : value;
+    }
+
+    public Bus registerServletAndGetBus(String contextRoot, BundleContext callingContext,
+            ServiceReference sref) {
+        Bus bus = new CXFBusFactory().createBus();
+        bus.setExtension(new DestinationRegistryImpl(), DestinationRegistry.class);
+        CXFNonSpringServlet cxf = new CXFNonSpringServlet();
+        cxf.setBus(bus);
+        try {
+            HttpService httpService = getHttpService();
+            httpService.registerServlet(contextRoot, cxf, new Hashtable<String, String>(),
+                                       getHttpContext(callingContext, httpService));
+            registerUnexportHook(sref, contextRoot);
+
+            LOG.info("Successfully registered CXF DOSGi servlet at " + contextRoot);
+        } catch (Exception e) {
+            throw new ServiceException("CXF DOSGi: problem registering CXF HTTP Servlet", e);
+        }
+        return bus;
+    }
+
+    protected HttpService getHttpService() {
+        Object service = tracker.getService();
+        if (service == null) {
+            throw new RuntimeException("No HTTPService found");
+        }
+        return (HttpService) service;
+    }
+
+    public String getServletContextRoot(Map<String, Object> sd) {
+        return OsgiUtils.getFirstNonEmptyStringProperty(sd,
+                Constants.WS_HTTP_SERVICE_CONTEXT,
+                Constants.WS_HTTP_SERVICE_CONTEXT_OLD,
+                Constants.WSDL_HTTP_SERVICE_CONTEXT,
+                Constants.RS_HTTP_SERVICE_CONTEXT);
+    }
+
+    private HttpContext getHttpContext(BundleContext bc, HttpService httpService) {
+        HttpContext httpContext = httpService.createDefaultHttpContext();
+        return new SecurityDelegatingHttpContext(bc, httpContext);
+    }
+
+    /**
+     * This listens for service removal events and "un-exports" the service
+     * from the HttpService.
+     *
+     * @param sref the service reference to track
+     * @param alias the HTTP servlet context alias
+     */
+    private void registerUnexportHook(ServiceReference sref, String alias) {
+        final Long sid = (Long) sref.getProperty(org.osgi.framework.Constants.SERVICE_ID);
+        LOG.debug("Registering service listener for service with ID {}", sid);
+
+        String previous = exportedAliases.put(sid, alias);
+        if (previous != null) {
+            LOG.warn("Overwriting service export for service with ID {}", sid);
+        }
+
+        try {
+            Filter f = bundleContext.createFilter("(" + org.osgi.framework.Constants.SERVICE_ID + "=" + sid + ")");
+            if (f != null) {
+                bundleContext.addServiceListener(new UnregisterListener(), f.toString());
+            } else {
+                LOG.warn("Service listener could not be started. The service will not be automatically unexported.");
+            }
+        } catch (InvalidSyntaxException e) {
+            LOG.warn("Service listener could not be started. The service will not be automatically unexported.", e);
+        }
+    }
+
+    protected String getDefaultAddress(Class<?> type) {
+        return "/" + type.getName().replace('.', '/');
+    }
+
+    protected String getAbsoluteAddress(String contextRoot, String relativeEndpointAddress) {
+        if (relativeEndpointAddress.startsWith("http")) {
+            return relativeEndpointAddress;
+        }
+        String effContextRoot = contextRoot == null ? cxfServletAlias : contextRoot;
+        return this.httpBase + effContextRoot + relativeEndpointAddress;
+    }
+
+    public void close() {
+        tracker.close();
+    }
+
+    private final class UnregisterListener implements ServiceListener {
+
+        public void serviceChanged(ServiceEvent event) {
+            if (!(event.getType() == ServiceEvent.UNREGISTERING)) {
+                return;
+            }
+            final ServiceReference sref = event.getServiceReference();
+            final Long sid = (Long) sref.getProperty(org.osgi.framework.Constants.SERVICE_ID);
+            final String alias = exportedAliases.remove(sid);
+            if (alias == null) {
+                LOG.error("Unable to unexport HTTP servlet for service class '{}',"
+                        + " service-id {}: no servlet alias found",
+                        sref.getProperty(org.osgi.framework.Constants.OBJECTCLASS), sid);
+                return;
+            }
+            LOG.debug("Unexporting HTTP servlet for alias '{}'", alias);
+            try {
+                HttpService http = getHttpService();
+                http.unregister(alias);
+            } catch (Exception e) {
+                LOG.warn("An exception occurred while unregistering service for HTTP servlet alias '{}'", alias, e);
+            }
+        }
+    }
+}
diff --git a/trunk/dsw/cxf-dsw/src/main/java/org/apache/cxf/dosgi/dsw/handlers/JaxRSPojoConfigurationTypeHandler.java b/trunk/dsw/cxf-dsw/src/main/java/org/apache/cxf/dosgi/dsw/handlers/JaxRSPojoConfigurationTypeHandler.java
new file mode 100644
index 0000000..b73e48b
--- /dev/null
+++ b/trunk/dsw/cxf-dsw/src/main/java/org/apache/cxf/dosgi/dsw/handlers/JaxRSPojoConfigurationTypeHandler.java
@@ -0,0 +1,204 @@
+/**
+ * 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.dsw.handlers;
+
+import java.net.URL;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.cxf.Bus;
+import org.apache.cxf.dosgi.dsw.Constants;
+import org.apache.cxf.dosgi.dsw.qos.IntentManager;
+import org.apache.cxf.dosgi.dsw.qos.IntentUnsatisfiedException;
+import org.apache.cxf.dosgi.dsw.util.OsgiUtils;
+import org.apache.cxf.endpoint.Server;
+import org.apache.cxf.jaxrs.JAXRSServerFactoryBean;
+import org.apache.cxf.jaxrs.client.Client;
+import org.apache.cxf.jaxrs.client.JAXRSClientFactoryBean;
+import org.apache.cxf.jaxrs.client.ProxyClassLoader;
+import org.apache.cxf.jaxrs.lifecycle.SingletonResourceProvider;
+import org.apache.cxf.jaxrs.model.UserResource;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.ServiceReference;
+import org.osgi.service.remoteserviceadmin.EndpointDescription;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class JaxRSPojoConfigurationTypeHandler extends AbstractPojoConfigurationTypeHandler {
+
+    private static final Logger LOG = LoggerFactory.getLogger(JaxRSPojoConfigurationTypeHandler.class);
+
+    public JaxRSPojoConfigurationTypeHandler(BundleContext dswBC,
+                                             IntentManager intentManager,
+                                             HttpServiceManager httpServiceManager) {
+        super(dswBC, intentManager, httpServiceManager);
+    }
+
+    public String[] getSupportedTypes() {
+        return new String[] {Constants.RS_CONFIG_TYPE};
+    }
+
+    public Object createProxy(ServiceReference serviceReference, BundleContext dswContext,
+                              BundleContext callingContext, Class<?> iClass,
+                              EndpointDescription endpoint) throws IntentUnsatisfiedException {
+        String address = getPojoAddress(endpoint, iClass);
+        if (address == null) {
+            LOG.warn("Remote address is unavailable");
+            return null;
+        }
+
+        ClassLoader oldClassLoader = Thread.currentThread().getContextClassLoader();
+        try {
+            return createJaxrsProxy(address, callingContext, dswContext, iClass, null, endpoint);
+        } catch (Throwable e) {
+            Thread.currentThread().setContextClassLoader(oldClassLoader);
+        }
+
+        try {
+            ProxyClassLoader cl = new ProxyClassLoader();
+            cl.addLoader(iClass.getClassLoader());
+            cl.addLoader(Client.class.getClassLoader());
+            return createJaxrsProxy(address, callingContext, dswContext, iClass, cl, endpoint);
+        } catch (Throwable e) {
+            LOG.warn("proxy creation failed", e);
+        }
+
+        return null;
+    }
+
+    protected Object createJaxrsProxy(String address,
+                                      BundleContext dswContext,
+                                      BundleContext callingContext,
+                                      Class<?> iClass,
+                                      ClassLoader loader,
+                                      EndpointDescription endpoint) {
+        JAXRSClientFactoryBean bean = new JAXRSClientFactoryBean();
+        bean.setAddress(address);
+        if (loader != null) {
+            bean.setClassLoader(loader);
+        }
+
+        addRsInterceptorsFeaturesProps(bean, callingContext, endpoint.getProperties());
+
+        List<UserResource> resources = JaxRSUtils.getModel(callingContext, iClass);
+        if (resources != null) {
+            bean.setModelBeansWithServiceClass(resources, iClass);
+        } else {
+            bean.setServiceClass(iClass);
+        }
+        List<Object> providers = JaxRSUtils.getProviders(callingContext, endpoint.getProperties());
+        if (providers != null && !providers.isEmpty()) {
+            bean.setProviders(providers);
+        }
+        Thread.currentThread().setContextClassLoader(JAXRSClientFactoryBean.class.getClassLoader());
+        return getProxy(bean.create(), iClass);
+    }
+
+    public ExportResult createServer(ServiceReference sref,
+                                     BundleContext dswContext,
+                                     BundleContext callingContext,
+                                     Map<String, Object> sd, Class<?> iClass,
+                                     Object serviceBean) throws IntentUnsatisfiedException {
+        String contextRoot = httpServiceManager.getServletContextRoot(sd);
+        String address;
+        if (contextRoot == null) {
+            address = getServerAddress(sd, iClass);
+        } else {
+            address = getClientAddress(sd);
+            if (address == null) {
+                address = "/";
+            }
+        }
+
+        Bus bus = contextRoot != null
+                ? httpServiceManager.registerServletAndGetBus(contextRoot, callingContext, sref) : null;
+
+        LOG.info("Creating a " + iClass.getName()
+                 + " endpoint via JaxRSPojoConfigurationTypeHandler, address is " + address);
+
+        JAXRSServerFactoryBean factory = createServerFactory(callingContext, sd, iClass, serviceBean, address, bus);
+        String completeEndpointAddress = httpServiceManager.getAbsoluteAddress(contextRoot, address);
+
+        // The properties for the EndpointDescription
+        Map<String, Object> endpointProps = createEndpointProps(sd, iClass, new String[] {Constants.RS_CONFIG_TYPE},
+                completeEndpointAddress, new String[] {"HTTP"});
+
+        return createServerFromFactory(factory, endpointProps);
+    }
+
+    private ExportResult createServerFromFactory(JAXRSServerFactoryBean factory,
+                                                       Map<String, Object> endpointProps) {
+        ClassLoader oldClassLoader = Thread.currentThread().getContextClassLoader();
+        try {
+            Thread.currentThread().setContextClassLoader(JAXRSServerFactoryBean.class.getClassLoader());
+            Server server = factory.create();
+            return new ExportResult(endpointProps, server);
+        } catch (Exception e) {
+            return new ExportResult(endpointProps, e);
+        } finally {
+            Thread.currentThread().setContextClassLoader(oldClassLoader);
+        }
+    }
+
+    private JAXRSServerFactoryBean createServerFactory(BundleContext callingContext,
+                                                       Map<String, Object> sd,
+                                                       Class<?> iClass,
+                                                       Object serviceBean,
+                                                       String address,
+                                                       Bus bus) {
+        JAXRSServerFactoryBean factory = new JAXRSServerFactoryBean();
+        if (bus != null) {
+            factory.setBus(bus);
+        }
+        List<UserResource> resources = JaxRSUtils.getModel(callingContext, iClass);
+        if (resources != null) {
+            factory.setModelBeansWithServiceClass(resources, iClass);
+            factory.setServiceBeanObjects(serviceBean);
+        } else {
+            factory.setServiceClass(iClass);
+            factory.setResourceProvider(iClass, new SingletonResourceProvider(serviceBean));
+        }
+        factory.setAddress(address);
+        List<Object> providers = JaxRSUtils.getProviders(callingContext, sd);
+        if (providers != null && !providers.isEmpty()) {
+            factory.setProviders(providers);
+        }
+        addRsInterceptorsFeaturesProps(factory, callingContext, sd);
+        String location = OsgiUtils.getProperty(sd, Constants.RS_WADL_LOCATION);
+        if (location != null) {
+            URL wadlURL = callingContext.getBundle().getResource(location);
+            if (wadlURL != null) {
+                factory.setDocLocation(wadlURL.toString());
+            }
+        }
+        return factory;
+    }
+
+    protected String getPojoAddress(EndpointDescription endpoint, Class<?> iClass) {
+        String address = OsgiUtils.getProperty(endpoint, Constants.RS_ADDRESS_PROPERTY);
+
+        if (address == null) {
+            address = httpServiceManager.getDefaultAddress(iClass);
+            if (address != null) {
+                LOG.info("Using a default address: " + address);
+            }
+        }
+        return address;
+    }
+}
diff --git a/trunk/dsw/cxf-dsw/src/main/java/org/apache/cxf/dosgi/dsw/handlers/JaxRSUtils.java b/trunk/dsw/cxf-dsw/src/main/java/org/apache/cxf/dosgi/dsw/handlers/JaxRSUtils.java
new file mode 100644
index 0000000..5573c09
--- /dev/null
+++ b/trunk/dsw/cxf-dsw/src/main/java/org/apache/cxf/dosgi/dsw/handlers/JaxRSUtils.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.dsw.handlers;
+
+import java.io.InputStream;
+import java.net.URL;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.cxf.dosgi.dsw.util.ClassUtils;
+import org.apache.cxf.dosgi.dsw.util.OsgiUtils;
+import org.apache.cxf.jaxrs.model.UserResource;
+import org.apache.cxf.jaxrs.provider.aegis.AegisElementProvider;
+import org.apache.cxf.jaxrs.utils.ResourceUtils;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.ServiceReference;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public final class JaxRSUtils {
+
+    public static final String MODEL_FOLDER = "/OSGI-INF/cxf/jaxrs/";
+    public static final String DEFAULT_MODEL = "/OSGI-INF/cxf/jaxrs/model.xml";
+    public static final String PROVIDERS_FILTER = "(|"
+            + "(objectClass=javax.ws.rs.ext.MessageBodyReader)"
+            + "(objectClass=javax.ws.rs.ext.MessageBodyWriter)"
+            + "(objectClass=javax.ws.rs.ext.ExceptionMapper)"
+            + "(objectClass=org.apache.cxf.jaxrs.ext.RequestHandler)"
+            + "(objectClass=org.apache.cxf.jaxrs.ext.ResponseHandler)"
+            + "(objectClass=org.apache.cxf.jaxrs.ext.ParameterHandler)"
+            + "(objectClass=org.apache.cxf.jaxrs.ext.ResponseExceptionMapper)"
+            + ")";
+    private static final Logger LOG = LoggerFactory.getLogger(JaxRSUtils.class);
+
+    private JaxRSUtils() {
+        // never constructed
+    }
+
+    static List<Object> getProviders(BundleContext callingContext, Map<String, Object> sd) {
+        List<Object> providers = new ArrayList<Object>();
+        if ("aegis".equals(sd.get(org.apache.cxf.dosgi.dsw.Constants.RS_DATABINDING_PROP_KEY))) {
+            providers.add(new AegisElementProvider());
+        }
+
+        providers.addAll(ClassUtils.loadProviderClasses(callingContext,
+                                                        sd,
+                                                        org.apache.cxf.dosgi.dsw.Constants.RS_PROVIDER_PROP_KEY));
+
+        Object globalQueryProp = sd.get(org.apache.cxf.dosgi.dsw.Constants.RS_PROVIDER_GLOBAL_PROP_KEY);
+        boolean globalQueryRequired = globalQueryProp == null || OsgiUtils.toBoolean(globalQueryProp);
+        if (!globalQueryRequired) {
+            return providers;
+        }
+
+        boolean cxfProvidersOnly = OsgiUtils.getBooleanProperty(sd,
+                org.apache.cxf.dosgi.dsw.Constants.RS_PROVIDER_EXPECTED_PROP_KEY);
+
+        try {
+            ServiceReference[] refs = callingContext.getServiceReferences((String)null, PROVIDERS_FILTER);
+            if (refs != null) {
+                for (ServiceReference ref : refs) {
+                    if (!cxfProvidersOnly
+                        || OsgiUtils.toBoolean(ref
+                            .getProperty(org.apache.cxf.dosgi.dsw.Constants.RS_PROVIDER_PROP_KEY))) {
+                        providers.add(callingContext.getService(ref));
+                    }
+                }
+            }
+        } catch (Exception ex) {
+            LOG.debug("Problems finding JAXRS providers " + ex.getMessage(), ex);
+        }
+        return providers;
+    }
+
+    static List<UserResource> getModel(BundleContext callingContext, Class<?> iClass) {
+        String classModel = MODEL_FOLDER + iClass.getSimpleName() + "-model.xml";
+        List<UserResource> list = getModel(callingContext, iClass, classModel);
+        return list != null ? list : getModel(callingContext, iClass, DEFAULT_MODEL);
+    }
+
+    private static List<UserResource> getModel(BundleContext callingContext, Class<?> iClass, String name) {
+        InputStream r = iClass.getClassLoader().getResourceAsStream(name);
+        if (r == null) {
+            URL u = callingContext.getBundle().getResource(name);
+            if (u != null) {
+                try {
+                    r = u.openStream();
+                } catch (Exception ex) {
+                    LOG.info("Problems opening a user model resource at " + u.toString());
+                }
+            }
+        }
+        if (r != null) {
+            try {
+                return ResourceUtils.getUserResources(r);
+            } catch (Exception ex) {
+                LOG.info("Problems reading a user model, it will be ignored");
+            }
+        }
+        return null;
+    }
+}
diff --git a/trunk/dsw/cxf-dsw/src/main/java/org/apache/cxf/dosgi/dsw/handlers/LocalHostUtil.java b/trunk/dsw/cxf-dsw/src/main/java/org/apache/cxf/dosgi/dsw/handlers/LocalHostUtil.java
new file mode 100644
index 0000000..50e2127
--- /dev/null
+++ b/trunk/dsw/cxf-dsw/src/main/java/org/apache/cxf/dosgi/dsw/handlers/LocalHostUtil.java
@@ -0,0 +1,92 @@
+/**
+ * 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.dsw.handlers;
+
+import java.net.InetAddress;
+import java.net.NetworkInterface;
+import java.net.SocketException;
+import java.net.UnknownHostException;
+import java.util.ArrayList;
+import java.util.Enumeration;
+import java.util.List;
+
+/**
+ * Utility methods to get the local address even on a linux host.
+ */
+public final class LocalHostUtil {
+
+    private LocalHostUtil() {
+        // Util Class
+    }
+
+    /**
+     * Returns an InetAddress representing the address of the localhost. Every
+     * attempt is made to find an address for this host that is not the loopback
+     * address. If no other address can be found, the loopback will be returned.
+     *
+     * @return InetAddress the address of localhost
+     * @throws UnknownHostException if there is a problem determining the address
+     */
+    public static InetAddress getLocalHost() throws UnknownHostException {
+        InetAddress localHost = InetAddress.getLocalHost();
+        if (!localHost.isLoopbackAddress()) {
+            return localHost;
+        }
+        InetAddress[] addrs = getAllLocalUsingNetworkInterface();
+        for (InetAddress addr : addrs) {
+            if (!addr.isLoopbackAddress() && !addr.getHostAddress().contains(":")) {
+                return addr;
+            }
+        }
+        return localHost;
+    }
+
+    /**
+     * Utility method that delegates to the methods of NetworkInterface to
+     * determine addresses for this machine.
+     *
+     * @return all addresses found from the NetworkInterfaces
+     * @throws UnknownHostException if there is a problem determining addresses
+     */
+    private static InetAddress[] getAllLocalUsingNetworkInterface() throws UnknownHostException {
+        try {
+            List<InetAddress> addresses = new ArrayList<InetAddress>();
+            Enumeration<NetworkInterface> e = NetworkInterface.getNetworkInterfaces();
+            while (e.hasMoreElements()) {
+                NetworkInterface ni = e.nextElement();
+                for (Enumeration<InetAddress> e2 = ni.getInetAddresses(); e2.hasMoreElements();) {
+                    addresses.add(e2.nextElement());
+                }
+            }
+            return addresses.toArray(new InetAddress[] {});
+        } catch (SocketException ex) {
+            throw new UnknownHostException("127.0.0.1");
+        }
+    }
+
+    public static String getLocalIp() {
+        String localIP;
+        try {
+            localIP = getLocalHost().getHostAddress();
+        } catch (Exception e) {
+            localIP = "localhost";
+        }
+        return localIP;
+    }
+}
diff --git a/trunk/dsw/cxf-dsw/src/main/java/org/apache/cxf/dosgi/dsw/handlers/PojoConfigurationTypeHandler.java b/trunk/dsw/cxf-dsw/src/main/java/org/apache/cxf/dosgi/dsw/handlers/PojoConfigurationTypeHandler.java
new file mode 100644
index 0000000..844d1e2
--- /dev/null
+++ b/trunk/dsw/cxf-dsw/src/main/java/org/apache/cxf/dosgi/dsw/handlers/PojoConfigurationTypeHandler.java
@@ -0,0 +1,174 @@
+/**
+ * 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.dsw.handlers;
+
+import java.util.Map;
+
+import javax.jws.WebService;
+
+import org.apache.cxf.Bus;
+import org.apache.cxf.aegis.databinding.AegisDatabinding;
+import org.apache.cxf.databinding.DataBinding;
+import org.apache.cxf.dosgi.dsw.Constants;
+import org.apache.cxf.dosgi.dsw.qos.IntentManager;
+import org.apache.cxf.dosgi.dsw.qos.IntentUnsatisfiedException;
+import org.apache.cxf.frontend.ClientProxyFactoryBean;
+import org.apache.cxf.frontend.ServerFactoryBean;
+import org.apache.cxf.jaxb.JAXBDataBinding;
+import org.apache.cxf.jaxws.JaxWsProxyFactoryBean;
+import org.apache.cxf.jaxws.JaxWsServerFactoryBean;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.ServiceReference;
+import org.osgi.service.remoteserviceadmin.EndpointDescription;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class PojoConfigurationTypeHandler extends AbstractPojoConfigurationTypeHandler {
+
+    private static final Logger LOG = LoggerFactory.getLogger(PojoConfigurationTypeHandler.class);
+
+    public PojoConfigurationTypeHandler(BundleContext dswBC,
+                                        IntentManager intentManager,
+                                        HttpServiceManager httpServiceManager) {
+        super(dswBC, intentManager, httpServiceManager);
+    }
+
+    public String[] getSupportedTypes() {
+        return new String[] {Constants.WS_CONFIG_TYPE, Constants.WS_CONFIG_TYPE_OLD};
+    }
+
+    public Object createProxy(ServiceReference sref, BundleContext dswContext, BundleContext callingContext,
+                              Class<?> iClass, EndpointDescription endpoint) throws IntentUnsatisfiedException {
+        Map<String, Object> sd = endpoint.getProperties();
+        String address = getClientAddress(sd);
+        if (address == null) {
+            LOG.warn("Remote address is unavailable");
+            // TODO: fire Event
+            return null;
+        }
+
+        LOG.info("Creating a " + iClass.getName() + " client, endpoint address is " + address);
+
+        ClassLoader oldClassLoader = Thread.currentThread().getContextClassLoader();
+        try {
+            ClientProxyFactoryBean factory = createClientProxyFactoryBean(sd, iClass);
+            factory.getServiceFactory().setDataBinding(getDataBinding(sd, iClass));
+            factory.setServiceClass(iClass);
+            factory.setAddress(address);
+            addWsInterceptorsFeaturesProps(factory.getClientFactoryBean(), callingContext, sd);
+            setClientWsdlProperties(factory.getClientFactoryBean(), dswContext, sd, false);
+
+            intentManager.applyIntents(factory.getFeatures(), factory.getClientFactoryBean(), sd);
+
+            Thread.currentThread().setContextClassLoader(ClientProxyFactoryBean.class.getClassLoader());
+            return getProxy(factory.create(), iClass);
+        } catch (Exception e) {
+            LOG.warn("proxy creation failed", e);
+        } finally {
+            Thread.currentThread().setContextClassLoader(oldClassLoader);
+        }
+        return null;
+    }
+
+    public ExportResult createServer(ServiceReference sref,
+                                     BundleContext dswContext,
+                                     BundleContext callingContext,
+                                     Map<String, Object> sd,
+                                     Class<?> iClass,
+                                     Object serviceBean) throws IntentUnsatisfiedException {
+        try {
+            String address = getPojoAddress(sd, iClass);
+            String contextRoot = httpServiceManager.getServletContextRoot(sd);
+
+            ServerFactoryBean factory = createServerFactoryBean(sd, iClass);
+            factory.setDataBinding(getDataBinding(sd, iClass));
+            if (contextRoot != null) {
+                Bus bus = httpServiceManager.registerServletAndGetBus(contextRoot, callingContext, sref);
+                factory.setBus(bus);
+            }
+            factory.setServiceClass(iClass);
+            factory.setAddress(address);
+            factory.setServiceBean(serviceBean);
+            addWsInterceptorsFeaturesProps(factory, callingContext, sd);
+            setWsdlProperties(factory, callingContext, sd, false);
+            String[] intents = intentManager.applyIntents(factory.getFeatures(), factory, sd);
+
+            String completeEndpointAddress = httpServiceManager.getAbsoluteAddress(contextRoot, address);
+
+            // The properties for the EndpointDescription
+            Map<String, Object> endpointProps = createEndpointProps(sd, iClass,
+                                                                    new String[]{Constants.WS_CONFIG_TYPE},
+                                                                    completeEndpointAddress, intents);
+
+            return createServerFromFactory(factory, endpointProps);
+        } catch (RuntimeException re) {
+            return new ExportResult(sd, re);
+        }
+    }
+
+    private String getPojoAddress(Map<String, Object> sd, Class<?> iClass) {
+        String address = getClientAddress(sd);
+        if (address != null) {
+            return address;
+        }
+
+        // If the property is not of type string this will cause an ClassCastException which
+        // will be propagated to the ExportRegistration exception property.
+        Object port = sd.get(Constants.WS_PORT_PROPERTY);
+        if (port == null) {
+            port = "9000";
+        }
+
+        address = "http://localhost:" + port + "/" + iClass.getName().replace('.', '/');
+        LOG.info("Using a default address: " + address);
+        return address;
+    }
+
+    private DataBinding getDataBinding(Map<String, Object> sd, Class<?> iClass) {
+        Object dataBindingBeanProp = sd.get(Constants.WS_DATABINDING_BEAN_PROP_KEY);
+        if (dataBindingBeanProp instanceof DataBinding) {
+            return (DataBinding)dataBindingBeanProp;
+        } 
+        return isJAXB(sd, iClass) ? new JAXBDataBinding() : new AegisDatabinding();
+    }
+
+    private boolean isJAXB(Map<String, Object> sd, Class<?> iClass) {
+        String dataBindingName = (String)sd.get(Constants.WS_DATABINDING_PROP_KEY);
+        return (iClass.getAnnotation(WebService.class) != null
+            || Constants.WS_DATA_BINDING_JAXB.equals(dataBindingName))
+            && !Constants.WS_DATA_BINDING_AEGIS.equals(dataBindingName);
+    }
+
+    // Isolated so that it can be substituted for testing
+    protected ClientProxyFactoryBean createClientProxyFactoryBean(Map<String, Object> sd, Class<?> iClass) {
+        return isJAXWS(sd, iClass) ? new JaxWsProxyFactoryBean() : new ClientProxyFactoryBean();
+    }
+
+    // Isolated so that it can be substituted for testing
+    protected ServerFactoryBean createServerFactoryBean(Map<String, Object> sd, Class<?> iClass) {
+        return isJAXWS(sd, iClass) ? new JaxWsServerFactoryBean() : new ServerFactoryBean();
+    }
+
+    private boolean isJAXWS(Map<String, Object> sd, Class<?> iClass) {
+        String frontEnd = (String)sd.get(Constants.WS_FRONTEND_PROP_KEY);
+        return (iClass.getAnnotation(WebService.class) != null
+            || Constants.WS_FRONTEND_JAXWS.equals(frontEnd))
+            && !Constants.WS_FRONTEND_SIMPLE.equals(frontEnd);
+    }
+}
diff --git a/trunk/dsw/cxf-dsw/src/main/java/org/apache/cxf/dosgi/dsw/handlers/SecurityDelegatingHttpContext.java b/trunk/dsw/cxf-dsw/src/main/java/org/apache/cxf/dosgi/dsw/handlers/SecurityDelegatingHttpContext.java
new file mode 100644
index 0000000..a9c12ef
--- /dev/null
+++ b/trunk/dsw/cxf-dsw/src/main/java/org/apache/cxf/dosgi/dsw/handlers/SecurityDelegatingHttpContext.java
@@ -0,0 +1,130 @@
+/**
+ * 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.dsw.handlers;
+
+import java.io.IOException;
+import java.net.URL;
+
+import javax.servlet.Filter;
+import javax.servlet.FilterChain;
+import javax.servlet.ServletException;
+import javax.servlet.ServletRequest;
+import javax.servlet.ServletResponse;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.InvalidSyntaxException;
+import org.osgi.framework.ServiceReference;
+import org.osgi.service.http.HttpContext;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * <p>
+ * An HttpContext that delegates to another HttpContext for all things other than security. This implementation handles
+ * security by delegating to a {@link FilterChain} based on the set of {@link Filter}s registered with a
+ * {@link #FILTER_PROP} property.
+ * </p>
+ * <p>
+ * If the {@link BundleContext} contains a {@link #FILTER_REQUIRED_PROP} property with value "true", requests will not
+ * be allowed until at least one {@link Filter} with a {@link #FILTER_PROP} property is registered.
+ * </p>
+ */
+public class SecurityDelegatingHttpContext implements HttpContext {
+
+    public static final String FILTER_PROP = "org.apache.cxf.httpservice.filter";
+    public static final String FILTER_REQUIRED_PROP = "org.apache.cxf.httpservice.requirefilter";
+    private static final Logger LOG = LoggerFactory.getLogger(SecurityDelegatingHttpContext.class);
+    private static final String FILTER_FILTER = "(" + FILTER_PROP + "=*)";
+
+    BundleContext bundleContext;
+    HttpContext delegate;
+    boolean requireFilter;
+
+    public SecurityDelegatingHttpContext(BundleContext bundleContext, HttpContext delegate) {
+        this.bundleContext = bundleContext;
+        this.delegate = delegate;
+        requireFilter = Boolean.TRUE.toString().equalsIgnoreCase(bundleContext.getProperty(FILTER_REQUIRED_PROP));
+    }
+
+    public String getMimeType(String name) {
+        return delegate.getMimeType(name);
+    }
+
+    public URL getResource(String name) {
+        return delegate.getResource(name);
+    }
+
+    public boolean handleSecurity(HttpServletRequest request, HttpServletResponse response) throws IOException {
+        ServiceReference[] refs;
+        try {
+            refs = bundleContext.getServiceReferences(Filter.class.getName(), FILTER_FILTER);
+        } catch (InvalidSyntaxException e) {
+            LOG.warn(e.getMessage(), e);
+            return false;
+        }
+        if (refs == null || refs.length == 0) {
+            LOG.info("No filter registered.");
+            return !requireFilter;
+        }
+        Filter[] filters = new Filter[refs.length];
+        try {
+            for (int i = 0; i < refs.length; i++) {
+                filters[i] = (Filter)bundleContext.getService(refs[i]);
+            }
+            try {
+                new Chain(filters).doFilter(request, response);
+                return !response.isCommitted();
+            } catch (ServletException e) {
+                LOG.warn(e.getMessage(), e);
+                return false;
+            }
+        } finally {
+            for (int i = 0; i < refs.length; i++) {
+                if (filters[i] != null) {
+                    bundleContext.ungetService(refs[i]);
+                }
+            }
+        }
+    }
+}
+
+/**
+ * A {@link FilterChain} composed of {@link Filter}s with the
+ */
+class Chain implements FilterChain {
+
+    private static final Logger LOG = LoggerFactory.getLogger(Chain.class);
+
+    int current;
+    final Filter[] filters;
+
+    Chain(Filter[] filters) {
+        this.filters = filters;
+    }
+
+    public void doFilter(ServletRequest request, ServletResponse response) throws IOException, ServletException {
+        if (current < filters.length && !response.isCommitted()) {
+            Filter filter = filters[current++];
+            LOG.info("doFilter() on {}", filter);
+            filter.doFilter(request, response, this);
+        }
+    }
+}
diff --git a/trunk/dsw/cxf-dsw/src/main/java/org/apache/cxf/dosgi/dsw/handlers/ServiceInvocationHandler.java b/trunk/dsw/cxf-dsw/src/main/java/org/apache/cxf/dosgi/dsw/handlers/ServiceInvocationHandler.java
new file mode 100644
index 0000000..6171a53
--- /dev/null
+++ b/trunk/dsw/cxf-dsw/src/main/java/org/apache/cxf/dosgi/dsw/handlers/ServiceInvocationHandler.java
@@ -0,0 +1,100 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.cxf.dosgi.dsw.handlers;
+
+import java.lang.reflect.InvocationHandler;
+import java.lang.reflect.Method;
+import java.lang.reflect.Proxy;
+import java.security.AccessController;
+import java.security.PrivilegedExceptionAction;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.osgi.framework.ServiceException;
+
+public class ServiceInvocationHandler implements InvocationHandler {
+
+    private static final String REMOTE_EXCEPTION_TYPE = "REMOTE";
+    private static final Collection<Method> OBJECT_METHODS = Arrays.asList(Object.class.getMethods());
+
+    private Map<Method, List<Class<?>>> exceptionsMap = new HashMap<Method, List<Class<?>>>();
+    private Object serviceObject;
+
+    public ServiceInvocationHandler(Object serviceObject, Class<?> iType) {
+        this.serviceObject = serviceObject;
+        introspectType(iType);
+    }
+
+    public Object invoke(Object proxy, final Method m, Object[] params) throws Throwable {
+        if (OBJECT_METHODS.contains(m)) {
+            if (m.getName().equals("equals")) {
+                params = new Object[] {Proxy.getInvocationHandler(params[0])};
+            }
+            return m.invoke(this, params);
+        }
+
+        ClassLoader oldCl = Thread.currentThread().getContextClassLoader();
+        try {
+            Thread.currentThread().setContextClassLoader(getClass().getClassLoader());
+            final Object[] paramsFinal = params;
+            return AccessController.doPrivileged(new PrivilegedExceptionAction<Object>() {
+                public Object run() throws Exception {
+                    return m.invoke(serviceObject, paramsFinal);
+                }
+            });
+        } catch (Throwable ex) {
+            Throwable theCause = ex.getCause() == null ? ex : ex.getCause();
+            Throwable theCauseCause = theCause.getCause() == null ? theCause : theCause.getCause();
+            List<Class<?>> excTypes = exceptionsMap.get(m);
+            if (excTypes != null) {
+                for (Class<?> type : excTypes) {
+                    if (type.isAssignableFrom(theCause.getClass())) {
+                        throw theCause;
+                    }
+                    if (type.isAssignableFrom(theCauseCause.getClass())) {
+                        throw theCauseCause;
+                    }
+                }
+            }
+
+            throw new ServiceException(REMOTE_EXCEPTION_TYPE, theCause);
+        } finally {
+            Thread.currentThread().setContextClassLoader(oldCl);
+        }
+    }
+
+    private void introspectType(Class<?> iType) {
+        for (Method m : iType.getDeclaredMethods()) {
+            for (Class<?> excType : m.getExceptionTypes()) {
+                if (Exception.class.isAssignableFrom(excType)) {
+                    List<Class<?>> types = exceptionsMap.get(m);
+                    if (types == null) {
+                        types = new ArrayList<Class<?>>();
+                        exceptionsMap.put(m, types);
+                    }
+                    types.add(excType);
+                }
+            }
+        }
+    }
+}
diff --git a/trunk/dsw/cxf-dsw/src/main/java/org/apache/cxf/dosgi/dsw/handlers/WsdlConfigurationTypeHandler.java b/trunk/dsw/cxf-dsw/src/main/java/org/apache/cxf/dosgi/dsw/handlers/WsdlConfigurationTypeHandler.java
new file mode 100644
index 0000000..bada39f
--- /dev/null
+++ b/trunk/dsw/cxf-dsw/src/main/java/org/apache/cxf/dosgi/dsw/handlers/WsdlConfigurationTypeHandler.java
@@ -0,0 +1,160 @@
+/**
+ * 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.dsw.handlers;
+
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.util.Map;
+
+import javax.xml.namespace.QName;
+import javax.xml.ws.Service;
+
+import org.apache.cxf.Bus;
+import org.apache.cxf.common.util.PackageUtils;
+import org.apache.cxf.databinding.DataBinding;
+import org.apache.cxf.dosgi.dsw.Constants;
+import org.apache.cxf.dosgi.dsw.qos.IntentManager;
+import org.apache.cxf.dosgi.dsw.util.OsgiUtils;
+import org.apache.cxf.jaxb.JAXBDataBinding;
+import org.apache.cxf.jaxws.JaxWsServerFactoryBean;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.ServiceReference;
+import org.osgi.service.remoteserviceadmin.EndpointDescription;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class WsdlConfigurationTypeHandler extends AbstractPojoConfigurationTypeHandler {
+
+    private static final Logger LOG = LoggerFactory.getLogger(WsdlConfigurationTypeHandler.class);
+
+    public WsdlConfigurationTypeHandler(BundleContext dswBC,
+                                        IntentManager intentManager,
+                                        HttpServiceManager httpServiceManager) {
+        super(dswBC, intentManager, httpServiceManager);
+    }
+
+    public String[] getSupportedTypes() {
+        return new String[] {Constants.WSDL_CONFIG_TYPE};
+    }
+
+    public Object createProxy(ServiceReference serviceReference,
+                              BundleContext dswContext,
+                              BundleContext callingContext,
+                              Class<?> iClass,
+                              EndpointDescription endpoint) {
+        String wsdlAddressProp = getWsdlAddress(endpoint, iClass);
+        if (wsdlAddressProp == null) {
+            LOG.warn("WSDL address is unavailable");
+            return null;
+        }
+
+        URL wsdlAddress;
+        try {
+            wsdlAddress = new URL(wsdlAddressProp);
+        } catch (MalformedURLException ex) {
+            LOG.warn("WSDL address is malformed");
+            return null;
+        }
+
+        LOG.info("Creating a " + endpoint.getInterfaces().toArray()[0] + " client, wsdl address is "
+                 + OsgiUtils.getProperty(endpoint, Constants.WSDL_CONFIG_PREFIX));
+
+        String serviceNs = OsgiUtils.getProperty(endpoint, Constants.WSDL_SERVICE_NAMESPACE);
+        if (serviceNs == null) {
+            serviceNs = PackageUtils.getNamespace(PackageUtils.getPackageName(iClass));
+        }
+        String serviceName = OsgiUtils.getProperty(endpoint, Constants.WSDL_SERVICE_NAME);
+        if (serviceName == null) {
+            serviceName = iClass.getSimpleName();
+        }
+        QName serviceQname = getServiceQName(iClass, endpoint.getProperties(),
+                                             Constants.WSDL_SERVICE_NAMESPACE,
+                                             Constants.WSDL_SERVICE_NAME);
+        QName portQname = getPortQName(serviceQname.getNamespaceURI(),
+                endpoint.getProperties(), Constants.WSDL_PORT_NAME);
+        Service service = createWebService(wsdlAddress, serviceQname);
+        Object proxy = getProxy(portQname == null ? service.getPort(iClass) : service.getPort(portQname, iClass),
+                                iClass);
+        // MARC: FIXME!!!! getDistributionProvider().addRemoteService(serviceReference);
+        return proxy;
+    }
+
+    // Isolated so that it can be overridden for test purposes.
+    Service createWebService(URL wsdlAddress, QName serviceQname) {
+        return Service.create(wsdlAddress, serviceQname);
+    }
+
+    public ExportResult createServer(ServiceReference sref,
+                               BundleContext dswContext,
+                               BundleContext callingContext,
+                               Map<String, Object> sd,
+                               Class<?> iClass,
+                               Object serviceBean) {
+        String location = OsgiUtils.getProperty(sd, Constants.WSDL_LOCATION);
+        if (location == null) {
+            throw new RuntimeException("WSDL location property is unavailable");
+        }
+        URL wsdlURL = dswContext.getBundle().getResource(location);
+        if (wsdlURL == null) {
+            throw new RuntimeException("WSDL resource at " + location + " is unavailable");
+        }
+
+        String address = getServerAddress(sd, iClass);
+        String contextRoot = httpServiceManager.getServletContextRoot(sd);
+        if (address == null && contextRoot == null) {
+            throw new RuntimeException("Remote address is unavailable");
+        }
+
+        LOG.info("Creating a " + iClass.getName() + " endpoint from CXF PublishHook, address is " + address);
+
+        DataBinding databinding = new JAXBDataBinding();
+        JaxWsServerFactoryBean factory = new JaxWsServerFactoryBean();
+        if (contextRoot != null) {
+            Bus bus = httpServiceManager.registerServletAndGetBus(contextRoot, callingContext, sref);
+            factory.setBus(bus);
+        }
+        factory.setServiceClass(iClass);
+        factory.setAddress(address != null ? address : "/");
+        factory.getServiceFactory().setDataBinding(databinding);
+        factory.setServiceBean(serviceBean);
+
+        addWsInterceptorsFeaturesProps(factory, callingContext, sd);
+
+        setWsdlProperties(factory, callingContext, sd, true);
+
+        String[] intents = intentManager.applyIntents(factory.getFeatures(), factory, sd);
+
+        // The properties for the EndpointDescription
+        Map<String, Object> endpointProps = createEndpointProps(sd, iClass,
+                                                                new String[]{Constants.WS_CONFIG_TYPE},
+                                                                address, intents);
+        return createServerFromFactory(factory, endpointProps);
+    }
+
+    private String getWsdlAddress(EndpointDescription endpoint, Class<?> iClass) {
+        String address = OsgiUtils.getProperty(endpoint, Constants.WSDL_CONFIG_PREFIX);
+        if (address == null) {
+            address = httpServiceManager.getDefaultAddress(iClass);
+            if (address != null) {
+                address += "?wsdl";
+            }
+        }
+        return address;
+    }
+}
diff --git a/trunk/dsw/cxf-dsw/src/main/java/org/apache/cxf/dosgi/dsw/qos/DefaultIntentMapFactory.java b/trunk/dsw/cxf-dsw/src/main/java/org/apache/cxf/dosgi/dsw/qos/DefaultIntentMapFactory.java
new file mode 100644
index 0000000..7e0dd2e
--- /dev/null
+++ b/trunk/dsw/cxf-dsw/src/main/java/org/apache/cxf/dosgi/dsw/qos/DefaultIntentMapFactory.java
@@ -0,0 +1,52 @@
+/**
+ * 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.dsw.qos;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import org.apache.cxf.binding.soap.Soap11;
+import org.apache.cxf.binding.soap.Soap12;
+import org.apache.cxf.binding.soap.SoapBindingConfiguration;
+import org.apache.cxf.binding.soap.SoapVersion;
+import org.apache.cxf.feature.LoggingFeature;
+
+public class DefaultIntentMapFactory {
+
+    public Map<String, Object> create() {
+        Map<String, Object> intentMap = new HashMap<String, Object>();
+        intentMap.put("logging", getLoggingFeature());
+        Object soap11 = getSoapBinding(Soap11.getInstance());
+        intentMap.put("SOAP", soap11);
+        intentMap.put("SOAP.1_1", soap11);
+        intentMap.put("SOAP.1_2", getSoapBinding(Soap12.getInstance()));
+        intentMap.put("HTTP", "PROVIDED");
+        return intentMap;
+    }
+
+    private Object getLoggingFeature() {
+        return new LoggingFeature();
+    }
+
+    private Object getSoapBinding(SoapVersion soapVersion) {
+        SoapBindingConfiguration soapBindingConfig = new SoapBindingConfiguration();
+        soapBindingConfig.setVersion(soapVersion);
+        return soapBindingConfig;
+    }
+}
diff --git a/trunk/dsw/cxf-dsw/src/main/java/org/apache/cxf/dosgi/dsw/qos/IntentManager.java b/trunk/dsw/cxf-dsw/src/main/java/org/apache/cxf/dosgi/dsw/qos/IntentManager.java
new file mode 100644
index 0000000..ecaf070
--- /dev/null
+++ b/trunk/dsw/cxf-dsw/src/main/java/org/apache/cxf/dosgi/dsw/qos/IntentManager.java
@@ -0,0 +1,31 @@
+/**
+ * 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.dsw.qos;
+
+import java.util.List;
+import java.util.Map;
+
+import org.apache.cxf.endpoint.AbstractEndpointFactory;
+import org.apache.cxf.feature.Feature;
+
+public interface IntentManager {
+
+    String[] applyIntents(List<Feature> features, AbstractEndpointFactory factory, Map<String, Object> props);
+    void assertAllIntentsSupported(Map<String, Object> serviceProperties);
+}
diff --git a/trunk/dsw/cxf-dsw/src/main/java/org/apache/cxf/dosgi/dsw/qos/IntentManagerImpl.java b/trunk/dsw/cxf-dsw/src/main/java/org/apache/cxf/dosgi/dsw/qos/IntentManagerImpl.java
new file mode 100644
index 0000000..d7b50f2
--- /dev/null
+++ b/trunk/dsw/cxf-dsw/src/main/java/org/apache/cxf/dosgi/dsw/qos/IntentManagerImpl.java
@@ -0,0 +1,154 @@
+/**
+ * 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.dsw.qos;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import org.apache.cxf.binding.BindingConfiguration;
+import org.apache.cxf.endpoint.AbstractEndpointFactory;
+import org.apache.cxf.feature.Feature;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class IntentManagerImpl implements IntentManager {
+
+    static final Logger LOG = LoggerFactory.getLogger(IntentManagerImpl.class);
+    private static final String PROVIDED_INTENT_VALUE = "PROVIDED";
+
+    private final IntentMap intentMap;
+    private final long maxIntentWaitTime;
+
+    public IntentManagerImpl(IntentMap intentMap) {
+        this(intentMap, 0);
+    }
+
+    public IntentManagerImpl(IntentMap intentMap, int maxIntentWaitTime) {
+        this.intentMap = intentMap;
+        this.maxIntentWaitTime = maxIntentWaitTime;
+    }
+
+    public String[] applyIntents(List<Feature> features, AbstractEndpointFactory factory,
+                                 Map<String, Object> props) throws IntentUnsatisfiedException {
+        Set<String> requestedIntents = IntentUtils.getRequestedIntents(props);
+        Set<String> appliedIntents = new HashSet<String>();
+        appliedIntents.addAll(reverseLookup(intentMap, PROVIDED_INTENT_VALUE));
+        boolean bindingApplied = false;
+        for (String intentName : requestedIntents) {
+            bindingApplied |= processIntent(features, factory, intentName, intentMap.get(intentName));
+            appliedIntents.add(intentName);
+        }
+        if (!bindingApplied) {
+            String defaultBindingName = "SOAP";
+            processIntent(features, factory, defaultBindingName, intentMap.get(defaultBindingName));
+            appliedIntents.add(defaultBindingName);
+        }
+        appliedIntents.addAll(addSynonymIntents(appliedIntents, intentMap));
+        return appliedIntents.toArray(new String[appliedIntents.size()]);
+    }
+
+    private boolean processIntent(List<Feature> features, AbstractEndpointFactory factory,
+                                  String intentName, Object intent) throws IntentUnsatisfiedException {
+        if (intent instanceof String) {
+            if (PROVIDED_INTENT_VALUE.equalsIgnoreCase((String) intent)) {
+                return false;
+            }
+        } else if (intent instanceof BindingConfiguration) {
+            BindingConfiguration bindingCfg = (BindingConfiguration)intent;
+            LOG.info("Applying intent: " + intentName + " via binding config: " + bindingCfg);
+            factory.setBindingConfig(bindingCfg);
+            return true;
+        } else if (intent instanceof Feature) {
+            Feature feature = (Feature) intent;
+            LOG.info("Applying intent: " + intentName + " via feature: " + feature);
+            features.add(feature);
+            return false;
+        } else {
+            LOG.info("No mapping for intent: " + intentName);
+            throw new IntentUnsatisfiedException(intentName);
+        }
+        return false;
+    }
+
+    private static Collection<String> addSynonymIntents(Collection<String> appliedIntents,
+                                                 IntentMap map) {
+        // E.g. SOAP and SOAP.1_1 are synonyms
+        List<Object> values = new ArrayList<Object>();
+        for (String key : appliedIntents) {
+            values.add(map.get(key));
+        }
+        return reverseLookup(map, values);
+    }
+
+    private static Collection<String> reverseLookup(IntentMap im, Object obj) {
+        return reverseLookup(im, Collections.singleton(obj));
+    }
+
+    /**
+     * Retrieves all keys whose mapped values are found in the given collection.
+     *
+     * @param im an intent map
+     * @param values a collection of potential values
+     * @return all keys whose mapped values are found in the given collection
+     */
+    private static Collection<String> reverseLookup(IntentMap im, Collection<?> values) {
+        Set<String> intentsFound = new HashSet<String>();
+        for (Map.Entry<String, Object> entry : im.entrySet()) {
+            if (values.contains(entry.getValue())) {
+                intentsFound.add(entry.getKey());
+            }
+        }
+        return intentsFound;
+    }
+
+    public void assertAllIntentsSupported(Map<String, Object> serviceProperties) {
+        long endTime = System.currentTimeMillis() + maxIntentWaitTime;
+        Set<String> requiredIntents = IntentUtils.getRequestedIntents(serviceProperties);
+        List<String> unsupportedIntents = new ArrayList<String>();
+        do {
+            unsupportedIntents.clear();
+            for (String ri : requiredIntents) {
+                if (!intentMap.containsKey(ri)) {
+                    unsupportedIntents.add(ri);
+                }
+            }
+            long remainingSeconds = (endTime - System.currentTimeMillis()) / 1000;
+            if (!unsupportedIntents.isEmpty() && remainingSeconds > 0) {
+                LOG.debug("Waiting for custom intents " + unsupportedIntents + " timeout in " + remainingSeconds);
+                try {
+                    synchronized (intentMap) {
+                        intentMap.wait(1000);
+                    }
+                } catch (InterruptedException e) {
+                    LOG.warn(e.getMessage(), e);
+                }
+            }
+        } while (!unsupportedIntents.isEmpty() && System.currentTimeMillis() < endTime);
+
+        if (!unsupportedIntents.isEmpty()) {
+            throw new RuntimeException("service cannot be exported because the following "
+                                       + "intents are not supported by this RSA: " + unsupportedIntents);
+        }
+    }
+}
diff --git a/trunk/dsw/cxf-dsw/src/main/java/org/apache/cxf/dosgi/dsw/qos/IntentMap.java b/trunk/dsw/cxf-dsw/src/main/java/org/apache/cxf/dosgi/dsw/qos/IntentMap.java
new file mode 100644
index 0000000..5ed4ef6
--- /dev/null
+++ b/trunk/dsw/cxf-dsw/src/main/java/org/apache/cxf/dosgi/dsw/qos/IntentMap.java
@@ -0,0 +1,62 @@
+/**
+ * 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.dsw.qos;
+
+import java.util.HashMap;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+
+/**
+ * Maps intent names to intent objects
+ * An intent object can be a Feature, a BindingConfiguration or a String
+ *
+ * Also supports a default intent map. Custom intents can override the defaults
+ */
+public class IntentMap extends ConcurrentHashMap<String, Object> {
+
+    private static final long serialVersionUID = 2606460607920520767L;
+    private Map<String, Object> defaultMap;
+
+    public IntentMap() {
+        this(new HashMap<String, Object>());
+    }
+
+    public IntentMap(Map<String, Object> defaultMap) {
+        this.defaultMap = defaultMap;
+        putAll(defaultMap);
+    }
+
+    @Override
+    public Object put(String key, Object value) {
+        Object result = super.put(key, value);
+        synchronized (this) {
+            notifyAll();
+        }
+        return result;
+    }
+
+    @Override
+    public Object remove(Object key) {
+        Object old = super.remove(key);
+        if (defaultMap.containsKey(key)) {
+            put((String)key, defaultMap.get(key));
+        }
+        return old;
+    }
+}
diff --git a/trunk/dsw/cxf-dsw/src/main/java/org/apache/cxf/dosgi/dsw/qos/IntentTracker.java b/trunk/dsw/cxf-dsw/src/main/java/org/apache/cxf/dosgi/dsw/qos/IntentTracker.java
new file mode 100644
index 0000000..4cae464
--- /dev/null
+++ b/trunk/dsw/cxf-dsw/src/main/java/org/apache/cxf/dosgi/dsw/qos/IntentTracker.java
@@ -0,0 +1,60 @@
+/**
+ * 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.dsw.qos;
+
+import org.apache.cxf.dosgi.dsw.Constants;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.Filter;
+import org.osgi.framework.InvalidSyntaxException;
+import org.osgi.framework.ServiceReference;
+import org.osgi.util.tracker.ServiceTracker;
+
+public class IntentTracker extends ServiceTracker {
+
+    private final IntentMap intentMap;
+
+    public IntentTracker(BundleContext context, IntentMap intentMap) {
+        super(context, getFilter(context), null);
+        this.intentMap = intentMap;
+    }
+
+    static Filter getFilter(BundleContext context) {
+        try {
+            return context.createFilter("(" + Constants.INTENT_NAME_PROP + "=*)");
+        } catch (InvalidSyntaxException e) {
+            throw new RuntimeException(e.getMessage(), e);
+        }
+    }
+
+    @Override
+    public Object addingService(ServiceReference reference) {
+        String intentName = (String) reference.getProperty(Constants.INTENT_NAME_PROP);
+        Object intent = super.addingService(reference);
+        IntentManagerImpl.LOG.info("Adding custom intent " + intentName);
+        intentMap.put(intentName, intent);
+        return intent;
+    }
+
+    @Override
+    public void removedService(ServiceReference reference, Object service) {
+        String intentName = (String) reference.getProperty(Constants.INTENT_NAME_PROP);
+        intentMap.remove(intentName);
+        super.removedService(reference, service);
+    }
+}
\ No newline at end of file
diff --git a/trunk/dsw/cxf-dsw/src/main/java/org/apache/cxf/dosgi/dsw/qos/IntentUnsatisfiedException.java b/trunk/dsw/cxf-dsw/src/main/java/org/apache/cxf/dosgi/dsw/qos/IntentUnsatisfiedException.java
new file mode 100644
index 0000000..a1b61fa
--- /dev/null
+++ b/trunk/dsw/cxf-dsw/src/main/java/org/apache/cxf/dosgi/dsw/qos/IntentUnsatisfiedException.java
@@ -0,0 +1,35 @@
+/**
+ * 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.dsw.qos;
+
+public class IntentUnsatisfiedException extends RuntimeException {
+
+    private static final long serialVersionUID = 1L;
+
+    private final String intent;
+
+    public IntentUnsatisfiedException(String intent) {
+        super(intent);
+        this.intent = intent;
+    }
+
+    public String getIntent() {
+        return intent;
+    }
+}
diff --git a/trunk/dsw/cxf-dsw/src/main/java/org/apache/cxf/dosgi/dsw/qos/IntentUtils.java b/trunk/dsw/cxf-dsw/src/main/java/org/apache/cxf/dosgi/dsw/qos/IntentUtils.java
new file mode 100644
index 0000000..407b2c3
--- /dev/null
+++ b/trunk/dsw/cxf-dsw/src/main/java/org/apache/cxf/dosgi/dsw/qos/IntentUtils.java
@@ -0,0 +1,92 @@
+/**
+ * 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.dsw.qos;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import org.apache.cxf.dosgi.dsw.Constants;
+import org.apache.cxf.dosgi.dsw.util.OsgiUtils;
+import org.apache.cxf.dosgi.dsw.util.Utils;
+import org.osgi.service.remoteserviceadmin.RemoteConstants;
+
+public final class IntentUtils {
+
+    private IntentUtils() {
+        // never constructed
+    }
+
+    public static String[] getIntentsImplementedByTheService(Map<String, Object> serviceProperties) {
+        // Get the Intents that are implemented by the service
+        return Utils.normalizeStringPlus(serviceProperties.get(RemoteConstants.SERVICE_INTENTS));
+    }
+
+    public static String[] mergeArrays(String[] a1, String[] a2) {
+        if (a1 == null) {
+            return a2;
+        }
+        if (a2 == null) {
+            return a1;
+        }
+
+        List<String> list = new ArrayList<String>(a1.length + a2.length);
+        Collections.addAll(list, a1);
+        for (String s : a2) {
+            if (!list.contains(s)) {
+                list.add(s);
+            }
+        }
+
+        return list.toArray(new String[list.size()]);
+    }
+
+    public static Set<String> getRequestedIntents(Map<String, Object> sd) {
+        Collection<String> intents = OsgiUtils.getMultiValueProperty(sd.get(RemoteConstants.SERVICE_EXPORTED_INTENTS));
+        Collection<String> intents2
+            = OsgiUtils.getMultiValueProperty(sd.get(RemoteConstants.SERVICE_EXPORTED_INTENTS_EXTRA));
+        @SuppressWarnings("deprecation")
+        Collection<String> oldIntents = OsgiUtils.getMultiValueProperty(sd.get(Constants.EXPORTED_INTENTS_OLD));
+        Set<String> allIntents = new HashSet<String>();
+        if (intents != null) {
+            allIntents.addAll(parseIntents(intents));
+        }
+        if (intents2 != null) {
+            allIntents.addAll(parseIntents(intents2));
+        }
+        if (oldIntents != null) {
+            allIntents.addAll(parseIntents(oldIntents));
+        }
+
+        return allIntents;
+    }
+
+    private static Collection<String> parseIntents(Collection<String> intents) {
+        List<String> parsed = new ArrayList<String>();
+        for (String intent : intents) {
+            parsed.addAll(Arrays.asList(intent.split("[ ]")));
+        }
+        return parsed;
+    }
+}
diff --git a/trunk/dsw/cxf-dsw/src/main/java/org/apache/cxf/dosgi/dsw/service/ClientServiceFactory.java b/trunk/dsw/cxf-dsw/src/main/java/org/apache/cxf/dosgi/dsw/service/ClientServiceFactory.java
new file mode 100644
index 0000000..b77950a
--- /dev/null
+++ b/trunk/dsw/cxf-dsw/src/main/java/org/apache/cxf/dosgi/dsw/service/ClientServiceFactory.java
@@ -0,0 +1,106 @@
+/**
+ * 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.dsw.service;
+
+import java.security.AccessController;
+import java.security.PrivilegedAction;
+import java.util.Arrays;
+import java.util.List;
+
+import org.apache.cxf.dosgi.dsw.handlers.ConfigurationTypeHandler;
+import org.apache.cxf.dosgi.dsw.qos.IntentUnsatisfiedException;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.ServiceFactory;
+import org.osgi.framework.ServiceRegistration;
+import org.osgi.service.remoteserviceadmin.EndpointDescription;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class ClientServiceFactory implements ServiceFactory {
+
+    private static final Logger LOG = LoggerFactory.getLogger(ClientServiceFactory.class);
+
+    private BundleContext dswContext;
+    private Class<?> iClass;
+    private EndpointDescription endpoint;
+    private ConfigurationTypeHandler handler;
+    private ImportRegistrationImpl importRegistration;
+
+    private boolean closeable;
+    private int serviceCounter;
+
+    public ClientServiceFactory(BundleContext dswContext, Class<?> iClass, EndpointDescription endpoint,
+                                ConfigurationTypeHandler handler, ImportRegistrationImpl ir) {
+        this.dswContext = dswContext;
+        this.iClass = iClass;
+        this.endpoint = endpoint;
+        this.handler = handler;
+        this.importRegistration = ir;
+    }
+
+    public Object getService(final Bundle requestingBundle, final ServiceRegistration sreg) {
+        List<String> interfaces = endpoint.getInterfaces();
+        String interfaceName = interfaces == null || interfaces.isEmpty() ? null : interfaces.get(0);
+        LOG.debug("getService() from serviceFactory for {}", interfaceName);
+        try {
+            Object proxy = AccessController.doPrivileged(new PrivilegedAction<Object>() {
+                public Object run() {
+                    return handler.createProxy(sreg.getReference(), dswContext,
+                            requestingBundle.getBundleContext(), iClass, endpoint);
+                }
+            });
+
+            synchronized (this) {
+                serviceCounter++;
+            }
+            return proxy;
+        } catch (IntentUnsatisfiedException iue) {
+            LOG.info("Did not create proxy for {} because intent {} could not be satisfied",
+                    interfaceName, iue.getIntent());
+        } catch (Exception e) {
+            LOG.warn("Problem creating a remote proxy for {}", interfaceName, e);
+        }
+        return null;
+    }
+
+    public void ungetService(Bundle requestingBundle, ServiceRegistration sreg, Object serviceObject) {
+        String[] interfaces = (String[])sreg.getReference().getProperty(org.osgi.framework.Constants.OBJECTCLASS);
+        LOG.info("Releasing a client object, interfaces: {}", Arrays.toString(interfaces));
+
+        synchronized (this) {
+            serviceCounter--;
+            LOG.debug("Services still provided by this ServiceFactory: {}", serviceCounter);
+            closeIfUnused();
+        }
+    }
+
+    public void setCloseable(boolean closeable) {
+        synchronized (this) {
+            this.closeable = closeable;
+            closeIfUnused();
+        }
+    }
+
+    private synchronized void closeIfUnused() {
+        if (serviceCounter <= 0 && closeable) {
+            importRegistration.closeAll();
+        }
+    }
+}
diff --git a/trunk/dsw/cxf-dsw/src/main/java/org/apache/cxf/dosgi/dsw/service/EventAdminHelper.java b/trunk/dsw/cxf-dsw/src/main/java/org/apache/cxf/dosgi/dsw/service/EventAdminHelper.java
new file mode 100644
index 0000000..133d3c7
--- /dev/null
+++ b/trunk/dsw/cxf-dsw/src/main/java/org/apache/cxf/dosgi/dsw/service/EventAdminHelper.java
@@ -0,0 +1,144 @@
+/**
+ * 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.dsw.service;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.InvalidSyntaxException;
+import org.osgi.framework.ServiceReference;
+import org.osgi.framework.Version;
+import org.osgi.service.event.Event;
+import org.osgi.service.event.EventAdmin;
+import org.osgi.service.remoteserviceadmin.EndpointDescription;
+import org.osgi.service.remoteserviceadmin.RemoteServiceAdminEvent;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import static org.apache.cxf.dosgi.dsw.util.Utils.setIfNotNull;
+
+public class EventAdminHelper {
+
+    private static final Logger LOG = LoggerFactory.getLogger(EventAdminHelper.class);
+
+    private BundleContext bctx;
+
+    public EventAdminHelper(BundleContext bc) {
+        bctx = bc;
+    }
+
+    private Event createEvent(Map<String, Object> props, String type) {
+        String topic = "org/osgi/service/remoteserviceadmin/" + type;
+        props.put("bundle", bctx.getBundle());
+        props.put("bundle.id", bctx.getBundle().getBundleId());
+        props.put("bundle.symbolicname", bctx.getBundle().getSymbolicName());
+
+        String version = (String)bctx.getBundle().getHeaders().get("Bundle-Version");
+        Version v = version != null ? new Version(version) : Version.emptyVersion;
+        setIfNotNull(props, "bundle.version", v);
+
+        return new Event(topic, props);
+    }
+
+    public void notifyEventAdmin(RemoteServiceAdminEvent rsae) {
+        String topic = remoteServiceAdminEventTypeToString(rsae.getType());
+
+        Map<String, Object> props = new HashMap<String, Object>();
+        setIfNotNull(props, "cause", rsae.getException());
+
+        EndpointDescription endpoint = null;
+        if (rsae.getImportReference() != null) {
+            endpoint = ((ImportRegistrationImpl)rsae.getImportReference()).getImportedEndpointAlways();
+            setIfNotNull(props, "import.registration", endpoint);
+        } else if (rsae.getExportReference() != null) {
+            endpoint = rsae.getExportReference().getExportedEndpoint();
+            setIfNotNull(props, "export.registration", endpoint);
+        }
+
+        if (endpoint != null) {
+            setIfNotNull(props, "service.remote.id", endpoint.getServiceId());
+            setIfNotNull(props, "service.remote.uuid", endpoint.getFrameworkUUID());
+            setIfNotNull(props, "service.remote.uri", endpoint.getId());
+            setIfNotNull(props, "objectClass", endpoint.getInterfaces().toArray());
+            setIfNotNull(props, "service.imported.configs", endpoint.getConfigurationTypes());
+        }
+        props.put("timestamp", System.currentTimeMillis());
+        props.put("event", rsae);
+
+        Event event = createEvent(props, topic);
+        notifyEventAdmins(topic, event);
+    }
+
+    private void notifyEventAdmins(String topic, Event event) {
+        ServiceReference[] refs = null;
+        try {
+            refs = bctx.getAllServiceReferences(EventAdmin.class.getName(), null);
+        } catch (InvalidSyntaxException e) {
+            LOG.error("Failed to get EventAdmin: " + e.getMessage(), e);
+        }
+
+        if (refs != null) {
+            LOG.debug("Publishing event to {} EventAdmins; Topic:[{}]", refs.length, topic);
+            for (ServiceReference serviceReference : refs) {
+                EventAdmin eventAdmin = (EventAdmin) bctx.getService(serviceReference);
+                try {
+                    eventAdmin.postEvent(event);
+                } finally {
+                    if (eventAdmin != null) {
+                        bctx.ungetService(serviceReference);
+                    }
+                }
+            }
+        }
+    }
+
+    private static String remoteServiceAdminEventTypeToString(int type) {
+        String retval;
+        switch (type) {
+        case RemoteServiceAdminEvent.EXPORT_ERROR:
+            retval = "EXPORT_ERROR";
+            break;
+        case RemoteServiceAdminEvent.EXPORT_REGISTRATION:
+            retval = "EXPORT_REGISTRATION";
+            break;
+        case RemoteServiceAdminEvent.EXPORT_UNREGISTRATION:
+            retval = "EXPORT_UNREGISTRATION";
+            break;
+        case RemoteServiceAdminEvent.EXPORT_WARNING:
+            retval = "EXPORT_WARNING";
+            break;
+        case RemoteServiceAdminEvent.IMPORT_ERROR:
+            retval = "IMPORT_ERROR";
+            break;
+        case RemoteServiceAdminEvent.IMPORT_REGISTRATION:
+            retval = "IMPORT_REGISTRATION";
+            break;
+        case RemoteServiceAdminEvent.IMPORT_UNREGISTRATION:
+            retval = "IMPORT_UNREGISTRATION";
+            break;
+        case RemoteServiceAdminEvent.IMPORT_WARNING:
+            retval = "IMPORT_WARNING";
+            break;
+        default:
+            retval = "UNKNOWN_EVENT";
+        }
+        return retval;
+    }
+}
diff --git a/trunk/dsw/cxf-dsw/src/main/java/org/apache/cxf/dosgi/dsw/service/EventProducer.java b/trunk/dsw/cxf-dsw/src/main/java/org/apache/cxf/dosgi/dsw/service/EventProducer.java
new file mode 100644
index 0000000..74ed7e2
--- /dev/null
+++ b/trunk/dsw/cxf-dsw/src/main/java/org/apache/cxf/dosgi/dsw/service/EventProducer.java
@@ -0,0 +1,111 @@
+/**
+ * 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.dsw.service;
+
+import java.util.List;
+
+import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.InvalidSyntaxException;
+import org.osgi.framework.ServiceReference;
+import org.osgi.service.remoteserviceadmin.ExportRegistration;
+import org.osgi.service.remoteserviceadmin.ImportRegistration;
+import org.osgi.service.remoteserviceadmin.RemoteServiceAdminEvent;
+import org.osgi.service.remoteserviceadmin.RemoteServiceAdminListener;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class EventProducer {
+
+    private static final Logger LOG = LoggerFactory.getLogger(EventProducer.class);
+    private final BundleContext bctx;
+    private final EventAdminHelper eaHelper;
+
+    public EventProducer(BundleContext bc) {
+        bctx = bc;
+        eaHelper = new EventAdminHelper(bctx);
+    }
+
+    protected void publishNotification(List<ExportRegistration> erl) {
+        for (ExportRegistration exportRegistration : erl) {
+            publishNotification(exportRegistration);
+        }
+    }
+
+    protected void publishNotification(ExportRegistration er) {
+        int type = er.getException() == null
+            ? RemoteServiceAdminEvent.EXPORT_REGISTRATION
+            : RemoteServiceAdminEvent.EXPORT_ERROR;
+        notify(type, null, er);
+    }
+
+    protected void publishNotification(ImportRegistration ir) {
+        int type = ir.getException() == null
+            ? RemoteServiceAdminEvent.IMPORT_REGISTRATION
+            : RemoteServiceAdminEvent.IMPORT_ERROR;
+        notify(type, ir, null);
+    }
+
+    public void notifyRemoval(ExportRegistration er) {
+        notify(RemoteServiceAdminEvent.EXPORT_UNREGISTRATION, null, er);
+    }
+
+    public void notifyRemoval(ImportRegistration ir) {
+        notify(RemoteServiceAdminEvent.IMPORT_UNREGISTRATION, ir, null);
+    }
+
+    // only one of ir or er must be set, and the other must be null
+    private void notify(int type, ImportRegistration ir, ExportRegistration er) {
+        try {
+            RemoteServiceAdminEvent event = ir != null
+                ? new RemoteServiceAdminEvent(type, bctx.getBundle(), ir.getImportReference(), ir.getException())
+                : new RemoteServiceAdminEvent(type, bctx.getBundle(), er.getExportReference(), er.getException());
+            notifyListeners(event);
+            eaHelper.notifyEventAdmin(event);
+        } catch (IllegalStateException ise) {
+            LOG.debug("can't send notifications since bundle context is no longer valid");
+        }
+    }
+
+    private void notifyListeners(RemoteServiceAdminEvent rsae) {
+        try {
+            ServiceReference[] listenerRefs = bctx.getServiceReferences(
+                    RemoteServiceAdminListener.class.getName(), null);
+            if (listenerRefs != null) {
+                for (ServiceReference sref : listenerRefs) {
+                    RemoteServiceAdminListener rsal = (RemoteServiceAdminListener)bctx.getService(sref);
+                    if (rsal != null) {
+                        try {
+                            Bundle bundle = sref.getBundle();
+                            if (bundle != null) {
+                                LOG.debug("notify RemoteServiceAdminListener {} of bundle {}",
+                                        rsal, bundle.getSymbolicName());
+                                rsal.remoteAdminEvent(rsae);
+                            }
+                        } finally {
+                            bctx.ungetService(sref);
+                        }
+                    }
+                }
+            }
+        } catch (InvalidSyntaxException e) {
+            LOG.error(e.getMessage(), e);
+        }
+    }
+}
diff --git a/trunk/dsw/cxf-dsw/src/main/java/org/apache/cxf/dosgi/dsw/service/ExportReferenceImpl.java b/trunk/dsw/cxf-dsw/src/main/java/org/apache/cxf/dosgi/dsw/service/ExportReferenceImpl.java
new file mode 100644
index 0000000..fcfc289
--- /dev/null
+++ b/trunk/dsw/cxf-dsw/src/main/java/org/apache/cxf/dosgi/dsw/service/ExportReferenceImpl.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.dsw.service;
+
+import org.osgi.framework.ServiceReference;
+import org.osgi.service.remoteserviceadmin.EndpointDescription;
+import org.osgi.service.remoteserviceadmin.ExportReference;
+
+public class ExportReferenceImpl implements ExportReference {
+
+    private ServiceReference serviceReference;
+    private EndpointDescription endpoint;
+
+    public ExportReferenceImpl(ServiceReference serviceReference, EndpointDescription endpoint) {
+        this.serviceReference = serviceReference;
+        this.endpoint = endpoint;
+    }
+
+    public ExportReferenceImpl(ExportReference exportReference) {
+        this(exportReference.getExportedService(), exportReference.getExportedEndpoint());
+    }
+
+    public EndpointDescription getExportedEndpoint() {
+        return endpoint;
+    }
+
+    public ServiceReference getExportedService() {
+        return serviceReference;
+    }
+
+    @Override
+    public int hashCode() {
+        final int prime = 31;
+        int result = 1;
+        result = prime * result + (endpoint == null ? 0 : endpoint.hashCode());
+        result = prime * result + (serviceReference == null ? 0 : serviceReference.hashCode());
+        return result;
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj) {
+            return true;
+        }
+        if (obj == null || getClass() != obj.getClass()) {
+            return false;
+        }
+        ExportReferenceImpl other = (ExportReferenceImpl) obj;
+        boolean ed = endpoint == null ? other.endpoint == null
+                : endpoint.equals(other.endpoint);
+        boolean sr = serviceReference == null ? other.serviceReference == null
+                : serviceReference.equals(other.serviceReference);
+        return ed && sr;
+    }
+
+    synchronized void close() {
+        this.endpoint = null;
+        this.serviceReference = null;
+    }
+}
diff --git a/trunk/dsw/cxf-dsw/src/main/java/org/apache/cxf/dosgi/dsw/service/ExportRegistrationImpl.java b/trunk/dsw/cxf-dsw/src/main/java/org/apache/cxf/dosgi/dsw/service/ExportRegistrationImpl.java
new file mode 100644
index 0000000..2a9757b
--- /dev/null
+++ b/trunk/dsw/cxf-dsw/src/main/java/org/apache/cxf/dosgi/dsw/service/ExportRegistrationImpl.java
@@ -0,0 +1,144 @@
+/**
+ * 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.dsw.service;
+
+import java.util.Arrays;
+import java.util.Map;
+import java.util.Set;
+
+import org.apache.cxf.endpoint.Server;
+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.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class ExportRegistrationImpl implements ExportRegistration {
+
+    private static final Logger LOG = LoggerFactory.getLogger(ExportRegistrationImpl.class);
+
+    private final RemoteServiceAdminCore rsaCore;
+    private final ExportReferenceImpl exportReference;
+    private final Server server;
+    private final Throwable exception;
+
+    private final ExportRegistrationImpl parent;
+    private int instanceCount;
+    private volatile boolean closed;
+
+    private ExportRegistrationImpl(ExportRegistrationImpl parent, RemoteServiceAdminCore rsaCore,
+            ExportReferenceImpl exportReference, Server server, Throwable exception) {
+        this.parent = parent != null ? parent.parent : this; // a parent points to itself
+        this.parent.addInstance();
+        this.rsaCore = rsaCore;
+        this.exportReference = exportReference;
+        this.server = server;
+        this.exception = exception;
+    }
+
+    // create a clone of the provided ExportRegistrationImpl that is linked to it
+    public ExportRegistrationImpl(ExportRegistrationImpl parent) {
+        this(parent, parent.rsaCore, new ExportReferenceImpl(parent.exportReference),
+            parent.server, parent.exception);
+    }
+
+    // create a new (parent) instance which was exported successfully with the given server
+    public ExportRegistrationImpl(ServiceReference sref, EndpointDescription endpoint,
+            RemoteServiceAdminCore rsaCore, Server server) {
+        this(null, rsaCore, new ExportReferenceImpl(sref, endpoint), server, null);
+    }
+
+    // create a new (parent) instance which failed to be exported with the given exception
+    public ExportRegistrationImpl(ServiceReference sref, EndpointDescription endpoint,
+            RemoteServiceAdminCore rsaCore, Throwable exception) {
+        this(null, rsaCore, new ExportReferenceImpl(sref, endpoint), null, exception);
+    }
+
+    private void ensureParent() {
+        if (parent != this) {
+            throw new IllegalStateException("this method may only be called on the parent");
+        }
+    }
+
+    public ExportReference getExportReference() {
+        return closed ? null : exportReference;
+    }
+
+    public Throwable getException() {
+        return closed ? null : exception;
+    }
+
+    public final void close() {
+        synchronized (this) {
+            if (closed) {
+                return;
+            }
+            closed = true;
+        }
+
+        rsaCore.removeExportRegistration(this);
+        exportReference.close();
+        parent.removeInstance();
+    }
+
+    private void addInstance() {
+        ensureParent();
+        synchronized (this) {
+            instanceCount++;
+        }
+    }
+
+    private void removeInstance() {
+        ensureParent();
+        synchronized (this) {
+            instanceCount--;
+            if (instanceCount <= 0) {
+                LOG.debug("really closing ExportRegistration now!");
+
+                if (server != null) {
+                    server.destroy();
+                }
+            }
+        }
+    }
+
+    @Override
+    public String toString() {
+        if (closed) {
+            return "ExportRegistration closed";
+        }
+        EndpointDescription endpoint = getExportReference().getExportedEndpoint();
+        ServiceReference serviceReference = getExportReference().getExportedService();
+        String r = "EndpointDescription for ServiceReference " + serviceReference;
+
+        r += "\n*** EndpointDescription: ****\n";
+        if (endpoint == null) {
+            r += "---> NULL <---- \n";
+        } else {
+            Set<Map.Entry<String, Object>> props = endpoint.getProperties().entrySet();
+            for (Map.Entry<String, Object> entry : props) {
+                Object value = entry.getValue();
+                r += entry.getKey() + " => "
+                    + (value instanceof Object[] ? Arrays.toString((Object[]) value) : value) + "\n";
+            }
+        }
+        return r;
+    }
+}
diff --git a/trunk/dsw/cxf-dsw/src/main/java/org/apache/cxf/dosgi/dsw/service/ImportRegistrationImpl.java b/trunk/dsw/cxf-dsw/src/main/java/org/apache/cxf/dosgi/dsw/service/ImportRegistrationImpl.java
new file mode 100644
index 0000000..0edde9f
--- /dev/null
+++ b/trunk/dsw/cxf-dsw/src/main/java/org/apache/cxf/dosgi/dsw/service/ImportRegistrationImpl.java
@@ -0,0 +1,229 @@
+/**
+ * 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.dsw.service;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.osgi.framework.ServiceReference;
+import org.osgi.framework.ServiceRegistration;
+import org.osgi.service.remoteserviceadmin.EndpointDescription;
+import org.osgi.service.remoteserviceadmin.ImportReference;
+import org.osgi.service.remoteserviceadmin.ImportRegistration;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class ImportRegistrationImpl implements ImportRegistration, ImportReference {
+
+    private static final Logger LOG = LoggerFactory.getLogger(ImportRegistrationImpl.class);
+
+    private volatile Throwable exception;
+    private volatile ServiceRegistration importedService; // used only in parent
+    private EndpointDescription endpoint;
+    private volatile ClientServiceFactory clientServiceFactory;
+    private RemoteServiceAdminCore rsaCore;
+    private boolean closed;
+    private boolean detached; // used only in parent
+
+    private ImportRegistrationImpl parent;
+    private List<ImportRegistrationImpl> children; // used only in parent
+
+    public ImportRegistrationImpl(Throwable ex) {
+        exception = ex;
+        initParent();
+    }
+
+    public ImportRegistrationImpl(EndpointDescription endpoint, RemoteServiceAdminCore rsac) {
+        this.endpoint = endpoint;
+        this.rsaCore = rsac;
+        initParent();
+    }
+
+    /**
+     * Creates a clone of the given parent instance.
+     */
+    public ImportRegistrationImpl(ImportRegistrationImpl ir) {
+        // we always want a link to the parent...
+        parent = ir.getParent();
+        exception = parent.getException();
+        endpoint = parent.getImportedEndpointDescription();
+        clientServiceFactory = parent.clientServiceFactory;
+        rsaCore = parent.rsaCore;
+
+        parent.instanceAdded(this);
+    }
+
+    private void initParent() {
+        parent = this;
+        children = new ArrayList<ImportRegistrationImpl>(1);
+    }
+
+    private void ensureParent() {
+        if (parent != this) {
+            throw new IllegalStateException("this method may only be called on the parent");
+        }
+    }
+
+    /**
+     * Called on parent when a child is added.
+     *
+     * @param iri the child
+     */
+    private synchronized void instanceAdded(ImportRegistrationImpl iri) {
+        ensureParent();
+        children.add(iri);
+    }
+
+    /**
+     * Called on parent when a child is closed.
+     *
+     * @param iri the child
+     */
+    private void instanceClosed(ImportRegistrationImpl iri) {
+        ensureParent();
+        synchronized (this) {
+            children.remove(iri);
+            if (!children.isEmpty() || detached || !closed) {
+                return;
+            }
+            detached = true;
+        }
+
+        LOG.debug("really closing ImportRegistration now");
+
+        if (importedService != null) {
+            try {
+                importedService.unregister();
+            } catch (IllegalStateException ise) {
+                LOG.debug("imported service is already unregistered");
+            }
+            importedService = null;
+        }
+        if (clientServiceFactory != null) {
+            clientServiceFactory.setCloseable(true);
+        }
+    }
+
+    public void close() {
+        LOG.debug("close() called");
+
+        synchronized (this) {
+            if (isInvalid()) {
+                return;
+            }
+            closed = true;
+        }
+        rsaCore.removeImportRegistration(this);
+        parent.instanceClosed(this);
+    }
+
+    /**
+     * Closes all ImportRegistrations which share the same parent as this one.
+     */
+    public void closeAll() {
+        if (this == parent) {
+            LOG.info("closing down all child ImportRegistrations");
+
+            // we must iterate over a copy of children since close() removes the child
+            // from the list (which would cause a ConcurrentModificationException)
+            for (ImportRegistrationImpl ir : copyChildren()) {
+                ir.close();
+            }
+            this.close();
+        } else {
+            parent.closeAll();
+        }
+    }
+
+    private List<ImportRegistrationImpl> copyChildren() {
+        synchronized (this) {
+            return new ArrayList<ImportRegistrationImpl>(children);
+        }
+    }
+
+    public EndpointDescription getImportedEndpointDescription() {
+        return isInvalid() ? null : endpoint;
+    }
+
+    @Override
+    public EndpointDescription getImportedEndpoint() {
+        return getImportedEndpointDescription();
+    }
+
+    @Override
+    public ServiceReference getImportedService() {
+        return isInvalid() || parent.importedService == null ? null : parent.importedService.getReference();
+    }
+
+    @Override
+    public ImportReference getImportReference() {
+        return this;
+    }
+
+    @Override
+    public Throwable getException() {
+        return exception;
+    }
+
+    public void setException(Throwable ex) {
+        exception = ex;
+    }
+
+    private synchronized boolean isInvalid() {
+        return exception != null || closed;
+    }
+
+    /**
+     * Sets the {@link ServiceRegistration} representing the locally
+     * registered {@link ClientServiceFactory} service which provides
+     * proxies to the remote imported service. It is set only on the parent.
+     *
+     * @param sreg the ServiceRegistration
+     */
+    public void setImportedServiceRegistration(ServiceRegistration sreg) {
+        ensureParent();
+        importedService = sreg;
+    }
+
+    /**
+     * Sets the {@link ClientServiceFactory} which is the implementation
+     * of the locally registered service which provides proxies to the
+     * remote imported service. It is set only on the parent.
+     *
+     * @param csf the ClientServiceFactory
+     */
+    public void setClientServiceFactory(ClientServiceFactory csf) {
+        ensureParent();
+        clientServiceFactory = csf;
+    }
+
+    public ImportRegistrationImpl getParent() {
+        return parent;
+    }
+
+    /**
+     * Returns the imported endpoint even if this
+     * instance is closed or has an exception.
+     *
+     * @return the imported endpoint
+     */
+    public EndpointDescription getImportedEndpointAlways() {
+        return endpoint;
+    }
+}
diff --git a/trunk/dsw/cxf-dsw/src/main/java/org/apache/cxf/dosgi/dsw/service/RemoteServiceAdminCore.java b/trunk/dsw/cxf-dsw/src/main/java/org/apache/cxf/dosgi/dsw/service/RemoteServiceAdminCore.java
new file mode 100644
index 0000000..e9bafa5
--- /dev/null
+++ b/trunk/dsw/cxf-dsw/src/main/java/org/apache/cxf/dosgi/dsw/service/RemoteServiceAdminCore.java
@@ -0,0 +1,515 @@
+/**
+ * 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.dsw.service;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Dictionary;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Hashtable;
+import java.util.Iterator;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import org.apache.cxf.dosgi.dsw.handlers.ConfigTypeHandlerFactory;
+import org.apache.cxf.dosgi.dsw.handlers.ConfigurationTypeHandler;
+import org.apache.cxf.dosgi.dsw.handlers.ExportResult;
+import org.apache.cxf.dosgi.dsw.util.ClassUtils;
+import org.apache.cxf.dosgi.dsw.util.OsgiUtils;
+import org.apache.cxf.dosgi.dsw.util.Utils;
+import org.osgi.framework.Bundle;
+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;
+import org.osgi.framework.ServiceRegistration;
+import org.osgi.service.remoteserviceadmin.EndpointDescription;
+import org.osgi.service.remoteserviceadmin.ExportReference;
+import org.osgi.service.remoteserviceadmin.ExportRegistration;
+import org.osgi.service.remoteserviceadmin.ImportReference;
+import org.osgi.service.remoteserviceadmin.ImportRegistration;
+import org.osgi.service.remoteserviceadmin.RemoteConstants;
+import org.osgi.service.remoteserviceadmin.RemoteServiceAdmin;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class RemoteServiceAdminCore implements RemoteServiceAdmin {
+
+    private static final Logger LOG = LoggerFactory.getLogger(RemoteServiceAdminCore.class);
+
+    private final Map<Map<String, Object>, Collection<ExportRegistration>> exportedServices
+        = new LinkedHashMap<Map<String, Object>, Collection<ExportRegistration>>();
+    private final Map<EndpointDescription, Collection<ImportRegistrationImpl>> importedServices
+        = new LinkedHashMap<EndpointDescription, Collection<ImportRegistrationImpl>>();
+
+    // Is stored in exportedServices while the export is in progress as a marker
+    private final List<ExportRegistration> exportInProgress = Collections.emptyList();
+
+    private final BundleContext bctx;
+    private final EventProducer eventProducer;
+    private final ConfigTypeHandlerFactory configTypeHandlerFactory;
+    private final ServiceListener exportedServiceListener;
+
+    public RemoteServiceAdminCore(BundleContext bc, ConfigTypeHandlerFactory configTypeHandlerFactory) {
+        this.bctx = bc;
+        this.eventProducer = new EventProducer(bctx);
+        this.configTypeHandlerFactory = configTypeHandlerFactory;
+        // listen for exported services being unregistered so we can close the export
+        this.exportedServiceListener = new ServiceListener() {
+            public void serviceChanged(ServiceEvent event) {
+                if (event.getType() == ServiceEvent.UNREGISTERING) {
+                    removeServiceExports(event.getServiceReference());
+                }
+            }
+        };
+        try {
+            String filter = "(" + RemoteConstants.SERVICE_EXPORTED_INTERFACES + "=*)";
+            bc.addServiceListener(exportedServiceListener, filter);
+        } catch (InvalidSyntaxException ise) {
+            throw new RuntimeException(ise); // can never happen
+        }
+    }
+
+    @Override
+    @SuppressWarnings({ "rawtypes", "unchecked" })
+    public List<ExportRegistration> exportService(ServiceReference serviceReference, Map additionalProperties)
+        throws IllegalArgumentException, UnsupportedOperationException {
+        Map<String, Object> serviceProperties = OsgiUtils.getProperties(serviceReference);
+        if (additionalProperties != null) {
+            OsgiUtils.overlayProperties(serviceProperties, additionalProperties);
+        }
+        Map<String, Object> key = makeKey(serviceProperties);
+
+        List<String> interfaces = getInterfaces(serviceProperties);
+
+        if (isCreatedByThisRSA(serviceReference)) {
+            LOG.debug("Skipping export of this service as we created it ourselves as a proxy {}", interfaces);
+            // TODO: publish error event? Not sure
+            return Collections.emptyList();
+        }
+
+        synchronized (exportedServices) {
+            // check if it is already exported...
+            Collection<ExportRegistration> existingRegs = exportedServices.get(key);
+
+            // if the export is already in progress, wait for it to be complete
+            while (existingRegs == exportInProgress) {
+                try {
+                    exportedServices.wait();
+                    existingRegs = exportedServices.get(key);
+                } catch (InterruptedException ie) {
+                    LOG.debug("interrupted while waiting for export in progress");
+                    return Collections.emptyList();
+                }
+            }
+
+            // if the export is complete, return a copy of existing export
+            if (existingRegs != null) {
+                LOG.debug("already exported this service. Returning existing exportRegs {} ", interfaces);
+                return copyExportRegistration(existingRegs);
+            }
+
+            // mark export as being in progress
+            exportedServices.put(key, exportInProgress);
+        }
+
+        try {
+            // do the export
+            List<ExportRegistration> exportRegs = exportInterfaces(interfaces, serviceReference, serviceProperties);
+            if (!exportRegs.isEmpty()) {
+                // enlist initial export registrations in global list of exportRegistrations
+                synchronized (exportedServices) {
+                    exportedServices.put(key, new ArrayList<ExportRegistration>(exportRegs));
+                }
+                eventProducer.publishNotification(exportRegs);
+            }
+            return exportRegs;
+        } finally {
+            synchronized (exportedServices) {
+                if (exportedServices.get(key) == exportInProgress) {
+                    exportedServices.remove(key);
+                }
+                exportedServices.notifyAll(); // in any case, always notify waiting threads
+            }
+        }
+    }
+
+    private List<ExportRegistration> exportInterfaces(List<String> interfaces,
+            ServiceReference serviceReference, Map<String, Object> serviceProperties) {
+        LOG.info("interfaces selected for export: " + interfaces);
+        ConfigurationTypeHandler handler;
+        try {
+            handler = configTypeHandlerFactory.getHandler(bctx, serviceProperties);
+        } catch (RuntimeException e) {
+            LOG.error(e.getMessage(), e);
+            return Collections.emptyList();
+        }
+        List<ExportRegistration> exportRegs = new ArrayList<ExportRegistration>(1);
+        Object service = bctx.getService(serviceReference);
+        Bundle bundle = serviceReference.getBundle();
+
+        // if service has been unregistered in the meantime
+        if (service == null || bundle == null) {
+            LOG.info("service has been unregistered, aborting export");
+            return exportRegs;
+        }
+
+        for (String iface : interfaces) {
+            LOG.info("creating server for interface " + iface);
+            // this is an extra sanity check, but do we really need it now?
+            Class<?> interfaceClass = ClassUtils.getInterfaceClass(service, iface);
+            if (interfaceClass != null) {
+                ExportResult exportResult = handler.createServer(serviceReference, bctx, bundle.getBundleContext(),
+                    serviceProperties, interfaceClass, service);
+                EndpointDescription endpoint = new EndpointDescription(exportResult.getEndpointProps());
+                ExportRegistrationImpl exportRegistration;
+                if (exportResult.getException() == null) {
+                    LOG.info("created server for interface " + iface);
+                    exportRegistration = new ExportRegistrationImpl(serviceReference, endpoint, this,
+                            exportResult.getServer());
+                } else {
+                    LOG.error("failed to create server for interface " + iface, exportResult.getException());
+                    exportRegistration = new ExportRegistrationImpl(serviceReference, endpoint, this,
+                            exportResult.getException());
+                }
+                exportRegs.add(exportRegistration);
+            }
+        }
+        return exportRegs;
+    }
+
+    /**
+     * Determines which interfaces should be exported.
+     *
+     * @param serviceProperties the exported service properties
+     * @return the interfaces to be exported
+     * @throws IllegalArgumentException if the service parameters are invalid
+     * @see RemoteServiceAdmin#exportService
+     * @see org.osgi.framework.Constants#OBJECTCLASS
+     * @see RemoteConstants#SERVICE_EXPORTED_INTERFACES
+     */
+    private List<String> getInterfaces(Map<String, Object> serviceProperties) {
+        String[] providedInterfaces = (String[])serviceProperties.get(org.osgi.framework.Constants.OBJECTCLASS);
+        if (providedInterfaces == null || providedInterfaces.length == 0) {
+            throw new IllegalArgumentException("service is missing the objectClass property");
+        }
+
+        String[] allowedInterfaces
+            = Utils.normalizeStringPlus(serviceProperties.get(RemoteConstants.SERVICE_EXPORTED_INTERFACES));
+        if (allowedInterfaces == null || allowedInterfaces.length == 0) {
+            throw new IllegalArgumentException("service is missing the service.exported.interfaces property");
+        }
+
+        List<String> interfaces = new ArrayList<String>(1);
+        if (allowedInterfaces.length == 1 && "*".equals(allowedInterfaces[0])) {
+            // FIXME: according to the spec, this should only return the interfaces, and not
+            // non-interface classes (which are valid OBJECTCLASS values, even if discouraged)
+            Collections.addAll(interfaces, providedInterfaces);
+        } else {
+            List<String> providedList = Arrays.asList(providedInterfaces);
+            List<String> allowedList = Arrays.asList(allowedInterfaces);
+            if (!providedList.containsAll(allowedList)) {
+                throw new IllegalArgumentException(String.format(
+                    "exported interfaces %s must be a subset of the service's registered types %s",
+                    allowedList, providedList));
+            }
+
+            Collections.addAll(interfaces, allowedInterfaces);
+        }
+        return interfaces;
+    }
+
+    /**
+     * Converts the given properties map into one that can be used as a map key itself.
+     * For example, if a value is an array, it is converted into a list so that the
+     * equals method will compare it properly.
+     *
+     * @param properties a properties map
+     * @return a map that represents the given map, but can be safely used as a map key itself
+     */
+    private Map<String, Object> makeKey(Map<String, Object> properties) {
+        // FIXME: we should also make logically equal values actually compare as equal
+        // (e.g. String+ values should be normalized)
+        Map<String, Object> converted = new HashMap<String, Object>(properties.size());
+        for (Map.Entry<String, Object> entry : properties.entrySet()) {
+            Object val = entry.getValue();
+            // convert arrays into lists so that they can be compared via equals()
+            if (val instanceof Object[]) {
+                val = Arrays.asList((Object[])val);
+            }
+            converted.put(entry.getKey(), val);
+        }
+        return converted;
+    }
+
+    private List<ExportRegistration> copyExportRegistration(Collection<ExportRegistration> regs) {
+        Set<EndpointDescription> copiedEndpoints = new HashSet<EndpointDescription>();
+
+        // create a new list with copies of the exportRegistrations
+        List<ExportRegistration> copy = new ArrayList<ExportRegistration>(regs.size());
+        for (ExportRegistration exportRegistration : regs) {
+            if (exportRegistration instanceof ExportRegistrationImpl) {
+                ExportRegistrationImpl exportRegistrationImpl = (ExportRegistrationImpl) exportRegistration;
+                EndpointDescription epd = exportRegistration.getExportReference().getExportedEndpoint();
+                // create one copy for each distinct endpoint description
+                if (!copiedEndpoints.contains(epd)) {
+                    copiedEndpoints.add(epd);
+                    copy.add(new ExportRegistrationImpl(exportRegistrationImpl));
+                }
+            }
+        }
+
+        regs.addAll(copy);
+
+        eventProducer.publishNotification(copy);
+        return copy;
+    }
+
+    private boolean isCreatedByThisRSA(ServiceReference sref) {
+        return bctx.getBundle().equals(sref.getBundle()); // sref bundle can be null
+    }
+
+    @Override
+    public Collection<ExportReference> getExportedServices() {
+        synchronized (exportedServices) {
+            List<ExportReference> ers = new ArrayList<ExportReference>();
+            for (Collection<ExportRegistration> exportRegistrations : exportedServices.values()) {
+                for (ExportRegistration er : exportRegistrations) {
+                    ers.add(new ExportReferenceImpl(er.getExportReference()));
+                }
+            }
+            return Collections.unmodifiableCollection(ers);
+        }
+    }
+
+    @Override
+    public Collection<ImportReference> getImportedEndpoints() {
+        synchronized (importedServices) {
+            List<ImportReference> irs = new ArrayList<ImportReference>();
+            for (Collection<ImportRegistrationImpl> irl : importedServices.values()) {
+                for (ImportRegistrationImpl impl : irl) {
+                    irs.add(impl.getImportReference());
+                }
+            }
+            return Collections.unmodifiableCollection(irs);
+        }
+    }
+
+    /**
+     * Importing form here...
+     */
+    @Override
+    public ImportRegistration importService(EndpointDescription endpoint) {
+        LOG.debug("importService() Endpoint: {}", endpoint.getProperties());
+
+        synchronized (importedServices) {
+            Collection<ImportRegistrationImpl> imRegs = importedServices.get(endpoint);
+            if (imRegs != null && !imRegs.isEmpty()) {
+                LOG.debug("creating copy of existing import registrations");
+                ImportRegistrationImpl irParent = imRegs.iterator().next();
+                ImportRegistrationImpl ir = new ImportRegistrationImpl(irParent);
+                imRegs.add(ir);
+                eventProducer.publishNotification(ir);
+                return ir;
+            }
+
+            ConfigurationTypeHandler handler;
+            try {
+                handler = configTypeHandlerFactory.getHandler(bctx, endpoint);
+            } catch (RuntimeException e) {
+                LOG.error("no handler found: " + e.getMessage(), e);
+                return null;
+            }
+
+            LOG.debug("Handler: {}", handler);
+
+            // TODO: somehow select the interfaces that should be imported ---> job of the TopologyManager?
+            List<String> matchingInterfaces = endpoint.getInterfaces();
+
+            LOG.info("Matching Interfaces for import: " + matchingInterfaces);
+
+            if (matchingInterfaces.size() == 1) {
+                LOG.info("Proxifying interface: " + matchingInterfaces.get(0));
+
+                ImportRegistrationImpl imReg = new ImportRegistrationImpl(endpoint, this);
+
+                proxifyMatchingInterface(matchingInterfaces.get(0), imReg, handler, bctx);
+                if (imRegs == null) {
+                    imRegs = new ArrayList<ImportRegistrationImpl>();
+                    importedServices.put(endpoint, imRegs);
+                }
+                imRegs.add(imReg);
+                eventProducer.publishNotification(imReg);
+                return imReg;
+            }
+            return null;
+        }
+    }
+
+    protected void proxifyMatchingInterface(String interfaceName, ImportRegistrationImpl imReg,
+                                            ConfigurationTypeHandler handler, BundleContext requestingContext) {
+        try {
+            // MARC: relies on dynamic imports?
+            Class<?> iClass = bctx.getBundle().loadClass(interfaceName);
+            if (iClass == null) {
+                throw new ClassNotFoundException("Cannot load interface class");
+            }
+
+            BundleContext actualContext = bctx;
+            Class<?> actualClass = requestingContext.getBundle().loadClass(interfaceName);
+            if (actualClass != iClass) {
+                LOG.info("Class " + interfaceName + " loaded by DSW's bundle context is not "
+                             + "equal to the one loaded by the requesting bundle context, "
+                             + "DSW will use the requesting bundle context to register a proxy service");
+                iClass = actualClass;
+                actualContext = requestingContext;
+            }
+
+            EndpointDescription endpoint = imReg.getImportedEndpointDescription();
+            /* TODO: add additional local params... */
+            Dictionary<String, Object> serviceProps = new Hashtable<String, Object>(endpoint.getProperties());
+            serviceProps.put(RemoteConstants.SERVICE_IMPORTED, true);
+            serviceProps.remove(RemoteConstants.SERVICE_EXPORTED_INTERFACES);
+
+            ClientServiceFactory csf = new ClientServiceFactory(actualContext, iClass, endpoint, handler, imReg);
+            imReg.setClientServiceFactory(csf);
+            ServiceRegistration proxyReg = actualContext.registerService(interfaceName, csf, serviceProps);
+            imReg.setImportedServiceRegistration(proxyReg);
+        } catch (Exception ex) {
+            // Only logging at debug level as this might be written to the log at the TopologyManager
+            LOG.debug("Can not proxy service with interface " + interfaceName + ": " + ex.getMessage(), ex);
+            imReg.setException(ex);
+        }
+    }
+
+    /**
+     * Removes and closes all exports for the given service.
+     * This is called when the service is unregistered.
+     *
+     * @param sref the service whose exports should be removed and closed
+     */
+    protected void removeServiceExports(ServiceReference sref) {
+        List<ExportRegistration> regs = new ArrayList<ExportRegistration>(1);
+        synchronized (exportedServices) {
+            for (Iterator<Collection<ExportRegistration>> it = exportedServices.values().iterator(); it.hasNext();) {
+                Collection<ExportRegistration> value = it.next();
+                for (Iterator<ExportRegistration> it2 = value.iterator(); it2.hasNext();) {
+                    ExportRegistration er = it2.next();
+                    if (er.getExportReference().getExportedService().equals(sref)) {
+                        regs.add(er);
+                    }
+                }
+            }
+            // do this outside of iteration to avoid concurrent modification
+            for (ExportRegistration er : regs) {
+                LOG.debug("closing export for service {}", sref);
+                er.close();
+            }
+        }
+
+    }
+
+    /**
+     * Removes the provided Export Registration from the internal management structures.
+     * This is called from the ExportRegistration itself when it is closed (so should
+     * not attempt to close it again here).
+     *
+     * @param eri the export registration to remove
+     */
+    protected void removeExportRegistration(ExportRegistrationImpl eri) {
+        synchronized (exportedServices) {
+            for (Iterator<Collection<ExportRegistration>> it = exportedServices.values().iterator(); it.hasNext();) {
+                Collection<ExportRegistration> value = it.next();
+                for (Iterator<ExportRegistration> it2 = value.iterator(); it2.hasNext();) {
+                    ExportRegistration er = it2.next();
+                    if (er.equals(eri)) {
+                        eventProducer.notifyRemoval(eri);
+                        it2.remove();
+                        if (value.isEmpty()) {
+                            it.remove();
+                        }
+                        return;
+                    }
+                }
+            }
+        }
+    }
+
+    // remove all export registrations associated with the given bundle
+    protected void removeExportRegistrations(Bundle exportingBundle) {
+        List<ExportRegistration> bundleExports = getExportsForBundle(exportingBundle);
+        for (ExportRegistration export : bundleExports) {
+            export.close();
+        }
+    }
+
+    // remove all import registrations
+    protected void removeImportRegistrations() {
+        Collection<ImportRegistrationImpl> copy = new ArrayList<ImportRegistrationImpl>();
+        synchronized (importedServices) {
+            for (Collection<ImportRegistrationImpl> irs : importedServices.values()) {
+                copy.addAll(irs);
+            }
+        }
+        for (ImportRegistrationImpl ir : copy) {
+            removeImportRegistration(ir);
+        }
+    }
+
+    private List<ExportRegistration> getExportsForBundle(Bundle exportingBundle) {
+        synchronized (exportedServices) {
+            List<ExportRegistration> bundleRegs = new ArrayList<ExportRegistration>();
+            for (Collection<ExportRegistration> regs : exportedServices.values()) {
+                if (!regs.isEmpty()) {
+                    Bundle regBundle = regs.iterator().next().getExportReference().getExportedService().getBundle();
+                    if (exportingBundle.equals(regBundle)) {
+                        bundleRegs.addAll(regs);
+                    }
+                }
+            }
+            return bundleRegs;
+        }
+    }
+
+    protected void removeImportRegistration(ImportRegistrationImpl iri) {
+        synchronized (importedServices) {
+            LOG.debug("Removing importRegistration {}", iri);
+
+            Collection<ImportRegistrationImpl> imRegs = importedServices.get(iri.getImportedEndpointAlways());
+            if (imRegs != null && imRegs.contains(iri)) {
+                imRegs.remove(iri);
+                eventProducer.notifyRemoval(iri);
+            }
+            if (imRegs == null || imRegs.isEmpty()) {
+                importedServices.remove(iri.getImportedEndpointAlways());
+            }
+        }
+    }
+
+    public void close() {
+        removeImportRegistrations();
+        bctx.removeServiceListener(exportedServiceListener);
+    }
+}
diff --git a/trunk/dsw/cxf-dsw/src/main/java/org/apache/cxf/dosgi/dsw/service/RemoteServiceAdminInstance.java b/trunk/dsw/cxf-dsw/src/main/java/org/apache/cxf/dosgi/dsw/service/RemoteServiceAdminInstance.java
new file mode 100644
index 0000000..286ce54
--- /dev/null
+++ b/trunk/dsw/cxf-dsw/src/main/java/org/apache/cxf/dosgi/dsw/service/RemoteServiceAdminInstance.java
@@ -0,0 +1,93 @@
+/**
+ * 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.dsw.service;
+
+import java.security.AccessController;
+import java.security.PrivilegedAction;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.cxf.dosgi.dsw.util.OsgiUtils;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.ServiceReference;
+import org.osgi.service.remoteserviceadmin.EndpointDescription;
+import org.osgi.service.remoteserviceadmin.EndpointPermission;
+import org.osgi.service.remoteserviceadmin.ExportReference;
+import org.osgi.service.remoteserviceadmin.ExportRegistration;
+import org.osgi.service.remoteserviceadmin.ImportReference;
+import org.osgi.service.remoteserviceadmin.ImportRegistration;
+import org.osgi.service.remoteserviceadmin.RemoteServiceAdmin;
+
+import static org.apache.cxf.dosgi.dsw.util.OsgiUtils.checkPermission;
+
+public class RemoteServiceAdminInstance implements RemoteServiceAdmin {
+
+    private final BundleContext bctx;
+    private final RemoteServiceAdminCore rsaCore;
+
+    private boolean closed;
+
+    public RemoteServiceAdminInstance(BundleContext bc, RemoteServiceAdminCore core) {
+        bctx = bc;
+        rsaCore = core;
+    }
+
+    @Override
+    @SuppressWarnings("rawtypes")
+    public List<ExportRegistration> exportService(final ServiceReference ref, final Map properties) {
+        checkPermission(new EndpointPermission("*", EndpointPermission.EXPORT));
+        return AccessController.doPrivileged(new PrivilegedAction<List<ExportRegistration>>() {
+            public List<ExportRegistration> run() {
+                return closed ? Collections.<ExportRegistration>emptyList() : rsaCore.exportService(ref, properties);
+            }
+        });
+    }
+
+    @Override
+    public Collection<ExportReference> getExportedServices() {
+        checkPermission(new EndpointPermission("*", EndpointPermission.READ));
+        return closed ? null : rsaCore.getExportedServices();
+    }
+
+    @Override
+    public Collection<ImportReference> getImportedEndpoints() {
+        checkPermission(new EndpointPermission("*", EndpointPermission.READ));
+        return closed ? null : rsaCore.getImportedEndpoints();
+    }
+
+    @Override
+    public ImportRegistration importService(final EndpointDescription endpoint) {
+        checkPermission(new EndpointPermission(endpoint, OsgiUtils.getUUID(bctx), EndpointPermission.IMPORT));
+        return AccessController.doPrivileged(new PrivilegedAction<ImportRegistration>() {
+            public ImportRegistration run() {
+                return closed ? null : rsaCore.importService(endpoint);
+            }
+        });
+    }
+
+    public void close(boolean closeAll) {
+        closed = true;
+        rsaCore.removeExportRegistrations(bctx.getBundle());
+        if (closeAll) {
+            rsaCore.close();
+        }
+    }
+}
diff --git a/trunk/dsw/cxf-dsw/src/main/java/org/apache/cxf/dosgi/dsw/service/RemoteServiceadminFactory.java b/trunk/dsw/cxf-dsw/src/main/java/org/apache/cxf/dosgi/dsw/service/RemoteServiceadminFactory.java
new file mode 100644
index 0000000..11f91c9
--- /dev/null
+++ b/trunk/dsw/cxf-dsw/src/main/java/org/apache/cxf/dosgi/dsw/service/RemoteServiceadminFactory.java
@@ -0,0 +1,49 @@
+/**
+ * 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.dsw.service;
+
+import org.osgi.framework.Bundle;
+import org.osgi.framework.ServiceFactory;
+import org.osgi.framework.ServiceRegistration;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class RemoteServiceadminFactory implements ServiceFactory {
+
+    private static final Logger LOG = LoggerFactory.getLogger(RemoteServiceadminFactory.class);
+
+    private final RemoteServiceAdminCore rsaCore;
+    private int instances;
+
+    public RemoteServiceadminFactory(RemoteServiceAdminCore rsaCore) {
+        this.rsaCore = rsaCore;
+    }
+
+    public synchronized Object getService(Bundle b, ServiceRegistration sreg) {
+        LOG.debug("new RemoteServiceAdmin ServiceInstance created for Bundle {}", b.getSymbolicName());
+        instances++;
+        return new RemoteServiceAdminInstance(b.getBundleContext(), rsaCore);
+    }
+
+    public synchronized void ungetService(Bundle b, ServiceRegistration sreg, Object serviceObject) {
+        LOG.debug("RemoteServiceAdmin ServiceInstance removed for Bundle {}", b.getSymbolicName());
+        instances--;
+        ((RemoteServiceAdminInstance)serviceObject).close(instances == 0);
+    }
+}
diff --git a/trunk/dsw/cxf-dsw/src/main/java/org/apache/cxf/dosgi/dsw/util/ClassUtils.java b/trunk/dsw/cxf-dsw/src/main/java/org/apache/cxf/dosgi/dsw/util/ClassUtils.java
new file mode 100644
index 0000000..d51527b
--- /dev/null
+++ b/trunk/dsw/cxf-dsw/src/main/java/org/apache/cxf/dosgi/dsw/util/ClassUtils.java
@@ -0,0 +1,142 @@
+/**
+ * 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.dsw.util;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.cxf.helpers.CastUtils;
+import org.osgi.framework.BundleContext;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public final class ClassUtils {
+
+    private static final Logger LOG = LoggerFactory.getLogger(ClassUtils.class);
+
+    private ClassUtils() {
+    }
+
+    public static Class<?> getInterfaceClass(Object service, String interfaceName) {
+        return getInterfaceClass(service.getClass(), interfaceName);
+    }
+
+    private static Class<?> getInterfaceClass(Class<?> serviceClass, String interfaceName) {
+        for (Class<?> iClass : serviceClass.getInterfaces()) {
+            if (iClass.getName().equals(interfaceName)) {
+                return iClass;
+            }
+            Class<?> intf = getInterfaceClass(iClass, interfaceName);
+            if (intf != null) {
+                return intf;
+            }
+        }
+
+        if (serviceClass.getName().equals(interfaceName)) {
+            return serviceClass;
+        }
+
+        Class<?> interfaceOnProxiedClass = getInterfaceClassOnSuperClasses(serviceClass, interfaceName);
+        if (interfaceOnProxiedClass != null) {
+            return interfaceOnProxiedClass;
+        }
+
+        return null;
+    }
+
+    /**
+     * This method tries to deal specifically with classes that might have been proxied
+     * eg. CGLIB proxies of which there might be a chain of proxies as different osgi frameworks
+     * might be proxying the original service class that has been registered and then proxying the proxy.
+     *
+     * @param serviceClass
+     * @param interfaceName
+     * @return
+     */
+    private static Class<?> getInterfaceClassOnSuperClasses(Class<?> serviceClass, String interfaceName) {
+        Class<?> superClass = serviceClass.getSuperclass();
+        if (superClass != null) {
+            for (Class<?> iClass : superClass.getInterfaces()) {
+                if (iClass.getName().equals(interfaceName)) {
+                    return iClass;
+                }
+                Class<?> intf = getInterfaceClass(iClass, interfaceName);
+                if (intf != null) {
+                    return intf;
+                }
+            }
+            Class<?> foundOnSuperclass = getInterfaceClassOnSuperClasses(superClass, interfaceName);
+            if (foundOnSuperclass != null) {
+                return foundOnSuperclass;
+            }
+        }
+        return null;
+    }
+
+    public static List<Object> loadProviderClasses(BundleContext callingContext,
+                                                   Map<String, Object> sd, String propName) {
+        Object serviceProviders = sd.get(propName);
+        if (serviceProviders != null) {
+            if (serviceProviders.getClass().isArray()) {
+                if (serviceProviders.getClass().getComponentType() == String.class) {
+                    return loadProviders(callingContext, (String[])serviceProviders);
+                } else {
+                    return Arrays.asList((Object[])serviceProviders);
+                }
+            } else if (serviceProviders.getClass() == String.class) {
+                String[] classNames = serviceProviders.toString().split(",");
+                return loadProviders(callingContext, classNames);
+            } else if (serviceProviders instanceof List) { 
+                List<Object> list = CastUtils.cast((List<?>)serviceProviders);
+                if (!list.isEmpty()) {
+                    List<Object> providers;
+                    if (list.get(0).getClass() == String.class) {
+                        providers = loadProviders(callingContext, list.toArray(new String[]{}));
+                    } else {
+                        providers = list;
+                    }
+                    return providers;
+                }
+            } else {
+                return Arrays.asList(serviceProviders);
+            }
+        }
+        return Collections.emptyList();
+        
+    }
+
+    private static List<Object> loadProviders(BundleContext callingContext, String[] classNames) {
+        List<Object> providers = new ArrayList<Object>();
+        for (String className : classNames) {
+            try {
+                String realName = className.trim();
+                if (!realName.isEmpty()) {
+                    Class<?> pClass = callingContext.getBundle().loadClass(realName);
+                    providers.add(pClass.newInstance());
+                }
+            } catch (Exception ex) {
+                LOG.warn("Provider " + className.trim() + " can not be loaded or created " + ex.getMessage(), ex);
+            }
+        }
+        return providers;
+    }
+}
diff --git a/trunk/dsw/cxf-dsw/src/main/java/org/apache/cxf/dosgi/dsw/util/OsgiUtils.java b/trunk/dsw/cxf-dsw/src/main/java/org/apache/cxf/dosgi/dsw/util/OsgiUtils.java
new file mode 100644
index 0000000..9f4216d
--- /dev/null
+++ b/trunk/dsw/cxf-dsw/src/main/java/org/apache/cxf/dosgi/dsw/util/OsgiUtils.java
@@ -0,0 +1,196 @@
+/**
+ * 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.dsw.util;
+
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.UUID;
+
+import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.ServiceReference;
+import org.osgi.service.packageadmin.ExportedPackage;
+import org.osgi.service.packageadmin.PackageAdmin;
+import org.osgi.service.remoteserviceadmin.EndpointDescription;
+import org.osgi.service.remoteserviceadmin.EndpointPermission;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public final class OsgiUtils {
+
+    public static final Logger LOG = LoggerFactory.getLogger(OsgiUtils.class);
+
+    private OsgiUtils() {
+    }
+
+    public static boolean getBooleanProperty(Map<String, Object> sd, String name) {
+        return toBoolean(sd.get(name));
+    }
+
+    public static boolean toBoolean(Object value) {
+        return value instanceof Boolean && (Boolean) value
+            || value instanceof String && Boolean.parseBoolean((String)value);
+    }
+
+    @SuppressWarnings("unchecked")
+    public static Collection<String> getMultiValueProperty(Object property) {
+        if (property == null) {
+            return null;
+        } else if (property instanceof Collection) {
+            return (Collection<String>)property;
+        } else if (property instanceof String[]) {
+            return Arrays.asList((String[])property);
+        } else {
+            return Collections.singleton(property.toString());
+        }
+    }
+
+    public static String getProperty(EndpointDescription endpoint, String name) {
+        return getProperty(endpoint.getProperties(), name);
+    }
+
+    public static String getProperty(Map<String, Object> dict, String name) {
+        Object value = dict.get(name);
+        return value instanceof String ? (String) value : null;
+    }
+
+    public static String getFirstNonEmptyStringProperty(Map<String, Object> dict, String ... keys) {
+        for (String key : keys) {
+            String value = getProperty(dict, key);
+            if (value != null) {
+                return value;
+            }
+        }
+        return null;
+    }
+
+    /**
+     * Tries to retrieve the version of iClass via the PackageAdmin.
+     *
+     * @param iClass tThe interface for which the version should be found
+     * @param bc any valid BundleContext
+     * @return the version of the interface or "0.0.0" if no version information could be found or an error
+     *         occurred during the retrieval
+     */
+    public static String getVersion(Class<?> iClass, BundleContext bc) {
+        ServiceReference paRef = bc.getServiceReference(PackageAdmin.class.getName());
+        if (paRef != null) {
+            PackageAdmin pa = (PackageAdmin)bc.getService(paRef);
+            try {
+                Bundle b = pa.getBundle(iClass);
+                if (b == null) {
+                    LOG.info("Unable to find interface version for interface " + iClass.getName()
+                            + ". Falling back to 0.0.0");
+                    return "0.0.0";
+                }
+                LOG.debug("Interface source bundle: {}", b.getSymbolicName());
+
+                ExportedPackage[] ep = pa.getExportedPackages(b);
+                LOG.debug("Exported Packages of the source bundle: {}", ep);
+
+                String pack = iClass.getPackage().getName();
+                LOG.debug("Looking for Package: {}", pack);
+                if (ep != null) {
+                    for (ExportedPackage p : ep) {
+                        if (p != null
+                            && pack.equals(p.getName())) {
+                            LOG.debug("found package -> Version: {}", p.getVersion());
+                            return p.getVersion().toString();
+                        }
+                    }
+                }
+            } finally {
+                if (pa != null) {
+                    bc.ungetService(paRef);
+                }
+            }
+        } else {
+            LOG.error("Was unable to obtain the package admin service -> can't resolve interface versions");
+        }
+
+        LOG.info("Unable to find interface version for interface " + iClass.getName()
+                 + ". Falling back to 0.0.0");
+        return "0.0.0";
+    }
+
+    public static String getUUID(BundleContext bc) {
+        synchronized ("org.osgi.framework.uuid") {
+            String uuid = bc.getProperty("org.osgi.framework.uuid");
+            if (uuid == null) {
+                uuid = UUID.randomUUID().toString();
+                System.setProperty("org.osgi.framework.uuid", uuid);
+            }
+            return uuid;
+        }
+    }
+
+    public static void overlayProperties(Map<String, Object> serviceProperties,
+                                         Map<String, Object> additionalProperties) {
+        Map<String, String> keysLowerCase = new HashMap<String, String>();
+        for (String key : serviceProperties.keySet()) {
+            keysLowerCase.put(key.toLowerCase(), key);
+        }
+
+        for (Map.Entry<String, Object> e : additionalProperties.entrySet()) {
+            String key = e.getKey();
+            String lowerKey = key.toLowerCase();
+            if (org.osgi.framework.Constants.SERVICE_ID.toLowerCase().equals(lowerKey)
+                || org.osgi.framework.Constants.OBJECTCLASS.toLowerCase().equals(lowerKey)) {
+                // objectClass and service.id must not be overwritten
+                LOG.info("exportService called with additional properties map that contained illegal key: "
+                          + key + ", the key is ignored");
+            } else {
+                String origKey = keysLowerCase.get(lowerKey);
+                if (origKey != null) {
+                    LOG.debug("Overwriting property [{}] with value [{}]", origKey, e.getValue());
+                } else {
+                    origKey = key;
+                    keysLowerCase.put(lowerKey, origKey);
+                }
+                serviceProperties.put(origKey, e.getValue());
+            }
+        }
+    }
+
+    /**
+     * Returns a service's properties as a map.
+     *
+     * @param serviceReference a service reference
+     * @return the service's properties as a map
+     */
+    public static Map<String, Object> getProperties(ServiceReference serviceReference) {
+        String[] keys = serviceReference.getPropertyKeys();
+        Map<String, Object> props = new HashMap<String, Object>(keys.length);
+        for (String key : keys) {
+            Object val = serviceReference.getProperty(key);
+            props.put(key, val);
+        }
+        return props;
+    }
+
+    public static void checkPermission(EndpointPermission permission) {
+        SecurityManager sm = System.getSecurityManager();
+        if (sm != null) {
+            sm.checkPermission(permission);
+        }
+    }
+}
diff --git a/trunk/dsw/cxf-dsw/src/main/java/org/apache/cxf/dosgi/dsw/util/Utils.java b/trunk/dsw/cxf-dsw/src/main/java/org/apache/cxf/dosgi/dsw/util/Utils.java
new file mode 100644
index 0000000..a101d21
--- /dev/null
+++ b/trunk/dsw/cxf-dsw/src/main/java/org/apache/cxf/dosgi/dsw/util/Utils.java
@@ -0,0 +1,94 @@
+/**
+ * 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.dsw.util;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Dictionary;
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public final class Utils {
+
+    private static final Logger LOG = LoggerFactory.getLogger(Utils.class);
+
+    private Utils() {
+        // never constructed
+    }
+
+    @SuppressWarnings("rawtypes")
+    public static String[] normalizeStringPlus(Object object) {
+        if (object instanceof String) {
+            String s = (String)object;
+            String[] values = s.split(",");
+            List<String> list = new ArrayList<String>();
+            for (String val : values) {
+                String actualValue = val.trim();
+                if (!actualValue.isEmpty()) {
+                    list.add(actualValue);
+                }
+            }
+            return list.toArray(new String[list.size()]);
+        }
+
+        if (object instanceof String[]) {
+            return (String[])object;
+        }
+        
+        if (object instanceof Collection) {
+            Collection col = (Collection)object;
+            List<String> ar = new ArrayList<String>(col.size());
+            for (Object o : col) {
+                if (o instanceof String) {
+                    String s = (String)o;
+                    ar.add(s);
+                } else {
+                    LOG.warn("stringPlus contained non string element in list! Element was skipped");
+                }
+            }
+            return ar.toArray(new String[ar.size()]);
+        }
+
+        return null;
+    }
+
+    public static <K, V> Map<K, V> toMap(Dictionary<K, V> dict) {
+        Map<K, V> map = new HashMap<K, V>();
+        if (dict == null) {
+            return map;
+        }
+        Enumeration<K> keys = dict.keys();
+        while (keys.hasMoreElements()) {
+            K key = keys.nextElement();
+            map.put(key, dict.get(key));
+        }
+        return map;
+    }
+
+    public static <K, V> void setIfNotNull(Map<K, V> map, K key, V val) {
+        if (val != null) {
+            map.put(key, val);
+        }
+    }
+}
diff --git a/trunk/dsw/cxf-dsw/src/main/resources/service-decoration.xsd b/trunk/dsw/cxf-dsw/src/main/resources/service-decoration.xsd
new file mode 100644
index 0000000..66e8d30
--- /dev/null
+++ b/trunk/dsw/cxf-dsw/src/main/resources/service-decoration.xsd
@@ -0,0 +1,67 @@
+<?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.
+-->
+<schema targetNamespace="http://cxf.apache.org/xmlns/service-decoration/1.0.0" xmlns="http://www.w3.org/2001/XMLSchema" xmlns:tns="http://cxf.apache.org/xmlns/service-decoration/1.0.0">
+    <element name="service-decorations" type="tns:ServiceDecorationsType"></element>
+
+    <complexType name="ServiceDecorationsType">
+        <sequence>
+            <element maxOccurs="unbounded" minOccurs="0"
+                ref="tns:service-decoration">
+            </element>
+        </sequence>
+    </complexType>
+
+    <complexType name="ServiceDecorationType">
+        <sequence>
+            <element maxOccurs="unbounded" minOccurs="0"
+                ref="tns:match">
+            </element>
+        </sequence>
+    </complexType>
+
+    <complexType name="MatchType">
+        <sequence>
+            <element maxOccurs="unbounded" minOccurs="0"
+                ref="tns:match-property">
+            </element>
+            <element maxOccurs="unbounded" minOccurs="0"
+                ref="tns:add-property">
+            </element>
+        </sequence>
+        <attribute name="interface" type="string"></attribute>
+    </complexType>
+
+    <complexType name="MatchPropertyType">
+        <attribute name="name" type="string"></attribute>
+        <attribute name="value" type="string"></attribute>
+    </complexType>
+
+    <complexType name="AddPropertyType">
+        <attribute name="name" type="string"></attribute>
+        <attribute name="value" type="string"></attribute>
+        <attribute name="type" type="string"></attribute>
+    </complexType>
+    <element name="service-decoration"
+        type="tns:ServiceDecorationType">
+    </element>
+    <element name="match" type="tns:MatchType"></element>
+    <element name="match-property" type="tns:MatchPropertyType"></element>
+    <element name="add-property" type="tns:AddPropertyType"></element>
+</schema>
\ No newline at end of file
diff --git a/trunk/dsw/cxf-dsw/src/test/java/org/apache/cxf/dosgi/dsw/ActivatorTest.java b/trunk/dsw/cxf-dsw/src/test/java/org/apache/cxf/dosgi/dsw/ActivatorTest.java
new file mode 100644
index 0000000..62007c7
--- /dev/null
+++ b/trunk/dsw/cxf-dsw/src/test/java/org/apache/cxf/dosgi/dsw/ActivatorTest.java
@@ -0,0 +1,63 @@
+/**
+ * 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.dsw;
+
+import java.util.Dictionary;
+import java.util.Hashtable;
+
+import junit.framework.TestCase;
+
+import org.easymock.EasyMock;
+import org.easymock.IMocksControl;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.Filter;
+import org.osgi.framework.ServiceRegistration;
+import org.osgi.service.remoteserviceadmin.RemoteServiceAdmin;
+
+public class ActivatorTest extends TestCase {
+
+    private BundleContext getMockBundleContext(IMocksControl control) {
+        Bundle b = control.createMock(Bundle.class);
+        Dictionary<String, String> ht = new Hashtable<String, String>();
+        EasyMock.expect(b.getHeaders()).andReturn(ht).anyTimes();
+        BundleContext bc = control.createMock(BundleContext.class);
+
+        EasyMock.expect(b.getBundleContext()).andReturn(bc).anyTimes();
+        EasyMock.expect(bc.getBundle()).andReturn(b).anyTimes();
+        return bc;
+    }
+
+    public void testCreateAndShutdownRemoteServiceAdminService() throws Exception {
+        IMocksControl control = EasyMock.createNiceControl();
+        BundleContext bc = getMockBundleContext(control);
+        Filter filter = control.createMock(Filter.class);
+        EasyMock.expect(bc.createFilter(EasyMock.<String>anyObject())).andReturn(filter);
+        EasyMock.expectLastCall().atLeastOnce();
+        ServiceRegistration sr = control.createMock(ServiceRegistration.class);
+        EasyMock.expect(bc.registerService(EasyMock.eq(RemoteServiceAdmin.class.getName()),
+                                           EasyMock.anyObject(), (Dictionary<String, String>)EasyMock.anyObject()))
+                                           .andReturn(sr).atLeastOnce();
+
+        control.replay();
+        Activator a = new Activator();
+        a.start(bc);
+        control.verify();
+    }
+}
diff --git a/trunk/dsw/cxf-dsw/src/test/java/org/apache/cxf/dosgi/dsw/TestUtils.java b/trunk/dsw/cxf-dsw/src/test/java/org/apache/cxf/dosgi/dsw/TestUtils.java
new file mode 100644
index 0000000..b81bf3e
--- /dev/null
+++ b/trunk/dsw/cxf-dsw/src/test/java/org/apache/cxf/dosgi/dsw/TestUtils.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.dsw;
+
+public final class TestUtils {
+
+//    private TestUtils() {
+//    }
+//
+//    public static ServiceEndpointDescription mockServiceDescription(String... interfaceNames) {
+//        List<String> iList = new ArrayList<String>();
+//        for (String iName : interfaceNames) {
+//            iList.add(iName);
+//        }
+//
+//        ServiceEndpointDescription sd = EasyMock.createNiceMock(ServiceEndpointDescription.class);
+//        sd.getProvidedInterfaces();
+//        EasyMock.expectLastCall().andReturn(iList);
+//        return sd;
+//    }
+}
diff --git a/trunk/dsw/cxf-dsw/src/test/java/org/apache/cxf/dosgi/dsw/decorator/DecorationParserTest.java b/trunk/dsw/cxf-dsw/src/test/java/org/apache/cxf/dosgi/dsw/decorator/DecorationParserTest.java
new file mode 100644
index 0000000..37c018a
--- /dev/null
+++ b/trunk/dsw/cxf-dsw/src/test/java/org/apache/cxf/dosgi/dsw/decorator/DecorationParserTest.java
@@ -0,0 +1,60 @@
+/**
+ * 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.dsw.decorator;
+
+import java.net.URL;
+import java.util.List;
+
+import org.apache.cxf.xmlns.service_decoration._1_0.AddPropertyType;
+import org.apache.cxf.xmlns.service_decoration._1_0.MatchPropertyType;
+import org.apache.cxf.xmlns.service_decoration._1_0.MatchType;
+import org.apache.cxf.xmlns.service_decoration._1_0.ServiceDecorationType;
+import org.junit.Assert;
+import org.junit.Test;
+
+import static org.junit.Assert.assertEquals;
+
+public class DecorationParserTest {
+
+    @Test
+    public void testGetDecoratorForSD() {
+        URL resource = getClass().getResource("/test-resources/sd.xml");
+        List<ServiceDecorationType> elements = new DecorationParser().getDecorations(resource);
+        assertEquals(1, elements.size());
+        ServiceDecorationType decoration = elements.get(0);
+        assertEquals(1, decoration.getMatch().size());
+        MatchType match = decoration.getMatch().get(0);
+        assertEquals("org.acme.foo.*", match.getInterface());
+        assertEquals(1, match.getMatchProperty().size());
+        MatchPropertyType matchProp = match.getMatchProperty().get(0);
+        assertEquals("test.prop", matchProp.getName());
+        assertEquals("xyz", matchProp.getValue());
+        assertEquals(1, match.getAddProperty().size());
+        AddPropertyType addProp = match.getAddProperty().get(0);
+        assertEquals("test.too", addProp.getName());
+        assertEquals("ahaha", addProp.getValue());
+        assertEquals("java.lang.String", addProp.getType());
+    }
+
+    @Test
+    public void testGetDecorationForNull() {
+        List<ServiceDecorationType> elements = new DecorationParser().getDecorations(null);
+        Assert.assertEquals(0, elements.size());
+    }
+}
diff --git a/trunk/dsw/cxf-dsw/src/test/java/org/apache/cxf/dosgi/dsw/decorator/InterfaceRuleTest.java b/trunk/dsw/cxf-dsw/src/test/java/org/apache/cxf/dosgi/dsw/decorator/InterfaceRuleTest.java
new file mode 100644
index 0000000..8b45d28
--- /dev/null
+++ b/trunk/dsw/cxf-dsw/src/test/java/org/apache/cxf/dosgi/dsw/decorator/InterfaceRuleTest.java
@@ -0,0 +1,162 @@
+/**
+ * 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.dsw.decorator;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import junit.framework.TestCase;
+
+import org.easymock.EasyMock;
+import org.easymock.IAnswer;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.Constants;
+import org.osgi.framework.ServiceReference;
+
+public class InterfaceRuleTest extends TestCase {
+
+    public void testDUMMY() {
+        assertTrue(true);
+    }
+
+    public void testInterfaceRuleGetBundle() {
+        Bundle b = EasyMock.createMock(Bundle.class);
+        EasyMock.replay(b);
+        InterfaceRule ir = new InterfaceRule(b, "org.apache.Foo");
+        assertSame(b, ir.getBundle());
+    }
+
+    public void testInterfaceRule1() {
+        InterfaceRule ir = new InterfaceRule(null, "org.apache.Foo");
+        ir.addProperty("x", "y", String.class.getName());
+
+        final Map<String, Object> serviceProps = new HashMap<String, Object>();
+        serviceProps.put(Constants.OBJECTCLASS, new String[] {"a.b.C", "org.apache.Foo"});
+        ServiceReference sref = mockServiceReference(serviceProps);
+
+        Map<String, Object> m = new HashMap<String, Object>();
+        m.put("a", "b");
+        ir.apply(sref, m);
+        Map<String, Object> expected = new HashMap<String, Object>();
+        expected.put("a", "b");
+        expected.put("x", "y");
+        assertEquals(expected, m);
+    }
+
+    public void testInterfaceRule2() {
+        InterfaceRule ir = new InterfaceRule(null, "org.apache.F(.*)");
+        ir.addPropMatch("boo", "baah");
+        ir.addProperty("x", "1", Integer.class.getName());
+        ir.addProperty("aaa.bbb", "true", Boolean.class.getName());
+
+        final Map<String, Object> serviceProps = new HashMap<String, Object>();
+        serviceProps.put("boo", "baah");
+        serviceProps.put(Constants.OBJECTCLASS, new String[] {"a.b.C", "org.apache.Foo"});
+        ServiceReference sref = mockServiceReference(serviceProps);
+
+        Map<String, Object> m = new HashMap<String, Object>();
+        ir.apply(sref, m);
+        Map<String, Object> expected = new HashMap<String, Object>();
+        expected.put("x", 1);
+        expected.put("aaa.bbb", Boolean.TRUE);
+        assertEquals(expected, m);
+    }
+
+    public void testInterfaceRule3() {
+        InterfaceRule ir = new InterfaceRule(null, "org.apache.F(.*)");
+        ir.addProperty("x", "y", String.class.getName());
+
+        final Map<String, Object> serviceProps = new HashMap<String, Object>();
+        serviceProps.put("boo", "baah");
+        serviceProps.put(Constants.OBJECTCLASS, new String[] {"org.apache.Boo"});
+        ServiceReference sref = mockServiceReference(serviceProps);
+
+        Map<String, Object> m = new HashMap<String, Object>();
+        ir.apply(sref, m);
+        assertEquals(0, m.size());
+    }
+
+    public void testInterfaceRule4() {
+        InterfaceRule ir = new InterfaceRule(null, "org.apache.F(.*)");
+        ir.addPropMatch("boo", "baah");
+        ir.addProperty("x", "y", String.class.getName());
+
+        final Map<String, Object> serviceProps = new HashMap<String, Object>();
+        serviceProps.put(Constants.OBJECTCLASS, new String[] {"org.apache.Foo"});
+        ServiceReference sref = mockServiceReference(serviceProps);
+
+        Map<String, Object> m = new HashMap<String, Object>();
+        ir.apply(sref, m);
+        assertEquals(0, m.size());
+    }
+
+    public void testInterfaceRule5() {
+        InterfaceRule ir = new InterfaceRule(null, "org.apache.Foo");
+        ir.addPropMatch("test.int", "42");
+        ir.addProperty("x", "1", Long.class.getName());
+
+        final Map<String, Object> serviceProps = new HashMap<String, Object>();
+        serviceProps.put("test.int", 42);
+        serviceProps.put(Constants.OBJECTCLASS, new String[] {"org.apache.Foo"});
+        ServiceReference sref = mockServiceReference(serviceProps);
+
+        Map<String, Object> m = new HashMap<String, Object>();
+        m.put("x", "foo");
+        m.put("aaa.bbb", Boolean.TRUE);
+        ir.apply(sref, m);
+        Map<String, Object> expected = new HashMap<String, Object>();
+        expected.put("x", 1L);
+        expected.put("aaa.bbb", Boolean.TRUE);
+        assertEquals(expected, m);
+    }
+
+    public void testInterfaceRule6() {
+        InterfaceRule ir = new InterfaceRule(null, "org.apache.Foo");
+        ir.addPropMatch("test.int", "42");
+        ir.addProperty("x", "1", Long.class.getName());
+
+        final Map<String, Object> serviceProps = new HashMap<String, Object>();
+        serviceProps.put("test.int", 51);
+        serviceProps.put(Constants.OBJECTCLASS, new String[] {"org.apache.Foo"});
+        ServiceReference sref = mockServiceReference(serviceProps);
+
+        Map<String, Object> m = new HashMap<String, Object>();
+        m.put("x", "foo");
+        m.put("aaa.bbb", Boolean.TRUE);
+        ir.apply(sref, m);
+        Map<String, Object> expected = new HashMap<String, Object>();
+        expected.put("x", "foo");
+        expected.put("aaa.bbb", Boolean.TRUE);
+        assertEquals(expected, m);
+    }
+
+    private ServiceReference mockServiceReference(final Map<String, Object> serviceProps) {
+        ServiceReference sref = EasyMock.createMock(ServiceReference.class);
+        EasyMock.expect(sref.getProperty((String) EasyMock.anyObject())).andAnswer(new IAnswer<Object>() {
+            public Object answer() throws Throwable {
+                return serviceProps.get(EasyMock.getCurrentArguments()[0]);
+            }
+        }).anyTimes();
+        EasyMock.expect(sref.getPropertyKeys())
+            .andReturn(serviceProps.keySet().toArray(new String[] {})).anyTimes();
+
+        EasyMock.replay(sref);
+        return sref;
+    }
+}
diff --git a/trunk/dsw/cxf-dsw/src/test/java/org/apache/cxf/dosgi/dsw/decorator/ServiceDecoratorBundleListenerTest.java b/trunk/dsw/cxf-dsw/src/test/java/org/apache/cxf/dosgi/dsw/decorator/ServiceDecoratorBundleListenerTest.java
new file mode 100644
index 0000000..1ca33fc
--- /dev/null
+++ b/trunk/dsw/cxf-dsw/src/test/java/org/apache/cxf/dosgi/dsw/decorator/ServiceDecoratorBundleListenerTest.java
@@ -0,0 +1,69 @@
+/**
+ * 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.dsw.decorator;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+import org.easymock.EasyMock;
+import org.junit.Test;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.BundleEvent;
+
+import static org.junit.Assert.assertEquals;
+
+public class ServiceDecoratorBundleListenerTest {
+
+    @Test
+    public void testBundleListener() {
+        BundleContext bc = EasyMock.createMock(BundleContext.class);
+        EasyMock.replay(bc);
+
+        final List<String> called = new ArrayList<String>();
+        ServiceDecoratorImpl serviceDecorator = new ServiceDecoratorImpl() {
+            @Override
+            void addDecorations(Bundle bundle) {
+                called.add("addDecorations");
+            }
+
+            @Override
+            void removeDecorations(Bundle bundle) {
+                called.add("removeDecorations");
+            }
+        };
+
+        Bundle b = EasyMock.createMock(Bundle.class);
+        EasyMock.replay(b);
+        
+        ServiceDecoratorBundleListener listener = new ServiceDecoratorBundleListener(serviceDecorator);
+
+        assertEquals("Precondition failed", 0, called.size());
+        listener.bundleChanged(new BundleEvent(BundleEvent.INSTALLED, b));
+        assertEquals(0, called.size());
+
+        listener.bundleChanged(new BundleEvent(BundleEvent.STARTED, b));
+        assertEquals(Arrays.asList("addDecorations"), called);
+
+        listener.bundleChanged(new BundleEvent(BundleEvent.STOPPING, b));
+        assertEquals(Arrays.asList("addDecorations", "removeDecorations"), called);
+
+    }
+}
diff --git a/trunk/dsw/cxf-dsw/src/test/java/org/apache/cxf/dosgi/dsw/decorator/ServiceDecoratorImplTest.java b/trunk/dsw/cxf-dsw/src/test/java/org/apache/cxf/dosgi/dsw/decorator/ServiceDecoratorImplTest.java
new file mode 100644
index 0000000..b770b89
--- /dev/null
+++ b/trunk/dsw/cxf-dsw/src/test/java/org/apache/cxf/dosgi/dsw/decorator/ServiceDecoratorImplTest.java
@@ -0,0 +1,184 @@
+/**
+ * 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.dsw.decorator;
+
+import java.net.URL;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+
+import junit.framework.Assert;
+import junit.framework.TestCase;
+
+import org.easymock.EasyMock;
+import org.easymock.IAnswer;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.Constants;
+import org.osgi.framework.ServiceReference;
+
+public class ServiceDecoratorImplTest extends TestCase {
+    private static final Map<String, Object> EMPTY = new HashMap<String, Object>();
+    private static final URL RES_SD = getResource("/test-resources/sd.xml");
+    private static final URL RES_SD1 = getResource("/test-resources/sd1.xml");
+    private static final URL RES_SD2 = getResource("/test-resources/sd2.xml");
+    private static final URL RES_SD0 = getResource("/test-resources/sd0.xml");
+    private static final URL RES_SD_1 = getResource("/test-resources/sd-1.xml");
+
+    public void testAddRemoveDecorations() {
+        final Map<String, Object> serviceProps = new HashMap<String, Object>();
+        serviceProps.put(Constants.OBJECTCLASS, new String[] {"org.acme.foo.Bar"});
+        serviceProps.put("test.prop", "xyz");
+
+        Bundle b = createBundleContaining(RES_SD);
+        ServiceDecoratorImpl sd = new ServiceDecoratorImpl();
+        assertEquals("Precondition failed", 0, sd.decorations.size());
+        sd.addDecorations(b);
+        assertEquals(1, sd.decorations.size());
+
+        Map<String, Object> target = new HashMap<String, Object>();
+        ServiceReference sref = EasyMock.createMock(ServiceReference.class);
+        EasyMock.expect(sref.getProperty((String) EasyMock.anyObject())).andAnswer(new IAnswer<Object>() {
+            public Object answer() throws Throwable {
+                return serviceProps.get(EasyMock.getCurrentArguments()[0]);
+            }
+        }).anyTimes();
+        EasyMock.replay(sref);
+        sd.decorate(sref, target);
+
+        Map<String, Object> expected = new HashMap<String, Object>();
+        expected.put("test.too", "ahaha");
+        assertEquals(expected, target);
+
+        // remove it again
+        sd.removeDecorations(b);
+        assertEquals(0, sd.decorations.size());
+        Map<String, Object> target2 = new HashMap<String, Object>();
+        sd.decorate(sref, target2);
+        assertEquals(EMPTY, target2);
+    }
+
+    public void testAddDecorations() {
+        final Map<String, Object> serviceProps = new HashMap<String, Object>();
+        serviceProps.put(Constants.OBJECTCLASS, new String[] {"org.acme.foo.Bar"});
+        serviceProps.put("test.prop", "xyz");
+
+        Map<String, Object> expected = new HashMap<String, Object>();
+        expected.put("test.too", "ahaha");
+        assertDecorate(serviceProps, expected, RES_SD);
+    }
+
+    public void testAddDecorations1() {
+        Map<String, Object> serviceProps = new HashMap<String, Object>();
+        serviceProps.put(Constants.OBJECTCLASS, new String[] {"org.test.A"});
+
+        Map<String, Object> expected = new HashMap<String, Object>();
+        expected.put("A", "B");
+        expected.put("C", 2);
+        assertDecorate(serviceProps, expected, RES_SD1, RES_SD2);
+    }
+
+    public void testAddDecorations2() {
+        Map<String, Object> serviceProps = new HashMap<String, Object>();
+        serviceProps.put(Constants.OBJECTCLASS, new String[] {"org.test.D"});
+
+        assertDecorate(serviceProps, EMPTY, RES_SD1, RES_SD2);
+    }
+
+    public void testAddDecorations3() {
+        Map<String, Object> serviceProps = new HashMap<String, Object>();
+        serviceProps.put(Constants.OBJECTCLASS, new String[] {"org.test.B"});
+        serviceProps.put("x", "y");
+
+        Map<String, Object> expected = new HashMap<String, Object>();
+        expected.put("bool", Boolean.TRUE);
+        assertDecorate(serviceProps, expected, RES_SD1, RES_SD2);
+    }
+
+    public void testAddDecorations4() {
+        Map<String, Object> serviceProps = new HashMap<String, Object>();
+        serviceProps.put(Constants.OBJECTCLASS, new String[] {"org.test.C"});
+        serviceProps.put("x", "z");
+
+        Map<String, Object> expected = new HashMap<String, Object>();
+        expected.put("bool", Boolean.FALSE);
+        assertDecorate(serviceProps, expected, RES_SD1, RES_SD2);
+    }
+
+    public void testAddDecorations5() {
+        Map<String, Object> serviceProps = new HashMap<String, Object>();
+        serviceProps.put(Constants.OBJECTCLASS, new String[] {"org.test.C"});
+        serviceProps.put("x", "x");
+
+        assertDecorate(serviceProps, EMPTY, RES_SD1, RES_SD2);
+    }
+
+    public void testAddDecorations6() {
+        Map<String, Object> serviceProps = new HashMap<String, Object>();
+        serviceProps.put(Constants.OBJECTCLASS, new String[] {"org.test.D"});
+
+        assertDecorate(serviceProps, EMPTY, RES_SD0);
+    }
+
+    public void testAddDecorations7() {
+        Map<String, Object> serviceProps = new HashMap<String, Object>();
+        serviceProps.put(Constants.OBJECTCLASS, new String[] {"org.test.D"});
+
+        assertDecorate(serviceProps, EMPTY, RES_SD_1);
+    }
+    
+    private void assertDecorate(final Map<String, Object> serviceProps, 
+                                Map<String, Object> expected, URL ... resources) {
+        Map<String, Object> actual = testDecorate(serviceProps, resources);
+        assertEquals(expected, actual);
+    }
+
+    private Map<String, Object> testDecorate(final Map<String, Object> serviceProps, URL ... resources) {
+        Bundle b = createBundleContaining(resources);
+
+        ServiceDecoratorImpl sd = new ServiceDecoratorImpl();
+        sd.addDecorations(b);
+
+        Map<String, Object> target = new HashMap<String, Object>();
+        ServiceReference sref = EasyMock.createMock(ServiceReference.class);
+        EasyMock.expect(sref.getProperty((String) EasyMock.anyObject())).andAnswer(new IAnswer<Object>() {
+            public Object answer() throws Throwable {
+                return serviceProps.get(EasyMock.getCurrentArguments()[0]);
+            }
+        }).anyTimes();
+        EasyMock.replay(sref);
+        sd.decorate(sref, target);
+        return target;
+    }
+
+    private Bundle createBundleContaining(URL... resources) {
+        Bundle b = EasyMock.createMock(Bundle.class);
+        EasyMock.expect(b.findEntries("OSGI-INF/remote-service", "*.xml", false)).andReturn(
+            Collections.enumeration(Arrays.asList(resources))).anyTimes();
+        EasyMock.replay(b);
+        return b;
+    }
+
+    private static URL getResource(String path) {
+        URL resource = ServiceDecoratorImplTest.class.getResource(path);
+        Assert.assertNotNull("Resource " + path + " not found!", resource);
+        return resource;
+    }
+
+}
diff --git a/trunk/dsw/cxf-dsw/src/test/java/org/apache/cxf/dosgi/dsw/handlers/ClientServiceFactoryTest.java b/trunk/dsw/cxf-dsw/src/test/java/org/apache/cxf/dosgi/dsw/handlers/ClientServiceFactoryTest.java
new file mode 100644
index 0000000..315c55b
--- /dev/null
+++ b/trunk/dsw/cxf-dsw/src/test/java/org/apache/cxf/dosgi/dsw/handlers/ClientServiceFactoryTest.java
@@ -0,0 +1,70 @@
+/**
+ * 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.dsw.handlers;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import junit.framework.TestCase;
+
+import org.apache.cxf.dosgi.dsw.service.ClientServiceFactory;
+import org.apache.cxf.dosgi.dsw.service.ImportRegistrationImpl;
+import org.easymock.EasyMock;
+import org.easymock.IMocksControl;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.Constants;
+import org.osgi.framework.ServiceReference;
+import org.osgi.framework.ServiceRegistration;
+import org.osgi.service.remoteserviceadmin.EndpointDescription;
+import org.osgi.service.remoteserviceadmin.RemoteConstants;
+
+public class ClientServiceFactoryTest extends TestCase {
+
+    public void testGetService() {
+        Object myTestProxyObject = new Object();
+
+        IMocksControl control = EasyMock.createNiceControl();
+        BundleContext dswContext = control.createMock(BundleContext.class);
+        Map<String, Object> map = new HashMap<String, Object>();
+        map.put(RemoteConstants.ENDPOINT_ID, "http://google.de");
+        map.put(RemoteConstants.SERVICE_IMPORTED_CONFIGS, "myGreatConfiguration");
+        map.put(Constants.OBJECTCLASS, new String[]{"my.class"});
+
+        EndpointDescription endpoint = new EndpointDescription(map);
+        ConfigurationTypeHandler handler = control.createMock(ConfigurationTypeHandler.class);
+
+        ImportRegistrationImpl iri = new ImportRegistrationImpl(endpoint, null);
+
+        BundleContext requestingContext = control.createMock(BundleContext.class);
+        Bundle requestingBundle = control.createMock(Bundle.class);
+        EasyMock.expect(requestingBundle.getBundleContext()).andReturn(requestingContext);
+
+        ServiceReference sr = control.createMock(ServiceReference.class);
+        ServiceRegistration sreg = control.createMock(ServiceRegistration.class);
+        EasyMock.expect(sreg.getReference()).andReturn(sr);
+
+        handler.createProxy(sr, dswContext, requestingContext, String.class, endpoint);
+        EasyMock.expectLastCall().andReturn(myTestProxyObject);
+        control.replay();
+
+        ClientServiceFactory csf = new ClientServiceFactory(dswContext, String.class, endpoint, handler, iri);
+        assertSame(myTestProxyObject, csf.getService(requestingBundle, sreg));
+    }
+}
diff --git a/trunk/dsw/cxf-dsw/src/test/java/org/apache/cxf/dosgi/dsw/handlers/ConfigTypeHandlerFactoryTest.java b/trunk/dsw/cxf-dsw/src/test/java/org/apache/cxf/dosgi/dsw/handlers/ConfigTypeHandlerFactoryTest.java
new file mode 100644
index 0000000..a74b194
--- /dev/null
+++ b/trunk/dsw/cxf-dsw/src/test/java/org/apache/cxf/dosgi/dsw/handlers/ConfigTypeHandlerFactoryTest.java
@@ -0,0 +1,112 @@
+/**
+ * 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.dsw.handlers;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import org.apache.cxf.dosgi.dsw.Constants;
+import org.apache.cxf.dosgi.dsw.qos.DefaultIntentMapFactory;
+import org.apache.cxf.dosgi.dsw.qos.IntentManager;
+import org.apache.cxf.dosgi.dsw.qos.IntentManagerImpl;
+import org.apache.cxf.dosgi.dsw.qos.IntentMap;
+import org.easymock.EasyMock;
+import org.junit.Test;
+import org.osgi.framework.BundleContext;
+import org.osgi.service.remoteserviceadmin.RemoteConstants;
+
+import static org.junit.Assert.assertTrue;
+
+public class ConfigTypeHandlerFactoryTest {
+
+    @Test
+    public void testGetDefaultHandlerNoIntents() {
+        ConfigurationTypeHandler handler = getHandlerWith(null, null);
+        assertTrue(handler instanceof PojoConfigurationTypeHandler);
+    }
+
+    @Test
+    public void testGetJaxrsHandlerNoIntents() {
+        ConfigurationTypeHandler handler = getHandlerWith(Constants.RS_CONFIG_TYPE, null);
+        assertTrue(handler instanceof JaxRSPojoConfigurationTypeHandler);
+    }
+
+    @Test
+    public void testGetJaxrsHandlerHttpIntents() {
+        ConfigurationTypeHandler handler = getHandlerWith(Constants.RS_CONFIG_TYPE, "HTTP");
+        assertTrue(handler instanceof JaxRSPojoConfigurationTypeHandler);
+    }
+
+    @Test
+    public void testJaxrsPropertyIgnored() {
+        ConfigurationTypeHandler handler = getHandlerWith(Constants.RS_CONFIG_TYPE, "SOAP HTTP");
+        assertTrue(handler instanceof PojoConfigurationTypeHandler);
+        assertTrue(!(handler instanceof JaxRSPojoConfigurationTypeHandler));
+    }
+
+    @Test
+    public void testJaxrsPropertyIgnored2() {
+        ConfigurationTypeHandler handler = getHandlerWith2(Constants.RS_CONFIG_TYPE, new String[] {"HTTP", "SOAP"});
+        assertTrue(handler instanceof PojoConfigurationTypeHandler);
+        assertTrue(!(handler instanceof JaxRSPojoConfigurationTypeHandler));
+    }
+
+    @Test
+    public void testGetPojoHandler() {
+        ConfigurationTypeHandler handler = getHandlerWith(Constants.WS_CONFIG_TYPE, null);
+        assertTrue(handler instanceof PojoConfigurationTypeHandler);
+    }
+
+    @Test
+    public void testGetWSDLHandler() {
+        ConfigurationTypeHandler handler = getHandlerWith(Constants.WSDL_CONFIG_TYPE, null);
+        assertTrue(handler instanceof WsdlConfigurationTypeHandler);
+    }
+
+    @Test(expected = RuntimeException.class)
+    public void testUnsupportedConfiguration() {
+        getHandlerWith("notSupportedConfig", null);
+    }
+
+    private ConfigurationTypeHandler getHandlerWith(String configType, String intents) {
+        BundleContext bc = EasyMock.createNiceMock(BundleContext.class);
+        EasyMock.replay(bc);
+        Map<String, Object> serviceProps = new HashMap<String, Object>();
+        serviceProps.put(RemoteConstants.SERVICE_EXPORTED_CONFIGS, configType);
+        serviceProps.put(RemoteConstants.SERVICE_EXPORTED_INTENTS, intents);
+        IntentMap intentMap = new IntentMap(new DefaultIntentMapFactory().create());
+        IntentManager intentManager = new IntentManagerImpl(intentMap);
+        HttpServiceManager httpServiceManager = new HttpServiceManager(bc, null, null);
+        ConfigTypeHandlerFactory f = new ConfigTypeHandlerFactory(bc, intentManager, httpServiceManager);
+        return f.getHandler(bc, serviceProps);
+    }
+
+    private ConfigurationTypeHandler getHandlerWith2(String configType, String[] intents) {
+        BundleContext bc = EasyMock.createNiceMock(BundleContext.class);
+        EasyMock.replay(bc);
+        Map<String, Object> serviceProps = new HashMap<String, Object>();
+        serviceProps.put(RemoteConstants.SERVICE_EXPORTED_CONFIGS, configType);
+        serviceProps.put(RemoteConstants.SERVICE_EXPORTED_INTENTS, intents);
+        IntentMap intentMap = new IntentMap(new DefaultIntentMapFactory().create());
+        IntentManager intentManager = new IntentManagerImpl(intentMap);
+        HttpServiceManager httpServiceManager = new HttpServiceManager(bc, null, null);
+        ConfigTypeHandlerFactory f = new ConfigTypeHandlerFactory(bc, intentManager, httpServiceManager);
+        return f.getHandler(bc, serviceProps);
+    }
+}
diff --git a/trunk/dsw/cxf-dsw/src/test/java/org/apache/cxf/dosgi/dsw/handlers/HttpServiceManagerTest.java b/trunk/dsw/cxf-dsw/src/test/java/org/apache/cxf/dosgi/dsw/handlers/HttpServiceManagerTest.java
new file mode 100644
index 0000000..208c457
--- /dev/null
+++ b/trunk/dsw/cxf-dsw/src/test/java/org/apache/cxf/dosgi/dsw/handlers/HttpServiceManagerTest.java
@@ -0,0 +1,124 @@
+/**
+ * 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.dsw.handlers;
+
+import java.util.Dictionary;
+
+import javax.servlet.Servlet;
+import javax.servlet.ServletConfig;
+import javax.servlet.ServletContext;
+import javax.servlet.ServletException;
+
+import junit.framework.Assert;
+import junit.framework.TestCase;
+
+import org.apache.cxf.Bus;
+import org.easymock.Capture;
+import org.easymock.EasyMock;
+import org.easymock.IMocksControl;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.Filter;
+import org.osgi.framework.ServiceEvent;
+import org.osgi.framework.ServiceListener;
+import org.osgi.framework.ServiceReference;
+import org.osgi.service.http.HttpContext;
+import org.osgi.service.http.HttpService;
+import org.osgi.service.http.NamespaceException;
+
+import static org.easymock.EasyMock.expect;
+import static org.easymock.EasyMock.expectLastCall;
+
+public class HttpServiceManagerTest extends TestCase {
+
+    public void testGetAbsoluteAddress() {
+        IMocksControl c = EasyMock.createControl();
+        BundleContext bundleContext = c.createMock(BundleContext.class);
+        c.replay();
+        HttpServiceManager manager = new HttpServiceManager(bundleContext, null, null, null);
+        String localIp = LocalHostUtil.getLocalIp();
+
+        String address1 = manager.getAbsoluteAddress(null, "/myservice");
+        assertEquals("http://" + localIp + ":8181/cxf/myservice", address1);
+
+        String address2 = manager.getAbsoluteAddress("/mycontext", "/myservice");
+        assertEquals("http://" + localIp + ":8181/mycontext/myservice", address2);
+
+        c.verify();
+    }
+
+    public void testRegisterAndUnregisterServlet() throws Exception {
+        IMocksControl c = EasyMock.createControl();
+        BundleContext dswContext = c.createMock(BundleContext.class);
+        Filter filter = c.createMock(Filter.class);
+        expect(dswContext.createFilter(EasyMock.eq("(service.id=12345)"))).andReturn(filter).once();
+        Capture<ServiceListener> captured = new Capture<ServiceListener>();
+        dswContext.addServiceListener(EasyMock.capture(captured), EasyMock.<String>anyObject());
+        expectLastCall().atLeastOnce();
+        expect(dswContext.getProperty("org.apache.cxf.httpservice.requirefilter")).andReturn(null).atLeastOnce();
+        ServletConfig config = c.createMock(ServletConfig.class);
+        expect(config.getInitParameter(EasyMock.<String>anyObject())).andReturn(null).atLeastOnce();
+        ServletContext servletContext = c.createMock(ServletContext.class);
+        expect(config.getServletContext()).andReturn(servletContext);
+        final HttpService httpService = new DummyHttpService(config);
+        ServiceReference sr = c.createMock(ServiceReference.class);
+        expect(sr.getProperty(EasyMock.eq("service.id"))).andReturn(12345L).atLeastOnce();
+        expect(servletContext.getResourceAsStream((String)EasyMock.anyObject())).andReturn(null).anyTimes();
+        c.replay();
+
+        HttpServiceManager h = new HttpServiceManager(dswContext, null, null, null) {
+            @Override
+            protected HttpService getHttpService() {
+                return httpService;
+            }
+        };
+        Bus bus = h.registerServletAndGetBus("/myService", dswContext, sr);
+        Assert.assertNotNull(bus);
+
+        ServiceEvent event = new ServiceEvent(ServiceEvent.UNREGISTERING, sr);
+        captured.getValue().serviceChanged(event);
+        c.verify();
+    }
+
+    static class DummyHttpService implements HttpService {
+
+        private ServletConfig config;
+
+        public DummyHttpService(ServletConfig config) {
+            this.config = config;
+        }
+
+        @SuppressWarnings("rawtypes")
+        public void registerServlet(String alias, Servlet servlet, Dictionary initparams, HttpContext context)
+            throws ServletException, NamespaceException {
+            Assert.assertEquals("/myService", alias);
+            servlet.init(config);
+        }
+
+        public void registerResources(String alias, String name, HttpContext context) throws NamespaceException {
+            throw new RuntimeException("This method should not be called");
+        }
+
+        public void unregister(String alias) {
+        }
+
+        public HttpContext createDefaultHttpContext() {
+            return EasyMock.createNiceMock(HttpContext.class);
+        }
+    }
+}
diff --git a/trunk/dsw/cxf-dsw/src/test/java/org/apache/cxf/dosgi/dsw/handlers/JaxRSUtilsTest.java b/trunk/dsw/cxf-dsw/src/test/java/org/apache/cxf/dosgi/dsw/handlers/JaxRSUtilsTest.java
new file mode 100644
index 0000000..b0976af
--- /dev/null
+++ b/trunk/dsw/cxf-dsw/src/test/java/org/apache/cxf/dosgi/dsw/handlers/JaxRSUtilsTest.java
@@ -0,0 +1,185 @@
+/**
+ * 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.dsw.handlers;
+
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import junit.framework.TestCase;
+
+import org.apache.cxf.dosgi.dsw.Constants;
+import org.apache.cxf.jaxrs.provider.JAXBElementProvider;
+import org.apache.cxf.jaxrs.provider.aegis.AegisElementProvider;
+import org.easymock.EasyMock;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.ServiceReference;
+import org.osgi.service.remoteserviceadmin.RemoteConstants;
+
+public class JaxRSUtilsTest extends TestCase {
+
+    private void addRequiredProps(Map<String, Object> props) {
+        props.put(RemoteConstants.ENDPOINT_ID, "http://google.de");
+        props.put(RemoteConstants.SERVICE_IMPORTED_CONFIGS, "myGreatConfiguration");
+        props.put(org.osgi.framework.Constants.OBJECTCLASS, new String[] {"my.class"});
+    }
+
+    public void testNoGlobalProviders() {
+        Map<String, Object> props = new HashMap<String, Object>();
+        addRequiredProps(props);
+        props.put(Constants.RS_PROVIDER_GLOBAL_PROP_KEY, "false");
+
+        assertEquals(0, JaxRSUtils.getProviders(null, props).size());
+    }
+
+    public void testAegisProvider() {
+        Map<String, Object> props = new HashMap<String, Object>();
+        props.put(Constants.RS_DATABINDING_PROP_KEY, "aegis");
+        props.put(Constants.RS_PROVIDER_GLOBAL_PROP_KEY, "false");
+
+        addRequiredProps(props);
+
+        List<Object> providers = JaxRSUtils.getProviders(null, props);
+        assertEquals(1, providers.size());
+        assertEquals(AegisElementProvider.class.getName(), providers.get(0).getClass().getName());
+    }
+
+    public void testServiceProviders() {
+        Map<String, Object> props = new HashMap<String, Object>();
+        props.put(Constants.RS_PROVIDER_PROP_KEY, new Object[] {
+            new AegisElementProvider()
+        });
+        props.put(Constants.RS_PROVIDER_GLOBAL_PROP_KEY, "false");
+        addRequiredProps(props);
+
+        List<Object> providers = JaxRSUtils.getProviders(null, props);
+        assertEquals(1, providers.size());
+        assertEquals(AegisElementProvider.class.getName(), providers.get(0).getClass().getName());
+    }
+
+    public void testServiceProviderProperty() throws Exception {
+        BundleContext bc = EasyMock.createMock(BundleContext.class);
+        Bundle bundle = EasyMock.createMock(Bundle.class);
+        bc.getBundle();
+        EasyMock.expectLastCall().andReturn(bundle).times(2);
+        bundle.loadClass(AegisElementProvider.class.getName());
+        EasyMock.expectLastCall().andReturn(AegisElementProvider.class);
+        bundle.loadClass(JAXBElementProvider.class.getName());
+        EasyMock.expectLastCall().andReturn(JAXBElementProvider.class);
+        EasyMock.replay(bc, bundle);
+
+        Map<String, Object> props = new HashMap<String, Object>();
+        props.put(Constants.RS_PROVIDER_PROP_KEY,
+                "\r\n " + AegisElementProvider.class.getName() + " , \r\n"
+                        + JAXBElementProvider.class.getName() + "\r\n");
+
+        props.put(Constants.RS_PROVIDER_GLOBAL_PROP_KEY, "false");
+        addRequiredProps(props);
+
+        List<Object> providers = JaxRSUtils.getProviders(bc, props);
+        assertEquals(2, providers.size());
+        assertEquals(AegisElementProvider.class.getName(), providers.get(0).getClass().getName());
+        assertEquals(JAXBElementProvider.class.getName(), providers.get(1).getClass().getName());
+    }
+
+    public void testServiceProviderStrings() throws Exception {
+        BundleContext bc = EasyMock.createMock(BundleContext.class);
+        Bundle bundle = EasyMock.createMock(Bundle.class);
+        bc.getBundle();
+        EasyMock.expectLastCall().andReturn(bundle).times(2);
+        bundle.loadClass(AegisElementProvider.class.getName());
+        EasyMock.expectLastCall().andReturn(AegisElementProvider.class);
+        bundle.loadClass(JAXBElementProvider.class.getName());
+        EasyMock.expectLastCall().andReturn(JAXBElementProvider.class);
+        EasyMock.replay(bc, bundle);
+
+        Map<String, Object> props = new HashMap<String, Object>();
+        props.put(Constants.RS_PROVIDER_PROP_KEY, new String[] {
+            "\r\n " + AegisElementProvider.class.getName(),
+            JAXBElementProvider.class.getName() + "\r\n"
+        });
+
+        props.put(Constants.RS_PROVIDER_GLOBAL_PROP_KEY, "false");
+        addRequiredProps(props);
+
+        List<Object> providers = JaxRSUtils.getProviders(bc, props);
+        assertEquals(2, providers.size());
+        assertEquals(AegisElementProvider.class.getName(), providers.get(0).getClass().getName());
+        assertEquals(JAXBElementProvider.class.getName(), providers.get(1).getClass().getName());
+    }
+
+    public void testCustomGlobalProvider() throws Exception {
+        ServiceReference sref = EasyMock.createNiceMock(ServiceReference.class);
+        BundleContext bc = EasyMock.createNiceMock(BundleContext.class);
+        bc.getServiceReferences((String)null, JaxRSUtils.PROVIDERS_FILTER);
+        EasyMock.expectLastCall().andReturn(new ServiceReference[] {sref});
+        sref.getProperty(Constants.RS_PROVIDER_EXPECTED_PROP_KEY);
+        EasyMock.expectLastCall().andReturn(false);
+        bc.getService(sref);
+        AegisElementProvider<?> p = new AegisElementProvider();
+        EasyMock.expectLastCall().andReturn(p);
+        EasyMock.replay(bc, sref);
+        Map<String, Object> props = new HashMap<String, Object>();
+        addRequiredProps(props);
+
+        List<Object> providers = JaxRSUtils.getProviders(bc, props);
+        assertEquals(1, providers.size());
+        assertSame(p, providers.get(0));
+    }
+
+    public void testNoCustomGlobalProvider() throws Exception {
+        ServiceReference sref = EasyMock.createNiceMock(ServiceReference.class);
+        BundleContext bc = EasyMock.createNiceMock(BundleContext.class);
+        bc.getServiceReferences((String)null, JaxRSUtils.PROVIDERS_FILTER);
+        EasyMock.expectLastCall().andReturn(new ServiceReference[] {sref});
+        sref.getProperty(Constants.RS_PROVIDER_PROP_KEY);
+        EasyMock.expectLastCall().andReturn(false);
+        bc.getService(sref);
+        AegisElementProvider<?> p = new AegisElementProvider();
+        EasyMock.expectLastCall().andReturn(p);
+        EasyMock.replay(bc);
+        Map<String, Object> props = new HashMap<String, Object>();
+        props.put(Constants.RS_PROVIDER_EXPECTED_PROP_KEY, "true");
+        addRequiredProps(props);
+
+        List<Object> providers = JaxRSUtils.getProviders(bc, props);
+        assertEquals(0, providers.size());
+    }
+
+    public void testCustomGlobalProviderExpected() throws Exception {
+        ServiceReference sref = EasyMock.createNiceMock(ServiceReference.class);
+        BundleContext bc = EasyMock.createNiceMock(BundleContext.class);
+        bc.getServiceReferences((String)null, JaxRSUtils.PROVIDERS_FILTER);
+        EasyMock.expectLastCall().andReturn(new ServiceReference[] {sref});
+        sref.getProperty(Constants.RS_PROVIDER_PROP_KEY);
+        EasyMock.expectLastCall().andReturn(true);
+        bc.getService(sref);
+        AegisElementProvider<?> p = new AegisElementProvider();
+        EasyMock.expectLastCall().andReturn(p);
+        EasyMock.replay(bc, sref);
+        Map<String, Object> props = new HashMap<String, Object>();
+        props.put(Constants.RS_PROVIDER_EXPECTED_PROP_KEY, "true");
+        addRequiredProps(props);
+
+        List<Object> providers = JaxRSUtils.getProviders(bc, props);
+        assertEquals(1, providers.size());
+        assertSame(p, providers.get(0));
+    }
+}
diff --git a/trunk/dsw/cxf-dsw/src/test/java/org/apache/cxf/dosgi/dsw/handlers/PojoConfigurationTypeHandlerTest.java b/trunk/dsw/cxf-dsw/src/test/java/org/apache/cxf/dosgi/dsw/handlers/PojoConfigurationTypeHandlerTest.java
new file mode 100644
index 0000000..3505035
--- /dev/null
+++ b/trunk/dsw/cxf-dsw/src/test/java/org/apache/cxf/dosgi/dsw/handlers/PojoConfigurationTypeHandlerTest.java
@@ -0,0 +1,425 @@
+/**
+ * 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.dsw.handlers;
+
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import javax.xml.namespace.QName;
+
+import junit.framework.Assert;
+import junit.framework.TestCase;
+
+import org.apache.cxf.dosgi.dsw.Constants;
+import org.apache.cxf.dosgi.dsw.handlers.jaxws.MyJaxWsEchoService;
+import org.apache.cxf.dosgi.dsw.handlers.jaxws.MyJaxWsEchoServiceImpl;
+import org.apache.cxf.dosgi.dsw.handlers.simple.MySimpleEchoService;
+import org.apache.cxf.dosgi.dsw.handlers.simple.MySimpleEchoServiceImpl;
+import org.apache.cxf.dosgi.dsw.qos.IntentManager;
+import org.apache.cxf.dosgi.dsw.qos.IntentManagerImpl;
+import org.apache.cxf.dosgi.dsw.qos.IntentMap;
+import org.apache.cxf.endpoint.AbstractEndpointFactory;
+import org.apache.cxf.endpoint.Endpoint;
+import org.apache.cxf.endpoint.EndpointImpl;
+import org.apache.cxf.endpoint.Server;
+import org.apache.cxf.feature.Feature;
+import org.apache.cxf.frontend.ClientProxyFactoryBean;
+import org.apache.cxf.frontend.ServerFactoryBean;
+import org.apache.cxf.jaxws.support.JaxWsEndpointImpl;
+import org.apache.cxf.service.factory.ReflectionServiceFactoryBean;
+import org.apache.cxf.transport.Destination;
+import org.apache.cxf.ws.addressing.AttributedURIType;
+import org.apache.cxf.ws.addressing.EndpointReferenceType;
+import org.easymock.IAnswer;
+import org.easymock.classextension.EasyMock;
+import org.easymock.classextension.IMocksControl;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.ServiceReference;
+import org.osgi.service.remoteserviceadmin.EndpointDescription;
+import org.osgi.service.remoteserviceadmin.RemoteConstants;
+
+public class PojoConfigurationTypeHandlerTest extends TestCase {
+
+    public void testGetPojoAddressEndpointURI() {
+        IntentManager intentManager = new IntentManagerImpl(new IntentMap());
+        PojoConfigurationTypeHandler handler = new PojoConfigurationTypeHandler(null,
+                                                                                intentManager,
+                                                                                dummyHttpServiceManager());
+        Map<String, Object> sd = new HashMap<String, Object>();
+        String url = "http://somewhere:1234/blah";
+        sd.put(RemoteConstants.ENDPOINT_ID, url);
+        assertEquals(url, handler.getServerAddress(sd, String.class));
+    }
+
+    private HttpServiceManager dummyHttpServiceManager() {
+        return new HttpServiceManager(null, null, null, null);
+    }
+
+    public void testGetPojoAddressEndpointCxf() {
+        IntentManager intentManager = new IntentManagerImpl(new IntentMap());
+        PojoConfigurationTypeHandler handler = new PojoConfigurationTypeHandler(null,
+                                                                                intentManager,
+                                                                                dummyHttpServiceManager());
+        Map<String, Object> sd = new HashMap<String, Object>();
+        String url = "http://somewhere:29/boo";
+        sd.put("org.apache.cxf.ws.address", url);
+        assertEquals(url, handler.getServerAddress(sd, String.class));
+    }
+
+    public void testGetPojoAddressEndpointPojo() {
+        IntentManager intentManager = new IntentManagerImpl(new IntentMap());
+        PojoConfigurationTypeHandler handler = new PojoConfigurationTypeHandler(null,
+                                                                                intentManager,
+                                                                                dummyHttpServiceManager());
+        Map<String, Object> sd = new HashMap<String, Object>();
+        String url = "http://somewhere:32768/foo";
+        sd.put("osgi.remote.configuration.pojo.address", url);
+        assertEquals(url, handler.getServerAddress(sd, String.class));
+    }
+
+    public void testGetDefaultPojoAddress() {
+        IntentManager intentManager = new IntentManagerImpl(new IntentMap());
+        PojoConfigurationTypeHandler handler = new PojoConfigurationTypeHandler(null,
+                                                                                intentManager ,
+                                                                                dummyHttpServiceManager());
+        Map<String, Object> sd = new HashMap<String, Object>();
+        assertEquals("/java/lang/String", handler.getServerAddress(sd, String.class));
+    }
+
+    // todo: add test for data bindings
+    public void testCreateProxy() {
+        IMocksControl c = EasyMock.createNiceControl();
+        BundleContext bc1 = c.createMock(BundleContext.class);
+        BundleContext bc2 = c.createMock(BundleContext.class);
+
+        ServiceReference sref = c.createMock(ServiceReference.class);
+
+        final ClientProxyFactoryBean cpfb = c.createMock(ClientProxyFactoryBean.class);
+        ReflectionServiceFactoryBean sf = c.createMock(ReflectionServiceFactoryBean.class);
+        EasyMock.expect(cpfb.getServiceFactory()).andReturn(sf).anyTimes();
+        IntentManager intentManager = new IntentManagerImpl(new IntentMap()) {
+            @Override
+            public String[] applyIntents(List<Feature> features,
+                                         AbstractEndpointFactory factory,
+                                         Map<String, Object> sd) {
+                return new String[0];
+            }
+        };
+        PojoConfigurationTypeHandler p = new PojoConfigurationTypeHandler(bc1,
+                                                                          intentManager,
+                                                                          dummyHttpServiceManager()) {
+            @Override
+            protected ClientProxyFactoryBean createClientProxyFactoryBean(Map<String, Object> sd, Class<?> iClass) {
+                return cpfb;
+            }
+        };
+
+        Map<String, Object> props = new HashMap<String, Object>();
+
+        props.put(RemoteConstants.ENDPOINT_ID, "http://google.de/");
+        props.put(org.osgi.framework.Constants.OBJECTCLASS, new String[]{"my.class"});
+        props.put(RemoteConstants.SERVICE_IMPORTED_CONFIGS, new String[]{"my.config"});
+        EndpointDescription endpoint = new EndpointDescription(props);
+
+        cpfb.setAddress((String)EasyMock.eq(props.get(RemoteConstants.ENDPOINT_ID)));
+        EasyMock.expectLastCall().atLeastOnce();
+
+        cpfb.setServiceClass(EasyMock.eq(CharSequence.class));
+        EasyMock.expectLastCall().atLeastOnce();
+
+        c.replay();
+        Object proxy = p.createProxy(sref, bc1, bc2, CharSequence.class, endpoint);
+        assertNotNull(proxy);
+        assertTrue("Proxy is not of the requested type! ", proxy instanceof CharSequence);
+        c.verify();
+    }
+
+    public void testCreateServerWithAddressProperty() {
+        BundleContext dswContext = EasyMock.createNiceMock(BundleContext.class);
+        EasyMock.replay(dswContext);
+
+        String myService = "Hi";
+        final ServerFactoryBean sfb = createMockServerFactoryBean();
+
+        IntentMap intentMap = new IntentMap();
+        IntentManager intentManager = new IntentManagerImpl(intentMap) {
+            @Override
+            public String[] applyIntents(List<Feature> features, AbstractEndpointFactory factory,
+                                         Map<String, Object> sd) {
+                return new String[]{};
+            }
+        };
+        PojoConfigurationTypeHandler p = new PojoConfigurationTypeHandler(dswContext, intentManager,
+                                                                          dummyHttpServiceManager()) {
+            @Override
+            protected ServerFactoryBean createServerFactoryBean(Map<String, Object> sd, Class<?> iClass) {
+                return sfb;
+            }
+        };
+
+        ServiceReference sr = EasyMock.createNiceMock(ServiceReference.class);
+        BundleContext callingContext = EasyMock.createNiceMock(BundleContext.class);
+        EasyMock.replay(sr);
+        EasyMock.replay(callingContext);
+
+        Map<String, Object> props = new HashMap<String, Object>();
+        props.put(Constants.WS_ADDRESS_PROPERTY, "http://alternate_host:80/myString");
+
+        ExportResult exportResult = p.createServer(sr, dswContext, callingContext, props, String.class, myService);
+
+        Map<String, Object> edProps = exportResult.getEndpointProps();
+
+        assertNotNull(edProps.get(RemoteConstants.SERVICE_IMPORTED_CONFIGS));
+        assertEquals(1, ((String[])edProps.get(RemoteConstants.SERVICE_IMPORTED_CONFIGS)).length);
+        assertEquals(Constants.WS_CONFIG_TYPE, ((String[])edProps.get(RemoteConstants.SERVICE_IMPORTED_CONFIGS))[0]);
+        assertEquals("http://alternate_host:80/myString", edProps.get(RemoteConstants.ENDPOINT_ID));
+    }
+
+    public void testAddressing() {
+        runAddressingTest(new HashMap<String, Object>(), "http://localhost:9000/java/lang/Runnable");
+
+        Map<String, Object> p1 = new HashMap<String, Object>();
+        p1.put("org.apache.cxf.ws.address", "http://somewhere");
+        runAddressingTest(p1, "http://somewhere");
+
+        Map<String, Object> p2 = new HashMap<String, Object>();
+        p2.put("org.apache.cxf.rs.address", "https://somewhereelse");
+        runAddressingTest(p2, "https://somewhereelse");
+
+        Map<String, Object> p3 = new HashMap<String, Object>();
+        p3.put("org.apache.cxf.ws.port", 65535);
+        runAddressingTest(p3, "http://localhost:65535/java/lang/Runnable");
+
+        Map<String, Object> p4 = new HashMap<String, Object>();
+        p4.put("org.apache.cxf.ws.port", "8181");
+        runAddressingTest(p4, "http://localhost:8181/java/lang/Runnable");
+    }
+
+    private void runAddressingTest(Map<String, Object> properties, String expectedAddress) {
+        BundleContext dswContext = EasyMock.createNiceMock(BundleContext.class);
+        EasyMock.replay(dswContext);
+
+        IntentManager intentManager = EasyMock.createNiceMock(IntentManager.class);
+        EasyMock.replay(intentManager);
+
+        PojoConfigurationTypeHandler handler = new PojoConfigurationTypeHandler(dswContext,
+                                                                                intentManager,
+                                                                                dummyHttpServiceManager()) {
+            @Override
+            protected ExportResult createServerFromFactory(ServerFactoryBean factory,
+                                                           Map<String, Object> endpointProps) {
+                return new ExportResult(endpointProps, (Server) null);
+            }
+        };
+
+        ServiceReference sref = EasyMock.createNiceMock(ServiceReference.class);
+        EasyMock.replay(sref);
+
+        Runnable myService = EasyMock.createMock(Runnable.class);
+        EasyMock.replay(myService);
+        ExportResult result = handler.createServer(sref, null, null, properties, Runnable.class, myService);
+        assertNull(result.getException());
+
+        Map<String, Object> props = result.getEndpointProps();
+        assertEquals(expectedAddress, props.get("org.apache.cxf.ws.address"));
+        assertEquals("Version of java. package is always 0", "0.0.0", props.get("endpoint.package.version.java.lang"));
+        assertTrue(Arrays.equals(new String[] {"org.apache.cxf.ws"}, (String[]) props.get("service.imported.configs")));
+        assertTrue(Arrays.equals(new String[] {"java.lang.Runnable"}, (String[]) props.get("objectClass")));
+        assertNotNull(props.get("endpoint.framework.uuid"));
+    }
+
+    public void testCreateServerException() {
+        BundleContext dswContext = EasyMock.createNiceMock(BundleContext.class);
+        EasyMock.replay(dswContext);
+
+        IntentManager intentManager = EasyMock.createNiceMock(IntentManager.class);
+        EasyMock.replay(intentManager);
+
+        PojoConfigurationTypeHandler handler = new PojoConfigurationTypeHandler(dswContext,
+                                                                                intentManager,
+                                                                                dummyHttpServiceManager()) {
+            @Override
+            protected ExportResult createServerFromFactory(ServerFactoryBean factory,
+                                                           Map<String, Object> endpointProps) {
+                throw new TestException();
+            }
+        };
+
+        ServiceReference sref = EasyMock.createNiceMock(ServiceReference.class);
+        EasyMock.replay(sref);
+
+        Map<String, Object> props = new HashMap<String, Object>();
+
+        Runnable myService = EasyMock.createMock(Runnable.class);
+        EasyMock.replay(myService);
+        ExportResult result = handler.createServer(sref, null, null, props, Runnable.class, myService);
+        Assert.assertTrue(result.getException() instanceof TestException);
+        Assert.assertEquals(props, result.getEndpointProps());
+    }
+
+    private ServerFactoryBean createMockServerFactoryBean() {
+        ReflectionServiceFactoryBean sf = EasyMock.createNiceMock(ReflectionServiceFactoryBean.class);
+        EasyMock.replay(sf);
+
+        final StringBuilder serverURI = new StringBuilder();
+
+        ServerFactoryBean sfb = EasyMock.createNiceMock(ServerFactoryBean.class);
+        Server server = createMockServer(sfb);
+
+        EasyMock.expect(sfb.getServiceFactory()).andReturn(sf).anyTimes();
+        EasyMock.expect(sfb.create()).andReturn(server);
+        sfb.setAddress((String) EasyMock.anyObject());
+        EasyMock.expectLastCall().andAnswer(new IAnswer<Object>() {
+            public Object answer() throws Throwable {
+                serverURI.setLength(0);
+                serverURI.append(EasyMock.getCurrentArguments()[0]);
+                return null;
+            }
+        });
+        EasyMock.expect(sfb.getAddress()).andAnswer(new IAnswer<String>() {
+            public String answer() throws Throwable {
+                return serverURI.toString();
+            }
+        });
+        EasyMock.replay(sfb);
+        return sfb;
+    }
+
+    private Server createMockServer(final ServerFactoryBean sfb) {
+        AttributedURIType addr = EasyMock.createMock(AttributedURIType.class);
+        EasyMock.expect(addr.getValue()).andAnswer(new IAnswer<String>() {
+            public String answer() throws Throwable {
+                return sfb.getAddress();
+            }
+        });
+        EasyMock.replay(addr);
+
+        EndpointReferenceType er = EasyMock.createMock(EndpointReferenceType.class);
+        EasyMock.expect(er.getAddress()).andReturn(addr);
+        EasyMock.replay(er);
+
+        Destination destination = EasyMock.createMock(Destination.class);
+        EasyMock.expect(destination.getAddress()).andReturn(er);
+        EasyMock.replay(destination);
+
+        Server server = EasyMock.createNiceMock(Server.class);
+        EasyMock.expect(server.getDestination()).andReturn(destination);
+        EasyMock.replay(server);
+        return server;
+    }
+
+    public void testCreateEndpointProps() {
+        BundleContext bc = EasyMock.createNiceMock(BundleContext.class);
+        EasyMock.expect(bc.getProperty("org.osgi.framework.uuid")).andReturn("some_uuid1");
+        EasyMock.replay(bc);
+
+        IntentManager intentManager = new IntentManagerImpl(new IntentMap());
+        PojoConfigurationTypeHandler pch = new PojoConfigurationTypeHandler(bc,
+                                                                            intentManager,
+                                                                            dummyHttpServiceManager());
+
+        Map<String, Object> sd = new HashMap<String, Object>();
+        sd.put(org.osgi.framework.Constants.SERVICE_ID, 42);
+        Map<String, Object> props = pch.createEndpointProps(sd, String.class, new String[] {"org.apache.cxf.ws"},
+                "http://localhost:12345", new String[] {"my_intent", "your_intent"});
+
+        assertFalse(props.containsKey(org.osgi.framework.Constants.SERVICE_ID));
+        assertEquals(42, props.get(RemoteConstants.ENDPOINT_SERVICE_ID));
+        assertEquals("some_uuid1", props.get(RemoteConstants.ENDPOINT_FRAMEWORK_UUID));
+        assertEquals("http://localhost:12345", props.get(RemoteConstants.ENDPOINT_ID));
+        assertEquals(Arrays.asList("java.lang.String"),
+                     Arrays.asList((Object[]) props.get(org.osgi.framework.Constants.OBJECTCLASS)));
+        assertEquals(Arrays.asList("org.apache.cxf.ws"),
+                     Arrays.asList((Object[]) props.get(RemoteConstants.SERVICE_IMPORTED_CONFIGS)));
+        assertEquals(Arrays.asList("my_intent", "your_intent"),
+                     Arrays.asList((Object[]) props.get(RemoteConstants.SERVICE_INTENTS)));
+        assertEquals("0.0.0", props.get("endpoint.package.version.java.lang"));
+    }
+
+    public void testCreateJaxWsEndpointWithoutIntents() {
+        IMocksControl c = EasyMock.createNiceControl();
+        BundleContext dswBC = c.createMock(BundleContext.class);
+        IntentManager intentManager = new DummyIntentManager();
+        PojoConfigurationTypeHandler handler = new PojoConfigurationTypeHandler(dswBC,
+                                                                                intentManager,
+                                                                                dummyHttpServiceManager());
+
+        Object serviceBean = new MyJaxWsEchoServiceImpl();
+        ServiceReference sref = c.createMock(ServiceReference.class);
+
+        Map<String, Object> sd = new HashMap<String, Object>();
+        sd.put(Constants.WS_ADDRESS_PROPERTY, "/somewhere");
+
+        c.replay();
+        ExportResult exportResult = handler.createServer(sref, dswBC, null, sd, MyJaxWsEchoService.class, serviceBean);
+        c.verify();
+
+        Server server = exportResult.getServer();
+        Endpoint ep = server.getEndpoint();
+        QName bindingName = ep.getEndpointInfo().getBinding().getName();
+        Assert.assertEquals(JaxWsEndpointImpl.class, ep.getClass());
+        Assert.assertEquals(new QName("http://jaxws.handlers.dsw.dosgi.cxf.apache.org/",
+                                      "MyJaxWsEchoServiceServiceSoapBinding"),
+                            bindingName);
+    }
+
+    public void testCreateSimpleEndpointWithoutIntents() {
+        IMocksControl c = EasyMock.createNiceControl();
+        BundleContext dswBC = c.createMock(BundleContext.class);
+        IntentManager intentManager = new DummyIntentManager();
+        PojoConfigurationTypeHandler handler
+            = new PojoConfigurationTypeHandler(dswBC, intentManager, dummyHttpServiceManager());
+        Object serviceBean = new MySimpleEchoServiceImpl();
+        ServiceReference sref = c.createMock(ServiceReference.class);
+        Map<String, Object> sd = new HashMap<String, Object>();
+        sd.put(Constants.WS_ADDRESS_PROPERTY, "/somewhere_else");
+
+        c.replay();
+        ExportResult exportResult = handler.createServer(sref, dswBC, null, sd, MySimpleEchoService.class, serviceBean);
+        Server server = exportResult.getServer();
+        c.verify();
+
+        Endpoint ep = server.getEndpoint();
+        QName bindingName = ep.getEndpointInfo().getBinding().getName();
+        Assert.assertEquals(EndpointImpl.class, ep.getClass());
+        Assert.assertEquals(new QName("http://simple.handlers.dsw.dosgi.cxf.apache.org/",
+                                      "MySimpleEchoServiceSoapBinding"),
+                            bindingName);
+    }
+
+    public static class DummyIntentManager implements IntentManager {
+
+        @Override
+        public String[] applyIntents(List<Feature> features,
+                                     AbstractEndpointFactory factory,
+                                     Map<String, Object> props) {
+            return new String[]{};
+        }
+
+        @Override
+        public void assertAllIntentsSupported(Map<String, Object> serviceProperties) {
+        }
+    }
+
+    @SuppressWarnings("serial")
+    public static class TestException extends RuntimeException {
+    }
+}
diff --git a/trunk/dsw/cxf-dsw/src/test/java/org/apache/cxf/dosgi/dsw/handlers/SecurityDelegatingHttpContextTest.java b/trunk/dsw/cxf-dsw/src/test/java/org/apache/cxf/dosgi/dsw/handlers/SecurityDelegatingHttpContextTest.java
new file mode 100644
index 0000000..22b3291
--- /dev/null
+++ b/trunk/dsw/cxf-dsw/src/test/java/org/apache/cxf/dosgi/dsw/handlers/SecurityDelegatingHttpContextTest.java
@@ -0,0 +1,264 @@
+/**
+ * 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.dsw.handlers;
+
+import java.io.PrintWriter;
+import java.net.URL;
+
+import javax.servlet.Filter;
+import javax.servlet.FilterChain;
+import javax.servlet.FilterConfig;
+import javax.servlet.ServletException;
+import javax.servlet.ServletRequest;
+import javax.servlet.ServletResponse;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import junit.framework.TestCase;
+
+import org.easymock.EasyMock;
+import org.junit.Assert;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.ServiceReference;
+import org.osgi.service.http.HttpContext;
+
+public class SecurityDelegatingHttpContextTest extends TestCase {
+
+    protected HttpContext defaultHttpContext;
+    protected SecurityDelegatingHttpContext httpContext;
+    protected CommitResponseFilter commitFilter;
+    protected DoNothingFilter doNothingFilter;
+    protected AccessDeniedFilter accessDeniedFilter;
+    protected String mimeType;
+    protected URL url; // does not need to exist
+
+    public void setUp() throws Exception {
+        mimeType = "text/xml";
+        url = new URL("file:test.xml"); // does not need to exist
+
+        // Sample filters
+        commitFilter = new CommitResponseFilter();
+        doNothingFilter = new DoNothingFilter();
+        accessDeniedFilter = new AccessDeniedFilter();
+
+        // Mock up the default http context
+        defaultHttpContext = EasyMock.createNiceMock(HttpContext.class);
+        EasyMock.expect(defaultHttpContext.getMimeType((String)EasyMock.anyObject())).andReturn(mimeType);
+        EasyMock.expect(defaultHttpContext.getResource((String)EasyMock.anyObject())).andReturn(url);
+        EasyMock.replay(defaultHttpContext);
+    }
+
+    public void testFilterRequired() throws Exception {
+        // Mock up the service references
+        ServiceReference[] serviceReferences = new ServiceReference[] {};
+
+        // Mock up the bundle context
+        BundleContext bundleContext = EasyMock.createNiceMock(BundleContext.class);
+        EasyMock.expect(bundleContext.getServiceReferences(Filter.class.getName(),
+                                                           "(org.apache.cxf.httpservice.filter=true)"))
+            .andReturn(serviceReferences);
+        EasyMock.replay(bundleContext);
+
+        // Set up the secure http context
+        httpContext = new SecurityDelegatingHttpContext(bundleContext, defaultHttpContext);
+        httpContext.requireFilter = true;
+
+        // Ensure that the httpContext doesn't allow the request to be processed, since there are no registered servlet
+        // filters
+        HttpServletRequest request = EasyMock.createNiceMock(HttpServletRequest.class);
+        EasyMock.replay(request);
+        HttpServletResponse response = EasyMock.createNiceMock(HttpServletResponse.class);
+        EasyMock.replay(response);
+        boolean requestAllowed = httpContext.handleSecurity(request, response);
+        Assert.assertFalse(requestAllowed);
+
+        // Ensure that the httpContext returns true if there is no requirement for registered servlet filters
+        httpContext.requireFilter = false;
+        requestAllowed = httpContext.handleSecurity(request, response);
+        Assert.assertTrue(requestAllowed);
+    }
+
+    public void testSingleCommitFilter() throws Exception {
+        // Mock up the service references
+        ServiceReference filterReference = EasyMock.createNiceMock(ServiceReference.class);
+        EasyMock.replay(filterReference);
+        ServiceReference[] serviceReferences = new ServiceReference[] {
+            filterReference
+        };
+
+        // Mock up the bundle context
+        BundleContext bundleContext = EasyMock.createNiceMock(BundleContext.class);
+        EasyMock.expect(bundleContext.getServiceReferences((String)EasyMock.anyObject(), (String)EasyMock.anyObject()))
+            .andReturn(serviceReferences);
+        EasyMock.expect(bundleContext.getService((ServiceReference)EasyMock.anyObject())).andReturn(commitFilter);
+        EasyMock.replay(bundleContext);
+
+        // Set up the secure http context
+        httpContext = new SecurityDelegatingHttpContext(bundleContext, defaultHttpContext);
+
+        // Ensure that the httpContext returns false, since the filter has committed the response
+        HttpServletRequest request = EasyMock.createNiceMock(HttpServletRequest.class);
+        EasyMock.replay(request);
+        HttpServletResponse response = EasyMock.createNiceMock(HttpServletResponse.class);
+        EasyMock.expect(response.isCommitted()).andReturn(false); // the first call checks to see whether to invoke the
+                                                                  // filter
+        EasyMock.expect(response.isCommitted()).andReturn(true); // the second is called to determine the handleSecurity
+                                                                 // return value
+        EasyMock.expect(response.getWriter()).andReturn(new PrintWriter(System.out));
+        EasyMock.replay(response);
+        Assert.assertFalse(httpContext.handleSecurity(request, response));
+
+        // Ensure that the appropriate filters were called
+        Assert.assertTrue(commitFilter.called);
+        Assert.assertFalse(doNothingFilter.called);
+        Assert.assertFalse(accessDeniedFilter.called);
+    }
+
+    public void testFilterChain() throws Exception {
+        // Mock up the service references
+        ServiceReference filterReference = EasyMock.createNiceMock(ServiceReference.class);
+        EasyMock.replay(filterReference);
+        ServiceReference[] serviceReferences = new ServiceReference[] {
+            filterReference, filterReference
+        };
+
+        // Mock up the bundle context
+        BundleContext bundleContext = EasyMock.createNiceMock(BundleContext.class);
+        EasyMock.expect(bundleContext.getServiceReferences((String)EasyMock.anyObject(), (String)EasyMock.anyObject()))
+            .andReturn(serviceReferences);
+        EasyMock.expect(bundleContext.getService((ServiceReference)EasyMock.anyObject())).andReturn(doNothingFilter);
+        EasyMock.expect(bundleContext.getService((ServiceReference)EasyMock.anyObject())).andReturn(commitFilter);
+        EasyMock.replay(bundleContext);
+
+        // Set up the secure http context
+        httpContext = new SecurityDelegatingHttpContext(bundleContext, defaultHttpContext);
+
+        // Ensure that the httpContext returns false, since the filter has committed the response
+        HttpServletRequest request = EasyMock.createNiceMock(HttpServletRequest.class);
+        EasyMock.replay(request);
+        HttpServletResponse response = EasyMock.createNiceMock(HttpServletResponse.class);
+        EasyMock.expect(response.isCommitted()).andReturn(false); // doNothingFilter should not commit the response
+        EasyMock.expect(response.getWriter()).andReturn(new PrintWriter(System.out));
+        EasyMock.expect(response.isCommitted()).andReturn(false);
+        EasyMock.expect(response.isCommitted()).andReturn(true); // the commit filter indicating that it committed the
+                                                                 // response
+        EasyMock.replay(response);
+        Assert.assertFalse(httpContext.handleSecurity(request, response));
+
+        // Ensure that the appropriate filters were called
+        Assert.assertTrue(doNothingFilter.called);
+        Assert.assertTrue(commitFilter.called);
+        Assert.assertFalse(accessDeniedFilter.called);
+    }
+
+    public void testAllowRequest() throws Exception {
+        // Mock up the service references
+        ServiceReference filterReference = EasyMock.createNiceMock(ServiceReference.class);
+        EasyMock.replay(filterReference);
+        ServiceReference[] serviceReferences = new ServiceReference[] {
+            filterReference
+        };
+
+        // Mock up the bundle context
+        BundleContext bundleContext = EasyMock.createNiceMock(BundleContext.class);
+        EasyMock.expect(bundleContext.getServiceReferences((String)EasyMock.anyObject(), (String)EasyMock.anyObject()))
+            .andReturn(serviceReferences);
+        EasyMock.expect(bundleContext.getService((ServiceReference)EasyMock.anyObject())).andReturn(doNothingFilter);
+        EasyMock.replay(bundleContext);
+
+        // Set up the secure http context
+        httpContext = new SecurityDelegatingHttpContext(bundleContext, defaultHttpContext);
+
+        // Ensure that the httpContext returns true, since the filter has not committed the response
+        HttpServletRequest request = EasyMock.createNiceMock(HttpServletRequest.class);
+        EasyMock.replay(request);
+        HttpServletResponse response = EasyMock.createNiceMock(HttpServletResponse.class);
+        EasyMock.expect(response.isCommitted()).andReturn(false);
+        EasyMock.replay(response);
+        Assert.assertTrue(httpContext.handleSecurity(request, response));
+
+        // Ensure that the appropriate filters were called
+        Assert.assertTrue(doNothingFilter.called);
+        Assert.assertFalse(commitFilter.called);
+        Assert.assertFalse(accessDeniedFilter.called);
+    }
+
+    public void testDelegation() throws Exception {
+        BundleContext bundleContext = EasyMock.createNiceMock(BundleContext.class);
+        EasyMock.replay(bundleContext);
+
+        // Set up the secure http context
+        httpContext = new SecurityDelegatingHttpContext(bundleContext, defaultHttpContext);
+
+        // Ensure that it delegates non-security calls to the wrapped implementation (in this case, the mock)
+        Assert.assertEquals(mimeType, httpContext.getMimeType(""));
+        Assert.assertEquals(url, httpContext.getResource(""));
+    }
+}
+
+class CommitResponseFilter implements Filter {
+
+    boolean called;
+
+    public void init(FilterConfig filterConfig) throws ServletException {
+    }
+
+    public void destroy() {
+    }
+
+    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
+        throws java.io.IOException, javax.servlet.ServletException {
+        called = true;
+        response.getWriter().write("committing the response");
+    }
+}
+
+class DoNothingFilter implements Filter {
+
+    boolean called;
+
+    public void init(FilterConfig filterConfig) throws ServletException {
+    }
+
+    public void destroy() {
+    }
+
+    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
+        throws java.io.IOException, javax.servlet.ServletException {
+        called = true;
+        chain.doFilter(request, response);
+    }
+}
+
+class AccessDeniedFilter implements Filter {
+
+    boolean called;
+
+    public void init(FilterConfig filterConfig) throws ServletException {
+    }
+
+    public void destroy() {
+    }
+
+    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
+        throws java.io.IOException, javax.servlet.ServletException {
+        called = true;
+        ((HttpServletResponse)response).sendError(HttpServletResponse.SC_FORBIDDEN);
+    }
+}
diff --git a/trunk/dsw/cxf-dsw/src/test/java/org/apache/cxf/dosgi/dsw/handlers/ServiceInvocationHandlerTest.java b/trunk/dsw/cxf-dsw/src/test/java/org/apache/cxf/dosgi/dsw/handlers/ServiceInvocationHandlerTest.java
new file mode 100644
index 0000000..64beeac
--- /dev/null
+++ b/trunk/dsw/cxf-dsw/src/test/java/org/apache/cxf/dosgi/dsw/handlers/ServiceInvocationHandlerTest.java
@@ -0,0 +1,75 @@
+/**
+ * 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.dsw.handlers;
+
+import java.lang.reflect.Method;
+import java.lang.reflect.Proxy;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import junit.framework.TestCase;
+
+public class ServiceInvocationHandlerTest extends TestCase {
+
+    private static final Map<String, Method> OBJECT_METHODS = new HashMap<String, Method>(); {
+        for (Method m : Object.class.getMethods()) {
+            OBJECT_METHODS.put(m.getName(), m);
+        }
+    }
+
+    public void testInvoke() throws Throwable {
+        ServiceInvocationHandler sih = new ServiceInvocationHandler("hello", String.class);
+        Method m = String.class.getMethod("length", new Class[] {});
+        assertEquals(5, sih.invoke(null, m, new Object[] {}));
+    }
+
+    public void testInvokeObjectMethod() throws Throwable {
+        final List<String> called = new ArrayList<String>();
+        ServiceInvocationHandler sih = new ServiceInvocationHandler("hi", String.class) {
+            public boolean equals(Object obj) {
+                called.add("equals");
+                return super.equals(obj);
+            }
+
+            public int hashCode() {
+                called.add("hashCode");
+                return super.hashCode();
+            }
+
+            public String toString() {
+                called.add("toString");
+                return "somestring";
+            }
+        };
+
+        Object proxy = Proxy.newProxyInstance(
+                getClass().getClassLoader(), new Class[] {Runnable.class}, sih);
+
+        assertEquals(true,
+                sih.invoke(null, OBJECT_METHODS.get("equals"), new Object[] {proxy}));
+        assertEquals(System.identityHashCode(sih),
+                sih.invoke(null, OBJECT_METHODS.get("hashCode"), new Object[] {}));
+        assertEquals("somestring",
+                sih.invoke(null, OBJECT_METHODS.get("toString"), new Object[] {}));
+        assertEquals(Arrays.asList("equals", "hashCode", "toString"), called);
+    }
+}
diff --git a/trunk/dsw/cxf-dsw/src/test/java/org/apache/cxf/dosgi/dsw/handlers/WsdlConfigurationTypeHandlerTest.java b/trunk/dsw/cxf-dsw/src/test/java/org/apache/cxf/dosgi/dsw/handlers/WsdlConfigurationTypeHandlerTest.java
new file mode 100644
index 0000000..df90758
--- /dev/null
+++ b/trunk/dsw/cxf-dsw/src/test/java/org/apache/cxf/dosgi/dsw/handlers/WsdlConfigurationTypeHandlerTest.java
@@ -0,0 +1,67 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.cxf.dosgi.dsw.handlers;
+
+import junit.framework.TestCase;
+
+public class WsdlConfigurationTypeHandlerTest extends TestCase {
+
+    public void testDUMMY() {
+        assertTrue(true);
+    }
+
+//    private Map<String, Object> handlerProps;
+//
+//    @Override
+//    protected void setUp() throws Exception {
+//        super.setUp();
+//
+//        handlerProps = new HashMap<String, Object>();
+//        handlerProps.put(Constants.DEFAULT_HOST_CONFIG, "somehost");
+//        handlerProps.put(Constants.DEFAULT_PORT_CONFIG, "54321");
+//    }
+//
+//    public void testCreateProxyPopulatesDistributionProvider() {
+//        ServiceReference sr = EasyMock.createNiceMock(ServiceReference.class);
+//        BundleContext dswContext = EasyMock.createNiceMock(BundleContext.class);
+//        BundleContext callingContext = EasyMock.createNiceMock(BundleContext.class);
+//        ServiceEndpointDescription sd = TestUtils.mockServiceDescription("Foo");
+//        EasyMock.replay(sr);
+//        EasyMock.replay(dswContext);
+//        EasyMock.replay(callingContext);
+//        EasyMock.replay(sd);
+//
+//        RemoteServiceAdminCore dp = new RemoteServiceAdminCore(dswContext);
+//        WsdlConfigurationTypeHandler w = new WsdlConfigurationTypeHandler(dswContext, dp, handlerProps) {
+//            @Override
+//            Service createWebService(URL wsdlAddress, QName serviceQname) {
+//                Service svc = EasyMock.createMock(Service.class);
+//                EasyMock.expect(svc.getPort(CharSequence.class)).andReturn("Hi").anyTimes();
+//                EasyMock.replay(svc);
+//                return svc;
+//            }
+//        };
+//
+//        assertEquals("Precondition failed", 0, dp.getRemoteServices().size());
+//        w.createProxy(sr, dswContext, callingContext, CharSequence.class, sd);
+//        assertEquals(1, dp.getRemoteServices().size());
+//        assertSame(sr, dp.getRemoteServices().iterator().next());
+//
+//    }
+}
diff --git a/trunk/dsw/cxf-dsw/src/test/java/org/apache/cxf/dosgi/dsw/handlers/jaxws/MyJaxWsEchoService.java b/trunk/dsw/cxf-dsw/src/test/java/org/apache/cxf/dosgi/dsw/handlers/jaxws/MyJaxWsEchoService.java
new file mode 100644
index 0000000..7814267
--- /dev/null
+++ b/trunk/dsw/cxf-dsw/src/test/java/org/apache/cxf/dosgi/dsw/handlers/jaxws/MyJaxWsEchoService.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.dsw.handlers.jaxws;
+
+import javax.jws.WebService;
+
+@WebService
+public interface MyJaxWsEchoService {
+    String echo(String message);
+}
\ No newline at end of file
diff --git a/trunk/dsw/cxf-dsw/src/test/java/org/apache/cxf/dosgi/dsw/handlers/jaxws/MyJaxWsEchoServiceImpl.java b/trunk/dsw/cxf-dsw/src/test/java/org/apache/cxf/dosgi/dsw/handlers/jaxws/MyJaxWsEchoServiceImpl.java
new file mode 100644
index 0000000..699c9ae
--- /dev/null
+++ b/trunk/dsw/cxf-dsw/src/test/java/org/apache/cxf/dosgi/dsw/handlers/jaxws/MyJaxWsEchoServiceImpl.java
@@ -0,0 +1,27 @@
+/**
+ * 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.dsw.handlers.jaxws;
+
+public class MyJaxWsEchoServiceImpl implements MyJaxWsEchoService {
+
+    @Override
+    public String echo(String message) {
+        return message;
+    }
+}
\ No newline at end of file
diff --git a/trunk/dsw/cxf-dsw/src/test/java/org/apache/cxf/dosgi/dsw/handlers/simple/MySimpleEchoService.java b/trunk/dsw/cxf-dsw/src/test/java/org/apache/cxf/dosgi/dsw/handlers/simple/MySimpleEchoService.java
new file mode 100644
index 0000000..7d574ca
--- /dev/null
+++ b/trunk/dsw/cxf-dsw/src/test/java/org/apache/cxf/dosgi/dsw/handlers/simple/MySimpleEchoService.java
@@ -0,0 +1,23 @@
+/**
+ * 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.dsw.handlers.simple;
+
+public interface MySimpleEchoService {
+    String echo(String message);
+}
\ No newline at end of file
diff --git a/trunk/dsw/cxf-dsw/src/test/java/org/apache/cxf/dosgi/dsw/handlers/simple/MySimpleEchoServiceImpl.java b/trunk/dsw/cxf-dsw/src/test/java/org/apache/cxf/dosgi/dsw/handlers/simple/MySimpleEchoServiceImpl.java
new file mode 100644
index 0000000..19dda4b
--- /dev/null
+++ b/trunk/dsw/cxf-dsw/src/test/java/org/apache/cxf/dosgi/dsw/handlers/simple/MySimpleEchoServiceImpl.java
@@ -0,0 +1,27 @@
+/**
+ * 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.dsw.handlers.simple;
+
+public class MySimpleEchoServiceImpl implements MySimpleEchoService {
+
+    @Override
+    public String echo(String message) {
+        return message;
+    }
+}
\ No newline at end of file
diff --git a/trunk/dsw/cxf-dsw/src/test/java/org/apache/cxf/dosgi/dsw/hooks/CxfFindListenerHookTest.java b/trunk/dsw/cxf-dsw/src/test/java/org/apache/cxf/dosgi/dsw/hooks/CxfFindListenerHookTest.java
new file mode 100644
index 0000000..fde48d2
--- /dev/null
+++ b/trunk/dsw/cxf-dsw/src/test/java/org/apache/cxf/dosgi/dsw/hooks/CxfFindListenerHookTest.java
@@ -0,0 +1,341 @@
+/**
+ * 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.dsw.hooks;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+public class CxfFindListenerHookTest extends Assert {
+
+    @Test
+    public void testDUMMY() throws Exception {
+    }
+
+//    private IMocksControl control;
+//
+//    @Before
+//    public void setUp() {
+//        control = EasyMock.createNiceControl();
+//    }
+
+    /* Todo this test doesn't apply at the moment since the ListenerHook doesn't
+     * have a serviceReferencesRequested() API (yet).
+    @Test
+    public void testSyncListenerHook() throws Exception {
+        Bundle bundle = control.createMock(Bundle.class);
+        bundle.findEntries(EasyMock.eq("OSGI-INF/remote-service"),
+            EasyMock.eq("*.xml"), EasyMock.anyBoolean());
+        EasyMock.expectLastCall().andReturn(Collections.enumeration(
+            Arrays.asList(getClass().getResource("/OSGI-INF/remote-service/remote-services.xml"))));
+        Dictionary<String, String> bundleHeaders = new Hashtable<String, String>();
+        bundleHeaders.put(org.osgi.framework.Constants.BUNDLE_NAME,
+                          "Test Bundle");
+        bundleHeaders.put(org.osgi.framework.Constants.BUNDLE_VERSION,
+                          "1.0.0");
+        bundle.getHeaders();
+        EasyMock.expectLastCall().andReturn(bundleHeaders).anyTimes();
+        bundle.loadClass(TestService.class.getName());
+        EasyMock.expectLastCall().andReturn(TestService.class).anyTimes();
+        final BundleContext requestingContext = control.createMock(BundleContext.class);
+        requestingContext.getBundle();
+        EasyMock.expectLastCall().andReturn(bundle).anyTimes();
+
+        BundleTestContext dswContext = new BundleTestContext(bundle);
+        dswContext.addServiceReference(TestService.class.getName(),
+                                       control.createMock(ServiceReference.class));
+        control.replay();
+
+        CxfListenerHook hook = new CxfListenerHook(dswContext, null);
+
+        // TODO : if the next call ends up being executed in a thread of its own then
+        // update the test accordingly, use Futures for ex
+
+        hook.serviceReferencesRequested(requestingContext,
+                                       TestService.class.getName(), null, true);
+
+        List<ServiceReference> registeredRefs = dswContext.getRegisteredReferences();
+        assertNotNull(registeredRefs);
+        assertEquals(1, registeredRefs.size());
+    } */
+
+//    @Test
+//    public void testTrackerPropertiesOnlyClassInFilterWithMatchingInterface() throws Exception {
+//        String filter = "(objectClass=" + TestService.class.getName() + ")";
+//        doTestTrackerPropertiesSet(filter,
+//                                   "osgi.remote.discovery.interest.interfaces",
+//                                   TestService.class.getName(),
+//                                   asList(TestService.class.getName()),
+//                                   Collections.EMPTY_SET);
+//    }
+//
+//    @Test
+//    public void testTrackerPropertiesGenericFilterWithMatchingInterface() throws Exception {
+//        String filter = "(&(objectClass=" + TestService.class.getName()
+//                        + ")(colour=blue))";
+//        doTestTrackerPropertiesSet(filter,
+//                                   "osgi.remote.discovery.interest.filters",
+//                                   replacePredicate(filter),
+//                                   asList(TestService.class.getName()),
+//                                   Collections.EMPTY_SET);
+//    }
+//
+//    @Test
+//    public void testTrackerPropertiesOnlyClassInFilterWithMatchingFilter() throws Exception {
+//        String filter = "(objectClass=" + TestService.class.getName() + ")";
+//        doTestTrackerPropertiesSet(filter,
+//                                   "osgi.remote.discovery.interest.interfaces",
+//                                   TestService.class.getName(),
+//                                   Collections.EMPTY_SET,
+//                                   asList(replacePredicate(filter)));
+//    }
+//
+//    @Test
+//    public void testTrackerPropertiesGenericFilterWithMatchingFilter() throws Exception {
+//        String filter = "(&(objectClass=" + TestService.class.getName()
+//                        + ")(colour=blue))";
+//        doTestTrackerPropertiesSet(filter,
+//                                   "osgi.remote.discovery.interest.filters",
+//                                   replacePredicate(filter),
+//                                   Collections.EMPTY_SET,
+//                                   asList(replacePredicate(filter)));
+//    }
+//
+//    @Test
+//    public void testTrackerPropertiesOnlyClassInFilterWithMatchingBoth() throws Exception {
+//        String filter = "(objectClass=" + TestService.class.getName() + ")";
+//        doTestTrackerPropertiesSet(filter,
+//                                   "osgi.remote.discovery.interest.interfaces",
+//                                   TestService.class.getName(),
+//                                   asList(TestService.class.getName()),
+//                                   asList(replacePredicate(filter)));
+//    }
+//
+//    @Test
+//    public void testTrackerPropertiesGenericFilterWithMatchingBoth() throws Exception {
+//        String filter = "(&(objectClass=" + TestService.class.getName()
+//                        + ")(colour=blue))";
+//        doTestTrackerPropertiesSet(filter,
+//                                   "osgi.remote.discovery.interest.filters",
+//                                   replacePredicate(filter),
+//                                   Collections.EMPTY_SET,
+//                                   asList(replacePredicate(filter)));
+//    }
+//
+//    private void doTestTrackerPropertiesSet(final String filter,
+//                                            String propKey,
+//                                            String propValue,
+//                                            Collection matchingInterfaces,
+//                                            Collection matchingFilters) throws Exception {
+//        Bundle bundle = control.createMock(Bundle.class);
+//        Dictionary<String, String> bundleHeaders = new Hashtable<String, String>();
+//        bundleHeaders.put(org.osgi.framework.Constants.BUNDLE_NAME,
+//                          "Test Bundle");
+//        bundleHeaders.put(org.osgi.framework.Constants.BUNDLE_VERSION,
+//                          "1.0.0");
+//        bundle.getHeaders();
+//        EasyMock.expectLastCall().andReturn(bundleHeaders).times(2);
+//        final String serviceClass = TestService.class.getName();
+//        bundle.loadClass(serviceClass);
+//        EasyMock.expectLastCall().andReturn(TestService.class).times(2);
+//        final BundleContext requestingContext = control.createMock(BundleContext.class);
+//
+//        BundleTestContext dswContext = new BundleTestContext(bundle);
+//        ServiceRegistration serviceRegistration = control.createMock(ServiceRegistration.class);
+//        dswContext.addServiceRegistration(serviceClass, serviceRegistration);
+//        serviceRegistration.unregister();
+//        EasyMock.expectLastCall().times(1);
+//        ServiceReference serviceReference = control.createMock(ServiceReference.class);
+//        dswContext.addServiceReference(serviceClass, serviceReference);
+//
+//        final String trackerClass = DiscoveredServiceTracker.class.getName();
+//        ServiceRegistration trackerRegistration = control.createMock(ServiceRegistration.class);
+//        dswContext.addServiceRegistration(trackerClass, trackerRegistration);
+//        ServiceReference trackerReference = control.createMock(ServiceReference.class);
+//        dswContext.addServiceReference(trackerClass, trackerReference);
+//
+//        List property = asList(propValue);
+//        Dictionary properties = new Hashtable();
+//        properties.put(propKey, property);
+//        trackerRegistration.setProperties(properties);
+//        EasyMock.expectLastCall();
+//
+//        if (matchingInterfaces.size() == 0 && matchingFilters.size() > 0) {
+//            Iterator filters = matchingFilters.iterator();
+//            while (filters.hasNext()) {
+//                Filter f = control.createMock(Filter.class);
+//                dswContext.addFilter((String)filters.next(), f);
+//                f.match(EasyMock.isA(Dictionary.class));
+//                EasyMock.expectLastCall().andReturn(true);
+//            }
+//        }
+//
+//        control.replay();
+//
+//        CxfFindListenerHook hook = new CxfFindListenerHook(dswContext, null);
+//
+//        ListenerHook.ListenerInfo info = new ListenerHook.ListenerInfo() {
+//            public BundleContext getBundleContext() {
+//                return requestingContext;
+//            }
+//
+//            public String getFilter() {
+//                return filter;
+//            }
+//
+//            public boolean isRemoved() {
+//                return false;
+//            }
+//        };
+//        hook.added(Collections.singleton(info));
+//
+//        DiscoveredServiceTracker tracker = (DiscoveredServiceTracker)
+//            dswContext.getService(trackerReference);
+//        assertNotNull(tracker);
+//
+//        Collection interfaces = asList(serviceClass);
+//
+//        notifyAvailable(tracker, matchingInterfaces, matchingFilters, "1234");
+//        notifyAvailable(tracker, matchingInterfaces, matchingFilters, "5678");
+//        notifyAvailable(tracker, matchingInterfaces, matchingFilters, "1234");
+//
+//        notifyUnAvailable(tracker, "1234");
+//        notifyUnAvailable(tracker, "5678");
+//
+//        notifyAvailable(tracker, matchingInterfaces, matchingFilters , "1234");
+//
+//        control.verify();
+//
+//        Map<String, ServiceReference> registeredRefs = dswContext.getRegisteredReferences();
+//        assertNotNull(registeredRefs);
+//        assertEquals(2, registeredRefs.size());
+//        assertNotNull(registeredRefs.get(serviceClass));
+//        assertSame(serviceReference, registeredRefs.get(serviceClass));
+//
+//        Map<String, ServiceRegistration> registeredRegs = dswContext.getRegisteredRegistrations();
+//        assertNotNull(registeredRegs);
+//        assertEquals(2, registeredRegs.size());
+//        assertNotNull(registeredRegs.get(trackerClass));
+//        assertSame(trackerRegistration, registeredRegs.get(trackerClass));
+//
+//        List<Object> registeredServices = dswContext.getRegisteredServices();
+//        assertNotNull(registeredServices);
+//        assertEquals(2, registeredServices.size());
+//    }
+//
+//    @Test
+//    public void testConstructorAndGetters() {
+//        BundleContext bc = control.createMock(BundleContext.class);
+//        CxfRemoteServiceAdmin dp = control.createMock(CxfRemoteServiceAdmin.class);
+//        control.replay();
+//
+//        CxfFindListenerHook clh = new CxfFindListenerHook(bc, dp);
+//        assertSame(bc, clh.getContext());
+//        assertSame(dp, clh.getDistributionProvider());
+//    }
+//
+//    @Test
+//    public void testFindHook() {
+//        BundleContext bc = EasyMock.createNiceMock(BundleContext.class);
+//
+//        final List<String> lookupCalls = new ArrayList<String>();
+//        CxfFindListenerHook fh = new CxfFindListenerHook(bc, null) {
+//            @Override
+//            protected synchronized void lookupDiscoveryService(
+//                    String interfaceName, String filterValue) {
+//                lookupCalls.add(interfaceName);
+//                lookupCalls.add(filterValue);
+//            }
+//        };
+//
+//        String clazz = "my.app.Class";
+//        String filter = "&(A=B)(C=D)";
+//        fh.find(null, clazz, filter, true, null);
+//
+//        assertEquals(Arrays.asList(clazz, filter), lookupCalls);
+//    }
+//
+//    private void notifyAvailable(DiscoveredServiceTracker tracker,
+//                                 Collection interfaces,
+//                                 Collection filters,
+//                                 String endpointId) {
+//        Map<String, Object> props = new Hashtable<String, Object>();
+//        props.put("osgi.remote.interfaces", "*");
+//        props.put("osgi.remote.endpoint.id", endpointId);
+//        tracker.serviceChanged(new Notification(AVAILABLE,
+//                                                TestService.class.getName(),
+//                                                interfaces,
+//                                                filters,
+//                                                props));
+//    }
+//
+//    private void notifyUnAvailable(DiscoveredServiceTracker tracker,
+//                                   String endpointId) {
+//        Map<String, Object> props = new Hashtable<String, Object>();
+//        props.put("osgi.remote.endpoint.id", endpointId);
+//        tracker.serviceChanged(new Notification(UNAVAILABLE,
+//                                                TestService.class.getName(),
+//                                                Collections.EMPTY_SET,
+//                                                Collections.EMPTY_SET,
+//                                                props));
+//    }
+//
+//    private List<String> asList(String s) {
+//        List l = new ArrayList<String>();
+//        l.add(s);
+//        return l;
+//    }
+//
+//    private String replacePredicate(String filter) {
+//        return filter.replace("objectClass", ServicePublication.SERVICE_INTERFACE_NAME);
+//    }
+//
+//    private class Notification implements DiscoveredServiceNotification {
+//        private int type;
+//        private ServiceEndpointDescription sed;
+//        private Collection interfaces;
+//        private Collection filters;
+//
+//        Notification(int type,
+//                     String interfaceName,
+//                     Collection interfaces,
+//                     Collection filters,
+//                     Map<String, Object> props) {
+//            this.type = type;
+//            this.sed = new ServiceEndpointDescriptionImpl(interfaceName, props);
+//            this.interfaces = interfaces;
+//            this.filters = filters;
+//        }
+//
+//        public int getType() {
+//            return type;
+//        }
+//
+//        public ServiceEndpointDescription getServiceEndpointDescription() {
+//            return sed;
+//        }
+//
+//        public Collection getInterfaces() {
+//            return interfaces;
+//        }
+//
+//        public Collection getFilters() {
+//            return filters;
+//        }
+//    }
+}
diff --git a/trunk/dsw/cxf-dsw/src/test/java/org/apache/cxf/dosgi/dsw/hooks/CxfPublishHookTest.java b/trunk/dsw/cxf-dsw/src/test/java/org/apache/cxf/dosgi/dsw/hooks/CxfPublishHookTest.java
new file mode 100644
index 0000000..40b40c5
--- /dev/null
+++ b/trunk/dsw/cxf-dsw/src/test/java/org/apache/cxf/dosgi/dsw/hooks/CxfPublishHookTest.java
@@ -0,0 +1,299 @@
+/**
+ * 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.dsw.hooks;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+public class CxfPublishHookTest extends Assert {
+
+    @Test
+    public void testDUMMY() throws Exception {
+    }
+
+    //
+    // private IMocksControl control;
+    //
+    // @Before
+    // public void setUp() {
+    // control = EasyMock.createNiceControl();
+    // }
+    //
+    // @Test
+    // public void testPublishSingleInterface() throws Exception {
+    // String[] serviceNames = new String[]{TestService.class.getName()};
+    // String[] addresses = new String[]{"http://localhost:9000/hello"};
+    // doTestPublishHook("remote-services.xml", serviceNames, addresses);
+    // }
+    //
+    // @Test
+    // public void testPublishSingleInterfaceAltFormat() throws Exception {
+    // String[] serviceNames = new String[]{TestService.class.getName()};
+    // String[] addresses = new String[]{"http://localhost:9000/hello"};
+    // doTestPublishHook("alt-remote-services.xml", serviceNames, addresses);
+    // }
+    //
+    // @Test
+    // public void testPublishMultiInterface() throws Exception {
+    // String[] serviceNames = new String[]{TestService.class.getName(),
+    // AdditionalInterface.class.getName()};
+    // String[] addresses = new String[]{"http://localhost:9001/hello",
+    // "http://localhost:9002/hello"};
+    // doTestPublishHook("multi-services.xml", serviceNames, addresses);
+    // }
+    //
+    // @SuppressWarnings("unchecked")
+    // private void doTestPublishHook(String remoteServices,
+    // String[] serviceNames,
+    // String[] addresses) throws Exception {
+    //
+    // Bundle bundle = control.createMock(Bundle.class);
+    // bundle.findEntries(EasyMock.eq("OSGI-INF/remote-service"),
+    // EasyMock.eq("*.xml"), EasyMock.anyBoolean());
+    // EasyMock.expectLastCall().andReturn(Collections.enumeration(
+    // Arrays.asList(getClass().getResource("/OSGI-INF/remote-service/" + remoteServices))));
+    // Dictionary<String, String> bundleHeaders = new Hashtable<String, String>();
+    // bundleHeaders.put(org.osgi.framework.Constants.BUNDLE_NAME,
+    // "Test Bundle");
+    // bundleHeaders.put(org.osgi.framework.Constants.BUNDLE_VERSION,
+    // "1.0.0");
+    // bundle.getHeaders();
+    // EasyMock.expectLastCall().andReturn(bundleHeaders).anyTimes();
+    // BundleContext requestingContext = control.createMock(BundleContext.class);
+    // bundle.getBundleContext();
+    // EasyMock.expectLastCall().andReturn(requestingContext).anyTimes();
+    //
+    // TestService serviceObject = new TestServiceImpl();
+    // Dictionary serviceProps = new Hashtable();
+    //
+    // ServiceReference sref = control.createMock(ServiceReference.class);
+    // sref.getBundle();
+    // EasyMock.expectLastCall().andReturn(bundle).anyTimes();
+    // sref.getProperty(Constants.OBJECTCLASS);
+    // EasyMock.expectLastCall().andReturn(serviceNames).anyTimes();
+    // sref.getPropertyKeys();
+    // EasyMock.expectLastCall().andReturn(new String[]{}).anyTimes();
+    //
+    // BundleTestContext dswContext = new BundleTestContext(bundle);
+    //
+    // ServiceRegistration[] serviceRegistrations =
+    // new ServiceRegistration[serviceNames.length];
+    //
+    // for (int i = 0; i < serviceNames.length ; i++) {
+    // serviceRegistrations[i] =
+    // control.createMock(ServiceRegistration.class);
+    // dswContext.addServiceRegistration(serviceNames[i],
+    // serviceRegistrations[i]);
+    // dswContext.addServiceReference(serviceNames[i], sref);
+    // }
+    // dswContext.registerService(serviceNames, serviceObject, serviceProps);
+    //
+    // Server server = control.createMock(Server.class);
+    //
+    // String publicationClass = ServicePublication.class.getName();
+    // ServiceRegistration publicationRegistration =
+    // control.createMock(ServiceRegistration.class);
+    // publicationRegistration.unregister();
+    // EasyMock.expectLastCall().times(serviceNames.length);
+    // dswContext.addServiceRegistration(publicationClass, publicationRegistration);
+    // ServiceReference publicationReference =
+    // control.createMock(ServiceReference.class);
+    // dswContext.addServiceReference(publicationClass, publicationReference);
+    // control.replay();
+    //
+    // TestPublishHook hook = new TestPublishHook(dswContext,
+    // serviceObject,
+    // server);
+    // hook.publishEndpoint(sref);
+    // hook.verify();
+    //
+    // assertEquals(1, hook.getEndpoints().size());
+    // List<EndpointInfo> list = hook.getEndpoints().get(sref);
+    // assertNotNull(list);
+    // assertEquals(serviceNames.length, list.size());
+    // for (int i = 0; i < serviceNames.length; i++) {
+    // assertNotNull(list.get(i));
+    // ServiceEndpointDescription sd = list.get(i).getServiceDescription();
+    // assertNotNull(sd);
+    // assertNotNull(sd.getProvidedInterfaces());
+    // assertEquals(1, sd.getProvidedInterfaces().size());
+    // Collection names = sd.getProvidedInterfaces();
+    // assertEquals(1, names.size());
+    // assertEquals(serviceNames[i], names.toArray()[0]);
+    // String excludeProp = "osgi.remote.interfaces";
+    // assertNull(sd.getProperties().get(excludeProp));
+    // String addrProp =
+    // org.apache.cxf.dosgi.dsw.Constants.WS_ADDRESS_PROPERTY_OLD;
+    // assertEquals(addresses[i], sd.getProperties().get(addrProp));
+    // }
+    //
+    // Map<String, ServiceRegistration> registeredRegs =
+    // dswContext.getRegisteredRegistrations();
+    // assertNotNull(registeredRegs);
+    // assertEquals(serviceNames.length + 1, registeredRegs.size());
+    // assertNotNull(registeredRegs.get(publicationClass));
+    // assertSame(publicationRegistration, registeredRegs.get(publicationClass));
+    //
+    // Map<String, List<Dictionary>> registeredProps =
+    // dswContext.getRegisteredProperties();
+    // assertNotNull(registeredProps);
+    // assertEquals(serviceNames.length + 1, registeredProps.size());
+    // assertNotNull(registeredProps.get(publicationClass));
+    // List<Dictionary> propsList = registeredProps.get(publicationClass);
+    // assertEquals(serviceNames.length, propsList.size());
+    // for (Dictionary props : propsList) {
+    // Collection interfaces =
+    // (Collection)props.get(SERVICE_INTERFACE_NAME);
+    // assertNotNull(interfaces);
+    // assertTrue(interfaces.contains(TestService.class.getName())
+    // || interfaces.contains(AdditionalInterface.class.getName()));
+    // }
+    //
+    // hook.removeEndpoints();
+    //
+    // control.verify();
+    // }
+    //
+    // @SuppressWarnings("unchecked")
+    // @Test
+    // public void testPublishMultipleTimes() {
+    // Bundle bundle = control.createMock(Bundle.class);
+    // bundle.findEntries(EasyMock.eq("OSGI-INF/remote-service"),
+    // EasyMock.eq("*.xml"), EasyMock.anyBoolean());
+    // EasyMock.expectLastCall().andAnswer(new IAnswer<Object>() {
+    // public Object answer() throws Throwable {
+    // return Collections.enumeration(Arrays.asList(
+    // getClass().getResource("/OSGI-INF/remote-service/remote-services.xml")));
+    // }
+    // }).anyTimes();
+    // Dictionary<String, String> bundleHeaders = new Hashtable<String, String>();
+    // bundleHeaders.put(org.osgi.framework.Constants.BUNDLE_NAME,
+    // "org.apache.cxf.example.bundle");
+    // bundleHeaders.put(org.osgi.framework.Constants.BUNDLE_VERSION,
+    // "1.0.0");
+    // bundle.getHeaders();
+    // EasyMock.expectLastCall().andReturn(bundleHeaders).anyTimes();
+    // BundleContext requestingContext = control.createMock(BundleContext.class);
+    // bundle.getBundleContext();
+    // EasyMock.expectLastCall().andReturn(requestingContext).anyTimes();
+    //
+    // TestService serviceObject = new TestServiceImpl();
+    // Dictionary serviceProps = new Hashtable();
+    //
+    // ServiceReference sref = control.createMock(ServiceReference.class);
+    // sref.getBundle();
+    // EasyMock.expectLastCall().andReturn(bundle).anyTimes();
+    // sref.getProperty(Constants.OBJECTCLASS);
+    // String[] serviceNames = {TestService.class.getName()};
+    // EasyMock.expectLastCall().andReturn(serviceNames).anyTimes();
+    // sref.getPropertyKeys();
+    // EasyMock.expectLastCall().andReturn(new String[]{}).anyTimes();
+    //
+    // BundleTestContext dswContext = new BundleTestContext(bundle);
+    // ServiceRegistration[] serviceRegistrations =
+    // new ServiceRegistration[serviceNames.length];
+    // for (int i = 0; i < serviceNames.length ; i++) {
+    // serviceRegistrations[i] =
+    // control.createMock(ServiceRegistration.class);
+    // dswContext.addServiceRegistration(serviceNames[i],
+    // serviceRegistrations[i]);
+    // dswContext.addServiceReference(serviceNames[i], sref);
+    // }
+    // dswContext.registerService(serviceNames, serviceObject, serviceProps);
+    //
+    // final Server server = control.createMock(Server.class);
+    // control.replay();
+    //
+    // CxfPublishHook hook = new CxfPublishHook(dswContext, null) {
+    // @Override
+    // Server createServer(ServiceReference sref, ServiceEndpointDescription sd) {
+    // return server;
+    // }
+    // };
+    // assertNull("Precondition not met", hook.getEndpoints().get(sref));
+    // hook.publishEndpoint(sref);
+    // assertEquals(1, hook.getEndpoints().get(sref).size());
+    //
+    // hook.endpoints.put(sref, new ArrayList<EndpointInfo>());
+    // assertEquals("Precondition failed", 0, hook.getEndpoints().get(sref).size());
+    // hook.publishEndpoint(sref);
+    // assertEquals(0, hook.getEndpoints().get(sref).size());
+    //
+    // control.verify();
+    // }
+    //
+    // private static class TestPublishHook extends CxfPublishHook {
+    //
+    // private boolean called;
+    // private TestService serviceObject;
+    // private Server server;
+    //
+    // public TestPublishHook(BundleContext bc, TestService serviceObject,
+    // Server s) {
+    // super(bc, null);
+    // this.serviceObject = serviceObject;
+    // this.server = s;
+    // }
+    //
+    // @Override
+    // protected ConfigurationTypeHandler getHandler(ServiceEndpointDescription sd,
+    // Map<String, Object> props) {
+    // return new ConfigurationTypeHandler() {
+    // public String getType() {
+    // return "test";
+    // }
+    //
+    // public Object createProxy(ServiceReference sr,
+    // BundleContext dswContext, BundleContext callingContext,
+    // Class<?> iClass, ServiceEndpointDescription sd) {
+    // throw new UnsupportedOperationException();
+    // }
+    //
+    // public Server createServer(ServiceReference sr,
+    // BundleContext dswContext, BundleContext callingContext,
+    // ServiceEndpointDescription sd, Class<?> iClass, Object serviceBean) {
+    // Assert.assertSame(serviceBean, serviceObject);
+    // TestPublishHook.this.setCalled();
+    // Map props = sd.getProperties();
+    // String address = (String)props.get(WS_ADDRESS_PROPERTY);
+    // if (address != null) {
+    // props.put(ENDPOINT_LOCATION, address);
+    // }
+    // return server;
+    // }
+    //
+    // };
+    // }
+    //
+    // public void setCalled() {
+    // called = true;
+    // }
+    //
+    // public void verify() {
+    // Assert.assertTrue(called);
+    // }
+    // }
+    //
+    // public interface AdditionalInterface {
+    // }
+    //
+    // private static class TestServiceImpl implements TestService, AdditionalInterface {
+    //
+    // }
+}
diff --git a/trunk/dsw/cxf-dsw/src/test/java/org/apache/cxf/dosgi/dsw/hooks/ServiceHookUtilsTest.java b/trunk/dsw/cxf-dsw/src/test/java/org/apache/cxf/dosgi/dsw/hooks/ServiceHookUtilsTest.java
new file mode 100644
index 0000000..c004702
--- /dev/null
+++ b/trunk/dsw/cxf-dsw/src/test/java/org/apache/cxf/dosgi/dsw/hooks/ServiceHookUtilsTest.java
@@ -0,0 +1,116 @@
+/**
+ * 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.dsw.hooks;
+
+import junit.framework.TestCase;
+
+public class ServiceHookUtilsTest extends TestCase {
+
+    public void testDUMMY() {
+        assertTrue(true);
+    }
+
+/*
+    public void testCreateServer() {
+        IMocksControl control = EasyMock.createNiceControl();
+
+        Server srvr = control.createMock(Server.class);
+        ServiceReference serviceReference = control.createMock(ServiceReference.class);
+        BundleContext dswContext = control.createMock(BundleContext.class);
+        BundleContext callingContext = control.createMock(BundleContext.class);
+        ServiceEndpointDescription sd = new ServiceEndpointDescriptionImpl("java.lang.String");
+        Object service = "hi";
+
+        ConfigurationTypeHandler handler = control.createMock(ConfigurationTypeHandler.class);
+        handler.createServer(serviceReference, dswContext, callingContext, sd, String.class, service);
+        EasyMock.expectLastCall().andReturn(srvr);
+        control.replay();
+
+        assertSame(srvr,
+            ServiceHookUtils.createServer(handler, serviceReference, dswContext, callingContext, sd, service));
+    }
+
+    public void testNoServerWhenNoInterfaceSpecified() {
+        IMocksControl control = EasyMock.createNiceControl();
+
+        Server srvr = control.createMock(Server.class);
+        ServiceReference serviceReference = control.createMock(ServiceReference.class);
+        BundleContext dswContext = control.createMock(BundleContext.class);
+        BundleContext callingContext = control.createMock(BundleContext.class);
+        ServiceEndpointDescription sd = mockServiceDescription(control, "Foo");
+        Object service = "hi";
+
+        ConfigurationTypeHandler handler = control.createMock(ConfigurationTypeHandler.class);
+        handler.createServer(serviceReference, dswContext, callingContext, sd, String.class, service);
+        EasyMock.expectLastCall().andReturn(srvr);
+        control.replay();
+
+        assertNull(ServiceHookUtils.createServer(handler, serviceReference, dswContext,
+                                                 callingContext, sd, service));
+    }
+
+    public void testPublish() throws Exception {
+        Map<String, Object> props = new HashMap<String, Object>();
+        props.put("foo", "bar");
+        props.put(ServicePublication.ENDPOINT_LOCATION, "http:localhost/xyz");
+        ServiceEndpointDescriptionImpl sed = new ServiceEndpointDescriptionImpl(String.class.getName(), props);
+        assertEquals(new URI("http:localhost/xyz"), sed.getLocation());
+
+        final Dictionary<String, Object> expectedProps = new Hashtable<String, Object>();
+        expectedProps.put(ServicePublication.SERVICE_PROPERTIES, props);
+        expectedProps.put(ServicePublication.SERVICE_INTERFACE_NAME, Collections.singleton(String.class.getName()));
+        expectedProps.put(ServicePublication.ENDPOINT_LOCATION, new URI("http:localhost/xyz"));
+
+        BundleContext bc = EasyMock.createMock(BundleContext.class);
+        EasyMock.expect(bc.registerService(
+            EasyMock.eq(ServicePublication.class.getName()),
+            EasyMock.anyObject(),
+            (Dictionary<?, ?>) EasyMock.anyObject()))
+                .andAnswer(new IAnswer<ServiceRegistration>() {
+                    public ServiceRegistration answer() throws Throwable {
+                        assertTrue(EasyMock.getCurrentArguments()[1] instanceof ServicePublication);
+                        Dictionary<?, ?> actualProps =
+                            (Dictionary<?, ?>) EasyMock.getCurrentArguments()[2];
+                        UUID uuid = UUID.fromString(actualProps.get(ServicePublication.ENDPOINT_SERVICE_ID)
+                                                        .toString());
+                        expectedProps.put(ServicePublication.ENDPOINT_SERVICE_ID, uuid.toString());
+                        assertEquals(expectedProps, actualProps);
+                        return EasyMock.createMock(ServiceRegistration.class);
+                    }
+                });
+        EasyMock.replay(bc);
+
+        ServiceHookUtils.publish(bc, null, sed);
+        EasyMock.verify(bc);
+    }
+
+    private ServiceEndpointDescription mockServiceDescription(IMocksControl control,
+                                                              String... interfaceNames) {
+        List<String> iList = new ArrayList<String>();
+        for (String iName : interfaceNames) {
+            iList.add(iName);
+        }
+        ServiceEndpointDescription sd = control.createMock(ServiceEndpointDescription.class);
+        sd.getProvidedInterfaces();
+        EasyMock.expectLastCall().andReturn(iList);
+        return sd;
+    }
+*/
+}
+
diff --git a/trunk/dsw/cxf-dsw/src/test/java/org/apache/cxf/dosgi/dsw/hooks/TestService.java b/trunk/dsw/cxf-dsw/src/test/java/org/apache/cxf/dosgi/dsw/hooks/TestService.java
new file mode 100644
index 0000000..07b5088
--- /dev/null
+++ b/trunk/dsw/cxf-dsw/src/test/java/org/apache/cxf/dosgi/dsw/hooks/TestService.java
@@ -0,0 +1,22 @@
+/**
+ * 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.dsw.hooks;
+
+public interface TestService {
+}
diff --git a/trunk/dsw/cxf-dsw/src/test/java/org/apache/cxf/dosgi/dsw/qos/IntentManagerImplTest.java b/trunk/dsw/cxf-dsw/src/test/java/org/apache/cxf/dosgi/dsw/qos/IntentManagerImplTest.java
new file mode 100644
index 0000000..d7dad6f
--- /dev/null
+++ b/trunk/dsw/cxf-dsw/src/test/java/org/apache/cxf/dosgi/dsw/qos/IntentManagerImplTest.java
@@ -0,0 +1,278 @@
+/**
+ * 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.dsw.qos;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import junit.framework.Assert;
+
+import org.apache.cxf.binding.BindingConfiguration;
+import org.apache.cxf.endpoint.AbstractEndpointFactory;
+import org.apache.cxf.feature.AbstractFeature;
+import org.apache.cxf.feature.Feature;
+import org.easymock.classextension.EasyMock;
+import org.easymock.classextension.IMocksControl;
+import org.junit.Test;
+
+public class IntentManagerImplTest extends Assert {
+
+    @Test
+    public void testIntents() throws Exception {
+        Map<String, Object> intents = new HashMap<String, Object>();
+        intents.put("A", new TestFeature("A"));
+        intents.put("SOAP", new TestFeature("SOAP"));
+        final IntentMap intentMap = new IntentMap(intents);
+
+        IMocksControl control = EasyMock.createNiceControl();
+        List<Feature> features = new ArrayList<Feature>();
+        AbstractEndpointFactory factory = control.createMock(AbstractEndpointFactory.class);
+        control.replay();
+
+        IntentManager intentManager = new IntentManagerImpl(intentMap, 10000);
+
+        Map<String, Object> props = new HashMap<String, Object>();
+        props.put("osgi.remote.requires.intents", "A");
+
+        List<String> effectiveIntents = Arrays.asList(intentManager.applyIntents(features, factory, props));
+        assertEquals(Arrays.asList("A", "SOAP"), effectiveIntents);
+    }
+
+    @Test
+    public void testMultiIntents() {
+        final IntentMap intentMap = new IntentMap(new DefaultIntentMapFactory().create());
+        intentMap.put("confidentiality.message", new TestFeature("confidentiality.message"));
+        intentMap.put("transactionality", new TestFeature("transactionality"));
+
+        IMocksControl control = EasyMock.createNiceControl();
+        List<Feature> features = new ArrayList<Feature>();
+        AbstractEndpointFactory factory = control.createMock(AbstractEndpointFactory.class);
+        control.replay();
+
+        IntentManager intentManager = new IntentManagerImpl(intentMap);
+
+        Map<String, Object> props = new HashMap<String, Object>();
+        props.put("osgi.remote.requires.intents", "transactionality confidentiality.message");
+
+        List<String> effectiveIntents = Arrays.asList(intentManager.applyIntents(features, factory, props));
+        assertTrue(effectiveIntents.contains("transactionality"));
+        assertTrue(effectiveIntents.contains("confidentiality.message"));
+    }
+
+    @Test
+    public void testFailedIntent() {
+        Map<String, Object> intents = new HashMap<String, Object>();
+        intents.put("A", new TestFeature("A"));
+        final IntentMap intentMap = new IntentMap(intents);
+
+        IMocksControl control = EasyMock.createNiceControl();
+        List<Feature> features = new ArrayList<Feature>();
+        AbstractEndpointFactory factory = control.createMock(AbstractEndpointFactory.class);
+        control.replay();
+
+        IntentManager intentManager = new IntentManagerImpl(intentMap);
+
+        Map<String, Object> props = new HashMap<String, Object>();
+        props.put("osgi.remote.requires.intents", "A B");
+        // ServiceEndpointDescription sd =
+        //         new ServiceEndpointDescriptionImpl(Arrays.asList(String.class.getName()), props);
+
+        try {
+            intentManager.applyIntents(features, factory, props);
+            Assert.fail("applyIntents() should have thrown an exception as there was an unsatisfiable intent");
+        } catch (IntentUnsatisfiedException iue) {
+            assertEquals("B", iue.getIntent());
+        }
+    }
+
+    @Test
+    public void testInferIntents() {
+        Map<String, Object> intents = new HashMap<String, Object>();
+        intents.put("SOAP", new TestFeature("SOAP"));
+        intents.put("Prov", "PROVIDED");
+        AbstractFeature feat1 = new TestFeature("feat1");
+        intents.put("A", feat1);
+        intents.put("A_alt", feat1);
+        intents.put("B", new TestFeature("B"));
+        final IntentMap intentMap = new IntentMap(intents);
+
+        IMocksControl control = EasyMock.createNiceControl();
+        List<Feature> features = new ArrayList<Feature>();
+        AbstractEndpointFactory factory = control.createMock(AbstractEndpointFactory.class);
+        control.replay();
+
+        IntentManager intentManager = new IntentManagerImpl(intentMap);
+
+        Map<String, Object> props = new HashMap<String, Object>();
+        props.put("osgi.remote.requires.intents", "A");
+        // ServiceEndpointDescription sd =
+        //         new ServiceEndpointDescriptionImpl(Arrays.asList(String.class.getName()), props);
+
+        List<String> effectiveIntents = Arrays.asList(intentManager.applyIntents(features, factory, props));
+        assertEquals(4, effectiveIntents.size());
+        assertTrue(effectiveIntents.contains("Prov"));
+        assertTrue(effectiveIntents.contains("A"));
+        assertTrue(effectiveIntents.contains("A_alt"));
+    }
+
+    @Test
+    public void testDefaultBindingIntent() {
+        IMocksControl control = EasyMock.createNiceControl();
+
+        Map<String, Object> intents = new HashMap<String, Object>();
+        BindingConfiguration feat1 = control.createMock(BindingConfiguration.class);
+        intents.put("A", new AbstractFeature() {
+        });
+        intents.put("SOAP", feat1);
+        intents.put("SOAP.1_1", feat1);
+        intents.put("SOAP.1_2", control.createMock(BindingConfiguration.class));
+        final IntentMap intentMap = new IntentMap(intents);
+
+        List<Feature> features = new ArrayList<Feature>();
+        AbstractEndpointFactory factory = control.createMock(AbstractEndpointFactory.class);
+        control.replay();
+        IntentManager intentManager = new IntentManagerImpl(intentMap);
+
+        Map<String, Object> props = new HashMap<String, Object>();
+        props.put("osgi.remote.requires.intents", "A");
+        // ServiceEndpointDescription sd =
+        //         new ServiceEndpointDescriptionImpl(Arrays.asList(String.class.getName()), props);
+
+        List<String> effectiveIntents = Arrays.asList(intentManager.applyIntents(features, factory, props));
+        assertEquals(3, effectiveIntents.size());
+        assertTrue(effectiveIntents.contains("A"));
+        assertTrue(effectiveIntents.contains("SOAP"));
+        assertTrue(effectiveIntents.contains("SOAP.1_1"));
+    }
+
+    @Test
+    public void testExplicitBindingIntent() {
+        IMocksControl control = EasyMock.createNiceControl();
+
+        Map<String, Object> intents = new HashMap<String, Object>();
+        BindingConfiguration feat1 = control.createMock(BindingConfiguration.class);
+        intents.put("A", new AbstractFeature() {
+        });
+        intents.put("SOAP", feat1);
+        intents.put("SOAP.1_1", feat1);
+        intents.put("SOAP.1_2", control.createMock(BindingConfiguration.class));
+        final IntentMap intentMap = new IntentMap(intents);
+
+        List<Feature> features = new ArrayList<Feature>();
+        AbstractEndpointFactory factory = control.createMock(AbstractEndpointFactory.class);
+        control.replay();
+
+        IntentManager intentManager = new IntentManagerImpl(intentMap);
+
+        Map<String, Object> props = new HashMap<String, Object>();
+        props.put("osgi.remote.requires.intents", "A SOAP.1_2");
+        // ServiceEndpointDescription sd =
+        //         new ServiceEndpointDescriptionImpl(Arrays.asList(String.class.getName()), props);
+
+        List<String> effectiveIntents = Arrays.asList(intentManager.applyIntents(features, factory, props));
+        assertEquals(2, effectiveIntents.size());
+        assertTrue(effectiveIntents.contains("A"));
+        assertTrue(effectiveIntents.contains("SOAP.1_2"));
+    }
+
+    public void testInheritMasterIntentMapDefault() {
+        List<String> features = runTestInheritMasterIntentMap("A B");
+
+        assertEquals(2, features.size());
+        assertTrue(features.contains("appFeatureA"));
+        assertTrue(features.contains("masterFeatureB"));
+    }
+
+    public void testInheritMasterIntentMap() {
+        List<String> features = runTestInheritMasterIntentMap("A B");
+
+        assertEquals(2, features.size());
+        assertTrue(features.contains("appFeatureA"));
+        assertTrue(features.contains("masterFeatureB"));
+    }
+
+    private List<String> runTestInheritMasterIntentMap(String requestedIntents) {
+        Map<String, Object> masterIntents = new HashMap<String, Object>();
+        masterIntents.put("A", new TestFeature("masterFeatureA"));
+        masterIntents.put("B", new TestFeature("masterFeatureB"));
+        final IntentMap intentMap = new IntentMap(masterIntents);
+        intentMap.put("A", new TestFeature("appFeatureA"));
+
+        IMocksControl control = EasyMock.createNiceControl();
+        List<Feature> features = new ArrayList<Feature>();
+        AbstractEndpointFactory factory = control.createMock(AbstractEndpointFactory.class);
+        control.replay();
+
+        Map<String, Object> props = new HashMap<String, Object>();
+        props.put("osgi.remote.requires.intents", requestedIntents);
+
+        IntentManagerImpl intentManager = new IntentManagerImpl(intentMap);
+        intentManager.applyIntents(features, factory, props);
+
+        List<String> featureNames = new ArrayList<String>();
+        for (Feature f : features) {
+            featureNames.add(f.toString());
+        }
+        return featureNames;
+    }
+
+    @Test
+    public void testProvidedIntents() {
+        Map<String, Object> masterIntents = new HashMap<String, Object>();
+        masterIntents.put("SOAP", "SOAP");
+        masterIntents.put("A", "Provided");
+        masterIntents.put("B", "PROVIDED");
+        final IntentMap intentMap = new IntentMap(masterIntents);
+
+        IMocksControl control = EasyMock.createNiceControl();
+        List<Feature> features = new ArrayList<Feature>();
+        AbstractEndpointFactory factory = control.createMock(AbstractEndpointFactory.class);
+        control.replay();
+
+        Map<String, Object> props = new HashMap<String, Object>();
+        props.put("osgi.remote.requires.intents", "B A");
+
+        IntentManager intentManager = new IntentManagerImpl(intentMap);
+
+        Set<String> effectiveIntents = new HashSet<String>(Arrays.asList(intentManager.applyIntents(features,
+                                                                                                    factory,
+                                                                                                    props)));
+        Set<String> expectedIntents = new HashSet<String>(Arrays.asList(new String[] {"A", "B", "SOAP"}));
+        assertEquals(expectedIntents, effectiveIntents);
+    }
+
+    private static final class TestFeature extends AbstractFeature {
+
+        private final String name;
+
+        private TestFeature(String n) {
+            name = n;
+        }
+
+        @Override
+        public String toString() {
+            return name;
+        }
+    }
+}
diff --git a/trunk/dsw/cxf-dsw/src/test/java/org/apache/cxf/dosgi/dsw/qos/IntentMapTest.java b/trunk/dsw/cxf-dsw/src/test/java/org/apache/cxf/dosgi/dsw/qos/IntentMapTest.java
new file mode 100644
index 0000000..aaa3f0e
--- /dev/null
+++ b/trunk/dsw/cxf-dsw/src/test/java/org/apache/cxf/dosgi/dsw/qos/IntentMapTest.java
@@ -0,0 +1,42 @@
+/**
+ * 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.dsw.qos;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import junit.framework.Assert;
+
+import org.junit.Test;
+
+public class IntentMapTest {
+
+    @Test
+    public void inheritanceTest() {
+        Map<String, Object> defaultMap = new HashMap<String, Object>();
+        defaultMap.put("key1", "defaultValue");
+        IntentMap intentMap = new IntentMap(defaultMap);
+        Assert.assertEquals("defaultValue", intentMap.get("key1"));
+        intentMap.put("key1", "overridden");
+        Assert.assertEquals("overridden", intentMap.get("key1"));
+        Object curValue = intentMap.remove("key1");
+        Assert.assertEquals("overridden", curValue);
+        Assert.assertEquals("defaultValue", intentMap.get("key1"));
+    }
+}
diff --git a/trunk/dsw/cxf-dsw/src/test/java/org/apache/cxf/dosgi/dsw/qos/IntentTrackerTest.java b/trunk/dsw/cxf-dsw/src/test/java/org/apache/cxf/dosgi/dsw/qos/IntentTrackerTest.java
new file mode 100644
index 0000000..74ecd21
--- /dev/null
+++ b/trunk/dsw/cxf-dsw/src/test/java/org/apache/cxf/dosgi/dsw/qos/IntentTrackerTest.java
@@ -0,0 +1,81 @@
+/**
+ * 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.dsw.qos;
+
+import junit.framework.Assert;
+
+import org.apache.cxf.dosgi.dsw.Constants;
+import org.apache.cxf.feature.AbstractFeature;
+import org.easymock.Capture;
+import org.easymock.classextension.EasyMock;
+import org.easymock.classextension.IMocksControl;
+import org.junit.Test;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.Filter;
+import org.osgi.framework.InvalidSyntaxException;
+import org.osgi.framework.ServiceEvent;
+import org.osgi.framework.ServiceListener;
+import org.osgi.framework.ServiceReference;
+
+import static org.easymock.EasyMock.expect;
+
+public class IntentTrackerTest {
+
+    private static final String MY_INTENT_NAME = "myIntent";
+
+    @Test
+    public void testIntentAsService() throws InvalidSyntaxException {
+        IMocksControl c = EasyMock.createControl();
+        BundleContext bc = c.createMock(BundleContext.class);
+        Filter filter = c.createMock(Filter.class);
+        expect(bc.createFilter(EasyMock.<String>anyObject())).andReturn(filter);
+        final Capture<ServiceListener> capturedListener = new Capture<ServiceListener>();
+        bc.addServiceListener(EasyMock.capture(capturedListener), EasyMock.<String>anyObject());
+        EasyMock.expectLastCall().atLeastOnce();
+        expect(bc.getServiceReferences(EasyMock.<String>anyObject(),
+                                       EasyMock.<String>anyObject())).andReturn(new ServiceReference[]{});
+        IntentMap intentMap = new IntentMap();
+
+        // Create a custom intent
+        @SuppressWarnings("unchecked")
+        ServiceReference<AbstractFeature> reference = c.createMock(ServiceReference.class);
+        expect(reference.getProperty(Constants.INTENT_NAME_PROP)).andReturn(MY_INTENT_NAME);
+        AbstractFeature testIntent = new AbstractFeature() {
+        };
+        expect(bc.getService(reference)).andReturn(testIntent).atLeastOnce();
+
+        c.replay();
+
+        IntentTracker tracker = new IntentTracker(bc, intentMap);
+        tracker.open();
+
+        Assert.assertFalse("IntentMap should not contain " + MY_INTENT_NAME, intentMap.containsKey(MY_INTENT_NAME));
+        ServiceListener listener = capturedListener.getValue();
+
+        // Simulate adding custom intent service
+        ServiceEvent event = new ServiceEvent(ServiceEvent.REGISTERED, reference);
+        listener.serviceChanged(event);
+
+        // our custom intent should now be available
+        Assert.assertTrue("IntentMap should contain " + MY_INTENT_NAME, intentMap.containsKey(MY_INTENT_NAME));
+        Assert.assertEquals(testIntent, intentMap.get(MY_INTENT_NAME));
+
+        c.verify();
+    }
+}
diff --git a/trunk/dsw/cxf-dsw/src/test/java/org/apache/cxf/dosgi/dsw/qos/IntentUtilsTest.java b/trunk/dsw/cxf-dsw/src/test/java/org/apache/cxf/dosgi/dsw/qos/IntentUtilsTest.java
new file mode 100644
index 0000000..92c157a
--- /dev/null
+++ b/trunk/dsw/cxf-dsw/src/test/java/org/apache/cxf/dosgi/dsw/qos/IntentUtilsTest.java
@@ -0,0 +1,69 @@
+/**
+ * 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.dsw.qos;
+
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+
+import org.apache.cxf.dosgi.dsw.Constants;
+import org.junit.Assert;
+import org.junit.Test;
+import org.osgi.service.remoteserviceadmin.RemoteConstants;
+
+public class IntentUtilsTest {
+
+    @Test
+    public void testMergeArrays() {
+        Assert.assertNull(IntentUtils.mergeArrays(null, null));
+
+        String[] sa1 = {};
+        Assert.assertEquals(0, IntentUtils.mergeArrays(sa1, null).length);
+
+        String[] sa2 = {"X"};
+        Assert.assertEquals(1, IntentUtils.mergeArrays(null, sa2).length);
+        Assert.assertEquals("X", IntentUtils.mergeArrays(null, sa2)[0]);
+
+        String[] sa3 = {"Y", "Z"};
+        String[] sa4 = {"A", "Z"};
+        Assert.assertEquals(3, IntentUtils.mergeArrays(sa3, sa4).length);
+        Assert.assertEquals(new HashSet<String>(Arrays.asList("A", "Y", "Z")),
+                new HashSet<String>(Arrays.asList(IntentUtils.mergeArrays(sa3, sa4))));
+    }
+
+    @Test
+    public void testRequestedIntents() {
+        Map<String, Object> props = new HashMap<String, Object>();
+        Assert.assertEquals(0, IntentUtils.getRequestedIntents(props).size());
+
+        props.put(RemoteConstants.SERVICE_EXPORTED_INTENTS, "one");
+        Assert.assertEquals(Collections.singleton("one"), IntentUtils.getRequestedIntents(props));
+
+        props.put(RemoteConstants.SERVICE_EXPORTED_INTENTS_EXTRA, new String[] {"two", "three"});
+        Set<String> expected1 = new HashSet<String>(Arrays.asList("one", "two", "three"));
+        Assert.assertEquals(expected1, IntentUtils.getRequestedIntents(props));
+
+        props.put(Constants.EXPORTED_INTENTS_OLD, "A B C");
+        Set<String> expected2 = new HashSet<String>(Arrays.asList("one", "two", "three", "A", "B", "C"));
+        Assert.assertEquals(expected2, IntentUtils.getRequestedIntents(props));
+    }
+}
diff --git a/trunk/dsw/cxf-dsw/src/test/java/org/apache/cxf/dosgi/dsw/service/DistributionProviderImplTest.java b/trunk/dsw/cxf-dsw/src/test/java/org/apache/cxf/dosgi/dsw/service/DistributionProviderImplTest.java
new file mode 100644
index 0000000..f3cf46d
--- /dev/null
+++ b/trunk/dsw/cxf-dsw/src/test/java/org/apache/cxf/dosgi/dsw/service/DistributionProviderImplTest.java
@@ -0,0 +1,124 @@
+/**
+ * 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.dsw.service;
+
+import junit.framework.TestCase;
+
+public class DistributionProviderImplTest extends TestCase {
+
+    public void testDUMMY() {
+        assertTrue(true);
+    }
+
+//    public void testExposedServices() {
+//        BundleContext bc = EasyMock.createNiceMock(BundleContext.class);
+//        EasyMock.replay(bc);
+//        RemoteServiceAdminCore dp = new RemoteServiceAdminCore(bc);
+//
+//        assertEquals(0, dp.getExposedServices().size());
+//        assertEquals(0, dp.getRemoteServices().size());
+//        ServiceReference sr = new TestServiceReference();
+//        ServiceReference sr2 = new TestServiceReference();
+//
+//        dp.addExposedService(sr, null);
+//        assertEquals(1, dp.getExposedServices().size());
+//        assertEquals(0, dp.getRemoteServices().size());
+//        assertSame(sr, dp.getExposedServices().iterator().next());
+//
+//        dp.addExposedService(sr, null);
+//        assertEquals(1, dp.getExposedServices().size());
+//        assertEquals(0, dp.getRemoteServices().size());
+//        assertSame(sr, dp.getExposedServices().iterator().next());
+//
+//        dp.addExposedService(sr2, null);
+//        assertEquals(2, dp.getExposedServices().size());
+//        assertEquals(0, dp.getRemoteServices().size());
+//    }
+//
+//    public void testRemoteServices() {
+//        BundleContext bc = EasyMock.createNiceMock(BundleContext.class);
+//        EasyMock.replay(bc);
+//        RemoteServiceAdminCore dp = new RemoteServiceAdminCore(bc);
+//
+//        assertEquals(0, dp.getExposedServices().size());
+//        assertEquals(0, dp.getRemoteServices().size());
+//        ServiceReference sr = new TestServiceReference();
+//        ServiceReference sr2 = new TestServiceReference();
+//
+//        dp.addRemoteService(sr);
+//        assertEquals(0, dp.getExposedServices().size());
+//        assertEquals(1, dp.getRemoteServices().size());
+//        assertSame(sr, dp.getRemoteServices().iterator().next());
+//
+//        dp.addRemoteService(sr);
+//        assertEquals(0, dp.getExposedServices().size());
+//        assertEquals(1, dp.getRemoteServices().size());
+//        assertSame(sr, dp.getRemoteServices().iterator().next());
+//
+//        dp.addRemoteService(sr2);
+//        assertEquals(0, dp.getExposedServices().size());
+//        assertEquals(2, dp.getRemoteServices().size());
+//    }
+//
+//    public void testPublicationProperties() {
+//        BundleContext bc = EasyMock.createNiceMock(BundleContext.class);
+//        EasyMock.replay(bc);
+//
+//        RemoteServiceAdminCore dp = new RemoteServiceAdminCore(bc);
+//        ServiceReference sr = new TestServiceReference();
+//        ServiceReference sr2 = new TestServiceReference();
+//
+//        assertNull(dp.getExposedProperties(sr));
+//
+//        dp.addExposedService(sr, null);
+//        Map<String, String> pp = new HashMap<String, String>();
+//        pp.put("a", "b");
+//        dp.addExposedService(sr2, pp);
+//
+//        assertEquals(0, dp.getExposedProperties(sr).size());
+//        assertEquals(pp, dp.getExposedProperties(sr2));
+//    }
+//
+//    private static class TestServiceReference implements ServiceReference {
+
+//        public Bundle getBundle() {
+//            return null;
+//        }
+//
+//        public Object getProperty(String arg0) {
+//            return null;
+//        }
+//
+//        public String[] getPropertyKeys() {
+//            return null;
+//        }
+//
+//        public Bundle[] getUsingBundles() {
+//            return null;
+//        }
+//
+//        public boolean isAssignableTo(Bundle arg0, String arg1) {
+//            return false;
+//        }
+//
+//        public int compareTo(Object o) {
+//            return 0;
+//        }
+//    }
+}
diff --git a/trunk/dsw/cxf-dsw/src/test/java/org/apache/cxf/dosgi/dsw/service/EventProducerTest.java b/trunk/dsw/cxf-dsw/src/test/java/org/apache/cxf/dosgi/dsw/service/EventProducerTest.java
new file mode 100644
index 0000000..d1c21e8
--- /dev/null
+++ b/trunk/dsw/cxf-dsw/src/test/java/org/apache/cxf/dosgi/dsw/service/EventProducerTest.java
@@ -0,0 +1,184 @@
+/**
+ * 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.dsw.service;
+
+import java.util.Arrays;
+import java.util.Dictionary;
+import java.util.Hashtable;
+import java.util.List;
+import java.util.UUID;
+
+import org.apache.cxf.endpoint.Server;
+import org.easymock.IAnswer;
+import org.easymock.classextension.EasyMock;
+import org.junit.Assert;
+import org.junit.Test;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.ServiceReference;
+import org.osgi.framework.Version;
+import org.osgi.service.event.Event;
+import org.osgi.service.event.EventAdmin;
+import org.osgi.service.remoteserviceadmin.EndpointDescription;
+import org.osgi.service.remoteserviceadmin.ExportReference;
+import org.osgi.service.remoteserviceadmin.ExportRegistration;
+import org.osgi.service.remoteserviceadmin.RemoteServiceAdminEvent;
+
+public class EventProducerTest {
+
+    @Test
+    public void testPublishNotification() throws Exception {
+        RemoteServiceAdminCore remoteServiceAdminCore = EasyMock.createNiceMock(RemoteServiceAdminCore.class);
+        EasyMock.replay(remoteServiceAdminCore);
+
+        final EndpointDescription endpoint = EasyMock.createNiceMock(EndpointDescription.class);
+        EasyMock.expect(endpoint.getServiceId()).andReturn(Long.MAX_VALUE).anyTimes();
+        final String uuid = UUID.randomUUID().toString();
+        EasyMock.expect(endpoint.getFrameworkUUID()).andReturn(uuid).anyTimes();
+        EasyMock.expect(endpoint.getId()).andReturn("foo://bar").anyTimes();
+        final List<String> interfaces = Arrays.asList("org.foo.Bar", "org.boo.Far");
+        EasyMock.expect(endpoint.getInterfaces()).andReturn(interfaces).anyTimes();
+        EasyMock.expect(endpoint.getConfigurationTypes()).andReturn(Arrays.asList("org.apache.cxf.ws")).anyTimes();
+        EasyMock.replay(endpoint);
+        final ServiceReference sref = EasyMock.createNiceMock(ServiceReference.class);
+        EasyMock.replay(sref);
+
+        final Bundle bundle = EasyMock.createNiceMock(Bundle.class);
+        EasyMock.expect(bundle.getBundleId()).andReturn(42L).anyTimes();
+        EasyMock.expect(bundle.getSymbolicName()).andReturn("test.bundle").anyTimes();
+        Dictionary<String, String> headers = new Hashtable<String, String>();
+        headers.put("Bundle-Version", "1.2.3.test");
+        EasyMock.expect(bundle.getHeaders()).andReturn(headers).anyTimes();
+        EasyMock.replay(bundle);
+
+        EventAdmin ea = EasyMock.createNiceMock(EventAdmin.class);
+        ea.postEvent((Event) EasyMock.anyObject());
+        EasyMock.expectLastCall().andAnswer(new IAnswer<Object>() {
+            @Override
+            public Object answer() throws Throwable {
+                Event event = (Event) EasyMock.getCurrentArguments()[0];
+
+                Assert.assertEquals("org/osgi/service/remoteserviceadmin/EXPORT_REGISTRATION", event.getTopic());
+                Assert.assertSame(bundle, event.getProperty("bundle"));
+                Assert.assertEquals(42L, event.getProperty("bundle.id"));
+                Assert.assertEquals("test.bundle", event.getProperty("bundle.symbolicname"));
+                Assert.assertEquals(new Version(1, 2, 3, "test"), event.getProperty("bundle.version"));
+                Assert.assertNull(event.getProperty("cause"));
+                Assert.assertEquals(endpoint, event.getProperty("export.registration"));
+
+                Assert.assertEquals(Long.MAX_VALUE, event.getProperty("service.remote.id"));
+                Assert.assertEquals(uuid, event.getProperty("service.remote.uuid"));
+                Assert.assertEquals("foo://bar", event.getProperty("service.remote.uri"));
+                Assert.assertTrue(Arrays.equals(interfaces.toArray(new String[] {}),
+                                                (String[]) event.getProperty("objectClass")));
+
+                Assert.assertNotNull(event.getProperty("timestamp"));
+
+                RemoteServiceAdminEvent rsae = (RemoteServiceAdminEvent) event.getProperty("event");
+                Assert.assertNull(rsae.getException());
+                Assert.assertEquals(RemoteServiceAdminEvent.EXPORT_REGISTRATION, rsae.getType());
+                Assert.assertSame(bundle, rsae.getSource());
+                ExportReference er = rsae.getExportReference();
+                Assert.assertSame(endpoint, er.getExportedEndpoint());
+                Assert.assertSame(sref, er.getExportedService());
+
+                return null;
+            }
+        });
+        EasyMock.replay(ea);
+
+        ServiceReference eaSref = EasyMock.createNiceMock(ServiceReference.class);
+        EasyMock.replay(eaSref);
+
+        BundleContext bc = EasyMock.createNiceMock(BundleContext.class);
+        EasyMock.expect(bc.getBundle()).andReturn(bundle).anyTimes();
+        EasyMock.expect(bc.getAllServiceReferences(EventAdmin.class.getName(), null))
+            .andReturn(new ServiceReference[] {eaSref}).anyTimes();
+        EasyMock.expect(bc.getService(eaSref)).andReturn(ea).anyTimes();
+        EasyMock.replay(bc);
+        EventProducer eventProducer = new EventProducer(bc);
+
+        ExportRegistrationImpl ereg = new ExportRegistrationImpl(sref, endpoint, remoteServiceAdminCore, (Server)null);
+        eventProducer.publishNotification(ereg);
+    }
+
+    @Test
+    public void testPublishErrorNotification() throws Exception {
+        RemoteServiceAdminCore rsaCore = EasyMock.createNiceMock(RemoteServiceAdminCore.class);
+        EasyMock.replay(rsaCore);
+
+        final EndpointDescription endpoint = EasyMock.createNiceMock(EndpointDescription.class);
+        EasyMock.expect(endpoint.getInterfaces()).andReturn(Arrays.asList("org.foo.Bar")).anyTimes();
+        EasyMock.replay(endpoint);
+        final ServiceReference sref = EasyMock.createNiceMock(ServiceReference.class);
+        EasyMock.replay(sref);
+
+        final Bundle bundle = EasyMock.createNiceMock(Bundle.class);
+        EasyMock.expect(bundle.getBundleId()).andReturn(42L).anyTimes();
+        EasyMock.expect(bundle.getSymbolicName()).andReturn("test.bundle").anyTimes();
+        EasyMock.expect(bundle.getHeaders()).andReturn(new Hashtable<String, String>()).anyTimes();
+        EasyMock.replay(bundle);
+
+        final Exception exportException = new Exception();
+
+        EventAdmin ea = EasyMock.createNiceMock(EventAdmin.class);
+        ea.postEvent((Event) EasyMock.anyObject());
+        EasyMock.expectLastCall().andAnswer(new IAnswer<Object>() {
+            @Override
+            public Object answer() throws Throwable {
+                Event event = (Event) EasyMock.getCurrentArguments()[0];
+
+                Assert.assertEquals("org/osgi/service/remoteserviceadmin/EXPORT_ERROR", event.getTopic());
+                Assert.assertSame(bundle, event.getProperty("bundle"));
+                Assert.assertEquals(42L, event.getProperty("bundle.id"));
+                Assert.assertEquals("test.bundle", event.getProperty("bundle.symbolicname"));
+                Assert.assertEquals(new Version("0"), event.getProperty("bundle.version"));
+                Assert.assertSame(exportException, event.getProperty("cause"));
+                Assert.assertEquals(endpoint, event.getProperty("export.registration"));
+                Assert.assertTrue(Arrays.equals(new String[] {"org.foo.Bar"},
+                                                (String[]) event.getProperty("objectClass")));
+
+                RemoteServiceAdminEvent rsae = (RemoteServiceAdminEvent) event.getProperty("event");
+                Assert.assertSame(exportException, rsae.getException());
+                Assert.assertEquals(RemoteServiceAdminEvent.EXPORT_ERROR, rsae.getType());
+                Assert.assertSame(bundle, rsae.getSource());
+                ExportReference er = rsae.getExportReference();
+                Assert.assertSame(endpoint, er.getExportedEndpoint());
+                Assert.assertSame(sref, er.getExportedService());
+
+                return null;
+            }
+        });
+        EasyMock.replay(ea);
+
+        ServiceReference eaSref = EasyMock.createNiceMock(ServiceReference.class);
+        EasyMock.replay(eaSref);
+
+        BundleContext bc = EasyMock.createNiceMock(BundleContext.class);
+        EasyMock.expect(bc.getBundle()).andReturn(bundle).anyTimes();
+        EasyMock.expect(bc.getAllServiceReferences(EventAdmin.class.getName(), null))
+            .andReturn(new ServiceReference[] {eaSref}).anyTimes();
+        EasyMock.expect(bc.getService(eaSref)).andReturn(ea).anyTimes();
+        EasyMock.replay(bc);
+        EventProducer eventProducer = new EventProducer(bc);
+
+        ExportRegistrationImpl ereg = new ExportRegistrationImpl(sref, endpoint, rsaCore, exportException);
+        eventProducer.publishNotification(Arrays.<ExportRegistration>asList(ereg));
+    }
+}
diff --git a/trunk/dsw/cxf-dsw/src/test/java/org/apache/cxf/dosgi/dsw/service/ImportRegistrationImplTest.java b/trunk/dsw/cxf-dsw/src/test/java/org/apache/cxf/dosgi/dsw/service/ImportRegistrationImplTest.java
new file mode 100644
index 0000000..95dfe9a
--- /dev/null
+++ b/trunk/dsw/cxf-dsw/src/test/java/org/apache/cxf/dosgi/dsw/service/ImportRegistrationImplTest.java
@@ -0,0 +1,177 @@
+/**
+ * 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.dsw.service;
+
+import org.easymock.IMocksControl;
+import org.easymock.classextension.EasyMock;
+import org.junit.Test;
+import org.osgi.framework.ServiceReference;
+import org.osgi.framework.ServiceRegistration;
+import org.osgi.service.remoteserviceadmin.EndpointDescription;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+
+public class ImportRegistrationImplTest {
+
+    @Test
+    public void testException() {
+        IMocksControl c = EasyMock.createNiceControl();
+        Exception e = c.createMock(Exception.class);
+        c.replay();
+
+        ImportRegistrationImpl i = new ImportRegistrationImpl(e);
+
+        assertEquals(e, i.getException());
+        assertNull(i.getImportedEndpointDescription());
+        assertNull(i.getImportedService());
+        assertEquals(i, i.getParent());
+    }
+
+    @Test
+    public void testDefaultCtor() {
+        IMocksControl c = EasyMock.createNiceControl();
+        EndpointDescription endpoint = c.createMock(EndpointDescription.class);
+        RemoteServiceAdminCore rsac = c.createMock(RemoteServiceAdminCore.class);
+
+        c.replay();
+
+        ImportRegistrationImpl i = new ImportRegistrationImpl(endpoint, rsac);
+
+        assertNull(i.getException());
+        assertEquals(i, i.getParent());
+        assertEquals(endpoint, i.getImportedEndpointDescription());
+    }
+
+    @Test
+    public void testCloneAndClose() {
+        IMocksControl c = EasyMock.createControl();
+        EndpointDescription endpoint = c.createMock(EndpointDescription.class);
+        RemoteServiceAdminCore rsac = c.createMock(RemoteServiceAdminCore.class);
+
+        ServiceRegistration sr = c.createMock(ServiceRegistration.class);
+        ServiceReference sref = c.createMock(ServiceReference.class);
+        EasyMock.expect(sr.getReference()).andReturn(sref).anyTimes();
+
+        c.replay();
+
+        ImportRegistrationImpl i1 = new ImportRegistrationImpl(endpoint, rsac);
+
+        ImportRegistrationImpl i2 = new ImportRegistrationImpl(i1);
+
+        ImportRegistrationImpl i3 = new ImportRegistrationImpl(i2);
+
+        try {
+            i2.setImportedServiceRegistration(sr);
+            assertTrue("An exception should be thrown here !", false);
+        } catch (IllegalStateException e) {
+            // must be thrown here
+        }
+
+        i1.setImportedServiceRegistration(sr);
+
+        assertEquals(i1, i1.getParent());
+        assertEquals(i1, i2.getParent());
+        assertEquals(i1, i3.getParent());
+
+        assertEquals(endpoint, i1.getImportedEndpointDescription());
+        assertEquals(endpoint, i2.getImportedEndpointDescription());
+        assertEquals(endpoint, i3.getImportedEndpointDescription());
+
+        c.verify();
+        c.reset();
+
+        rsac.removeImportRegistration(EasyMock.eq(i3));
+        EasyMock.expectLastCall().once();
+
+        c.replay();
+
+        i3.close();
+        i3.close(); // shouldn't change anything
+
+        assertNull(i3.getImportedEndpointDescription());
+
+        c.verify();
+        c.reset();
+
+        rsac.removeImportRegistration(EasyMock.eq(i1));
+        EasyMock.expectLastCall().once();
+
+        c.replay();
+
+        i1.close();
+
+        c.verify();
+        c.reset();
+
+        rsac.removeImportRegistration(EasyMock.eq(i2));
+        EasyMock.expectLastCall().once();
+
+        sr.unregister();
+        EasyMock.expectLastCall().once();
+
+        c.replay();
+
+        i2.close();
+
+        c.verify();
+    }
+
+    @Test
+    public void testCloseAll() {
+        IMocksControl c = EasyMock.createControl();
+        EndpointDescription endpoint = c.createMock(EndpointDescription.class);
+        RemoteServiceAdminCore rsac = c.createMock(RemoteServiceAdminCore.class);
+
+        c.replay();
+
+        ImportRegistrationImpl i1 = new ImportRegistrationImpl(endpoint, rsac);
+
+        ImportRegistrationImpl i2 = new ImportRegistrationImpl(i1);
+
+        ImportRegistrationImpl i3 = new ImportRegistrationImpl(i2);
+
+        assertEquals(i1, i1.getParent());
+        assertEquals(i1, i2.getParent());
+        assertEquals(i1, i3.getParent());
+
+        c.verify();
+        c.reset();
+
+        rsac.removeImportRegistration(EasyMock.eq(i2));
+        EasyMock.expectLastCall().once();
+
+        c.replay();
+
+        i2.close();
+
+        c.verify();
+        c.reset();
+
+        rsac.removeImportRegistration(EasyMock.eq(i1));
+        EasyMock.expectLastCall().once();
+        rsac.removeImportRegistration(EasyMock.eq(i3));
+        EasyMock.expectLastCall().once();
+
+        c.replay();
+        i3.closeAll();
+        c.verify();
+    }
+}
diff --git a/trunk/dsw/cxf-dsw/src/test/java/org/apache/cxf/dosgi/dsw/service/RemoteServiceAdminCoreTest.java b/trunk/dsw/cxf-dsw/src/test/java/org/apache/cxf/dosgi/dsw/service/RemoteServiceAdminCoreTest.java
new file mode 100644
index 0000000..dcc6002
--- /dev/null
+++ b/trunk/dsw/cxf-dsw/src/test/java/org/apache/cxf/dosgi/dsw/service/RemoteServiceAdminCoreTest.java
@@ -0,0 +1,366 @@
+/**
+ * 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.dsw.service;
+
+import java.lang.reflect.Field;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Dictionary;
+import java.util.HashMap;
+import java.util.Hashtable;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.cxf.dosgi.dsw.handlers.ConfigTypeHandlerFactory;
+import org.apache.cxf.dosgi.dsw.handlers.ConfigurationTypeHandler;
+import org.apache.cxf.dosgi.dsw.handlers.ExportResult;
+import org.apache.cxf.dosgi.dsw.handlers.HttpServiceManager;
+import org.apache.cxf.dosgi.dsw.qos.DefaultIntentMapFactory;
+import org.apache.cxf.dosgi.dsw.qos.IntentManager;
+import org.apache.cxf.dosgi.dsw.qos.IntentManagerImpl;
+import org.apache.cxf.dosgi.dsw.qos.IntentMap;
+import org.apache.cxf.endpoint.Server;
+import org.easymock.IAnswer;
+import org.easymock.IMocksControl;
+import org.easymock.classextension.EasyMock;
+import org.junit.Test;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.Constants;
+import org.osgi.framework.FrameworkUtil;
+import org.osgi.framework.InvalidSyntaxException;
+import org.osgi.framework.ServiceListener;
+import org.osgi.framework.ServiceReference;
+import org.osgi.service.remoteserviceadmin.EndpointDescription;
+import org.osgi.service.remoteserviceadmin.ExportRegistration;
+import org.osgi.service.remoteserviceadmin.ImportRegistration;
+import org.osgi.service.remoteserviceadmin.RemoteConstants;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertSame;
+import static org.junit.Assert.assertTrue;
+
+public class RemoteServiceAdminCoreTest {
+
+    @Test
+    public void testDontExportOwnServiceProxies() throws InvalidSyntaxException {
+        IMocksControl c = EasyMock.createControl();
+        Bundle b = c.createMock(Bundle.class);
+        BundleContext bc = c.createMock(BundleContext.class);
+
+        EasyMock.expect(bc.getBundle()).andReturn(b).anyTimes();
+        bc.addServiceListener(EasyMock.<ServiceListener>anyObject(), EasyMock.<String>anyObject());
+        EasyMock.expectLastCall().anyTimes();
+        bc.removeServiceListener(EasyMock.<ServiceListener>anyObject());
+        EasyMock.expectLastCall().anyTimes();
+
+        Dictionary<String, String> d = new Hashtable<String, String>();
+        EasyMock.expect(b.getHeaders()).andReturn(d).anyTimes();
+
+        ServiceReference sref = c.createMock(ServiceReference.class);
+        EasyMock.expect(sref.getBundle()).andReturn(b).anyTimes();
+        EasyMock.expect(sref.getPropertyKeys())
+            .andReturn(new String[]{"objectClass", "service.exported.interfaces"}).anyTimes();
+        EasyMock.expect(sref.getProperty("objectClass")).andReturn(new String[] {"a.b.C"}).anyTimes();
+        EasyMock.expect(sref.getProperty("service.exported.interfaces")).andReturn("*").anyTimes();
+
+        ConfigTypeHandlerFactory configTypeHandlerFactory = c.createMock(ConfigTypeHandlerFactory.class);
+
+        c.replay();
+
+        RemoteServiceAdminCore rsaCore = new RemoteServiceAdminCore(bc, configTypeHandlerFactory);
+
+        // must return an empty List as sref if from the same bundle
+        List<ExportRegistration> exRefs = rsaCore.exportService(sref, null);
+
+        assertNotNull(exRefs);
+        assertEquals(0, exRefs.size());
+
+        // must be empty
+        assertEquals(rsaCore.getExportedServices().size(), 0);
+
+        c.verify();
+    }
+
+    @Test
+    public void testImport() {
+        IMocksControl c = EasyMock.createNiceControl();
+        Bundle b = c.createMock(Bundle.class);
+        BundleContext bc = c.createMock(BundleContext.class);
+
+        Dictionary<String, String> d = new Hashtable<String, String>();
+        EasyMock.expect(b.getHeaders()).andReturn(d).anyTimes();
+
+        EasyMock.expect(bc.getBundle()).andReturn(b).anyTimes();
+        EasyMock.expect(b.getSymbolicName()).andReturn("BundleName").anyTimes();
+
+        Map<String, Object> p = new HashMap<String, Object>();
+        p.put(RemoteConstants.ENDPOINT_ID, "http://google.de");
+        p.put(Constants.OBJECTCLASS, new String[] {
+            "es.schaaf.my.class"
+        });
+        p.put(RemoteConstants.SERVICE_IMPORTED_CONFIGS, "unsupportedConfiguration");
+        EndpointDescription endpoint = new EndpointDescription(p);
+        IntentMap intentMap = new IntentMap(new DefaultIntentMapFactory().create());
+        IntentManager intentManager = new IntentManagerImpl(intentMap, 10000);
+        HttpServiceManager httpServiceManager = c.createMock(HttpServiceManager.class);
+        ConfigTypeHandlerFactory configTypeHandlerFactory
+            = new ConfigTypeHandlerFactory(bc, intentManager, httpServiceManager);
+
+        c.replay();
+
+        RemoteServiceAdminCore rsaCore = new RemoteServiceAdminCore(bc, configTypeHandlerFactory) {
+            @Override
+            protected void proxifyMatchingInterface(String interfaceName, ImportRegistrationImpl imReg,
+                                                    ConfigurationTypeHandler handler,
+                                                    BundleContext requestingContext) {
+            }
+        };
+
+        // must be null as the endpoint doesn't contain any usable configurations
+        assertNull(rsaCore.importService(endpoint));
+        // must be empty
+        assertEquals(0, rsaCore.getImportedEndpoints().size());
+
+        p.put(RemoteConstants.SERVICE_IMPORTED_CONFIGS, org.apache.cxf.dosgi.dsw.Constants.WS_CONFIG_TYPE);
+        endpoint = new EndpointDescription(p);
+
+        ImportRegistration ireg = rsaCore.importService(endpoint);
+        assertNotNull(ireg);
+
+        assertEquals(1, rsaCore.getImportedEndpoints().size());
+
+        // lets import the same endpoint once more -> should get a copy of the ImportRegistration
+        ImportRegistration ireg2 = rsaCore.importService(endpoint);
+        assertNotNull(ireg2);
+        assertEquals(2, rsaCore.getImportedEndpoints().size());
+
+        assertEquals(ireg.getImportReference(), (rsaCore.getImportedEndpoints().toArray())[0]);
+
+        assertEquals(ireg.getImportReference().getImportedEndpoint(), ireg2.getImportReference()
+            .getImportedEndpoint());
+
+        // remove the registration
+
+        // first call shouldn't remove the import
+        ireg2.close();
+        assertEquals(1, rsaCore.getImportedEndpoints().size());
+
+        // second call should really close and remove the import
+        ireg.close();
+        assertEquals(0, rsaCore.getImportedEndpoints().size());
+
+        c.verify();
+    }
+
+    @Test
+    public void testExport() throws Exception {
+        BundleContext bc = EasyMock.createMock(BundleContext.class);
+        EasyMock.expect(bc.getProperty(Constants.FRAMEWORK_VERSION)).andReturn(null).anyTimes();
+        bc.addServiceListener(EasyMock.<ServiceListener>anyObject(), EasyMock.<String>anyObject());
+        EasyMock.expectLastCall().anyTimes();
+        bc.removeServiceListener(EasyMock.<ServiceListener>anyObject());
+        EasyMock.expectLastCall().anyTimes();
+        EasyMock.expect(bc.getServiceReferences(EasyMock.<String>anyObject(),
+                                                EasyMock.<String>anyObject())).andReturn(null).anyTimes();
+        EasyMock.expect(bc.getAllServiceReferences(EasyMock.<String>anyObject(),
+                                                   EasyMock.<String>anyObject())).andReturn(null).anyTimes();
+
+        Bundle b = createDummyRsaBundle(bc);
+
+        final Map<String, Object> sProps = new HashMap<String, Object>();
+        sProps.put("objectClass", new String[] {"java.lang.Runnable"});
+        sProps.put("service.id", 51L);
+        sProps.put("myProp", "myVal");
+        sProps.put("service.exported.interfaces", "*");
+        ServiceReference sref = mockServiceReference(sProps);
+
+        Runnable svcObject = EasyMock.createNiceMock(Runnable.class);
+        EasyMock.replay(svcObject);
+
+        EasyMock.expect(bc.getService(sref)).andReturn(svcObject).anyTimes();
+        EasyMock.expect(bc.getBundle()).andReturn(b).anyTimes();
+        EasyMock.expect(bc.createFilter("(service.id=51)"))
+            .andReturn(FrameworkUtil.createFilter("(service.id=51)")).anyTimes();
+        EasyMock.replay(bc);
+
+        Map<String, Object> eProps = new HashMap<String, Object>(sProps);
+        eProps.put("endpoint.id", "http://something");
+        eProps.put("service.imported.configs", new String[] {"org.apache.cxf.ws"});
+        ExportResult er = new ExportResult(eProps, (Server) null);
+
+        ConfigurationTypeHandler handler = EasyMock.createNiceMock(ConfigurationTypeHandler.class);
+        EasyMock.expect(handler.createServer(sref,
+                                             bc,
+                                             sref.getBundle().getBundleContext(),
+                                             sProps, Runnable.class, svcObject)).andReturn(er).once();
+        EasyMock.replay(handler);
+
+        ConfigTypeHandlerFactory handlerFactory = EasyMock.createNiceMock(ConfigTypeHandlerFactory.class);
+        EasyMock.expect(handlerFactory.getHandler(bc, sProps))
+            .andReturn(handler).once(); // Second time shouldn't get there because it should simply copy
+        EasyMock.replay(handlerFactory);
+        RemoteServiceAdminCore rsaCore = new RemoteServiceAdminCore(bc, handlerFactory);
+
+        // Export the service for the first time
+        List<ExportRegistration> ereg = rsaCore.exportService(sref, null);
+        assertEquals(1, ereg.size());
+        assertNull(ereg.get(0).getException());
+        assertSame(sref, ereg.get(0).getExportReference().getExportedService());
+        EndpointDescription endpoint = ereg.get(0).getExportReference().getExportedEndpoint();
+
+        Map<String, Object> edProps = endpoint.getProperties();
+        assertEquals("http://something", edProps.get("endpoint.id"));
+        assertNotNull(edProps.get("service.imported"));
+        assertTrue(Arrays.equals(new String[] {"java.lang.Runnable"},
+                                 (Object[]) edProps.get("objectClass")));
+        assertTrue(Arrays.equals(new String[] {"org.apache.cxf.ws"},
+                                 (Object[]) edProps.get("service.imported.configs")));
+
+        // Ask to export the same service again, this should not go through the whole process again but simply return
+        // a copy of the first instance.
+        final Map<String, Object> sProps2 = new HashMap<String, Object>();
+        sProps2.put("objectClass", new String[] {"java.lang.Runnable"});
+        sProps2.put("service.id", 51L);
+        sProps2.put("service.exported.interfaces", "*");
+        ServiceReference sref2 = mockServiceReference(sProps2);
+        Map<String, Object> props2 = new HashMap<String, Object>();
+        props2.put("myProp", "myVal");
+        List<ExportRegistration> ereg2 = rsaCore.exportService(sref2, props2);
+
+        assertEquals(1, ereg2.size());
+        assertNull(ereg2.get(0).getException());
+        assertEquals(ereg.get(0).getExportReference().getExportedEndpoint().getProperties(),
+                ereg2.get(0).getExportReference().getExportedEndpoint().getProperties());
+
+        // Look at the exportedServices data structure
+        Field field = RemoteServiceAdminCore.class.getDeclaredField("exportedServices");
+        field.setAccessible(true);
+        @SuppressWarnings("unchecked")
+        Map<Map<String, Object>, Collection<ExportRegistration>> exportedServices =
+                (Map<Map<String, Object>, Collection<ExportRegistration>>) field.get(rsaCore);
+
+        assertEquals("One service was exported", 1, exportedServices.size());
+        assertEquals("There are 2 export registrations (identical copies)",
+                2, exportedServices.values().iterator().next().size());
+
+        // Unregister one of the exports
+        rsaCore.removeExportRegistration((ExportRegistrationImpl) ereg.get(0));
+        assertEquals("One service was exported", 1, exportedServices.size());
+        assertEquals("There 1 export registrations left",
+                1, exportedServices.values().iterator().next().size());
+
+        // Unregister the other export
+        rsaCore.removeExportRegistration((ExportRegistrationImpl) ereg2.get(0));
+        assertEquals("No more exported services", 0, exportedServices.size());
+    }
+
+    private Bundle createDummyRsaBundle(BundleContext bc) {
+        Bundle b = EasyMock.createNiceMock(Bundle.class);
+        EasyMock.expect(b.getBundleContext()).andReturn(bc).anyTimes();
+        EasyMock.expect(b.getSymbolicName()).andReturn("rsabundle").anyTimes();
+        EasyMock.expect(b.getHeaders()).andReturn(new Hashtable<String, String>()).anyTimes();
+        EasyMock.replay(b);
+        return b;
+    }
+
+    @Test
+    public void testExportException() throws Exception {
+        BundleContext bc = EasyMock.createNiceMock(BundleContext.class);
+
+        Bundle b = createDummyRsaBundle(bc);
+
+        final Map<String, Object> sProps = new HashMap<String, Object>();
+        sProps.put("objectClass", new String[] {"java.lang.Runnable"});
+        sProps.put("service.id", 51L);
+        sProps.put("service.exported.interfaces", "*");
+        ServiceReference sref = mockServiceReference(sProps);
+
+        Runnable svcObject = EasyMock.createNiceMock(Runnable.class);
+        EasyMock.replay(svcObject);
+
+        EasyMock.expect(bc.getService(sref)).andReturn(svcObject).anyTimes();
+        EasyMock.expect(bc.getBundle()).andReturn(b).anyTimes();
+        EasyMock.replay(bc);
+
+        Map<String, Object> eProps = new HashMap<String, Object>(sProps);
+        eProps.put("endpoint.id", "http://something");
+        eProps.put("service.imported.configs", new String[] {"org.apache.cxf.ws"});
+        ExportResult er = new ExportResult(eProps, new TestException());
+
+        ConfigurationTypeHandler handler = EasyMock.createNiceMock(ConfigurationTypeHandler.class);
+        EasyMock.expect(handler.createServer(sref, bc, sref.getBundle().getBundleContext(),
+                                             sProps, Runnable.class, svcObject)).andReturn(er);
+        EasyMock.replay(handler);
+
+        ConfigTypeHandlerFactory handlerFactory = EasyMock.createNiceMock(ConfigTypeHandlerFactory.class);
+        EasyMock.expect(handlerFactory.getHandler(bc, sProps)).andReturn(handler).anyTimes();
+        EasyMock.replay(handlerFactory);
+        RemoteServiceAdminCore rsaCore = new RemoteServiceAdminCore(bc, handlerFactory);
+
+        List<ExportRegistration> ereg = rsaCore.exportService(sref, null);
+        assertEquals(1, ereg.size());
+        assertTrue(ereg.get(0).getException() instanceof TestException);
+        assertSame(sref, ereg.get(0).getExportReference().getExportedService());
+
+        // Look at the exportedServices data structure
+        Field field = RemoteServiceAdminCore.class.getDeclaredField("exportedServices");
+        field.setAccessible(true);
+        @SuppressWarnings("unchecked")
+        Map<Map<String, Object>, Collection<ExportRegistration>> exportedServices =
+                (Map<Map<String, Object>, Collection<ExportRegistration>>) field.get(rsaCore);
+
+        assertEquals("One service was exported", 1, exportedServices.size());
+        assertEquals("There is 1 export registration",
+                1, exportedServices.values().iterator().next().size());
+
+        // Remove all export registrations from the service bundle
+        rsaCore.removeExportRegistrations(sref.getBundle());
+        assertEquals("No more exported services", 0, exportedServices.size());
+    }
+
+    private ServiceReference mockServiceReference(final Map<String, Object> sProps) {
+        BundleContext bc = EasyMock.createNiceMock(BundleContext.class);
+
+        Bundle b = EasyMock.createNiceMock(Bundle.class);
+        EasyMock.expect(b.getBundleContext()).andReturn(bc).anyTimes();
+        EasyMock.replay(b);
+
+        EasyMock.expect(bc.getBundle()).andReturn(b).anyTimes();
+        EasyMock.replay(bc);
+
+        ServiceReference sref = EasyMock.createNiceMock(ServiceReference.class);
+        EasyMock.expect(sref.getBundle()).andReturn(b).anyTimes();
+        EasyMock.expect(sref.getPropertyKeys()).andReturn(sProps.keySet().toArray(new String[] {})).anyTimes();
+        EasyMock.expect(sref.getProperty((String) EasyMock.anyObject())).andAnswer(new IAnswer<Object>() {
+            @Override
+            public Object answer() throws Throwable {
+                return sProps.get(EasyMock.getCurrentArguments()[0]);
+            }
+        }).anyTimes();
+        EasyMock.replay(sref);
+        return sref;
+    }
+
+    @SuppressWarnings("serial")
+    private static class TestException extends Exception {
+    }
+}
diff --git a/trunk/dsw/cxf-dsw/src/test/java/org/apache/cxf/dosgi/dsw/service/UtilsTest.java b/trunk/dsw/cxf-dsw/src/test/java/org/apache/cxf/dosgi/dsw/service/UtilsTest.java
new file mode 100644
index 0000000..1ceebe8
--- /dev/null
+++ b/trunk/dsw/cxf-dsw/src/test/java/org/apache/cxf/dosgi/dsw/service/UtilsTest.java
@@ -0,0 +1,167 @@
+/**
+ * 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.dsw.service;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.apache.cxf.dosgi.dsw.util.OsgiUtils;
+import org.apache.cxf.dosgi.dsw.util.Utils;
+import org.junit.Test;
+import org.osgi.framework.Constants;
+
+import static org.junit.Assert.assertArrayEquals;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+
+public class UtilsTest {
+
+    @Test
+    public void testSplitString() {
+        String[] values = Utils.normalizeStringPlus("1, 2");
+        assertEquals(2, values.length);
+        assertEquals(values[0], "1");
+        assertEquals(values[1], "2");
+    }
+
+    @Test
+    public void testNormalizeStringPlus() {
+        String s1 = "s1";
+        String s2 = "s2";
+        String s3 = "s3";
+
+        String[] sa = new String[] {
+            s1, s2, s3
+        };
+
+        Collection<Object> sl = new ArrayList<Object>(4);
+        sl.add(s1);
+        sl.add(s2);
+        sl.add(s3);
+        sl.add(new Object()); // must be skipped
+
+        assertArrayEquals(null, Utils.normalizeStringPlus(new Object()));
+        assertArrayEquals(new String[] {
+            s1
+        }, Utils.normalizeStringPlus(s1));
+        assertArrayEquals(sa, Utils.normalizeStringPlus(sa));
+        assertArrayEquals(sa, Utils.normalizeStringPlus(sl));
+    }
+
+    @Test
+    public void testOverlayProperties() {
+        Map<String, Object> original = new HashMap<String, Object>();
+
+        original.put("MyProp", "my value");
+        original.put(Constants.OBJECTCLASS, "myClass");
+
+        Map<String, Object> copy = new HashMap<String, Object>();
+        copy.putAll(original);
+
+        // nothing should change here
+        Map<String, Object> overload = new HashMap<String, Object>();
+        OsgiUtils.overlayProperties(copy, overload);
+
+        assertEquals(original.size(), copy.size());
+        for (Object key : original.keySet()) {
+            assertEquals(original.get(key), copy.get(key));
+        }
+
+        copy.clear();
+        copy.putAll(original);
+
+        // a property should be added
+        overload = new HashMap<String, Object>();
+        overload.put("new", "prop");
+
+        OsgiUtils.overlayProperties(copy, overload);
+
+        assertEquals(original.size() + 1, copy.size());
+        for (Object key : original.keySet()) {
+            assertEquals(original.get(key), copy.get(key));
+        }
+        assertNotNull(overload.get("new"));
+        assertEquals("prop", overload.get("new"));
+
+        copy.clear();
+        copy.putAll(original);
+
+        // only one property should be added
+        overload = new HashMap<String, Object>();
+        overload.put("new", "prop");
+        overload.put("NEW", "prop");
+
+        OsgiUtils.overlayProperties(copy, overload);
+
+        assertEquals(original.size() + 1, copy.size());
+        for (Object key : original.keySet()) {
+            assertEquals(original.get(key), copy.get(key));
+        }
+        assertNotNull(overload.get("new"));
+        assertEquals("prop", overload.get("new"));
+
+        copy.clear();
+        copy.putAll(original);
+
+        // nothing should change here
+        overload = new HashMap<String, Object>();
+        overload.put(Constants.OBJECTCLASS, "assd");
+        overload.put(Constants.SERVICE_ID, "asasdasd");
+        OsgiUtils.overlayProperties(copy, overload);
+
+        assertEquals(original.size(), copy.size());
+        for (Object key : original.keySet()) {
+            assertEquals(original.get(key), copy.get(key));
+        }
+
+        copy.clear();
+        copy.putAll(original);
+
+        // overwrite own prop
+        overload = new HashMap<String, Object>();
+        overload.put("MyProp", "newValue");
+        OsgiUtils.overlayProperties(copy, overload);
+
+        assertEquals(original.size(), copy.size());
+        for (Object key : original.keySet()) {
+            if (!"MyProp".equals(key)) {
+                assertEquals(original.get(key), copy.get(key));
+            }
+        }
+        assertEquals("newValue", copy.get("MyProp"));
+
+        copy.clear();
+        copy.putAll(original);
+
+        // overwrite own prop in different case
+        overload = new HashMap<String, Object>();
+        overload.put("MYPROP", "newValue");
+        OsgiUtils.overlayProperties(copy, overload);
+
+        assertEquals(original.size(), copy.size());
+        for (Object key : original.keySet()) {
+            if (!"MyProp".equals(key)) {
+                assertEquals(original.get(key), copy.get(key));
+            }
+        }
+        assertEquals("newValue", copy.get("MyProp"));
+    }
+}
diff --git a/trunk/dsw/cxf-dsw/src/test/java/org/apache/cxf/dosgi/dsw/util/ClassUtilsTest.java b/trunk/dsw/cxf-dsw/src/test/java/org/apache/cxf/dosgi/dsw/util/ClassUtilsTest.java
new file mode 100644
index 0000000..e920d75
--- /dev/null
+++ b/trunk/dsw/cxf-dsw/src/test/java/org/apache/cxf/dosgi/dsw/util/ClassUtilsTest.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.dsw.util;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+
+import junit.framework.TestCase;
+
+import org.easymock.classextension.EasyMock;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleContext;
+
+public class ClassUtilsTest extends TestCase {
+
+    public void testGetInterfaceClass() {
+        assertEquals(String.class,
+                ClassUtils.getInterfaceClass("Hello", "java.lang.String"));
+        assertNull(ClassUtils.getInterfaceClass("Hello", "java.lang.Integer"));
+        assertEquals(List.class, ClassUtils.getInterfaceClass(
+                new ArrayList<String>(), "java.util.List"));
+        assertEquals(Collection.class, ClassUtils.getInterfaceClass(
+                new ArrayList<String>(), "java.util.Collection"));
+    }
+
+    public void testGetInterfaceClassFromSubclass() {
+        assertEquals(Map.class, ClassUtils.getInterfaceClass(
+                new MySubclassFour(), "java.util.Map"));
+        assertNull(ClassUtils.getInterfaceClass(new MySubclassFour(),
+                "java.util.UnknownType"));
+    }
+
+    public void testLoadProvidersAsString() throws Exception {
+        BundleContext bc = mockBundleContext();
+        Map<String, Object> sd = Collections.<String, Object>singletonMap("providers", Provider.class.getName());
+        List<Object> providers = ClassUtils.loadProviderClasses(bc, sd, "providers");
+        assertEquals(1, providers.size());
+        assertTrue(providers.get(0) instanceof Provider);
+    }
+
+    public void testLoadProvidersAsStringArray() throws Exception {
+        BundleContext bc = mockBundleContext();
+        Map<String, Object> sd = Collections.<String, Object>singletonMap("providers",
+                new String[]{Provider.class.getName()});
+        List<Object> providers = ClassUtils.loadProviderClasses(bc, sd, "providers");
+        assertEquals(1, providers.size());
+        assertTrue(providers.get(0) instanceof Provider);
+    }
+
+    public void testLoadProvidersAsObject() throws Exception {
+        Map<String, Object> sd = Collections.<String, Object>singletonMap("providers", new Provider());
+        List<Object> providers = ClassUtils.loadProviderClasses(null, sd, "providers");
+        assertEquals(1, providers.size());
+        assertTrue(providers.get(0) instanceof Provider);
+    }
+
+    public void testLoadProvidersAsObjectArray() throws Exception {
+        Map<String, Object> sd = Collections.<String, Object>singletonMap("providers", new Object[]{new Provider()});
+        List<Object> providers = ClassUtils.loadProviderClasses(null, sd, "providers");
+        assertEquals(1, providers.size());
+        assertTrue(providers.get(0) instanceof Provider);
+    }
+
+    public void testLoadProvidersAsObjectList() throws Exception {
+        List<Object> list = new LinkedList<Object>();
+        list.add(new Provider());
+        Map<String, Object> sd = Collections.<String, Object>singletonMap("providers", list);
+        List<Object> providers = ClassUtils.loadProviderClasses(null, sd, "providers");
+        assertEquals(1, providers.size());
+        assertTrue(providers.get(0) instanceof Provider);
+    }
+
+    public void testLoadProvidersAsStringList() throws Exception {
+        List<Object> list = new LinkedList<Object>();
+        list.add(Provider.class.getName());
+        Map<String, Object> sd = Collections.<String, Object>singletonMap("providers", list);
+        List<Object> providers = ClassUtils.loadProviderClasses(mockBundleContext(), sd, "providers");
+        assertEquals(1, providers.size());
+        assertTrue(providers.get(0) instanceof Provider);
+    }
+
+    private BundleContext mockBundleContext() throws Exception {
+        BundleContext bc = EasyMock.createMock(BundleContext.class);
+        Bundle bundle = EasyMock.createMock(Bundle.class);
+        bc.getBundle();
+        EasyMock.expectLastCall().andReturn(bundle);
+        bundle.loadClass(Provider.class.getName());
+        EasyMock.expectLastCall().andReturn(Provider.class);
+        EasyMock.replay(bc, bundle);
+        return bc;
+    }
+
+    @SuppressWarnings({ "serial", "rawtypes" })
+    private static class MyMapSubclass extends HashMap {
+    }
+
+    @SuppressWarnings("serial")
+    static class MySubclassOne extends MyMapSubclass {
+    }
+
+    @SuppressWarnings("serial")
+    static class MySubclassTwo extends MySubclassOne {
+    }
+
+    @SuppressWarnings("serial")
+    static class MySubclassThree extends MySubclassTwo {
+    }
+
+    @SuppressWarnings("serial")
+    static class MySubclassFour extends MySubclassThree {
+    }
+}
diff --git a/trunk/dsw/cxf-dsw/src/test/java/org/apache/cxf/dosgi/dsw/util/OsgiUtilsTest.java b/trunk/dsw/cxf-dsw/src/test/java/org/apache/cxf/dosgi/dsw/util/OsgiUtilsTest.java
new file mode 100644
index 0000000..3bcb096
--- /dev/null
+++ b/trunk/dsw/cxf-dsw/src/test/java/org/apache/cxf/dosgi/dsw/util/OsgiUtilsTest.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.dsw.util;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import junit.framework.TestCase;
+
+import org.easymock.EasyMock;
+import org.easymock.IMocksControl;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.Constants;
+import org.osgi.framework.ServiceReference;
+import org.osgi.framework.Version;
+import org.osgi.service.packageadmin.ExportedPackage;
+import org.osgi.service.packageadmin.PackageAdmin;
+import org.osgi.service.remoteserviceadmin.EndpointDescription;
+import org.osgi.service.remoteserviceadmin.RemoteConstants;
+
+public class OsgiUtilsTest extends TestCase {
+
+    public void testMultiValuePropertyAsString() {
+        assertEquals(Collections.singleton("hi"),
+            OsgiUtils.getMultiValueProperty("hi"));
+    }
+
+    public void testMultiValuePropertyAsArray() {
+        assertEquals(Arrays.asList("a", "b"),
+                OsgiUtils.getMultiValueProperty(new String[] {"a", "b"}));
+    }
+
+    public void testMultiValuePropertyAsCollection() {
+        List<String> list = new ArrayList<String>();
+        list.add("1");
+        list.add("2");
+        list.add("3");
+        assertEquals(list, OsgiUtils.getMultiValueProperty(list));
+    }
+
+    public void testMultiValuePropertyNull() {
+        assertNull(OsgiUtils.getMultiValueProperty(null));
+    }
+
+    public void testGetUUID() {
+        BundleContext bc = EasyMock.createNiceMock(BundleContext.class);
+        EasyMock.expect(bc.getProperty(EasyMock.eq("org.osgi.framework.uuid"))).andReturn(null).atLeastOnce();
+        EasyMock.replay(bc);
+        String uuid = OsgiUtils.getUUID(bc);
+        assertNotNull(uuid);
+
+        assertEquals(System.getProperty("org.osgi.framework.uuid"), uuid);
+
+        EasyMock.verify(bc);
+    }
+
+    public void testGetVersion() {
+        IMocksControl c = EasyMock.createNiceControl();
+        BundleContext bc = c.createMock(BundleContext.class);
+        ServiceReference sref = c.createMock(ServiceReference.class);
+        PackageAdmin pa = c.createMock(PackageAdmin.class);
+        Bundle b = c.createMock(Bundle.class);
+
+        EasyMock.expect(bc.getServiceReference(EasyMock.eq(PackageAdmin.class.getName()))).andReturn(sref);
+        EasyMock.expect(bc.getService(EasyMock.eq(sref))).andReturn(pa);
+
+        Class<?> iClass = CharSequence.class;
+
+        c.replay();
+        // version 0.0.0 because of missing bundle
+
+        assertEquals("0.0.0", OsgiUtils.getVersion(iClass, bc));
+
+        c.verify();
+        c.reset();
+        // version 1.2.3
+
+        EasyMock.expect(bc.getServiceReference(EasyMock.eq(PackageAdmin.class.getName()))).andReturn(sref);
+        EasyMock.expect(bc.getService(EasyMock.eq(sref))).andReturn(pa);
+        EasyMock.expect(pa.getBundle(EasyMock.eq(iClass))).andReturn(b);
+
+        ExportedPackage[] exP = new ExportedPackage[] {new MyExportedPackage(iClass.getPackage(), "1.2.3"),
+                                                       new MyExportedPackage(String.class.getPackage(), "4.5.6") };
+
+        EasyMock.expect(pa.getExportedPackages(EasyMock.eq(b))).andReturn(exP).atLeastOnce();
+
+        c.replay();
+        assertEquals("1.2.3", OsgiUtils.getVersion(iClass, bc));
+        c.verify();
+    }
+
+    public void testOverlayProperties() {
+        Map<String, Object> sProps = new HashMap<String, Object>();
+        Map<String, Object> aProps = new HashMap<String, Object>();
+
+        OsgiUtils.overlayProperties(sProps, aProps);
+        assertEquals(0, sProps.size());
+
+        sProps.put("aaa", "aval");
+        sProps.put("bbb", "bval");
+        sProps.put(Constants.OBJECTCLASS, new String[] {"X"});
+        sProps.put(Constants.SERVICE_ID, 17L);
+
+        aProps.put("AAA", "achanged");
+        aProps.put("CCC", "CVAL");
+        aProps.put(Constants.OBJECTCLASS, new String[] {"Y"});
+        aProps.put(Constants.SERVICE_ID.toUpperCase(), 51L);
+
+        Map<String, Object> aPropsOrg = new HashMap<String, Object>(aProps);
+        OsgiUtils.overlayProperties(sProps, aProps);
+        assertEquals("The additional properties should not be modified", aPropsOrg, aProps);
+
+        assertEquals(5, sProps.size());
+        assertEquals("achanged", sProps.get("aaa"));
+        assertEquals("bval", sProps.get("bbb"));
+        assertEquals("CVAL", sProps.get("CCC"));
+        assertTrue("Should not be possible to override the objectClass property",
+                Arrays.equals(new String[] {"X"}, (Object[]) sProps.get(Constants.OBJECTCLASS)));
+        assertEquals("Should not be possible to override the service.id property",
+                17L, sProps.get(Constants.SERVICE_ID));
+    }
+
+    private static class MyExportedPackage implements ExportedPackage {
+
+        Package package1;
+        String version;
+
+        public MyExportedPackage(Package package1, String version) {
+            this.package1 = package1;
+            this.version = version;
+        }
+
+        public Bundle getExportingBundle() {
+            return null;
+        }
+
+        public Bundle[] getImportingBundles() {
+            return null;
+        }
+
+        public String getName() {
+            return package1.getName();
+        }
+
+        public String getSpecificationVersion() {
+            return null;
+        }
+
+        public Version getVersion() {
+            return new Version(version);
+        }
+
+        public boolean isRemovalPending() {
+            return false;
+        }
+    }
+
+    public void testGetProperty() {
+        Map<String, Object> p = new HashMap<String, Object>();
+        p.put(RemoteConstants.ENDPOINT_ID, "http://google.de");
+        p.put("notAString", new Object());
+        p.put(org.osgi.framework.Constants.OBJECTCLASS, new String[]{"my.class"});
+        p.put(RemoteConstants.SERVICE_IMPORTED_CONFIGS, new String[]{"my.config"});
+
+        EndpointDescription endpoint = new EndpointDescription(p);
+
+        assertNull(OsgiUtils.getProperty(endpoint, "unknownProp"));
+        assertEquals(p.get(RemoteConstants.ENDPOINT_ID), OsgiUtils.getProperty(endpoint, RemoteConstants.ENDPOINT_ID));
+        assertEquals(null, OsgiUtils.getProperty(endpoint, "notAString"));
+    }
+}
diff --git a/trunk/dsw/cxf-dsw/src/test/java/org/apache/cxf/dosgi/dsw/util/Provider.java b/trunk/dsw/cxf-dsw/src/test/java/org/apache/cxf/dosgi/dsw/util/Provider.java
new file mode 100644
index 0000000..ecd7c78
--- /dev/null
+++ b/trunk/dsw/cxf-dsw/src/test/java/org/apache/cxf/dosgi/dsw/util/Provider.java
@@ -0,0 +1,23 @@
+/**
+ * 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.dsw.util;
+
+
+public class Provider {
+}
diff --git a/trunk/dsw/cxf-dsw/src/test/resources/OSGI-INF/remote-service/alt-remote-services.xml b/trunk/dsw/cxf-dsw/src/test/resources/OSGI-INF/remote-service/alt-remote-services.xml
new file mode 100644
index 0000000..36409ce
--- /dev/null
+++ b/trunk/dsw/cxf-dsw/src/test/resources/OSGI-INF/remote-service/alt-remote-services.xml
@@ -0,0 +1,32 @@
+<?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.
+-->
+
+<service-descriptions xmlns="http://www.osgi.org/xmlns/sd/v1.0.0">
+  <service-description>
+    <provide interface="org.apache.cxf.dosgi.dsw.hooks.TestService" />
+    <provide interface="org.apache.cxf.dosgi.dsw.hooks.CxfPublishHookTest$AdditionalInterface" />
+
+    <property name="osgi.remote.interfaces" value="*" />
+    <property name="osgi.remote.requires.intents" value="SOAP HTTP" />
+    <property name="osgi.remote.configuration.type" value="pojo" />
+    <property name="osgi.remote.configuration.pojo.address" value="http://localhost:9000/hello" />
+  </service-description>
+</service-descriptions>
diff --git a/trunk/dsw/cxf-dsw/src/test/resources/OSGI-INF/remote-service/multi-services.xml b/trunk/dsw/cxf-dsw/src/test/resources/OSGI-INF/remote-service/multi-services.xml
new file mode 100644
index 0000000..3d20c08
--- /dev/null
+++ b/trunk/dsw/cxf-dsw/src/test/resources/OSGI-INF/remote-service/multi-services.xml
@@ -0,0 +1,38 @@
+<?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.
+-->
+
+<service-descriptions xmlns="http://www.osgi.org/xmlns/sd/v1.0.0">
+  <service-description>
+    <provide interface="org.apache.cxf.dosgi.dsw.hooks.TestService" />
+    <provide interface="org.apache.cxf.dosgi.dsw.hooks.CxfPublishHookTest$AdditionalInterface" />
+    <property name="osgi.remote.interfaces">org.apache.cxf.dosgi.dsw.hooks.TestService,org.apache.cxf.dosgi.dsw.hooks.CxfPublishHookTest$AdditionalInterface</property>
+    <property name="osgi.remote.requires.intents">SOAP HTTP</property>
+    <property name="osgi.remote.configuration.type">pojo</property>
+    <property name="osgi.remote.configuration.pojo.address"
+              interface="org.apache.cxf.dosgi.dsw.hooks.TestService">
+      http://localhost:9001/hello
+    </property>
+    <property name="osgi.remote.configuration.pojo.address"
+              interface="org.apache.cxf.dosgi.dsw.hooks.CxfPublishHookTest$AdditionalInterface">
+      http://localhost:9002/hello
+    </property>
+  </service-description>
+</service-descriptions>
diff --git a/trunk/dsw/cxf-dsw/src/test/resources/OSGI-INF/remote-service/remote-services.xml b/trunk/dsw/cxf-dsw/src/test/resources/OSGI-INF/remote-service/remote-services.xml
new file mode 100644
index 0000000..45b2a20
--- /dev/null
+++ b/trunk/dsw/cxf-dsw/src/test/resources/OSGI-INF/remote-service/remote-services.xml
@@ -0,0 +1,32 @@
+<?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.
+-->
+
+<service-descriptions xmlns="http://www.osgi.org/xmlns/sd/v1.0.0">
+  <service-description>
+    <provide interface="org.apache.cxf.dosgi.dsw.hooks.TestService" />
+    <provide interface="org.apache.cxf.dosgi.dsw.hooks.CxfPublishHookTest$AdditionalInterface" />
+
+    <property name="osgi.remote.interfaces">*</property>
+    <property name="osgi.remote.requires.intents">SOAP HTTP</property>
+    <property name="osgi.remote.configuration.type">pojo</property>
+    <property name="osgi.remote.configuration.pojo.address">http://localhost:9000/hello</property>
+  </service-description>
+</service-descriptions>
diff --git a/trunk/dsw/cxf-dsw/src/test/resources/test-resources/rs1.xml b/trunk/dsw/cxf-dsw/src/test/resources/test-resources/rs1.xml
new file mode 100644
index 0000000..f67a833
--- /dev/null
+++ b/trunk/dsw/cxf-dsw/src/test/resources/test-resources/rs1.xml
@@ -0,0 +1,31 @@
+<?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.
+-->
+
+<service-descriptions xmlns="http://www.osgi.org/xmlns/sd/v1.0.0">
+  <service-description>
+    <provide interface="SomeService" />
+    <property name="osgi.remote.requires.intents">confidentiality</property>
+  </service-description>
+  <service-description>
+    <provide interface="SomeOtherService" />
+    <provide interface="WithSomeSecondInterface" />
+  </service-description>
+</service-descriptions>
diff --git a/trunk/dsw/cxf-dsw/src/test/resources/test-resources/rs2.xml b/trunk/dsw/cxf-dsw/src/test/resources/test-resources/rs2.xml
new file mode 100644
index 0000000..098aa21
--- /dev/null
+++ b/trunk/dsw/cxf-dsw/src/test/resources/test-resources/rs2.xml
@@ -0,0 +1,28 @@
+<?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.
+-->
+
+<service-descriptions xmlns="http://www.osgi.org/xmlns/sd/v1.0.0">
+  <service-description>
+    <provide interface="org.example.Service" />
+    <property name="deployment.intents">confidentiality.message integrity</property>
+    <property name="osgi.remote.interfaces">*</property>
+  </service-description>
+</service-descriptions>
diff --git a/trunk/dsw/cxf-dsw/src/test/resources/test-resources/sd-1.xml b/trunk/dsw/cxf-dsw/src/test/resources/test-resources/sd-1.xml
new file mode 100644
index 0000000..483b196
--- /dev/null
+++ b/trunk/dsw/cxf-dsw/src/test/resources/test-resources/sd-1.xml
@@ -0,0 +1,3 @@
+<test>
+  <some-other-tag/>
+</test>
\ No newline at end of file
diff --git a/trunk/dsw/cxf-dsw/src/test/resources/test-resources/sd.xml b/trunk/dsw/cxf-dsw/src/test/resources/test-resources/sd.xml
new file mode 100644
index 0000000..c7cebfb
--- /dev/null
+++ b/trunk/dsw/cxf-dsw/src/test/resources/test-resources/sd.xml
@@ -0,0 +1,8 @@
+<service-decorations xmlns="http://cxf.apache.org/xmlns/service-decoration/1.0.0">
+  <service-decoration>
+    <match interface="org.acme.foo.*">
+      <match-property name="test.prop" value="xyz"/>
+      <add-property name="test.too" value="ahaha" type="java.lang.String"/>
+    </match>
+  </service-decoration>
+</service-decorations>
\ No newline at end of file
diff --git a/trunk/dsw/cxf-dsw/src/test/resources/test-resources/sd0.xml b/trunk/dsw/cxf-dsw/src/test/resources/test-resources/sd0.xml
new file mode 100644
index 0000000..0ad0ad1
--- /dev/null
+++ b/trunk/dsw/cxf-dsw/src/test/resources/test-resources/sd0.xml
@@ -0,0 +1,2 @@
+<service-decorations xmlns="http://cxf.apache.org/xmlns/service-decoration/1.0.0">
+</service-decorations>
\ No newline at end of file
diff --git a/trunk/dsw/cxf-dsw/src/test/resources/test-resources/sd1.xml b/trunk/dsw/cxf-dsw/src/test/resources/test-resources/sd1.xml
new file mode 100644
index 0000000..6a5e811
--- /dev/null
+++ b/trunk/dsw/cxf-dsw/src/test/resources/test-resources/sd1.xml
@@ -0,0 +1,8 @@
+<service-decorations xmlns="http://cxf.apache.org/xmlns/service-decoration/1.0.0">
+  <service-decoration>
+    <match interface="org.test.A">
+      <add-property name="A" value="B"/>
+      <add-property name="C" value="2" type="java.lang.Integer"/>
+    </match>
+  </service-decoration>
+</service-decorations>
\ No newline at end of file
diff --git a/trunk/dsw/cxf-dsw/src/test/resources/test-resources/sd2.xml b/trunk/dsw/cxf-dsw/src/test/resources/test-resources/sd2.xml
new file mode 100644
index 0000000..fb6a93a
--- /dev/null
+++ b/trunk/dsw/cxf-dsw/src/test/resources/test-resources/sd2.xml
@@ -0,0 +1,14 @@
+<service-decorations xmlns="http://cxf.apache.org/xmlns/service-decoration/1.0.0">
+  <service-decoration>
+    <match interface="org.test.(B|C)">
+      <match-property name="x" value="y"/>
+      <add-property name="bool" value="true" type="java.lang.Boolean"/>
+    </match>
+  </service-decoration>
+  <service-decoration>
+    <match interface="org.test.(B|C)">
+      <match-property name="x" value="z"/>
+      <add-property name="bool" value="false" type="java.lang.Boolean"/>
+    </match>
+  </service-decoration>
+</service-decorations>
\ No newline at end of file
diff --git a/trunk/dsw/cxf-topology-manager/pom.xml b/trunk/dsw/cxf-topology-manager/pom.xml
new file mode 100644
index 0000000..ad22f04
--- /dev/null
+++ b/trunk/dsw/cxf-topology-manager/pom.xml
@@ -0,0 +1,94 @@
+<?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>
+    <artifactId>cxf-dosgi-ri-topology-manager</artifactId>
+    <packaging>bundle</packaging>
+    <name>Distributed OSGi Topology Manager implementation</name>
+
+    <parent>
+        <groupId>org.apache.cxf.dosgi</groupId>
+        <artifactId>cxf-dosgi-ri-parent</artifactId>
+        <version>1.6.0</version>
+        <relativePath>../../parent/pom.xml</relativePath>
+    </parent>
+
+    <properties>
+        <topDirectoryLocation>../..</topDirectoryLocation>
+    </properties>
+
+    <dependencies>
+        <dependency>
+            <groupId>org.osgi</groupId>
+            <artifactId>org.osgi.core</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.osgi</groupId>
+            <artifactId>org.osgi.compendium</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>org.slf4j</groupId>
+            <artifactId>slf4j-api</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>junit</groupId>
+            <artifactId>junit</artifactId>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.easymock</groupId>
+            <artifactId>easymockclassextension</artifactId>
+            <scope>test</scope>
+        </dependency>
+    </dependencies>
+
+    <build>
+        <plugins>
+            <plugin>
+                <groupId>org.apache.felix</groupId>
+                <artifactId>maven-bundle-plugin</artifactId>
+                <configuration>
+                    <instructions>
+                        <Bundle-Name>CXF dOSGi Topology Manager</Bundle-Name>
+                        <Bundle-Description>The default CXF Topology Manager as described in the OSGi Remote Service Admin specification</Bundle-Description>
+                        <Bundle-SymbolicName>${project.artifactId}</Bundle-SymbolicName>
+                        <Bundle-Vendor>The Apache Software Foundation</Bundle-Vendor>
+                        <Bundle-Activator>org.apache.cxf.dosgi.topologymanager.Activator</Bundle-Activator>
+                        <Import-Package>
+                            org.osgi.service.remoteserviceadmin;version="[${remote.service.admin.interfaces.version},2)",
+                            *
+                        </Import-Package>
+                        <Export-Package>
+                            !*
+                        </Export-Package>
+                    </instructions>
+                </configuration>
+            </plugin>
+
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-surefire-plugin</artifactId>
+            </plugin>
+        </plugins>
+    </build>
+</project>
diff --git a/trunk/dsw/cxf-topology-manager/src/main/java/org/apache/cxf/dosgi/topologymanager/Activator.java b/trunk/dsw/cxf-topology-manager/src/main/java/org/apache/cxf/dosgi/topologymanager/Activator.java
new file mode 100644
index 0000000..5cf8479
--- /dev/null
+++ b/trunk/dsw/cxf-topology-manager/src/main/java/org/apache/cxf/dosgi/topologymanager/Activator.java
@@ -0,0 +1,55 @@
+/**
+ * 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 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.service.remoteserviceadmin.RemoteServiceAdmin;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class Activator implements BundleActivator {
+
+    private static final Logger LOG = LoggerFactory.getLogger(Activator.class);
+
+    private TopologyManagerExport topologyManagerExport;
+    private TopologyManagerImport topologyManagerImport;
+    private SimpleServiceTracker<RemoteServiceAdmin> rsaTracker;
+
+    public void start(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);
+
+        rsaTracker.open();
+        topologyManagerExport.start();
+        topologyManagerImport.start();
+    }
+
+    public void stop(BundleContext bc) throws Exception {
+        LOG.debug("TopologyManager: stop()");
+        topologyManagerExport.stop();
+        topologyManagerImport.stop();
+        rsaTracker.close();
+    }
+}
diff --git a/trunk/dsw/cxf-topology-manager/src/main/java/org/apache/cxf/dosgi/topologymanager/exporter/EndpointListenerNotifier.java b/trunk/dsw/cxf-topology-manager/src/main/java/org/apache/cxf/dosgi/topologymanager/exporter/EndpointListenerNotifier.java
new file mode 100644
index 0000000..7050814
--- /dev/null
+++ b/trunk/dsw/cxf-topology-manager/src/main/java/org/apache/cxf/dosgi/topologymanager/exporter/EndpointListenerNotifier.java
@@ -0,0 +1,161 @@
+/**
+ * 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.Dictionary;
+import java.util.List;
+
+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.InvalidSyntaxException;
+import org.osgi.framework.ServiceReference;
+import org.osgi.service.remoteserviceadmin.EndpointDescription;
+import org.osgi.service.remoteserviceadmin.EndpointListener;
+import org.osgi.util.tracker.ServiceTracker;
+import org.slf4j.Logger;
+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 ServiceTracker stEndpointListeners;
+
+    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.stEndpointListeners = new ServiceTracker(bctx, filter, null) {
+            @Override
+            public Object addingService(ServiceReference epListenerRef) {
+                LOG.debug("new EndpointListener detected");
+                // the super.addingService call must come before notifyListener, since we need
+                // to keep at least one service reference alive when ungetService is called
+                Object service = super.addingService(epListenerRef);
+                notifyListener(true, epListenerRef, endpointRepository.getAllEndpoints());
+                return service;
+            }
+
+            @Override
+            public void modifiedService(ServiceReference epListenerRef, Object service) {
+                LOG.debug("EndpointListener modified");
+                notifyListener(true, epListenerRef, endpointRepository.getAllEndpoints());
+                super.modifiedService(epListenerRef, service);
+            }
+        };
+    }
+
+    public void start() {
+        stEndpointListeners.open();
+    }
+
+    public void stop() {
+        stEndpointListeners.close();
+    }
+
+    /**
+     * 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) {
+        if (endpoints.isEmpty()) { // a little optimization to prevent unnecessary processing
+            return;
+        }
+        ServiceReference[] listeners = stEndpointListeners.getServiceReferences();
+        if (listeners != null) {
+            for (ServiceReference eplReference : listeners) {
+                notifyListener(added, eplReference, endpoints);
+            }
+        }
+    }
+
+    /**
+     * Notifies an endpoint listener about endpoints being added or removed.
+     *
+     * @param added 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 endpointListenerRef,
+                                Collection<EndpointDescription> endpoints) {
+        List<Filter> filters = getFiltersFromEndpointListenerScope(endpointListenerRef, bctx);
+        EndpointListener 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());
+                    }
+                }
+            }
+        } finally {
+            if (endpointListener != null) {
+                bctx.ungetService(endpointListenerRef);
+            }
+        }
+    }
+
+    static List<Filter> getFiltersFromEndpointListenerScope(ServiceReference sref, BundleContext bctx) {
+        List<Filter> filters = new ArrayList<Filter>();
+        String[] scopes = Utils.getStringPlusProperty(sref.getProperty(EndpointListener.ENDPOINT_LISTENER_SCOPE));
+        for (String scope : scopes) {
+            try {
+                filters.add(bctx.createFilter(scope));
+            } catch (InvalidSyntaxException e) {
+                LOG.error("invalid endpoint listener scope: {}", scope, e);
+            }
+        }
+        return filters;
+    }
+
+    private static List<Filter> getMatchingFilters(List<Filter> filters, EndpointDescription endpoint) {
+        List<Filter> matchingFilters = new ArrayList<Filter>();
+        Dictionary<String, Object> dict = Utils.getEndpointProperties(endpoint);
+
+        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;
+    }
+}
diff --git a/trunk/dsw/cxf-topology-manager/src/main/java/org/apache/cxf/dosgi/topologymanager/exporter/EndpointRepository.java b/trunk/dsw/cxf-topology-manager/src/main/java/org/apache/cxf/dosgi/topologymanager/exporter/EndpointRepository.java
new file mode 100644
index 0000000..489b051
--- /dev/null
+++ b/trunk/dsw/cxf-topology-manager/src/main/java/org/apache/cxf/dosgi/topologymanager/exporter/EndpointRepository.java
@@ -0,0 +1,120 @@
+/**
+ * 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.apache.cxf.dosgi.topologymanager.util.Utils;
+import org.osgi.framework.ServiceReference;
+import org.osgi.service.remoteserviceadmin.EndpointDescription;
+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.
+ */
+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>>>();
+
+    /**
+     * 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) {
+        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);
+            }
+        }
+        return removedEndpoints;
+    }
+
+    synchronized List<EndpointDescription> removeService(ServiceReference sref) {
+        List<EndpointDescription> removedEndpoints = new ArrayList<EndpointDescription>();
+        Map<RemoteServiceAdmin, Collection<EndpointDescription>> rsas = exportedServices.get(sref);
+        if (rsas != null) {
+            for (Collection<EndpointDescription> endpoints : rsas.values()) {
+                removedEndpoints.addAll(endpoints);
+            }
+            exportedServices.remove(sref);
+        }
+        return removedEndpoints;
+    }
+
+    synchronized void addService(ServiceReference sref) {
+        if (!exportedServices.containsKey(sref)) {
+            LOG.info("Marking service from bundle {} for export", Utils.getBundleName(sref));
+            exportedServices.put(sref, new LinkedHashMap<RemoteServiceAdmin, Collection<EndpointDescription>>());
+        }
+    }
+
+    synchronized void addEndpoints(ServiceReference sref, RemoteServiceAdmin rsa,
+                                   List<EndpointDescription> endpoints) {
+        if (endpoints == null) {
+            throw new NullPointerException();
+        }
+        addService(sref);
+        Map<RemoteServiceAdmin, Collection<EndpointDescription>> exports = exportedServices.get(sref);
+        exports.put(rsa, endpoints);
+    }
+
+    synchronized boolean isAlreadyExportedForRsa(ServiceReference sref, RemoteServiceAdmin rsa) {
+        Map<RemoteServiceAdmin, Collection<EndpointDescription>> exports = exportedServices.get(sref);
+        return exports != null && exports.containsKey(rsa);
+    }
+
+    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;
+    }
+
+    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;
+    }
+}
diff --git a/trunk/dsw/cxf-topology-manager/src/main/java/org/apache/cxf/dosgi/topologymanager/exporter/TopologyManagerExport.java b/trunk/dsw/cxf-topology-manager/src/main/java/org/apache/cxf/dosgi/topologymanager/exporter/TopologyManagerExport.java
new file mode 100644
index 0000000..767376e
--- /dev/null
+++ b/trunk/dsw/cxf-topology-manager/src/main/java/org/apache/cxf/dosgi/topologymanager/exporter/TopologyManagerExport.java
@@ -0,0 +1,245 @@
+/**
+ * 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.List;
+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.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;
+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 {
+
+    private static final String DOSGI_SERVICES = "(" + RemoteConstants.SERVICE_EXPORTED_INTERFACES + "=*)";
+
+    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 EndpointRepository endpointRepo;
+
+    public TopologyManagerExport(BundleContext ctx, SimpleServiceTracker<RemoteServiceAdmin> rsaTracker) {
+        this(ctx, rsaTracker, null);
+    }
+
+    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(RemoteServiceAdmin rsa) {
+                LOG.debug("RemoteServiceAdmin added: {}, total {}",
+                        rsa, remoteServiceAdminTracker.getAllServices().size());
+                for (ServiceReference serviceRef : endpointRepo.getServicesToBeExportedFor(rsa)) {
+                    triggerExport(serviceRef);
+                }
+            }
+
+            public void removed(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);
+                }
+            }
+        };
+    }
+
+    /**
+     * checks if a Service is intended to be exported
+     */
+    private boolean shouldExportService(ServiceReference sref) {
+        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) {
+        execService.execute(new Runnable() {
+            public void run() {
+                try {
+                    doExportService(sref);
+                } catch (Throwable t) {
+                    LOG.error("export failed", t);
+                }
+            }
+        });
+    }
+
+    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()) {
+            LOG.error("No RemoteServiceAdmin available! Unable to export service from bundle {}, interfaces: {}",
+                    Utils.getBundleName(sref),
+                    sref.getProperty(org.osgi.framework.Constants.OBJECTCLASS));
+        }
+
+        for (final RemoteServiceAdmin remoteServiceAdmin : rsaList) {
+            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);
+            }
+        }
+    }
+
+    private void exportServiceUsingRemoteServiceAdmin(final ServiceReference sref,
+                                                      final RemoteServiceAdmin remoteServiceAdmin) {
+        // 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, 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) {
+            if (reg.getException() == null) {
+                EndpointDescription endpoint = getExportedEndpoint(reg);
+                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();
+            }
+        }
+        // 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);
+            epListenerNotifier.notifyListeners(true, 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();
+    }
+
+    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);
+        }
+    }
+}
diff --git a/trunk/dsw/cxf-topology-manager/src/main/java/org/apache/cxf/dosgi/topologymanager/importer/EndpointListenerManager.java b/trunk/dsw/cxf-topology-manager/src/main/java/org/apache/cxf/dosgi/topologymanager/importer/EndpointListenerManager.java
new file mode 100644
index 0000000..42a8bc4
--- /dev/null
+++ b/trunk/dsw/cxf-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 serviceRegistration;
+    private final List<String> filters = new ArrayList<String>();
+    private final EndpointListener endpointListener;
+
+    protected EndpointListenerManager(BundleContext bc, EndpointListener endpointListener) {
+        this.bctx = bc;
+        this.endpointListener = endpointListener;
+    }
+
+    protected void start() {
+        serviceRegistration = bctx.registerService(EndpointListener.class.getName(), 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());
+        }
+    }
+}
diff --git a/trunk/dsw/cxf-topology-manager/src/main/java/org/apache/cxf/dosgi/topologymanager/importer/ListenerHookImpl.java b/trunk/dsw/cxf-topology-manager/src/main/java/org/apache/cxf/dosgi/topologymanager/importer/ListenerHookImpl.java
new file mode 100644
index 0000000..0ab5e39
--- /dev/null
+++ b/trunk/dsw/cxf-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.apache.cxf.dosgi.topologymanager.util.Utils;
+import org.osgi.framework.BundleContext;
+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;
+
+    public ListenerHookImpl(BundleContext bc, ServiceInterestListener serviceInterestListener) {
+        this.bctx = bc;
+        this.serviceInterestListener = serviceInterestListener;
+    }
+
+    @SuppressWarnings("rawtypes")
+    public void added(Collection/* <ListenerInfo> */ listeners) {
+        LOG.debug("added listeners {}", listeners);
+        for (Object li : listeners) {
+            ListenerInfo listenerInfo = (ListenerInfo)li;
+            LOG.debug("Filter {}", listenerInfo.getFilter());
+
+            String className = Utils.getObjectClass(listenerInfo.getFilter());
+
+            if (listenerInfo.getBundleContext().getBundle().equals(bctx.getBundle())) {
+                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(), bctx);
+            serviceInterestListener.addServiceInterest(exFilter);
+        }
+    }
+
+    @SuppressWarnings("rawtypes")
+    public void removed(Collection/* <ListenerInfo> */ listeners) {
+        LOG.debug("removed listeners {}", listeners);
+
+        for (Object li : listeners) {
+            ListenerInfo listenerInfo = (ListenerInfo)li;
+            LOG.debug("Filter {}", listenerInfo.getFilter());
+
+            // TODO: determine if service was handled?
+            String exFilter = extendFilter(listenerInfo.getFilter(), bctx);
+            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;
+    }
+
+    static String extendFilter(String filter, BundleContext bctx) {
+        return "(&" + filter + "(!(" + RemoteConstants.ENDPOINT_FRAMEWORK_UUID + "=" + Utils.getUUID(bctx) + ")))";
+    }
+}
diff --git a/trunk/dsw/cxf-topology-manager/src/main/java/org/apache/cxf/dosgi/topologymanager/importer/ServiceInterestListener.java b/trunk/dsw/cxf-topology-manager/src/main/java/org/apache/cxf/dosgi/topologymanager/importer/ServiceInterestListener.java
new file mode 100644
index 0000000..f4db92e
--- /dev/null
+++ b/trunk/dsw/cxf-topology-manager/src/main/java/org/apache/cxf/dosgi/topologymanager/importer/ServiceInterestListener.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;
+
+public interface ServiceInterestListener {
+
+    void addServiceInterest(String filter);
+
+    void removeServiceInterest(String filter);
+}
\ No newline at end of file
diff --git a/trunk/dsw/cxf-topology-manager/src/main/java/org/apache/cxf/dosgi/topologymanager/importer/TopologyManagerImport.java b/trunk/dsw/cxf-topology-manager/src/main/java/org/apache/cxf/dosgi/topologymanager/importer/TopologyManagerImport.java
new file mode 100644
index 0000000..47f7840
--- /dev/null
+++ b/trunk/dsw/cxf-topology-manager/src/main/java/org/apache/cxf/dosgi/topologymanager/importer/TopologyManagerImport.java
@@ -0,0 +1,349 @@
+/**
+ * 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.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+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.ReferenceCounter;
+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.hooks.service.ListenerHook;
+import org.osgi.service.remoteserviceadmin.EndpointDescription;
+import org.osgi.service.remoteserviceadmin.EndpointListener;
+import org.osgi.service.remoteserviceadmin.ImportReference;
+import org.osgi.service.remoteserviceadmin.ImportRegistration;
+import org.osgi.service.remoteserviceadmin.RemoteServiceAdmin;
+import org.osgi.service.remoteserviceadmin.RemoteServiceAdminEvent;
+import org.osgi.service.remoteserviceadmin.RemoteServiceAdminListener;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Listens for remote endpoints using the EndpointListener interface and the EndpointListenerManager.
+ * Listens for local service interests using the ListenerHookImpl that calls back through the
+ * ServiceInterestListener interface.
+ * Manages local creation and destruction of service imports using the available RemoteServiceAdmin services.
+ */
+public class TopologyManagerImport implements EndpointListener, RemoteServiceAdminListener, ServiceInterestListener {
+
+    private static final Logger LOG = LoggerFactory.getLogger(TopologyManagerImport.class);
+    private ExecutorService execService;
+
+    private final EndpointListenerManager endpointListenerManager;
+    private final BundleContext bctx;
+    private final SimpleServiceTracker<RemoteServiceAdmin> remoteServiceAdminTracker;
+    private final ListenerHookImpl listenerHook;
+
+    /**
+     * If set to false only one service is imported for each import interest even it multiple services are
+     * available. If set to true, all available services are imported.
+     *
+     * TODO: Make this available as a configuration option
+     */
+    private boolean importAllAvailable = true;
+
+    /**
+     * Contains an instance of the Class Import Interest for each distinct import request. If the same filter
+     * is requested multiple times the existing instance of the Object increments an internal reference
+     * counter. If an interest is removed, the related ServiceInterest object is used to reduce the reference
+     * counter until it reaches zero. in this case the interest is removed.
+     */
+    private final ReferenceCounter<String> importInterestsCounter = new ReferenceCounter<String>();
+
+    /**
+     * List of Endpoints by matched filter that were reported by the EndpointListener and can be imported
+     */
+    private final Map<String /* filter */, List<EndpointDescription>> importPossibilities
+        = new HashMap<String, List<EndpointDescription>>();
+
+    /**
+     * List of already imported Endpoints by their matched filter
+     */
+    private final Map<String /* filter */, List<ImportRegistration>> importedServices
+        = new HashMap<String, List<ImportRegistration>>();
+
+    public TopologyManagerImport(BundleContext bc, SimpleServiceTracker<RemoteServiceAdmin> rsaTracker) {
+        bctx = bc;
+        remoteServiceAdminTracker = rsaTracker;
+        remoteServiceAdminTracker.addListener(new SimpleServiceTrackerListener<RemoteServiceAdmin>() {
+
+            public void added(RemoteServiceAdmin rsa) {
+                triggerImportsForRemoteServiceAdmin(rsa);
+            }
+
+            public void removed(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.getName(), this, null);
+        bctx.registerService(ListenerHook.class.getName(), listenerHook, null);
+        endpointListenerManager.start();
+    }
+
+    public void stop() {
+        endpointListenerManager.stop();
+        execService.shutdown();
+        // this is called from Activator.stop(), which implicitly unregisters our registered services
+    }
+
+    /* (non-Javadoc)
+     * @see org.apache.cxf.dosgi.topologymanager.ServiceInterestListener#addServiceInterest(java.lang.String)
+     */
+    public void addServiceInterest(String filter) {
+        if (importInterestsCounter.add(filter) == 1) {
+            endpointListenerManager.extendScope(filter);
+        }
+    }
+
+    /* (non-Javadoc)
+     * @see org.apache.cxf.dosgi.topologymanager.ServiceInterestListener#removeServiceInterest(java.lang.String)
+     */
+    public void removeServiceInterest(String filter) {
+        if (importInterestsCounter.remove(filter) == 0) {
+            LOG.debug("last reference to import interest is gone -> removing interest filter: {}", filter);
+            endpointListenerManager.reduceScope(filter);
+            synchronized (importedServices) {
+                List<ImportRegistration> irs = importedServices.remove(filter);
+                if (irs != null) {
+                    for (ImportRegistration ir : irs) {
+                        ir.close();
+                    }
+                }
+            }
+        }
+    }
+
+    public void endpointAdded(EndpointDescription endpoint, String filter) {
+        if (filter == null) {
+            LOG.error("Endpoint is not handled because no matching filter was provided!");
+            return;
+        }
+        LOG.debug("importable service added for filter {}, endpoint {}", filter, endpoint);
+        addImportPossibility(endpoint, filter);
+        triggerImport(filter);
+    }
+
+    public void endpointRemoved(EndpointDescription endpoint, String filter) {
+        LOG.debug("EndpointRemoved {}", endpoint);
+        removeImportPossibility(endpoint, filter);
+        triggerImport(filter);
+    }
+
+    private void addImportPossibility(EndpointDescription endpoint, String filter) {
+        synchronized (importPossibilities) {
+            List<EndpointDescription> endpoints = importPossibilities.get(filter);
+            if (endpoints == null) {
+                endpoints = new ArrayList<EndpointDescription>();
+                importPossibilities.put(filter, endpoints);
+            }
+            // prevent adding the same endpoint multiple times, which can happen sometimes,
+            // and which causes imports to remain available even when services are actually down
+            if (!endpoints.contains(endpoint)) {
+                endpoints.add(endpoint);
+            }
+        }
+    }
+
+    private void removeImportPossibility(EndpointDescription endpoint, String filter) {
+        synchronized (importPossibilities) {
+            List<EndpointDescription> endpoints = importPossibilities.get(filter);
+            if (endpoints != null) {
+                endpoints.remove(endpoint);
+                if (endpoints.isEmpty()) {
+                    importPossibilities.remove(filter);
+                }
+            }
+        }
+    }
+
+    public void triggerImportsForRemoteServiceAdmin(RemoteServiceAdmin rsa) {
+        LOG.debug("New RemoteServiceAdmin {} detected, trying to import services with it", rsa);
+        synchronized (importPossibilities) {
+            for (String filter : importPossibilities.keySet()) {
+                triggerImport(filter);
+            }
+        }
+    }
+
+    private void triggerImport(final String filter) {
+        LOG.debug("Import of a service for filter {} was queued", filter);
+
+        execService.execute(new Runnable() {
+            public void run() {
+                try {
+                    unexportNotAvailableServices(filter);
+                    importServices(filter);
+                } catch (Exception e) {
+                    LOG.error(e.getMessage(), e);
+                }
+                // Notify EndpointListeners? NO!
+            }
+        });
+    }
+
+    private void unexportNotAvailableServices(String filter) {
+        synchronized (importedServices) {
+            List<ImportRegistration> importRegistrations = importedServices.get(filter);
+            if (importRegistrations != null) {
+                // iterate over a copy
+                for (ImportRegistration ir : new ArrayList<ImportRegistration>(importRegistrations)) {
+                    EndpointDescription endpoint = ir.getImportReference().getImportedEndpoint();
+                    if (!isImportPossibilityAvailable(endpoint, filter)) {
+                        removeImport(ir, null); // also unexports the service
+                    }
+                }
+            }
+        }
+    }
+
+    private boolean isImportPossibilityAvailable(EndpointDescription endpoint, String filter) {
+        synchronized (importPossibilities) {
+            List<EndpointDescription> endpoints = importPossibilities.get(filter);
+            return endpoints != null && endpoints.contains(endpoint);
+        }
+    }
+
+    // return a copy to prevent sync issues
+    private List<EndpointDescription> getImportPossibilitiesCopy(String filter) {
+        synchronized (importPossibilities) {
+            List<EndpointDescription> possibilities = importPossibilities.get(filter);
+            return possibilities == null
+                ? Collections.<EndpointDescription>emptyList()
+                : new ArrayList<EndpointDescription>(possibilities);
+        }
+    }
+
+    private void importServices(String filter) {
+        synchronized (importedServices) {
+            List<ImportRegistration> importRegistrations = importedServices.get(filter);
+            for (EndpointDescription endpoint : getImportPossibilitiesCopy(filter)) {
+                // TODO but optional: if the service is already imported and the endpoint is still
+                // in the list of possible imports check if a "better" endpoint is now in the list
+                if (!alreadyImported(endpoint, importRegistrations)) {
+                    // service not imported yet -> import it now
+                    ImportRegistration ir = importService(endpoint);
+                    if (ir != null) {
+                        // import was successful
+                        if (importRegistrations == null) {
+                            importRegistrations = new ArrayList<ImportRegistration>();
+                            importedServices.put(filter, importRegistrations);
+                        }
+                        importRegistrations.add(ir);
+                        if (!importAllAvailable) {
+                            return;
+                        }
+                    }
+                }
+            }
+        }
+    }
+
+    private boolean alreadyImported(EndpointDescription endpoint, List<ImportRegistration> importRegistrations) {
+        if (importRegistrations != null) {
+            for (ImportRegistration ir : importRegistrations) {
+                if (endpoint.equals(ir.getImportReference().getImportedEndpoint())) {
+                    return true;
+                }
+            }
+        }
+        return false;
+    }
+
+    /**
+     * Tries to import the service with each rsa until one import is successful
+     *
+     * @param endpoint endpoint to import
+     * @return import registration of the first successful import
+     */
+    private ImportRegistration importService(EndpointDescription endpoint) {
+        for (RemoteServiceAdmin rsa : remoteServiceAdminTracker.getAllServices()) {
+            ImportRegistration ir = rsa.importService(endpoint);
+            if (ir != null) {
+                if (ir.getException() == null) {
+                    LOG.debug("Service import was successful {}", ir);
+                    return ir;
+                } else {
+                    LOG.info("Error importing service " + endpoint, ir.getException());
+                }
+            }
+        }
+        return null;
+    }
+
+    /**
+     * Remove and close (unexport) the given import. The import is specified either
+     * by its ImportRegistration or by its ImportReference (only one of them must
+     * be specified).
+     * <p>
+     * If this method is called from within iterations on the underlying data structure,
+     * the iterations must be made on copies of the structures rather than the original
+     * references in order to prevent ConcurrentModificationExceptions.
+     *
+     * @param reg the import registration to remove
+     * @param ref the import reference to remove
+     */
+    private void removeImport(ImportRegistration reg, ImportReference ref) {
+        // this method may be called recursively by calling ImportRegistration.close()
+        // and receiving a RemoteServiceAdminEvent for its unregistration, which results
+        // in a ConcurrentModificationException. We avoid this by closing the registrations
+        // only after data structure manipulation is done, and being re-entrant.
+        synchronized (importedServices) {
+            List<ImportRegistration> removed = new ArrayList<ImportRegistration>();
+            for (Iterator<List<ImportRegistration>> it1 = importedServices.values().iterator(); it1.hasNext();) {
+                Collection<ImportRegistration> irs = it1.next();
+                for (Iterator<ImportRegistration> it2 = irs.iterator(); it2.hasNext();) {
+                    ImportRegistration ir = it2.next();
+                    if (ir.equals(reg) || ir.getImportReference().equals(ref)) {
+                        removed.add(ir);
+                        it2.remove();
+                    }
+                }
+                if (irs.isEmpty()) {
+                    it1.remove();
+                }
+            }
+            for (ImportRegistration ir : removed) {
+                ir.close();
+            }
+        }
+    }
+
+    public void remoteAdminEvent(RemoteServiceAdminEvent event) {
+        if (event.getType() == RemoteServiceAdminEvent.IMPORT_UNREGISTRATION) {
+            removeImport(null, event.getImportReference());
+        }
+    }
+}
diff --git a/trunk/dsw/cxf-topology-manager/src/main/java/org/apache/cxf/dosgi/topologymanager/util/ReferenceCounter.java b/trunk/dsw/cxf-topology-manager/src/main/java/org/apache/cxf/dosgi/topologymanager/util/ReferenceCounter.java
new file mode 100644
index 0000000..04d2e2c
--- /dev/null
+++ b/trunk/dsw/cxf-topology-manager/src/main/java/org/apache/cxf/dosgi/topologymanager/util/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.util;
+
+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;
+            }
+        }
+    }
+}
diff --git a/trunk/dsw/cxf-topology-manager/src/main/java/org/apache/cxf/dosgi/topologymanager/util/SimpleServiceTracker.java b/trunk/dsw/cxf-topology-manager/src/main/java/org/apache/cxf/dosgi/topologymanager/util/SimpleServiceTracker.java
new file mode 100644
index 0000000..a5339f8
--- /dev/null
+++ b/trunk/dsw/cxf-topology-manager/src/main/java/org/apache/cxf/dosgi/topologymanager/util/SimpleServiceTracker.java
@@ -0,0 +1,117 @@
+/**
+ * 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.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 ConcurrentMap<ServiceReference<T>, T> services;
+    private List<SimpleServiceTrackerListener<T>> listeners;
+
+    /**
+     * Create a <code>SimpleServiceTracker</code> on the specified class' name.
+     * <p>
+     * Services registered under the specified class' name will be tracked by
+     * this <code>SimpleServiceTracker</code>.
+     *
+     * @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);
+        this.listeners = new CopyOnWriteArrayList<SimpleServiceTrackerListener<T>>();
+        this.services = new ConcurrentHashMap<ServiceReference<T>, T>();
+    }
+
+    /**
+     * 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 = (T) super.addingService(reference);
+        services.put(reference, service);
+        for (SimpleServiceTrackerListener<T> listener : listeners) {
+            listener.added(service);
+        }
+        return service;
+    }
+
+    @Override
+    public void removedService(ServiceReference<T> reference, T service) {
+        services.remove(reference, service);
+        for (SimpleServiceTrackerListener<T> listener : listeners) {
+            listener.removed(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());
+    }
+}
diff --git a/trunk/dsw/cxf-topology-manager/src/main/java/org/apache/cxf/dosgi/topologymanager/util/SimpleServiceTrackerListener.java b/trunk/dsw/cxf-topology-manager/src/main/java/org/apache/cxf/dosgi/topologymanager/util/SimpleServiceTrackerListener.java
new file mode 100644
index 0000000..22375c4
--- /dev/null
+++ b/trunk/dsw/cxf-topology-manager/src/main/java/org/apache/cxf/dosgi/topologymanager/util/SimpleServiceTrackerListener.java
@@ -0,0 +1,42 @@
+/**
+ * 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;
+
+/**
+ * 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 service the newly added service
+     */
+    void added(T service);
+
+    /**
+     * Called when a service is removed from the tracked services.
+     *
+     * @param service the removed service
+     */
+    void removed(T service);
+}
diff --git a/trunk/dsw/cxf-topology-manager/src/main/java/org/apache/cxf/dosgi/topologymanager/util/Utils.java b/trunk/dsw/cxf-topology-manager/src/main/java/org/apache/cxf/dosgi/topologymanager/util/Utils.java
new file mode 100644
index 0000000..7140cd1
--- /dev/null
+++ b/trunk/dsw/cxf-topology-manager/src/main/java/org/apache/cxf/dosgi/topologymanager/util/Utils.java
@@ -0,0 +1,111 @@
+/**
+ * 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.Dictionary;
+import java.util.Hashtable;
+import java.util.UUID;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.Constants;
+import org.osgi.framework.ServiceReference;
+import org.osgi.service.remoteserviceadmin.EndpointDescription;
+
+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
+    }
+
+    /**
+     * Retrieves an endpoint's properties as a Dictionary.
+     *
+     * @param endpoint an endpoint description
+     * @return endpoint properties (will never return null)
+     */
+    public static Dictionary<String, Object> getEndpointProperties(EndpointDescription endpoint) {
+        if (endpoint == null || endpoint.getProperties() == null) {
+            return new Hashtable<String, Object>();
+        } else {
+            return new Hashtable<String, Object>(endpoint.getProperties());
+        }
+    }
+
+    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 getUUID(BundleContext bctx) {
+        synchronized ("org.osgi.framework.uuid") {
+            String uuid = bctx.getProperty("org.osgi.framework.uuid");
+            if (uuid == null) {
+                uuid = UUID.randomUUID().toString();
+                System.setProperty("org.osgi.framework.uuid", uuid);
+            }
+            return uuid;
+        }
+    }
+
+    public static String getBundleName(ServiceReference sref) {
+        Bundle bundle = sref.getBundle();
+        return bundle == null ? "<unregistered>" : bundle.getSymbolicName();
+    }
+}
diff --git a/trunk/dsw/cxf-topology-manager/src/test/java/org/apache/cxf/dosgi/topologymanager/exporter/EndpointListenerNotifierTest.java b/trunk/dsw/cxf-topology-manager/src/test/java/org/apache/cxf/dosgi/topologymanager/exporter/EndpointListenerNotifierTest.java
new file mode 100644
index 0000000..b6fab7f
--- /dev/null
+++ b/trunk/dsw/cxf-topology-manager/src/test/java/org/apache/cxf/dosgi/topologymanager/exporter/EndpointListenerNotifierTest.java
@@ -0,0 +1,183 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.cxf.dosgi.topologymanager.exporter;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.easymock.IAnswer;
+import org.easymock.IMocksControl;
+import org.easymock.classextension.EasyMock;
+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 static org.junit.Assert.assertEquals;
+
+public class EndpointListenerNotifierTest {
+
+    @Test
+    public void testNotifyListenersOfRemovalIfAppropriate() throws InvalidSyntaxException {
+        IMocksControl c = EasyMock.createNiceControl();
+
+        BundleContext bc = c.createMock(BundleContext.class);
+        ServiceReference sref = c.createMock(ServiceReference.class);
+        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)"));
+        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);
+
+        tm.notifyListener(false, sref, endpoints);
+
+        c.verify();
+        EasyMock.verify(epl);
+    }
+
+    @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();
+        }
+    }
+
+    @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();
+        }
+    }
+
+    @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));
+
+            EasyMock.verify(sr);
+            EasyMock.verify(bc);
+        } catch (InvalidSyntaxException e) {
+            e.printStackTrace();
+        }
+    }
+}
diff --git a/trunk/dsw/cxf-topology-manager/src/test/java/org/apache/cxf/dosgi/topologymanager/exporter/ExportServiceTest.java b/trunk/dsw/cxf-topology-manager/src/test/java/org/apache/cxf/dosgi/topologymanager/exporter/ExportServiceTest.java
new file mode 100644
index 0000000..6d0140c
--- /dev/null
+++ b/trunk/dsw/cxf-topology-manager/src/test/java/org/apache/cxf/dosgi/topologymanager/exporter/ExportServiceTest.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.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.IAnswer;
+import org.easymock.classextension.EasyMock;
+import org.easymock.classextension.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;
+
+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;
+    }
+}
diff --git a/trunk/dsw/cxf-topology-manager/src/test/java/org/apache/cxf/dosgi/topologymanager/importer/EndpointListenerImplTest.java b/trunk/dsw/cxf-topology-manager/src/test/java/org/apache/cxf/dosgi/topologymanager/importer/EndpointListenerImplTest.java
new file mode 100644
index 0000000..0e905ab
--- /dev/null
+++ b/trunk/dsw/cxf-topology-manager/src/test/java/org/apache/cxf/dosgi/topologymanager/importer/EndpointListenerImplTest.java
@@ -0,0 +1,112 @@
+/**
+ * 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.Dictionary;
+import java.util.List;
+
+import org.easymock.IAnswer;
+import org.easymock.classextension.EasyMock;
+import org.junit.Assert;
+import org.junit.Test;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.ServiceRegistration;
+import org.osgi.service.remoteserviceadmin.EndpointListener;
+
+public class EndpointListenerImplTest extends Assert {
+
+    int testCase;
+
+    @SuppressWarnings("rawtypes")
+    @Test
+    public void testScopeChange() {
+        BundleContext bc = EasyMock.createNiceMock(BundleContext.class);
+        TopologyManagerImport tm = EasyMock.createNiceMock(TopologyManagerImport.class);
+        ServiceRegistration sr = EasyMock.createNiceMock(ServiceRegistration.class);
+
+        // expect Listener registration
+        EasyMock.expect(bc.registerService((String)EasyMock.anyObject(),
+                                           EasyMock.anyObject(),
+                                           (Dictionary)EasyMock.anyObject())).andReturn(sr).atLeastOnce();
+
+        sr.setProperties((Dictionary)EasyMock.anyObject());
+
+        // expect property changes based on later calls
+        EasyMock.expectLastCall().andAnswer(new IAnswer<Object>() {
+
+            public Object answer() throws Throwable {
+                Object[] args = EasyMock.getCurrentArguments();
+                Dictionary props = (Dictionary)args[0];
+                @SuppressWarnings("unchecked")
+                List<String> scope = (List<String>)props.get(EndpointListener.ENDPOINT_LISTENER_SCOPE);
+                switch (testCase) {
+                case 1:
+                    assertEquals(1, scope.size());
+                    assertEquals("(a=b)", scope.get(0));
+                    break;
+                case 2:
+                    assertEquals(0, scope.size());
+                    break;
+                case 3:
+                    assertEquals("adding entry to empty list failed", 1, scope.size());
+                    assertEquals("(a=b)", scope.get(0));
+                    break;
+                case 4:
+                    assertEquals("adding second entry failed", 2, scope.size());
+                    assertNotNull(scope.contains("(a=b)"));
+                    assertNotNull(scope.contains("(c=d)"));
+                    break;
+                case 5:
+                    assertEquals("remove failed", 1, scope.size());
+                    assertEquals("(c=d)", scope.get(0));
+                    break;
+                default:
+                    assertTrue("This should not happen!", false);
+                }
+                return null;
+            }
+        }).atLeastOnce();
+
+        EasyMock.replay(bc);
+        EasyMock.replay(tm);
+        EasyMock.replay(sr);
+
+        EndpointListenerManager endpointListener = new EndpointListenerManager(bc, tm);
+
+        endpointListener.start();
+
+        testCase = 1;
+        endpointListener.extendScope("(a=b)");
+        testCase = 2;
+        endpointListener.reduceScope("(a=b)");
+
+        testCase = 3;
+        endpointListener.extendScope("(a=b)");
+        testCase = 4;
+        endpointListener.extendScope("(c=d)");
+        testCase = 5;
+        endpointListener.reduceScope("(a=b)");
+
+        endpointListener.stop();
+
+        EasyMock.verify(bc);
+        EasyMock.verify(tm);
+        EasyMock.verify(sr);
+    }
+}
diff --git a/trunk/dsw/cxf-topology-manager/src/test/java/org/apache/cxf/dosgi/topologymanager/importer/ListenerHookImplTest.java b/trunk/dsw/cxf-topology-manager/src/test/java/org/apache/cxf/dosgi/topologymanager/importer/ListenerHookImplTest.java
new file mode 100644
index 0000000..f2ff694
--- /dev/null
+++ b/trunk/dsw/cxf-topology-manager/src/test/java/org/apache/cxf/dosgi/topologymanager/importer/ListenerHookImplTest.java
@@ -0,0 +1,56 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.cxf.dosgi.topologymanager.importer;
+
+import java.util.Dictionary;
+import java.util.Hashtable;
+
+import org.easymock.classextension.EasyMock;
+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.service.remoteserviceadmin.RemoteConstants;
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+public class ListenerHookImplTest {
+
+    @Test
+    public void testUUIDFilterExtension() throws InvalidSyntaxException {
+        String filter = "(a=b)";
+
+        BundleContext bc = EasyMock.createNiceMock(BundleContext.class);
+        EasyMock.expect(bc.getProperty(EasyMock.eq("org.osgi.framework.uuid"))).andReturn("MyUUID").atLeastOnce();
+        EasyMock.replay(bc);
+
+        filter = ListenerHookImpl.extendFilter(filter, bc);
+
+        Filter f = FrameworkUtil.createFilter(filter);
+
+        Dictionary<String, String> m = new Hashtable<String, String>();
+        m.put("a", "b");
+
+        assertTrue(filter + " filter must match as uuid is missing", f.match(m));
+        m.put(RemoteConstants.ENDPOINT_FRAMEWORK_UUID, "MyUUID");
+        assertFalse(filter + " filter must NOT match as uuid is the local one", f.match(m));
+    }
+}
diff --git a/trunk/dsw/cxf-topology-manager/src/test/java/org/apache/cxf/dosgi/topologymanager/importer/TopologyManagerImportTest.java b/trunk/dsw/cxf-topology-manager/src/test/java/org/apache/cxf/dosgi/topologymanager/importer/TopologyManagerImportTest.java
new file mode 100644
index 0000000..a43120a
--- /dev/null
+++ b/trunk/dsw/cxf-topology-manager/src/test/java/org/apache/cxf/dosgi/topologymanager/importer/TopologyManagerImportTest.java
@@ -0,0 +1,91 @@
+/**
+ * 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.Arrays;
+import java.util.Dictionary;
+import java.util.concurrent.Semaphore;
+import java.util.concurrent.TimeUnit;
+
+import org.apache.cxf.dosgi.topologymanager.util.SimpleServiceTracker;
+import org.apache.cxf.dosgi.topologymanager.util.SimpleServiceTrackerListener;
+import org.easymock.IAnswer;
+import org.easymock.IMocksControl;
+import org.easymock.classextension.EasyMock;
+import org.junit.Test;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.ServiceRegistration;
+import org.osgi.service.remoteserviceadmin.EndpointDescription;
+import org.osgi.service.remoteserviceadmin.ImportReference;
+import org.osgi.service.remoteserviceadmin.ImportRegistration;
+import org.osgi.service.remoteserviceadmin.RemoteServiceAdmin;
+
+import static org.junit.Assert.assertTrue;
+
+public class TopologyManagerImportTest {
+
+    @SuppressWarnings("rawtypes")
+    @Test
+    public void testImportForNewlyAddedRSA() throws InterruptedException {
+        IMocksControl c = EasyMock.createControl();
+
+        c.makeThreadSafe(true);
+
+        final Semaphore sema = new Semaphore(0);
+
+        BundleContext bc = c.createMock(BundleContext.class);
+        SimpleServiceTracker<RemoteServiceAdmin> rsaTracker = c.createMock(SimpleServiceTracker.class);
+        ServiceRegistration sreg = c.createMock(ServiceRegistration.class);
+        sreg.unregister();
+        EasyMock.expectLastCall().once();
+        EasyMock.expect(bc.registerService((String)EasyMock.anyObject(),
+                                           EasyMock.anyObject(),
+                                           (Dictionary)EasyMock.anyObject())).andReturn(sreg).anyTimes();
+
+        EndpointDescription endpoint = c.createMock(EndpointDescription.class);
+        RemoteServiceAdmin rsa = c.createMock(RemoteServiceAdmin.class);
+        final ImportRegistration ireg = c.createMock(ImportRegistration.class);
+        EasyMock.expect(ireg.getException()).andReturn(null).anyTimes();
+        ImportReference iref = c.createMock(ImportReference.class);
+
+        rsaTracker.addListener(EasyMock.<SimpleServiceTrackerListener>anyObject());
+        EasyMock.expect(rsaTracker.getAllServices()).andReturn(Arrays.asList(rsa)).anyTimes();
+
+        EasyMock.expect(rsa.importService(EasyMock.eq(endpoint))).andAnswer(new IAnswer<ImportRegistration>() {
+            public ImportRegistration answer() throws Throwable {
+                sema.release();
+                return ireg;
+            }
+        }).once();
+        EasyMock.expect(ireg.getImportReference()).andReturn(iref).anyTimes();
+        EasyMock.expect(iref.getImportedEndpoint()).andReturn(endpoint).anyTimes();
+        c.replay();
+
+        TopologyManagerImport tm = new TopologyManagerImport(bc, rsaTracker);
+
+        tm.start();
+        // no RSA available yet so no import...
+        tm.endpointAdded(endpoint, "myFilter");
+        tm.triggerImportsForRemoteServiceAdmin(rsa);
+        assertTrue("importService should have been called on RemoteServiceAdmin",
+                   sema.tryAcquire(100, TimeUnit.SECONDS));
+        tm.stop();
+        c.verify();
+    }
+}
diff --git a/trunk/dsw/cxf-topology-manager/src/test/java/org/apache/cxf/dosgi/topologymanager/util/ReferenceCounterTest.java b/trunk/dsw/cxf-topology-manager/src/test/java/org/apache/cxf/dosgi/topologymanager/util/ReferenceCounterTest.java
new file mode 100644
index 0000000..8cdbb9b
--- /dev/null
+++ b/trunk/dsw/cxf-topology-manager/src/test/java/org/apache/cxf/dosgi/topologymanager/util/ReferenceCounterTest.java
@@ -0,0 +1,42 @@
+/**
+ * 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.junit.Test;
+
+import static org.junit.Assert.assertEquals;
+
+public class ReferenceCounterTest {
+
+    @Test
+    public void testCounter() {
+        ReferenceCounter<String> counter = new ReferenceCounter<String>();
+        assertEquals(-1, counter.remove("a"));
+        assertEquals(-1, counter.remove("a"));
+        assertEquals(1, counter.add("a"));
+        assertEquals(2, counter.add("a"));
+        assertEquals(3, counter.add("a"));
+        assertEquals(2, counter.remove("a"));
+        assertEquals(1, counter.remove("a"));
+        assertEquals(2, counter.add("a"));
+        assertEquals(1, counter.remove("a"));
+        assertEquals(0, counter.remove("a"));
+        assertEquals(-1, counter.remove("a"));
+    }
+}
diff --git a/trunk/dsw/cxf-topology-manager/src/test/java/org/apache/cxf/dosgi/topologymanager/util/SimpleServiceTrackerTest.java b/trunk/dsw/cxf-topology-manager/src/test/java/org/apache/cxf/dosgi/topologymanager/util/SimpleServiceTrackerTest.java
new file mode 100644
index 0000000..f73cdf0
--- /dev/null
+++ b/trunk/dsw/cxf-topology-manager/src/test/java/org/apache/cxf/dosgi/topologymanager/util/SimpleServiceTrackerTest.java
@@ -0,0 +1,162 @@
+/**
+ * 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.Arrays;
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.List;
+
+import org.easymock.Capture;
+import org.easymock.IAnswer;
+import org.easymock.classextension.EasyMock;
+import org.easymock.classextension.IMocksControl;
+import org.junit.Test;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.Filter;
+import org.osgi.framework.InvalidSyntaxException;
+import org.osgi.framework.ServiceEvent;
+import org.osgi.framework.ServiceListener;
+import org.osgi.framework.ServiceReference;
+import org.osgi.service.remoteserviceadmin.RemoteServiceAdmin;
+
+import static org.easymock.EasyMock.anyObject;
+import static org.easymock.EasyMock.eq;
+import static org.easymock.EasyMock.expect;
+import static org.easymock.EasyMock.expectLastCall;
+import static org.easymock.EasyMock.replay;
+import static org.easymock.EasyMock.verify;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+
+public class SimpleServiceTrackerTest {
+
+    private ServiceReference<RemoteServiceAdmin> createUserServiceBundle(IMocksControl c, BundleContext context) {
+        @SuppressWarnings("unchecked")
+        final ServiceReference<RemoteServiceAdmin> sref = c.createMock(ServiceReference.class);
+        Bundle srefBundle = c.createMock(Bundle.class);
+        expect(srefBundle.getBundleContext()).andReturn(context).anyTimes();
+        expect(sref.getBundle()).andReturn(srefBundle).anyTimes();
+        expect(srefBundle.getSymbolicName()).andReturn("serviceBundleName").anyTimes();
+        return sref;
+    }
+
+    private static <T> void assertEqualsUnordered(Collection<T> c1, Collection<T> c2) {
+        assertEquals(new HashSet<T>(c1), new HashSet<T>(c2));
+    }
+    
+    @Test
+    public void testTracker() throws InvalidSyntaxException {
+        IMocksControl c = org.easymock.classextension.EasyMock.createControl();
+        // create context mock
+        BundleContext context = c.createMock(BundleContext.class);
+        // capture service listener so we can invoke it
+        Capture<ServiceListener> capturedListener = new Capture<ServiceListener>();
+        context.addServiceListener(EasyMock.<ServiceListener>capture(capturedListener), (String)anyObject());
+        expectLastCall().once();
+        context.removeServiceListener((ServiceListener)anyObject());
+        expectLastCall().once();
+        // support context.createFilter
+        Filter filter = c.createMock(Filter.class);
+        expect(context.createFilter("(objectClass=org.osgi.service.remoteserviceadmin.RemoteServiceAdmin)"))
+                .andReturn(filter).atLeastOnce();
+        // support context.getServiceReferences based on our list
+        final List<RemoteServiceAdmin> services = new ArrayList<RemoteServiceAdmin>();
+        final List<ServiceReference<RemoteServiceAdmin>> srefs = new ArrayList<ServiceReference<RemoteServiceAdmin>>();
+        expect(context.getServiceReferences((String)anyObject(), eq((String)null))).andAnswer(
+                new IAnswer<ServiceReference<?>[]>() {
+                @Override
+                public ServiceReference<?>[] answer() {
+                    return srefs.toArray(new ServiceReference[srefs.size()]);
+                }
+            });
+        // create services
+        ServiceReference<RemoteServiceAdmin> sref1 = createUserServiceBundle(c, context);
+        ServiceReference<RemoteServiceAdmin> sref2 = createUserServiceBundle(c, context);
+        RemoteServiceAdmin service1 = c.createMock(RemoteServiceAdmin.class);
+        RemoteServiceAdmin service2 = c.createMock(RemoteServiceAdmin.class);
+        expect(context.getService(sref1)).andReturn(service1).atLeastOnce();
+        expect(context.getService(sref2)).andReturn(service2).atLeastOnce();
+        expect(context.ungetService(sref1)).andReturn(false).atLeastOnce();
+        expect(context.ungetService(sref2)).andReturn(false).atLeastOnce();
+
+        replay(context);
+
+        // start tracking
+        final SimpleServiceTracker<RemoteServiceAdmin> tracker =
+                new SimpleServiceTracker<RemoteServiceAdmin>(context, RemoteServiceAdmin.class);
+        tracker.open();
+        ServiceListener sl = capturedListener.getValue();
+        // add our listener
+        SimpleServiceTrackerListener<RemoteServiceAdmin> listener =
+                new SimpleServiceTrackerListener<RemoteServiceAdmin>() {
+                @SuppressWarnings({
+                    "unchecked", "rawtypes"
+                })
+                @Override
+                public void added(RemoteServiceAdmin service) {
+                    // prove that original ServiceTracker fails here
+                    Object[] trackerServices = (Object[])
+                        (tracker.getServices() != null ? tracker.getServices() : new Object[0]);
+                    assertFalse(new HashSet(services)
+                                .equals(new HashSet(Arrays.asList(trackerServices))));
+                    // but we succeed
+                    assertEqualsUnordered(services, tracker.getAllServices());
+                }
+
+                @Override
+                public void removed(RemoteServiceAdmin service) {
+                    assertEqualsUnordered(services, tracker.getAllServices());
+                }
+            };
+        tracker.addListener(listener);
+
+        // add and remove services and verify that getAllServices() is up to date
+        srefs.add(sref1);
+        services.add(service1);
+        sl.serviceChanged(new ServiceEvent(ServiceEvent.REGISTERED, sref1));
+        assertEqualsUnordered(services, tracker.getAllServices());
+
+        srefs.add(sref2);
+        services.add(service2);
+        sl.serviceChanged(new ServiceEvent(ServiceEvent.REGISTERED, sref2));
+        assertEqualsUnordered(services, tracker.getAllServices());
+
+        srefs.remove(sref1);
+        services.remove(service1);
+        sl.serviceChanged(new ServiceEvent(ServiceEvent.UNREGISTERING, sref1));
+        assertEqualsUnordered(services, tracker.getAllServices());
+
+        srefs.remove(sref2);
+        services.remove(service2);
+        sl.serviceChanged(new ServiceEvent(ServiceEvent.UNREGISTERING, sref2));
+        assertEqualsUnordered(services, tracker.getAllServices());
+
+        srefs.add(sref1);
+        services.add(service1);
+        sl.serviceChanged(new ServiceEvent(ServiceEvent.REGISTERED, sref1));
+        services.remove(service1);
+        tracker.close();
+        assertEqualsUnordered(services, tracker.getAllServices());
+
+        verify(context);
+    }
+}
diff --git a/trunk/dsw/cxf-topology-manager/src/test/java/org/apache/cxf/dosgi/topologymanager/util/UtilsTest.java b/trunk/dsw/cxf-topology-manager/src/test/java/org/apache/cxf/dosgi/topologymanager/util/UtilsTest.java
new file mode 100644
index 0000000..95b5dde
--- /dev/null
+++ b/trunk/dsw/cxf-topology-manager/src/test/java/org/apache/cxf/dosgi/topologymanager/util/UtilsTest.java
@@ -0,0 +1,54 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.cxf.dosgi.topologymanager.util;
+
+import org.easymock.classextension.EasyMock;
+import org.junit.Test;
+import org.osgi.framework.BundleContext;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+
+public class UtilsTest {
+
+    @Test
+    public void testGetNewUUID() {
+        BundleContext bc = EasyMock.createNiceMock(BundleContext.class);
+        EasyMock.expect(bc.getProperty(EasyMock.eq("org.osgi.framework.uuid"))).andReturn(null).atLeastOnce();
+        EasyMock.replay(bc);
+        String uuid = Utils.getUUID(bc);
+        assertNotNull(uuid);
+
+        assertEquals(System.getProperty("org.osgi.framework.uuid"), uuid);
+
+        EasyMock.verify(bc);
+    }
+
+    @Test
+    public void testGetExistingUUID() {
+        BundleContext bc = EasyMock.createNiceMock(BundleContext.class);
+        EasyMock.expect(bc.getProperty(EasyMock.eq("org.osgi.framework.uuid"))).andReturn("MyUUID").atLeastOnce();
+        EasyMock.replay(bc);
+        String uuid = Utils.getUUID(bc);
+
+        assertEquals("MyUUID", uuid);
+
+        EasyMock.verify(bc);
+    }
+}
diff --git a/trunk/dsw/pom.xml b/trunk/dsw/pom.xml
new file mode 100644
index 0000000..4ab3dd9
--- /dev/null
+++ b/trunk/dsw/pom.xml
@@ -0,0 +1,45 @@
+<?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>
+    <groupId>org.apache.cxf.dosgi</groupId>
+    <artifactId>cxf-dosgi-ri-dsw</artifactId>
+    <version>1.6.0</version>
+    <packaging>pom</packaging>
+    <name>Distributed OSGI Distributed Software Modules</name>
+    <url>http://cxf.apache.org</url>
+
+    <parent>
+      <groupId>org.apache.cxf.dosgi</groupId>
+      <artifactId>cxf-dosgi-ri-parent</artifactId>
+      <version>1.6.0</version>
+      <relativePath>../parent/pom.xml</relativePath>
+    </parent>
+
+    <properties>
+      <topDirectoryLocation>..</topDirectoryLocation>
+    </properties>
+
+    <modules>
+      <module>cxf-dsw</module>
+      <module>cxf-topology-manager</module>
+    </modules>
+</project>
diff --git a/trunk/felix/pom.xml b/trunk/felix/pom.xml
new file mode 100644
index 0000000..0006a28
--- /dev/null
+++ b/trunk/felix/pom.xml
@@ -0,0 +1,42 @@
+<?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>
+    <artifactId>cxf-dosgi-ri-felix</artifactId>
+    <packaging>pom</packaging>
+    <name>Distributed OSGi Temporary Private Felix Framework Build</name>
+
+    <parent>
+        <groupId>org.apache.cxf.dosgi</groupId>
+        <artifactId>cxf-dosgi-ri-parent</artifactId>
+        <version>1.6.0</version>
+        <relativePath>../parent/pom.xml</relativePath>
+    </parent>
+
+    <properties>
+        <topDirectoryLocation>..</topDirectoryLocation>
+    </properties>
+
+    <modules>
+        <module>shell.tui</module>
+        <module>profiles</module>
+    </modules>
+
+</project>
diff --git a/trunk/felix/profiles/pom.xml b/trunk/felix/profiles/pom.xml
new file mode 100644
index 0000000..c862958
--- /dev/null
+++ b/trunk/felix/profiles/pom.xml
@@ -0,0 +1,201 @@
+<?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>
+    <artifactId>cxf-dosgi-ri-felix-profiles</artifactId>
+    <packaging>jar</packaging>
+    <name>Distributed OSGi Felix Profiles</name>
+
+    <parent>
+      <groupId>org.apache.cxf.dosgi</groupId>
+      <artifactId>cxf-dosgi-ri-parent</artifactId>
+      <version>1.6.0</version>
+      <relativePath>../../parent/pom.xml</relativePath>
+  </parent>
+
+    <properties>
+        <topDirectoryLocation>../..</topDirectoryLocation>
+    </properties>
+
+    <dependencies>
+        <dependency>
+            <groupId>org.eclipse.jetty</groupId>
+            <artifactId>jetty-server</artifactId>
+            <version>${jetty.version}</version>
+        </dependency>
+
+        <dependency>
+            <groupId>org.eclipse.jetty</groupId>
+            <artifactId>jetty-util</artifactId>
+            <version>${jetty.version}</version>
+        </dependency>
+
+        <dependency>
+           <groupId>org.apache.servicemix.specs</groupId>
+           <artifactId>org.apache.servicemix.specs.stax-api-1.0</artifactId>
+           <version>${servicemix.specs.version}</version>
+        </dependency>
+        <dependency>
+           <groupId>org.apache.servicemix.specs</groupId>
+           <artifactId>org.apache.servicemix.specs.jaxb-api-2.1</artifactId>
+           <version>${servicemix.specs.version}</version>
+        </dependency>
+        <dependency>
+           <groupId>org.apache.servicemix.specs</groupId>
+           <artifactId>org.apache.servicemix.specs.jaxws-api-2.1</artifactId>
+           <version>${servicemix.specs.version}</version>
+        </dependency>
+        <dependency>
+           <groupId>org.apache.servicemix.specs</groupId>
+           <artifactId>org.apache.servicemix.specs.saaj-api-1.3</artifactId>
+           <version>${servicemix.specs.version}</version>
+        </dependency>
+
+        <dependency>
+            <groupId>org.apache.geronimo.specs</groupId>
+            <artifactId>geronimo-javamail_1.4_spec</artifactId>
+            <version>1.7.1</version>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.geronimo.specs</groupId>
+            <artifactId>geronimo-activation_1.1_spec</artifactId>
+            <version>1.1</version>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.geronimo.specs</groupId>
+            <artifactId>geronimo-ws-metadata_2.0_spec</artifactId>
+            <version>1.1.3</version>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.geronimo.specs</groupId>
+            <artifactId>geronimo-servlet_3.0_spec</artifactId>
+            <version>1.0</version>
+        </dependency>
+
+        <dependency>
+            <groupId>org.apache.geronimo.specs</groupId>
+            <artifactId>geronimo-annotation_1.0_spec</artifactId>
+            <version>1.1.1</version>
+        </dependency>
+
+        <dependency>
+           <groupId>org.apache.ws.xmlschema</groupId>
+           <artifactId>xmlschema-core</artifactId>
+           <version>${xmlschema.bundle.version}</version>
+        </dependency>
+        <dependency>
+           <groupId>org.apache.servicemix.bundles</groupId>
+           <artifactId>org.apache.servicemix.bundles.xmlresolver</artifactId>
+           <version>${xmlresolver.bundle.version}</version>
+        </dependency>
+        <dependency>
+           <groupId>org.apache.neethi</groupId>
+           <artifactId>neethi</artifactId>
+           <version>${neethi.bundle.version}</version>
+        </dependency>
+        <dependency>
+          <groupId>org.apache.servicemix.bundles</groupId>
+          <artifactId>org.apache.servicemix.bundles.wsdl4j</artifactId>
+          <version>${wsdl4j.bundle.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.santuario</groupId>
+            <artifactId>xmlsec</artifactId>
+            <version>${xmlsec.version}</version>
+        </dependency>
+
+        <dependency>
+           <groupId>org.apache.servicemix.bundles</groupId>
+           <artifactId>org.apache.servicemix.bundles.jaxb-impl</artifactId>
+           <version>${jaxbimpl.bundle.version}</version>
+        </dependency>
+
+        <dependency>
+           <groupId>org.apache.servicemix.bundles</groupId>
+           <artifactId>org.apache.servicemix.bundles.asm</artifactId>
+           <version>${asm.bundle.version}</version>
+        </dependency>
+
+        <dependency>
+           <groupId>org.codehaus.woodstox</groupId>
+           <artifactId>woodstox-core-asl</artifactId>
+           <version>${woodstox.bundle.version}</version>
+        </dependency>
+
+        <dependency>
+          <groupId>org.springframework</groupId>
+          <artifactId>spring-core</artifactId>
+          <version>${spring.version}</version>
+        </dependency>
+
+        <dependency>
+          <groupId>org.springframework</groupId>
+          <artifactId>spring-beans</artifactId>
+          <version>${spring.version}</version>
+        </dependency>
+
+        <dependency>
+          <groupId>org.springframework</groupId>
+          <artifactId>spring-context</artifactId>
+          <version>${spring.version}</version>
+        </dependency>
+
+        <dependency>
+          <groupId>org.springframework</groupId>
+          <artifactId>spring-aop</artifactId>
+          <version>${spring.version}</version>
+        </dependency>
+
+        <dependency>
+          <groupId>org.springframework.osgi</groupId>
+          <artifactId>spring-osgi-core</artifactId>
+          <version>${spring.osgi.version}</version>
+        </dependency>
+        <dependency>
+          <groupId>org.springframework.osgi</groupId>
+          <artifactId>spring-osgi-io</artifactId>
+          <version>${spring.osgi.version}</version>
+        </dependency>
+        <dependency>
+          <groupId>org.springframework.osgi</groupId>
+          <artifactId>spring-osgi-extender</artifactId>
+          <version>${spring.osgi.version}</version>
+        </dependency>
+
+        <!-- for maven filtering to happen -->
+        <dependency>
+          <groupId>junit</groupId>
+          <artifactId>junit</artifactId>
+          <scope>test</scope>
+        </dependency>
+
+    </dependencies>
+
+    <build>
+	<resources>
+  	   <resource>
+              <directory>src/main/resources/</directory>
+              <filtering>true</filtering>
+           </resource>
+        </resources>
+    </build>
+
+</project>
diff --git a/trunk/felix/profiles/resources/OSGI-INF/remote-service/alt-remote-services.xml b/trunk/felix/profiles/resources/OSGI-INF/remote-service/alt-remote-services.xml
new file mode 100644
index 0000000..36409ce
--- /dev/null
+++ b/trunk/felix/profiles/resources/OSGI-INF/remote-service/alt-remote-services.xml
@@ -0,0 +1,32 @@
+<?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.
+-->
+
+<service-descriptions xmlns="http://www.osgi.org/xmlns/sd/v1.0.0">
+  <service-description>
+    <provide interface="org.apache.cxf.dosgi.dsw.hooks.TestService" />
+    <provide interface="org.apache.cxf.dosgi.dsw.hooks.CxfPublishHookTest$AdditionalInterface" />
+
+    <property name="osgi.remote.interfaces" value="*" />
+    <property name="osgi.remote.requires.intents" value="SOAP HTTP" />
+    <property name="osgi.remote.configuration.type" value="pojo" />
+    <property name="osgi.remote.configuration.pojo.address" value="http://localhost:9000/hello" />
+  </service-description>
+</service-descriptions>
diff --git a/trunk/felix/profiles/resources/OSGI-INF/remote-service/multi-services.xml b/trunk/felix/profiles/resources/OSGI-INF/remote-service/multi-services.xml
new file mode 100644
index 0000000..3d20c08
--- /dev/null
+++ b/trunk/felix/profiles/resources/OSGI-INF/remote-service/multi-services.xml
@@ -0,0 +1,38 @@
+<?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.
+-->
+
+<service-descriptions xmlns="http://www.osgi.org/xmlns/sd/v1.0.0">
+  <service-description>
+    <provide interface="org.apache.cxf.dosgi.dsw.hooks.TestService" />
+    <provide interface="org.apache.cxf.dosgi.dsw.hooks.CxfPublishHookTest$AdditionalInterface" />
+    <property name="osgi.remote.interfaces">org.apache.cxf.dosgi.dsw.hooks.TestService,org.apache.cxf.dosgi.dsw.hooks.CxfPublishHookTest$AdditionalInterface</property>
+    <property name="osgi.remote.requires.intents">SOAP HTTP</property>
+    <property name="osgi.remote.configuration.type">pojo</property>
+    <property name="osgi.remote.configuration.pojo.address"
+              interface="org.apache.cxf.dosgi.dsw.hooks.TestService">
+      http://localhost:9001/hello
+    </property>
+    <property name="osgi.remote.configuration.pojo.address"
+              interface="org.apache.cxf.dosgi.dsw.hooks.CxfPublishHookTest$AdditionalInterface">
+      http://localhost:9002/hello
+    </property>
+  </service-description>
+</service-descriptions>
diff --git a/trunk/felix/profiles/resources/OSGI-INF/remote-service/remote-services.xml b/trunk/felix/profiles/resources/OSGI-INF/remote-service/remote-services.xml
new file mode 100644
index 0000000..45b2a20
--- /dev/null
+++ b/trunk/felix/profiles/resources/OSGI-INF/remote-service/remote-services.xml
@@ -0,0 +1,32 @@
+<?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.
+-->
+
+<service-descriptions xmlns="http://www.osgi.org/xmlns/sd/v1.0.0">
+  <service-description>
+    <provide interface="org.apache.cxf.dosgi.dsw.hooks.TestService" />
+    <provide interface="org.apache.cxf.dosgi.dsw.hooks.CxfPublishHookTest$AdditionalInterface" />
+
+    <property name="osgi.remote.interfaces">*</property>
+    <property name="osgi.remote.requires.intents">SOAP HTTP</property>
+    <property name="osgi.remote.configuration.type">pojo</property>
+    <property name="osgi.remote.configuration.pojo.address">http://localhost:9000/hello</property>
+  </service-description>
+</service-descriptions>
diff --git a/trunk/felix/profiles/resources/test-resources/rs1.xml b/trunk/felix/profiles/resources/test-resources/rs1.xml
new file mode 100644
index 0000000..f67a833
--- /dev/null
+++ b/trunk/felix/profiles/resources/test-resources/rs1.xml
@@ -0,0 +1,31 @@
+<?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.
+-->
+
+<service-descriptions xmlns="http://www.osgi.org/xmlns/sd/v1.0.0">
+  <service-description>
+    <provide interface="SomeService" />
+    <property name="osgi.remote.requires.intents">confidentiality</property>
+  </service-description>
+  <service-description>
+    <provide interface="SomeOtherService" />
+    <provide interface="WithSomeSecondInterface" />
+  </service-description>
+</service-descriptions>
diff --git a/trunk/felix/profiles/resources/test-resources/rs2.xml b/trunk/felix/profiles/resources/test-resources/rs2.xml
new file mode 100644
index 0000000..098aa21
--- /dev/null
+++ b/trunk/felix/profiles/resources/test-resources/rs2.xml
@@ -0,0 +1,28 @@
+<?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.
+-->
+
+<service-descriptions xmlns="http://www.osgi.org/xmlns/sd/v1.0.0">
+  <service-description>
+    <provide interface="org.example.Service" />
+    <property name="deployment.intents">confidentiality.message integrity</property>
+    <property name="osgi.remote.interfaces">*</property>
+  </service-description>
+</service-descriptions>
diff --git a/trunk/felix/profiles/resources/test-resources/sd-1.xml b/trunk/felix/profiles/resources/test-resources/sd-1.xml
new file mode 100644
index 0000000..483b196
--- /dev/null
+++ b/trunk/felix/profiles/resources/test-resources/sd-1.xml
@@ -0,0 +1,3 @@
+<test>
+  <some-other-tag/>
+</test>
\ No newline at end of file
diff --git a/trunk/felix/profiles/resources/test-resources/sd.xml b/trunk/felix/profiles/resources/test-resources/sd.xml
new file mode 100644
index 0000000..c7cebfb
--- /dev/null
+++ b/trunk/felix/profiles/resources/test-resources/sd.xml
@@ -0,0 +1,8 @@
+<service-decorations xmlns="http://cxf.apache.org/xmlns/service-decoration/1.0.0">
+  <service-decoration>
+    <match interface="org.acme.foo.*">
+      <match-property name="test.prop" value="xyz"/>
+      <add-property name="test.too" value="ahaha" type="java.lang.String"/>
+    </match>
+  </service-decoration>
+</service-decorations>
\ No newline at end of file
diff --git a/trunk/felix/profiles/resources/test-resources/sd0.xml b/trunk/felix/profiles/resources/test-resources/sd0.xml
new file mode 100644
index 0000000..0ad0ad1
--- /dev/null
+++ b/trunk/felix/profiles/resources/test-resources/sd0.xml
@@ -0,0 +1,2 @@
+<service-decorations xmlns="http://cxf.apache.org/xmlns/service-decoration/1.0.0">
+</service-decorations>
\ No newline at end of file
diff --git a/trunk/felix/profiles/resources/test-resources/sd1.xml b/trunk/felix/profiles/resources/test-resources/sd1.xml
new file mode 100644
index 0000000..6a5e811
--- /dev/null
+++ b/trunk/felix/profiles/resources/test-resources/sd1.xml
@@ -0,0 +1,8 @@
+<service-decorations xmlns="http://cxf.apache.org/xmlns/service-decoration/1.0.0">
+  <service-decoration>
+    <match interface="org.test.A">
+      <add-property name="A" value="B"/>
+      <add-property name="C" value="2" type="java.lang.Integer"/>
+    </match>
+  </service-decoration>
+</service-decorations>
\ No newline at end of file
diff --git a/trunk/felix/profiles/resources/test-resources/sd2.xml b/trunk/felix/profiles/resources/test-resources/sd2.xml
new file mode 100644
index 0000000..fb6a93a
--- /dev/null
+++ b/trunk/felix/profiles/resources/test-resources/sd2.xml
@@ -0,0 +1,14 @@
+<service-decorations xmlns="http://cxf.apache.org/xmlns/service-decoration/1.0.0">
+  <service-decoration>
+    <match interface="org.test.(B|C)">
+      <match-property name="x" value="y"/>
+      <add-property name="bool" value="true" type="java.lang.Boolean"/>
+    </match>
+  </service-decoration>
+  <service-decoration>
+    <match interface="org.test.(B|C)">
+      <match-property name="x" value="z"/>
+      <add-property name="bool" value="false" type="java.lang.Boolean"/>
+    </match>
+  </service-decoration>
+</service-decorations>
\ No newline at end of file
diff --git a/trunk/felix/profiles/src/main/java/felix/EmptyClass.java b/trunk/felix/profiles/src/main/java/felix/EmptyClass.java
new file mode 100644
index 0000000..58758f7
--- /dev/null
+++ b/trunk/felix/profiles/src/main/java/felix/EmptyClass.java
@@ -0,0 +1,22 @@
+/**
+ * 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 felix;
+
+public class EmptyClass {
+}
\ No newline at end of file
diff --git a/trunk/felix/profiles/src/main/resources/client_bundles.txt b/trunk/felix/profiles/src/main/resources/client_bundles.txt
new file mode 100644
index 0000000..0bf6534
--- /dev/null
+++ b/trunk/felix/profiles/src/main/resources/client_bundles.txt
@@ -0,0 +1,82 @@
+start file:${maven.repo.local}/org/apache/geronimo/specs/geronimo-annotation_1.0_spec/1.1.1/geronimo-annotation_1.0_spec-1.1.1.jar
+
+start file:${maven.repo.local}/org/apache/geronimo/specs/geronimo-activation_1.1_spec/1.1/geronimo-activation_1.1_spec-1.1.jar
+
+start file:${maven.repo.local}/org/apache/geronimo/specs/geronimo-javamail_1.4_spec/1.7.1/geronimo-javamail_1.4_spec-1.7.1.jar
+
+start file:${maven.repo.local}/org/apache/geronimo/specs/geronimo-ws-metadata_2.0_spec/1.1.3/geronimo-ws-metadata_2.0_spec-1.1.3.jar
+
+start file:${maven.repo.local}/org/apache/geronimo/specs/geronimo-servlet_3.0_spec/1.0/geronimo-servlet_3.0_spec-1.0.jar
+
+start file:${maven.repo.local}/org/apache/commons/com.springsource.org.apache.commons.logging/1.1.1/com.springsource.org.apache.commons.logging-1.1.1.jar
+
+start file:${maven.repo.local}/org/jdom/com.springsource.org.jdom/1.1.0/com.springsource.org.jdom-1.1.0.jar
+
+start file:${maven.repo.local}/org/jaxen/com.springsource.org.jaxen/1.1.1/com.springsource.org.jaxen-1.1.1.jar
+
+start file:${maven.repo.local}/org/springframework/spring-core/${spring.version}/spring-core-${spring.version}.jar
+
+start file:${maven.repo.local}/org/springframework/spring-beans/${spring.version}/spring-beans-${spring.version}.jar
+
+start file:${maven.repo.local}/org/springframework/spring-context/${spring.version}/spring-context-${spring.version}.jar
+
+start file:${maven.repo.local}/org/aopalliance/com.springsource.org.aopalliance/1.0.0/com.springsource.org.aopalliance-1.0.0.jar
+
+start file:${maven.repo.local}/org/springframework/spring-aop/${spring.version}/spring-aop-${spring.version}.jar
+
+start file:${maven.repo.local}/org/springframework/spring-expression/${spring.version}/spring-expression-${spring.version}.jar
+
+start file:${maven.repo.local}/org/springframework/spring-asm/${spring.version}/spring-asm-${spring.version}.jar
+
+start file:${maven.repo.local}/org/springframework/osgi/spring-osgi-io/${spring.osgi.version}/spring-osgi-io-${spring.osgi.version}.jar
+
+start file:${maven.repo.local}/org/springframework/osgi/spring-osgi-core/${spring.osgi.version}/spring-osgi-core-${spring.osgi.version}.jar
+
+start file:${maven.repo.local}/org/springframework/osgi/spring-osgi-extender/${spring.osgi.version}/spring-osgi-extender-${spring.osgi.version}.jar
+
+start file:${maven.repo.local}/org/eclipse/jetty/aggregate/jetty-all-server/${jetty.version}/jetty-all-server-${jetty.version}.jar
+
+start file:${maven.repo.local}/org/apache/servicemix/specs/org.apache.servicemix.specs.locator/${servicemix.specs.version}/org.apache.servicemix.specs.locator-${servicemix.specs.version}.jar
+
+start file:${maven.repo.local}/org/apache/servicemix/specs/org.apache.servicemix.specs.saaj-api-1.3/${servicemix.specs.version}/org.apache.servicemix.specs.saaj-api-1.3-${servicemix.specs.version}.jar
+
+start file:${maven.repo.local}/org/apache/servicemix/specs/org.apache.servicemix.specs.stax-api-1.0/${servicemix.specs.version}/org.apache.servicemix.specs.stax-api-1.0-${servicemix.specs.version}.jar
+
+start file:${maven.repo.local}/org/apache/servicemix/specs/org.apache.servicemix.specs.jaxb-api-2.1/${servicemix.specs.version}/org.apache.servicemix.specs.jaxb-api-2.1-${servicemix.specs.version}.jar
+
+start file:${maven.repo.local}/org/apache/servicemix/specs/org.apache.servicemix.specs.jaxws-api-2.1/${servicemix.specs.version}/org.apache.servicemix.specs.jaxws-api-2.1-${servicemix.specs.version}.jar
+
+start file:${maven.repo.local}/org/apache/servicemix/bundles/org.apache.servicemix.bundles.jaxb-impl/${jaxbimpl.bundle.version}/org.apache.servicemix.bundles.jaxb-impl-${jaxbimpl.bundle.version}.jar
+
+start file:${maven.repo.local}/org/apache/servicemix/bundles/org.apache.servicemix.bundles.wsdl4j/${wsdl4j.bundle.version}/org.apache.servicemix.bundles.wsdl4j-${wsdl4j.bundle.version}.jar
+
+start file:${maven.repo.local}/org/apache/servicemix/bundles/org.apache.servicemix.bundles.xmlsec/${xmlsec.bundle.version}/org.apache.servicemix.bundles.xmlsec-${xmlsec.bundle.version}.jar
+
+start file:${maven.repo.local}/org/apache/servicemix/bundles/org.apache.servicemix.bundles.wss4j/${wss4j.bundle.version}/org.apache.servicemix.bundles.wss4j-${wss4j.bundle.version}.jar
+
+start file:${maven.repo.local}/org/apache/sws/xmlschema/xmlschema-core/${xmlschema.bundle.version}/xmlschema-core-${xmlschema.bundle.version}.jar
+
+start file:${maven.repo.local}/org/apache/servicemix/bundles/org.apache.servicemix.bundles.asm/${asm.bundle.version}/org.apache.servicemix.bundles.asm-${asm.bundle.version}.jar
+
+start file:${maven.repo.local}/org/apache/servicemix/bundles/org.apache.servicemix.bundles.xmlresolver/${xmlresolver.bundle.version}/org.apache.servicemix.bundles.xmlresolver-${xmlresolver.bundle.version}.jar
+
+start file:${maven.repo.local}/org/apache/neethi/neethi/${neethi.bundle.version}/neethi-${neethi.bundle.version}.jar
+
+start file:${maven.repo.local}/org/codehaus/woodstox/stax2-api/3.1.1/stax2-api-3.1.1.jar
+
+start file:${maven.repo.local}/org/codehaus/woodstox/woodstox-core-asl/${woodstox.bundle.version}/woodstox-core-asl-${woodstox.bundle.version}.jar
+
+start file:${maven.repo.local}/org/apache/servicemix/bundles/org.apache.servicemix.bundles.joda-time/1.5.2_4/org.apache.servicemix.bundles.joda-time-1.5.2_4.jar
+
+start file:${maven.repo.local}/org/apache/servicemix/bundles/org.apache.servicemix.bundles.opensaml/2.4.1_1/org.apache.servicemix.bundles.opensaml-2.4.1_1.jar
+
+start file:${maven.repo.local}/org/apache/cxf/cxf-bundle-minimal/${cxf.version}/cxf-bundle-minimal-${cxf.version}.jar
+
+start file:${maven.repo.local}/org/apache/cxf/cxf-dosgi-ri-discovery-local/${project.version}/cxf-dosgi-ri-discovery-local-${project.version}.jar
+
+start file:${maven.repo.local}/org/apache/cxf/cxf-dosgi-ri-dsw-cxf/${project.version}/cxf-dosgi-ri-dsw-cxf-${project.version}.jar
+
+start file:${maven.repo.local}/org/apache/cxf/cxf-dosgi-ri-samples-greeter-interface/${project.version}/cxf-dosgi-ri-samples-greeter-interface-${project.version}.jar
+
+start file:${maven.repo.local}/org/apache/cxf/cxf-dosgi-ri-samples-greeter-client/${project.version}/cxf-dosgi-ri-samples-greeter-client-${project.version}.jar
+
diff --git a/trunk/felix/profiles/src/main/resources/dosgi_bundles.txt b/trunk/felix/profiles/src/main/resources/dosgi_bundles.txt
new file mode 100644
index 0000000..8506239
--- /dev/null
+++ b/trunk/felix/profiles/src/main/resources/dosgi_bundles.txt
@@ -0,0 +1,78 @@
+start file:${maven.repo.local}/org/apache/geronimo/specs/geronimo-annotation_1.0_spec/1.1.1/geronimo-annotation_1.0_spec-1.1.1.jar
+
+start file:${maven.repo.local}/org/apache/geronimo/specs/geronimo-activation_1.1_spec/1.1/geronimo-activation_1.1_spec-1.1.jar
+
+start file:${maven.repo.local}/org/apache/geronimo/specs/geronimo-javamail_1.4_spec/1.7.1/geronimo-javamail_1.4_spec-1.7.1.jar
+
+start file:${maven.repo.local}/org/apache/geronimo/specs/geronimo-ws-metadata_2.0_spec/1.1.3/geronimo-ws-metadata_2.0_spec-1.1.3.jar
+
+start file:${maven.repo.local}/org/apache/geronimo/specs/geronimo-servlet_3.0_spec/1.0/geronimo-servlet_3.0_spec-1.0.jar
+
+start file:${maven.repo.local}/org/apache/commons/com.springsource.org.apache.commons.logging/1.1.1/com.springsource.org.apache.commons.logging-1.1.1.jar
+
+start file:${maven.repo.local}/org/jdom/com.springsource.org.jdom/1.1.0/com.springsource.org.jdom-1.1.0.jar
+
+start file:${maven.repo.local}/org/jaxen/com.springsource.org.jaxen/1.1.1/com.springsource.org.jaxen-1.1.1.jar
+
+start file:${maven.repo.local}/org/springframework/spring-core/${spring.version}/spring-core-${spring.version}.jar
+
+start file:${maven.repo.local}/org/springframework/spring-beans/${spring.version}/spring-beans-${spring.version}.jar
+
+start file:${maven.repo.local}/org/springframework/spring-context/${spring.version}/spring-context-${spring.version}.jar
+
+start file:${maven.repo.local}/org/aopalliance/com.springsource.org.aopalliance/1.0.0/com.springsource.org.aopalliance-1.0.0.jar
+
+start file:${maven.repo.local}/org/springframework/spring-aop/${spring.version}/spring-aop-${spring.version}.jar
+
+start file:${maven.repo.local}/org/springframework/spring-expression/${spring.version}/spring-expression-${spring.version}.jar
+
+start file:${maven.repo.local}/org/springframework/spring-asm/${spring.version}/spring-asm-${spring.version}.jar
+
+start file:${maven.repo.local}/org/springframework/osgi/spring-osgi-io/${spring.osgi.version}/spring-osgi-io-${spring.osgi.version}.jar
+
+start file:${maven.repo.local}/org/springframework/osgi/spring-osgi-core/${spring.osgi.version}/spring-osgi-core-${spring.osgi.version}.jar
+
+start file:${maven.repo.local}/org/springframework/osgi/spring-osgi-extender/${spring.osgi.version}/spring-osgi-extender-${spring.osgi.version}.jar
+
+start file:${maven.repo.local}/org/eclipse/jetty/aggregate/jetty-all-server/${jetty.version}/jetty-all-server-${jetty.version}.jar
+
+start file:${maven.repo.local}/org/apache/servicemix/specs/org.apache.servicemix.specs.locator/${servicemix.specs.version}/org.apache.servicemix.specs.locator-${servicemix.specs.version}.jar
+
+start file:${maven.repo.local}/org/apache/servicemix/specs/org.apache.servicemix.specs.saaj-api-1.3/${servicemix.specs.version}/org.apache.servicemix.specs.saaj-api-1.3-${servicemix.specs.version}.jar
+
+start file:${maven.repo.local}/org/apache/servicemix/specs/org.apache.servicemix.specs.stax-api-1.0/${servicemix.specs.version}/org.apache.servicemix.specs.stax-api-1.0-${servicemix.specs.version}.jar
+
+start file:${maven.repo.local}/org/apache/servicemix/specs/org.apache.servicemix.specs.jaxb-api-2.1/${servicemix.specs.version}/org.apache.servicemix.specs.jaxb-api-2.1-${servicemix.specs.version}.jar
+
+start file:${maven.repo.local}/org/apache/servicemix/specs/org.apache.servicemix.specs.jaxws-api-2.1/${servicemix.specs.version}/org.apache.servicemix.specs.jaxws-api-2.1-${servicemix.specs.version}.jar
+
+start file:${maven.repo.local}/org/apache/servicemix/bundles/org.apache.servicemix.bundles.jaxb-impl/${jaxbimpl.bundle.version}/org.apache.servicemix.bundles.jaxb-impl-${jaxbimpl.bundle.version}.jar
+
+start file:${maven.repo.local}/org/apache/servicemix/bundles/org.apache.servicemix.bundles.wsdl4j/${wsdl4j.bundle.version}/org.apache.servicemix.bundles.wsdl4j-${wsdl4j.bundle.version}.jar
+
+start file:${maven.repo.local}/org/apache/servicemix/bundles/org.apache.servicemix.bundles.xmlsec/${xmlsec.bundle.version}/org.apache.servicemix.bundles.xmlsec-${xmlsec.bundle.version}.jar
+
+start file:${maven.repo.local}/org/apache/servicemix/bundles/org.apache.servicemix.bundles.wss4j/${wss4j.bundle.version}/org.apache.servicemix.bundles.wss4j-${wss4j.bundle.version}.jar
+
+start file:${maven.repo.local}/org/apache/sws/xmlschema/xmlschema-core/${xmlschema.bundle.version}/xmlschema-core-${xmlschema.bundle.version}.jar
+
+start file:${maven.repo.local}/org/apache/servicemix/bundles/org.apache.servicemix.bundles.asm/${asm.bundle.version}/org.apache.servicemix.bundles.asm-${asm.bundle.version}.jar
+
+start file:${maven.repo.local}/org/apache/servicemix/bundles/org.apache.servicemix.bundles.xmlresolver/${xmlresolver.bundle.version}/org.apache.servicemix.bundles.xmlresolver-${xmlresolver.bundle.version}.jar
+
+start file:${maven.repo.local}/org/apache/neethi/neethi/${neethi.bundle.version}/neethi-${neethi.bundle.version}.jar
+
+start file:${maven.repo.local}/org/codehaus/woodstox/stax2-api/3.1.1/stax2-api-3.1.1.jar
+
+start file:${maven.repo.local}/org/codehaus/woodstox/woodstox-core-asl/${woodstox.bundle.version}/woodstox-core-asl-${woodstox.bundle.version}.jar
+
+start file:${maven.repo.local}/org/apache/servicemix/bundles/org.apache.servicemix.bundles.joda-time/1.5.2_4/org.apache.servicemix.bundles.joda-time-1.5.2_4.jar
+
+start file:${maven.repo.local}/org/apache/servicemix/bundles/org.apache.servicemix.bundles.opensaml/2.4.1_1/org.apache.servicemix.bundles.opensaml-2.4.1_1.jar
+
+start file:${maven.repo.local}/org/apache/cxf/cxf-bundle-minimal/${cxf.version}/cxf-bundle-minimal-${cxf.version}.jar
+
+start file:${maven.repo.local}/org/apache/cxf/cxf-dosgi-ri-discovery-local/${project.version}/cxf-dosgi-ri-discovery-local-${project.version}.jar
+
+start file:${maven.repo.local}/org/apache/cxf/cxf-dosgi-ri-dsw-cxf/${project.version}/cxf-dosgi-ri-dsw-cxf-${project.version}.jar
+
diff --git a/trunk/felix/profiles/src/main/resources/server_bundles.txt b/trunk/felix/profiles/src/main/resources/server_bundles.txt
new file mode 100644
index 0000000..b15a054
--- /dev/null
+++ b/trunk/felix/profiles/src/main/resources/server_bundles.txt
@@ -0,0 +1,82 @@
+start file:${maven.repo.local}/org/apache/geronimo/specs/geronimo-annotation_1.0_spec/1.1.1/geronimo-annotation_1.0_spec-1.1.1.jar
+
+start file:${maven.repo.local}/org/apache/geronimo/specs/geronimo-activation_1.1_spec/1.1/geronimo-activation_1.1_spec-1.1.jar
+
+start file:${maven.repo.local}/org/apache/geronimo/specs/geronimo-javamail_1.4_spec/1.7.1/geronimo-javamail_1.4_spec-1.7.1.jar
+
+start file:${maven.repo.local}/org/apache/geronimo/specs/geronimo-ws-metadata_2.0_spec/1.1.3/geronimo-ws-metadata_2.0_spec-1.1.3.jar
+
+start file:${maven.repo.local}/org/apache/geronimo/specs/geronimo-servlet_3.0_spec/1.0/geronimo-servlet_3.0_spec-1.0.jar
+
+start file:${maven.repo.local}/org/apache/commons/com.springsource.org.apache.commons.logging/1.1.1/com.springsource.org.apache.commons.logging-1.1.1.jar
+
+start file:${maven.repo.local}/org/jdom/com.springsource.org.jdom/1.1.0/com.springsource.org.jdom-1.1.0.jar
+
+start file:${maven.repo.local}/org/jaxen/com.springsource.org.jaxen/1.1.1/com.springsource.org.jaxen-1.1.1.jar
+
+start file:${maven.repo.local}/org/springframework/spring-core/${spring.version}/spring-core-${spring.version}.jar
+
+start file:${maven.repo.local}/org/springframework/spring-beans/${spring.version}/spring-beans-${spring.version}.jar
+
+start file:${maven.repo.local}/org/springframework/spring-context/${spring.version}/spring-context-${spring.version}.jar
+
+start file:${maven.repo.local}/org/aopalliance/com.springsource.org.aopalliance/1.0.0/com.springsource.org.aopalliance-1.0.0.jar
+
+start file:${maven.repo.local}/org/springframework/spring-aop/${spring.version}/spring-aop-${spring.version}.jar
+
+start file:${maven.repo.local}/org/springframework/spring-expression/${spring.version}/spring-expression-${spring.version}.jar
+
+start file:${maven.repo.local}/org/springframework/spring-asm/${spring.version}/spring-asm-${spring.version}.jar
+
+start file:${maven.repo.local}/org/springframework/osgi/spring-osgi-io/${spring.osgi.version}/spring-osgi-io-${spring.osgi.version}.jar
+
+start file:${maven.repo.local}/org/springframework/osgi/spring-osgi-core/${spring.osgi.version}/spring-osgi-core-${spring.osgi.version}.jar
+
+start file:${maven.repo.local}/org/springframework/osgi/spring-osgi-extender/${spring.osgi.version}/spring-osgi-extender-${spring.osgi.version}.jar
+
+start file:${maven.repo.local}/org/eclipse/jetty/aggregate/jetty-all-server/${jetty.version}/jetty-all-server-${jetty.version}.jar
+
+start file:${maven.repo.local}/org/apache/servicemix/specs/org.apache.servicemix.specs.locator/${servicemix.specs.version}/org.apache.servicemix.specs.locator-${servicemix.specs.version}.jar
+
+start file:${maven.repo.local}/org/apache/servicemix/specs/org.apache.servicemix.specs.saaj-api-1.3/${servicemix.specs.version}/org.apache.servicemix.specs.saaj-api-1.3-${servicemix.specs.version}.jar
+
+start file:${maven.repo.local}/org/apache/servicemix/specs/org.apache.servicemix.specs.stax-api-1.0/${servicemix.specs.version}/org.apache.servicemix.specs.stax-api-1.0-${servicemix.specs.version}.jar
+
+start file:${maven.repo.local}/org/apache/servicemix/specs/org.apache.servicemix.specs.jaxb-api-2.1/${servicemix.specs.version}/org.apache.servicemix.specs.jaxb-api-2.1-${servicemix.specs.version}.jar
+
+start file:${maven.repo.local}/org/apache/servicemix/specs/org.apache.servicemix.specs.jaxws-api-2.1/${servicemix.specs.version}/org.apache.servicemix.specs.jaxws-api-2.1-${servicemix.specs.version}.jar
+
+start file:${maven.repo.local}/org/apache/servicemix/bundles/org.apache.servicemix.bundles.jaxb-impl/${jaxbimpl.bundle.version}/org.apache.servicemix.bundles.jaxb-impl-${jaxbimpl.bundle.version}.jar
+
+start file:${maven.repo.local}/org/apache/servicemix/bundles/org.apache.servicemix.bundles.wsdl4j/${wsdl4j.bundle.version}/org.apache.servicemix.bundles.wsdl4j-${wsdl4j.bundle.version}.jar
+
+start file:${maven.repo.local}/org/apache/servicemix/bundles/org.apache.servicemix.bundles.xmlsec/${xmlsec.bundle.version}/org.apache.servicemix.bundles.xmlsec-${xmlsec.bundle.version}.jar
+
+start file:${maven.repo.local}/org/apache/servicemix/bundles/org.apache.servicemix.bundles.wss4j/${wss4j.bundle.version}/org.apache.servicemix.bundles.wss4j-${wss4j.bundle.version}.jar
+
+start file:${maven.repo.local}/org/apache/sws/xmlschema/xmlschema-core/${xmlschema.bundle.version}/xmlschema-core-${xmlschema.bundle.version}.jar
+
+start file:${maven.repo.local}/org/apache/servicemix/bundles/org.apache.servicemix.bundles.asm/${asm.bundle.version}/org.apache.servicemix.bundles.asm-${asm.bundle.version}.jar
+
+start file:${maven.repo.local}/org/apache/servicemix/bundles/org.apache.servicemix.bundles.xmlresolver/${xmlresolver.bundle.version}/org.apache.servicemix.bundles.xmlresolver-${xmlresolver.bundle.version}.jar
+
+start file:${maven.repo.local}/org/apache/neethi/neethi/${neethi.bundle.version}/neethi-${neethi.bundle.version}.jar
+
+start file:${maven.repo.local}/org/codehaus/woodstox/stax2-api/3.1.1/stax2-api-3.1.1.jar
+
+start file:${maven.repo.local}/org/codehaus/woodstox/woodstox-core-asl/${woodstox.bundle.version}/woodstox-core-asl-${woodstox.bundle.version}.jar
+
+start file:${maven.repo.local}/org/apache/servicemix/bundles/org.apache.servicemix.bundles.joda-time/1.5.2_4/org.apache.servicemix.bundles.joda-time-1.5.2_4.jar
+
+start file:${maven.repo.local}/org/apache/servicemix/bundles/org.apache.servicemix.bundles.opensaml/2.4.1_1/org.apache.servicemix.bundles.opensaml-2.4.1_1.jar
+
+start file:${maven.repo.local}/org/apache/cxf/cxf-bundle-minimal/${cxf.version}/cxf-bundle-minimal-${cxf.version}.jar
+
+start file:${maven.repo.local}/org/apache/cxf/cxf-dosgi-ri-discovery-local/${project.version}/cxf-dosgi-ri-discovery-local-${project.version}.jar
+
+start file:${maven.repo.local}/org/apache/cxf/cxf-dosgi-ri-dsw-cxf/${project.version}/cxf-dosgi-ri-dsw-cxf-${project.version}.jar
+
+start file:${maven.repo.local}/org/apache/cxf/cxf-dosgi-ri-samples-greeter-interface/${project.version}/cxf-dosgi-ri-samples-greeter-interface-${project.version}.jar
+
+start file:${maven.repo.local}/org/apache/cxf/cxf-dosgi-ri-samples-greeter-impl/${project.version}/cxf-dosgi-ri-samples-greeter-impl-${project.version}.jar
+
diff --git a/trunk/felix/remote-debug.txt b/trunk/felix/remote-debug.txt
new file mode 100644
index 0000000..229262b
--- /dev/null
+++ b/trunk/felix/remote-debug.txt
@@ -0,0 +1 @@
+-Xdebug -Xnoagent -Djava.compiler=NONE -Xrunjdwp:transport=dt_socket,server=y,suspend=n,address=5005
diff --git a/trunk/felix/shell.tui/LICENSE b/trunk/felix/shell.tui/LICENSE
new file mode 100644
index 0000000..d645695
--- /dev/null
+++ b/trunk/felix/shell.tui/LICENSE
@@ -0,0 +1,202 @@
+
+                                 Apache License
+                           Version 2.0, January 2004
+                        http://www.apache.org/licenses/
+
+   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+   1. Definitions.
+
+      "License" shall mean the terms and conditions for use, reproduction,
+      and distribution as defined by Sections 1 through 9 of this document.
+
+      "Licensor" shall mean the copyright owner or entity authorized by
+      the copyright owner that is granting the License.
+
+      "Legal Entity" shall mean the union of the acting entity and all
+      other entities that control, are controlled by, or are under common
+      control with that entity. For the purposes of this definition,
+      "control" means (i) the power, direct or indirect, to cause the
+      direction or management of such entity, whether by contract or
+      otherwise, or (ii) ownership of fifty percent (50%) or more of the
+      outstanding shares, or (iii) beneficial ownership of such entity.
+
+      "You" (or "Your") shall mean an individual or Legal Entity
+      exercising permissions granted by this License.
+
+      "Source" form shall mean the preferred form for making modifications,
+      including but not limited to software source code, documentation
+      source, and configuration files.
+
+      "Object" form shall mean any form resulting from mechanical
+      transformation or translation of a Source form, including but
+      not limited to compiled object code, generated documentation,
+      and conversions to other media types.
+
+      "Work" shall mean the work of authorship, whether in Source or
+      Object form, made available under the License, as indicated by a
+      copyright notice that is included in or attached to the work
+      (an example is provided in the Appendix below).
+
+      "Derivative Works" shall mean any work, whether in Source or Object
+      form, that is based on (or derived from) the Work and for which the
+      editorial revisions, annotations, elaborations, or other modifications
+      represent, as a whole, an original work of authorship. For the purposes
+      of this License, Derivative Works shall not include works that remain
+      separable from, or merely link (or bind by name) to the interfaces of,
+      the Work and Derivative Works thereof.
+
+      "Contribution" shall mean any work of authorship, including
+      the original version of the Work and any modifications or additions
+      to that Work or Derivative Works thereof, that is intentionally
+      submitted to Licensor for inclusion in the Work by the copyright owner
+      or by an individual or Legal Entity authorized to submit on behalf of
+      the copyright owner. For the purposes of this definition, "submitted"
+      means any form of electronic, verbal, or written communication sent
+      to the Licensor or its representatives, including but not limited to
+      communication on electronic mailing lists, source code control systems,
+      and issue tracking systems that are managed by, or on behalf of, the
+      Licensor for the purpose of discussing and improving the Work, but
+      excluding communication that is conspicuously marked or otherwise
+      designated in writing by the copyright owner as "Not a Contribution."
+
+      "Contributor" shall mean Licensor and any individual or Legal Entity
+      on behalf of whom a Contribution has been received by Licensor and
+      subsequently incorporated within the Work.
+
+   2. Grant of Copyright License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      copyright license to reproduce, prepare Derivative Works of,
+      publicly display, publicly perform, sublicense, and distribute the
+      Work and such Derivative Works in Source or Object form.
+
+   3. Grant of Patent License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      (except as stated in this section) patent license to make, have made,
+      use, offer to sell, sell, import, and otherwise transfer the Work,
+      where such license applies only to those patent claims licensable
+      by such Contributor that are necessarily infringed by their
+      Contribution(s) alone or by combination of their Contribution(s)
+      with the Work to which such Contribution(s) was submitted. If You
+      institute patent litigation against any entity (including a
+      cross-claim or counterclaim in a lawsuit) alleging that the Work
+      or a Contribution incorporated within the Work constitutes direct
+      or contributory patent infringement, then any patent licenses
+      granted to You under this License for that Work shall terminate
+      as of the date such litigation is filed.
+
+   4. Redistribution. You may reproduce and distribute copies of the
+      Work or Derivative Works thereof in any medium, with or without
+      modifications, and in Source or Object form, provided that You
+      meet the following conditions:
+
+      (a) You must give any other recipients of the Work or
+          Derivative Works a copy of this License; and
+
+      (b) You must cause any modified files to carry prominent notices
+          stating that You changed the files; and
+
+      (c) You must retain, in the Source form of any Derivative Works
+          that You distribute, all copyright, patent, trademark, and
+          attribution notices from the Source form of the Work,
+          excluding those notices that do not pertain to any part of
+          the Derivative Works; and
+
+      (d) If the Work includes a "NOTICE" text file as part of its
+          distribution, then any Derivative Works that You distribute must
+          include a readable copy of the attribution notices contained
+          within such NOTICE file, excluding those notices that do not
+          pertain to any part of the Derivative Works, in at least one
+          of the following places: within a NOTICE text file distributed
+          as part of the Derivative Works; within the Source form or
+          documentation, if provided along with the Derivative Works; or,
+          within a display generated by the Derivative Works, if and
+          wherever such third-party notices normally appear. The contents
+          of the NOTICE file are for informational purposes only and
+          do not modify the License. You may add Your own attribution
+          notices within Derivative Works that You distribute, alongside
+          or as an addendum to the NOTICE text from the Work, provided
+          that such additional attribution notices cannot be construed
+          as modifying the License.
+
+      You may add Your own copyright statement to Your modifications and
+      may provide additional or different license terms and conditions
+      for use, reproduction, or distribution of Your modifications, or
+      for any such Derivative Works as a whole, provided Your use,
+      reproduction, and distribution of the Work otherwise complies with
+      the conditions stated in this License.
+
+   5. Submission of Contributions. Unless You explicitly state otherwise,
+      any Contribution intentionally submitted for inclusion in the Work
+      by You to the Licensor shall be under the terms and conditions of
+      this License, without any additional terms or conditions.
+      Notwithstanding the above, nothing herein shall supersede or modify
+      the terms of any separate license agreement you may have executed
+      with Licensor regarding such Contributions.
+
+   6. Trademarks. This License does not grant permission to use the trade
+      names, trademarks, service marks, or product names of the Licensor,
+      except as required for reasonable and customary use in describing the
+      origin of the Work and reproducing the content of the NOTICE file.
+
+   7. Disclaimer of Warranty. Unless required by applicable law or
+      agreed to in writing, Licensor provides the Work (and each
+      Contributor provides its Contributions) on an "AS IS" BASIS,
+      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+      implied, including, without limitation, any warranties or conditions
+      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+      PARTICULAR PURPOSE. You are solely responsible for determining the
+      appropriateness of using or redistributing the Work and assume any
+      risks associated with Your exercise of permissions under this License.
+
+   8. Limitation of Liability. In no event and under no legal theory,
+      whether in tort (including negligence), contract, or otherwise,
+      unless required by applicable law (such as deliberate and grossly
+      negligent acts) or agreed to in writing, shall any Contributor be
+      liable to You for damages, including any direct, indirect, special,
+      incidental, or consequential damages of any character arising as a
+      result of this License or out of the use or inability to use the
+      Work (including but not limited to damages for loss of goodwill,
+      work stoppage, computer failure or malfunction, or any and all
+      other commercial damages or losses), even if such Contributor
+      has been advised of the possibility of such damages.
+
+   9. Accepting Warranty or Additional Liability. While redistributing
+      the Work or Derivative Works thereof, You may choose to offer,
+      and charge a fee for, acceptance of support, warranty, indemnity,
+      or other liability obligations and/or rights consistent with this
+      License. However, in accepting such obligations, You may act only
+      on Your own behalf and on Your sole responsibility, not on behalf
+      of any other Contributor, and only if You agree to indemnify,
+      defend, and hold each Contributor harmless for any liability
+      incurred by, or claims asserted against, such Contributor by reason
+      of your accepting any such warranty or additional liability.
+
+   END OF TERMS AND CONDITIONS
+
+   APPENDIX: How to apply the Apache License to your work.
+
+      To apply the Apache License to your work, attach the following
+      boilerplate notice, with the fields enclosed by brackets "[]"
+      replaced with your own identifying information. (Don't include
+      the brackets!)  The text should be enclosed in the appropriate
+      comment syntax for the file format. We also recommend that a
+      file or class name and description of purpose be included on the
+      same "printed page" as the copyright notice for easier
+      identification within third-party archives.
+
+   Copyright [yyyy] [name of copyright owner]
+
+   Licensed 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.
diff --git a/trunk/felix/shell.tui/NOTICE b/trunk/felix/shell.tui/NOTICE
new file mode 100644
index 0000000..d96621a
--- /dev/null
+++ b/trunk/felix/shell.tui/NOTICE
@@ -0,0 +1,20 @@
+Apache Felix Shell Textual Interface
+Copyright 2006-2008 The Apache Software Foundation
+
+I. Included Software
+
+This product includes software developed at
+The Apache Software Foundation (http://www.apache.org/).
+Licensed under the Apache License 2.0.
+
+
+II. Used Software
+
+This product uses software developed at
+The OSGi Alliance (http://www.osgi.org/).
+Copyright 2006 The OSGi Alliance.
+Licensed under the Apache License 2.0.
+
+
+III. License Summary
+- Apache License 2.0
diff --git a/trunk/felix/shell.tui/pom.xml b/trunk/felix/shell.tui/pom.xml
new file mode 100644
index 0000000..933ab2b
--- /dev/null
+++ b/trunk/felix/shell.tui/pom.xml
@@ -0,0 +1,92 @@
+<?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>
+  <packaging>bundle</packaging>
+  <name>Distributed OSGi Temporary Private Apache Felix Shell TUI Build</name>
+  <description>A simple textual user interface for Felix' shell service.</description>
+  <groupId>org.apache.cxf.dosgi</groupId>
+  <artifactId>felix-shell-extension</artifactId>
+  <version>1.6.0</version>
+
+  <parent>
+      <groupId>org.apache.cxf.dosgi</groupId>
+      <artifactId>cxf-dosgi-ri-parent</artifactId>
+      <version>1.6.0</version>
+      <relativePath>../../parent/pom.xml</relativePath>
+  </parent>
+
+   <properties>
+      <maven.test.skip>true</maven.test.skip>
+   </properties>
+
+  <dependencies>
+    <dependency>
+      <groupId>org.apache.felix</groupId>
+      <artifactId>org.osgi.core</artifactId>
+      <version>1.0.1</version>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.felix</groupId>
+      <artifactId>org.apache.felix.shell</artifactId>
+      <version>1.0.1</version>
+    </dependency>
+  </dependencies>
+  <build>
+    <plugins>
+      <plugin>
+          <groupId>org.apache.maven.plugins</groupId>
+          <artifactId>maven-checkstyle-plugin</artifactId>
+          <version>2.8</version>
+          <configuration>
+             <excludes>**/*.java</excludes>
+          </configuration>
+      </plugin>
+      <plugin>
+          <groupId>org.apache.maven.plugins</groupId>
+          <artifactId>maven-pmd-plugin</artifactId>
+          <version>2.6</version>
+          <configuration>
+             <excludes>
+                 <exclude>**/*.java</exclude>
+             </excludes>
+          </configuration>
+      </plugin>
+
+      <plugin>
+        <groupId>org.apache.felix</groupId>
+        <artifactId>maven-bundle-plugin</artifactId>
+        <version>1.4.0</version>
+        <extensions>true</extensions>
+        <configuration>
+          <instructions>
+            <Private-Package>org.apache.felix.shell.tui.*</Private-Package>
+            <Bundle-Activator>org.apache.felix.shell.tui.Activator</Bundle-Activator>
+            <Bundle-DocURL>http://oscar-osgi.sf.net/obr2/${project.artifactId}/</Bundle-DocURL>
+            <Bundle-SymbolicName>${project.artifactId}</Bundle-SymbolicName>
+            <Bundle-Vendor>The Apache Software Foundation</Bundle-Vendor>
+            <Import-Service>org.apache.felix.shell.ShellService</Import-Service>
+          </instructions>
+        </configuration>
+      </plugin>
+    </plugins>
+  </build>
+</project>
diff --git a/trunk/felix/shell.tui/src/main/java/org/apache/felix/shell/tui/Activator.java b/trunk/felix/shell.tui/src/main/java/org/apache/felix/shell/tui/Activator.java
new file mode 100644
index 0000000..c41ca32
--- /dev/null
+++ b/trunk/felix/shell.tui/src/main/java/org/apache/felix/shell/tui/Activator.java
@@ -0,0 +1,187 @@
+/**
+ * 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.felix.shell.tui;
+
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileReader;
+import java.io.IOException;
+import java.io.InputStreamReader;
+
+import org.apache.felix.shell.ShellService;
+import org.osgi.framework.BundleActivator;
+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;
+
+public class Activator implements BundleActivator {
+
+    private static final String RUN_CMD = "run ";
+
+    private BundleContext context;
+    private ShellTuiRunnable shellRunnable;
+    private Thread thread;
+    private ServiceListener listener;
+    private ServiceReference shellRef;
+    private ShellService shell;
+
+    public void start(BundleContext bcontext) {
+        context = bcontext;
+
+        // Listen for registering/unregistering impl service.
+        listener = new ShellServiceListener();
+        try {
+            context.addServiceListener(listener,
+                    "(objectClass=" + org.apache.felix.shell.ShellService.class.getName() + ")");
+        } catch (InvalidSyntaxException ex) {
+            System.err.println("ShellTui: Cannot add service listener.");
+            System.err.println("ShellTui: " + ex);
+        }
+
+        // Now try to manually initialize the impl service
+        // since one might already be available.
+        initializeService();
+
+        // Start impl thread.
+        shellRunnable = new ShellTuiRunnable();
+        thread = new Thread(shellRunnable, "Felix Shell TUI");
+        thread.start();
+    }
+
+    public void stop(BundleContext bcontext) {
+        if (shellRunnable != null) {
+            shellRunnable.stop();
+            thread.interrupt();
+        }
+        if (listener != null) {
+            context.removeServiceListener(listener);
+        }
+        uninitializeService();
+    }
+
+    private synchronized void initializeService() {
+        if (shell != null) {
+            return;
+        }
+        shellRef = context.getServiceReference(org.apache.felix.shell.ShellService.class.getName());
+        if (shellRef == null) {
+            return;
+        }
+        shell = (ShellService)context.getService(shellRef);
+    }
+
+    private synchronized void uninitializeService() {
+        if (shellRef != null) {
+            context.ungetService(shellRef);
+        }
+        shellRef = null;
+        shell = null;
+    }
+
+    private class ShellServiceListener implements ServiceListener {
+        public void serviceChanged(ServiceEvent event) {
+            synchronized (Activator.this) {
+                if (event.getType() == ServiceEvent.REGISTERED) {
+                    // Ignore additional services if we already have one.
+                    if (shellRef == null) {
+                        // Initialize the service if we don't have one.
+                        initializeService();
+                    }
+                } else if (event.getType() == ServiceEvent.UNREGISTERING
+                        && event.getServiceReference().equals(shellRef)) {
+                    // Unget the service if it is unregistering.
+                    uninitializeService();
+                    // Try to get another service.
+                    initializeService();
+                }
+            }
+        }
+    }
+
+    private class ShellTuiRunnable implements Runnable {
+
+        private volatile boolean stop;
+
+        public void stop() {
+            stop = true;
+        }
+
+        public void run() {
+            String line;
+            BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
+
+            while (!stop) {
+                System.out.print("-> ");
+
+                try {
+                    line = in.readLine();
+                } catch (IOException ex) {
+                    System.err.println("Could not read input, please try again.");
+                    continue;
+                }
+
+                synchronized (Activator.this) {
+                    if (shell == null) {
+                        System.out.println("No impl service available.");
+                        continue;
+                    }
+
+                    if (line == null) {
+                        continue;
+                    }
+
+                    line = line.trim();
+
+                    if (line.isEmpty()) {
+                        continue;
+                    }
+
+                    try {
+                        if (line.startsWith(RUN_CMD)) {
+                            String path = line.substring(RUN_CMD.length()).trim();
+                            System.out.println("loading commands from: " + path);
+                            File commands = new File(path);
+                            if (commands.exists()) {
+                                BufferedReader reader = new BufferedReader(new FileReader(commands));
+                                String command = reader.readLine().trim();
+                                while (command != null) {
+                                    if (!command.isEmpty()) {
+                                        System.out.println("\nexecuting: " + command);
+                                        shell.executeCommand(command.trim(), System.out, System.err);
+                                    }
+                                    command = reader.readLine();
+                                }
+                                reader.close();
+                            } else {
+                                System.err.println(path + " not found");
+                            }
+                        } else {
+                            shell.executeCommand(line, System.out, System.err);
+                        }
+                    } catch (Exception ex) {
+                        System.err.println("ShellTui: " + ex);
+                        ex.printStackTrace();
+                    }
+                }
+            }
+        }
+    }
+}
diff --git a/trunk/osgi-api/pom.xml b/trunk/osgi-api/pom.xml
new file mode 100644
index 0000000..4ad1bb4
--- /dev/null
+++ b/trunk/osgi-api/pom.xml
@@ -0,0 +1,69 @@
+<?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>
+    <artifactId>cxf-dosgi-ri-osgi-api</artifactId>
+    <packaging>bundle</packaging>
+    <name>CXF dOSGi Required OSGi Compendium APIs</name>
+    <description>The minimal set of OSGi Compendium APIs required by DOSGi</description>
+    <!--
+        This bundle should be deployed instead of the full OSGi Compendium bundle to prevent issues
+        caused by multiple exports of other OSGi APIs that are not used by DOSGi. See DOSGI-208.
+    -->
+
+    <parent>
+        <groupId>org.apache.cxf.dosgi</groupId>
+        <artifactId>cxf-dosgi-ri-parent</artifactId>
+        <version>1.6.0</version>
+        <relativePath>../parent/pom.xml</relativePath>
+    </parent>
+
+    <properties>
+        <!-- the minimal set of OSGi Compendium packages that is required for DOSGi to run -->
+        <required-packages>org.osgi.service.remoteserviceadmin,org.osgi.service.event</required-packages>
+    </properties>
+
+    <build>
+        <plugins>
+            <plugin>
+                <groupId>org.apache.felix</groupId>
+                <artifactId>maven-bundle-plugin</artifactId>
+                <configuration>
+                    <instructions>
+                        <Bundle-SymbolicName>${project.artifactId}</Bundle-SymbolicName>
+                        <!-- we must both import and export to prevent trouble if another bundle exports them too -->
+                        <Import-Package>${required-packages},*</Import-Package>
+                        <Export-Package>${required-packages}</Export-Package>
+                        <!-- embed the packages in this bundle -->
+                        <Private-Package>${required-packages}</Private-Package>
+                    </instructions>
+                </configuration>
+            </plugin>
+        </plugins>
+    </build>
+
+    <dependencies>
+        <dependency>
+            <groupId>org.osgi</groupId>
+            <artifactId>org.osgi.compendium</artifactId>
+        </dependency>
+    </dependencies>
+
+</project>
diff --git a/trunk/parent/pom.xml b/trunk/parent/pom.xml
new file mode 100644
index 0000000..4284763
--- /dev/null
+++ b/trunk/parent/pom.xml
@@ -0,0 +1,394 @@
+<?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">
+
+    <parent>
+        <groupId>org.apache.cxf.dosgi</groupId>
+        <artifactId>cxf-dosgi-ri</artifactId>
+        <version>1.6.0</version>
+    </parent>
+
+    <modelVersion>4.0.0</modelVersion>
+    <groupId>org.apache.cxf.dosgi</groupId>
+    <artifactId>cxf-dosgi-ri-parent</artifactId>
+    <version>1.6.0</version>
+
+    <packaging>pom</packaging>
+    <name>Distributed OSGI Reference Implementation Parent</name>
+
+    <!-- Some versions of libraries used are different to the ones from CXF, 
+        this is generally caused by the fact that not all versions are available 
+        yet as OSGi bundles. -->
+
+    <!-- Note: the Felix Framework bundle contains the org.osgi core packages, 
+        which may override the standalone org.osgi dependency bundles - so if the 
+        org.osgi bundle versions are modified below, the corresponding Felix Framework 
+        version must be updated as well. -->
+
+    <properties>
+        <!-- portable text resource processing -->
+        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
+
+        <osgi.version>4.3.1</osgi.version>
+        <osgi.compendium.version>4.3.1</osgi.compendium.version>
+        <cxf.version>2.7.8</cxf.version>
+        <cxf.build-utils.version>2.5.0</cxf.build-utils.version>
+        <felix.version>4.2.1</felix.version>
+        <spring.version>3.0.6.RELEASE</spring.version>
+        <spring.osgi.version>1.2.1</spring.osgi.version>
+        <zookeeper.version>3.3.2</zookeeper.version>
+
+        <remote.service.admin.interfaces.version>1.0.0</remote.service.admin.interfaces.version>
+
+        <servicemix.specs.version>2.2.0</servicemix.specs.version>
+        <pax.web.version>1.0.11</pax.web.version>
+        <pax.logging.version>1.7.0</pax.logging.version>
+        <servlet.version>3.0</servlet.version>
+        <log4j.version>1.2.17</log4j.version>
+        <jetty.version>7.4.2.v20110526</jetty.version>
+        <xmlschema.bundle.version>2.0.3</xmlschema.bundle.version>
+        <xmlresolver.bundle.version>1.2_5</xmlresolver.bundle.version>
+        <neethi.bundle.version>3.0.2</neethi.bundle.version>
+        <wsdl4j.bundle.version>1.6.2_6</wsdl4j.bundle.version>
+        <xmlsec.version>1.5.3</xmlsec.version>
+        <asm.bundle.version>3.3.1_1</asm.bundle.version>
+        <commons.pool.bundle.version>1.5.4_1</commons.pool.bundle.version>
+        <woodstox.bundle.version>4.1.4</woodstox.bundle.version>
+        <jaxbimpl.bundle.version>2.2.1.1_2</jaxbimpl.bundle.version>
+        <slf4j.version>1.7.0</slf4j.version>
+        <felix.plugin.version>2.4.0</felix.plugin.version>
+        <exam.version>3.2.0</exam.version>
+        <cxf.resources.base.path />
+        <cxf.checkstyle.extension />
+    </properties>
+
+    <dependencyManagement>
+        <dependencies>
+            <dependency>
+                <groupId>org.osgi</groupId>
+                <artifactId>org.osgi.core</artifactId>
+                <version>${osgi.version}</version>
+            </dependency>
+            <dependency>
+                <groupId>org.osgi</groupId>
+                <artifactId>org.osgi.compendium</artifactId>
+                <version>${osgi.compendium.version}</version>
+            </dependency>
+            <dependency>
+                <groupId>org.slf4j</groupId>
+                <artifactId>slf4j-api</artifactId>
+                <version>${slf4j.version}</version>
+            </dependency>
+            <dependency>
+                <groupId>org.slf4j</groupId>
+                <artifactId>slf4j-jcl</artifactId>
+                <version>${slf4j.version}</version>
+            </dependency>
+            <dependency>
+                <groupId>junit</groupId>
+                <artifactId>junit</artifactId>
+                <version>4.7</version>
+                <scope>test</scope>
+            </dependency>
+            <dependency>
+                <groupId>org.easymock</groupId>
+                <artifactId>easymock</artifactId>
+                <version>2.5.2</version>
+                <scope>test</scope>
+            </dependency>
+            <dependency>
+                <groupId>org.easymock</groupId>
+                <artifactId>easymockclassextension</artifactId>
+                <version>2.5.2</version>
+                <scope>test</scope>
+            </dependency>
+            <dependency>
+                <groupId>xmlunit</groupId>
+                <artifactId>xmlunit</artifactId>
+                <version>1.4</version>
+                <scope>test</scope>
+            </dependency>
+            <dependency>
+                <groupId>org.apache.geronimo.specs</groupId>
+                <artifactId>geronimo-atinject_1.0_spec</artifactId>
+                <version>1.0</version>
+                <scope>test</scope>
+            </dependency>
+            <dependency>
+                <groupId>org.ops4j.pax.exam</groupId>
+                <artifactId>pax-exam-junit4</artifactId>
+                <version>${exam.version}</version>
+            </dependency>
+            <dependency>
+                <groupId>org.ops4j.pax.exam</groupId>
+                <artifactId>pax-exam-inject</artifactId>
+                <version>${exam.version}</version>
+            </dependency>
+            <dependency>
+                <groupId>org.ops4j.pax.exam</groupId>
+                <artifactId>pax-exam-container-forked</artifactId>
+                <version>${exam.version}</version>
+            </dependency>
+            <dependency>
+                <groupId>org.ops4j.pax.exam</groupId>
+                <artifactId>pax-exam-link-mvn</artifactId>
+                <version>${exam.version}</version>
+                <scope>test</scope>
+            </dependency>
+
+            <dependency>
+                <groupId>org.eclipse</groupId>
+                <artifactId>org.eclipse.osgi</artifactId>
+                <version>3.8.0.v20120529-1548</version>
+            </dependency>
+            
+            <dependency>
+                <groupId>org.apache.felix</groupId>
+                <artifactId>org.apache.felix.framework</artifactId> 
+                <version>${felix.version}</version>
+            </dependency>
+
+            <dependency>
+                <groupId>org.ops4j.pax.tinybundles</groupId>
+                <artifactId>tinybundles</artifactId>
+                <version>2.0.0</version>
+            </dependency>
+        </dependencies>
+    </dependencyManagement>
+
+    <build>
+        <defaultGoal>install</defaultGoal>
+
+        <pluginManagement>
+            <plugins>
+                <plugin>
+                    <groupId>org.apache.felix</groupId>
+                    <artifactId>maven-bundle-plugin</artifactId>
+                    <version>${felix.plugin.version}</version>
+                    <extensions>true</extensions>
+                </plugin>
+                <plugin>
+                    <groupId>org.apache.maven.plugins</groupId>
+                    <artifactId>maven-assembly-plugin</artifactId>
+                    <version>2.2.1</version>
+                </plugin>
+                <plugin>
+                    <groupId>org.apache.maven.plugins</groupId>
+                    <artifactId>maven-surefire-plugin</artifactId>
+                    <version>2.8.1</version>
+                </plugin>
+                <plugin>
+                    <groupId>org.apache.maven.plugins</groupId>
+                    <artifactId>maven-compiler-plugin</artifactId>
+                    <version>2.5.1</version>
+                    <configuration>
+                        <source>1.6</source>
+                        <target>1.6</target>
+                        <maxmem>256M</maxmem>
+                        <fork>false</fork>
+                    </configuration>
+                </plugin>
+                <plugin>
+                    <groupId>org.apache.maven.plugins</groupId>
+                    <artifactId>maven-antrun-plugin</artifactId>
+                    <version>1.6</version>
+                    <dependencies>
+                        <dependency>
+                            <groupId>ant</groupId>
+                            <artifactId>ant-trax</artifactId>
+                            <version>1.6.5</version>
+                        </dependency>
+                    </dependencies>
+                </plugin>
+                <plugin>
+                    <groupId>org.apache.maven.plugins</groupId>
+                    <artifactId>maven-resources-plugin</artifactId>
+                    <version>2.5</version>
+                </plugin>
+                <plugin>
+                    <groupId>org.apache.maven.plugins</groupId>
+                    <artifactId>maven-dependency-plugin</artifactId>
+                    <version>2.8</version>
+                </plugin>
+
+                <plugin>
+                    <groupId>org.apache.maven.plugins</groupId>
+                    <artifactId>maven-remote-resources-plugin</artifactId>
+                    <version>1.2</version>
+                    <dependencies>
+                        <dependency>
+                            <groupId>org.apache.cxf.build-utils</groupId>
+                            <artifactId>cxf-buildtools</artifactId>
+                            <version>${cxf.build-utils.version}</version>
+                        </dependency>
+                    </dependencies>
+                    <executions>
+                        <execution>
+                            <goals>
+                                <goal>process</goal>
+                            </goals>
+                            <configuration>
+                                <resourceBundles>
+                                    <resourceBundle>org.apache:apache-jar-resource-bundle:1.4</resourceBundle>
+                                </resourceBundles>
+                                <supplementalModels>
+                                    <supplementalModel>notice-supplements.xml</supplementalModel>
+                                </supplementalModels>
+                                <properties>
+                                    <projectName>Apache CXF Distributed
+                                        OSGi DSW Reference
+                                        Implementation</projectName>
+                                </properties>
+                            </configuration>
+                        </execution>
+                    </executions>
+                </plugin>
+                <plugin>
+                    <groupId>org.apache.maven.plugins</groupId>
+                    <artifactId>maven-eclipse-plugin</artifactId>
+                    <dependencies>
+                        <dependency>
+                            <groupId>org.apache.cxf.build-utils</groupId>
+                            <artifactId>cxf-buildtools</artifactId>
+                            <version>${cxf.build-utils.version}</version>
+                        </dependency>
+                    </dependencies>
+                    <configuration>
+                        <buildcommands>
+                            <java.lang.String>org.eclipse.jdt.core.javabuilder</java.lang.String>
+                            <java.lang.String>net.sf.eclipsecs.core.CheckstyleBuilder</java.lang.String>
+                            <java.lang.String>net.sourceforge.pmd.eclipse.plugin.pmdBuilder</java.lang.String>
+                        </buildcommands>
+                        <projectnatures>
+                            <nature>org.eclipse.jdt.core.javanature</nature>
+                            <nature>net.sf.eclipsecs.core.CheckstyleNature</nature>
+                            <nature>net.sourceforge.pmd.eclipse.plugin.pmdNature</nature>
+                        </projectnatures>
+                        <ajdtVersion>none</ajdtVersion>
+                        <additionalConfig>
+                            <file>
+                                <name>.checkstyle</name>
+                                <location>/cxf-eclipse-checkstyle</location>
+                            </file>
+                            <file>
+                                <name>.pmd</name>
+                                <location>/cxf-eclipse-pmd</location>
+                            </file>
+                            <file>
+                                <name>.ruleset</name>
+                                <location>/cxf-pmd-ruleset.xml</location>
+                            </file>
+                        </additionalConfig>
+                    </configuration>
+                </plugin>
+            </plugins>
+        </pluginManagement>
+
+        <plugins>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-remote-resources-plugin</artifactId>
+                <version>1.2</version>
+                <dependencies>
+                    <dependency>
+                        <groupId>org.apache.cxf.build-utils</groupId>
+                        <artifactId>cxf-buildtools</artifactId>
+                        <version>${cxf.build-utils.version}</version>
+                    </dependency>
+                </dependencies>
+                <executions>
+                    <execution>
+                        <goals>
+                            <goal>process</goal>
+                        </goals>
+                        <configuration>
+                            <resourceBundles>
+                                <resourceBundle>org.apache:apache-jar-resource-bundle:1.4</resourceBundle>
+                            </resourceBundles>
+                            <supplementalModels>
+                                <supplementalModel>notice-supplements.xml</supplementalModel>
+                            </supplementalModels>
+                            <properties>
+                                <projectName>Apache CXF Distributed OSGi
+                                    DSW Reference Implementation</projectName>
+                            </properties>
+                        </configuration>
+                    </execution>
+                </executions>
+            </plugin>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-checkstyle-plugin</artifactId>
+                <version>2.9.1</version>
+                <dependencies>
+                    <dependency>
+                        <groupId>org.apache.cxf.build-utils</groupId>
+                        <artifactId>cxf-buildtools</artifactId>
+                        <version>${cxf.build-utils.version}</version>
+                    </dependency>
+                </dependencies>
+                <configuration>
+                    <encoding>UTF-8</encoding>
+                </configuration>
+                <executions>
+                    <execution>
+                        <id>validate</id>
+                        <phase>validate</phase>
+                        <configuration>
+                            <configLocation>${cxf.resources.base.path}cxf-checkstyle${cxf.checkstyle.extension}.xml</configLocation>
+                            <consoleOutput>true</consoleOutput>
+                            <failsOnError>true</failsOnError>
+                            <linkXRef>false</linkXRef>
+                            <suppressionsLocation>${cxf.resources.base.path}cxf-checkstyle-suppressions.xml</suppressionsLocation>
+                            <sourceDirectory>${basedir}/src</sourceDirectory>
+                            <excludes>**/archetype-resources/**/*.java</excludes>
+                        </configuration>
+                        <goals>
+                            <goal>checkstyle</goal>
+                        </goals>
+                    </execution>
+                </executions>
+            </plugin>
+        </plugins>
+    </build>
+
+    <repositories>
+        <repository>
+            <id>apache.snapshots</id>
+            <name>Apache Maven Snapshot Repository</name>
+            <url>http://repository.apache.org/content/groups/snapshots/</url>
+            <releases>
+                <enabled>false</enabled>
+            </releases>
+            <snapshots>
+                <enabled>true</enabled>
+            </snapshots>
+        </repository>
+
+    </repositories>
+
+    <pluginRepositories>
+        <pluginRepository>
+            <id>apache.snapshots</id>
+            <name>Apache Maven Snapshot Repository</name>
+            <url>http://repository.apache.org/content/groups/snapshots/</url>
+            <layout>default</layout>
+            <snapshots>
+                <enabled>true</enabled>
+            </snapshots>
+            <releases>
+                <enabled>false</enabled>
+            </releases>
+        </pluginRepository>
+    </pluginRepositories>
+
+</project>
diff --git a/trunk/pom.xml b/trunk/pom.xml
new file mode 100644
index 0000000..5a55293
--- /dev/null
+++ b/trunk/pom.xml
@@ -0,0 +1,179 @@
+<?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>
+    <groupId>org.apache.cxf.dosgi</groupId>
+    <artifactId>cxf-dosgi-ri</artifactId>
+    <version>1.6.0</version>
+
+    <packaging>pom</packaging>
+    <name>Distributed OSGI Reference Implementation</name>
+ 
+    <scm>
+        <connection>scm:svn:http://svn.apache.org/repos/asf/cxf/dosgi/tags/cxf-dosgi-ri-1.6.0</connection>
+        <developerConnection>scm:svn:https://svn.apache.org/repos/asf/cxf/dosgi/tags/cxf-dosgi-ri-1.6.0</developerConnection>
+    </scm>
+
+    <issueManagement>
+        <system>jira</system>
+        <url>https://issues.apache.org/jira/browse/DOSGI</url>
+    </issueManagement>
+
+    <prerequisites>
+        <maven>3.0</maven>
+    </prerequisites>
+
+    <distributionManagement>
+        <repository>
+            <id>apache.releases.https</id>
+            <name>Apache Release Distribution Repository</name>
+            <url>https://repository.apache.org/service/local/staging/deploy/maven2</url>
+        </repository>
+        <snapshotRepository>
+            <id>apache.snapshots.https</id>
+            <name>Apache Development Snapshot Repository</name>
+            <url>https://repository.apache.org/content/repositories/snapshots</url>
+            <uniqueVersion>false</uniqueVersion>
+        </snapshotRepository>
+    </distributionManagement>
+
+    <inceptionYear>2008</inceptionYear>
+    <mailingLists>
+        <mailingList>
+            <name>Apache CXF User List</name>
+            <subscribe>users-subscribe@cxf.apache.org</subscribe>
+            <unsubscribe>users-unsubscribe@cxf.apache.org</unsubscribe>
+            <post>users@cxf.apache.org</post>
+            <archive>http://mail-archives.apache.org/mod_mbox/cxf-users</archive>
+        </mailingList>
+        <mailingList>
+            <name>Apache CXF Developer List</name>
+            <subscribe>dev-subscribe@cxf.apache.org</subscribe>
+            <unsubscribe>dev-unsubscribe@cxf.apache.org</unsubscribe>
+            <post>dev@cxf.apache.org</post>
+            <archive>http://mail-archives.apache.org/mod_mbox/cxf-dev</archive>
+        </mailingList>
+        <mailingList>
+            <name>Apache CXF Commits List</name>
+            <subscribe>commits-subscribe@cxf.apache.org</subscribe>
+            <unsubscribe>commits-unsubscribe@cxf.apache.org</unsubscribe>
+            <post>commits@cxf.apache.org</post>
+            <archive>http://mail-archives.apache.org/mod_mbox/cxf-commits</archive>
+        </mailingList>
+        <mailingList>
+            <name>Apache CXF Issues List</name>
+            <subscribe>issues-subscribe@cxf.apache.org</subscribe>
+            <unsubscribe>issues-unsubscribe@cxf.apache.org</unsubscribe>
+            <post>issues@cxf.apache.org</post>
+            <archive>http://mail-archives.apache.org/mod_mbox/cxf-issues</archive>
+        </mailingList>
+    </mailingLists>
+
+    <licenses>
+        <license>
+            <name>The Apache Software License, Version 2.0</name>
+            <url>http://www.apache.org/licenses/LICENSE-2.0.txt</url>
+            <distribution>repo</distribution>
+        </license>
+    </licenses>
+
+    <organization>
+        <name>The Apache Software Foundation</name>
+        <url>http://www.apache.org/</url>
+    </organization>
+
+    <modules>
+        <module>parent</module>
+        <module>felix</module>
+        <module>dsw</module>
+        <module>discovery</module>
+        <module>samples</module>
+        <module>osgi-api</module>
+        <module>distribution</module>
+        <module>systests2</module>
+    </modules>
+
+    <profiles>
+        <profile>
+            <id>release</id>
+            <build>
+                <plugins>
+                    <!-- We want to deploy the artifact to a staging location for perusal -->
+                    <plugin>
+                        <inherited>true</inherited>
+                        <artifactId>maven-deploy-plugin</artifactId>
+                        <version>2.6</version>
+                        <configuration>
+                            <altDeploymentRepository>${deploy.altRepository}</altDeploymentRepository>
+                            <updateReleaseInfo>true</updateReleaseInfo>
+                        </configuration>
+                    </plugin>
+                    <!-- We want to sign the artifact, the POM, and all attached artifacts -->
+                    <plugin>
+                        <artifactId>maven-gpg-plugin</artifactId>
+                        <version>1.3</version>
+                        <executions>
+                            <execution>
+                                <goals>
+                                    <goal>sign</goal>
+                                </goals>
+                            </execution>
+                        </executions>
+                    </plugin>
+                </plugins>
+            </build>
+        </profile>
+    </profiles>
+
+    <build>
+        <defaultGoal>install</defaultGoal>
+
+        <pluginManagement>
+            <plugins>
+                <plugin>
+                    <groupId>org.apache.maven.plugins</groupId>
+                    <artifactId>maven-release-plugin</artifactId>
+                    <configuration>
+                        <tagBase>https://svn.apache.org/repos/asf/cxf/dosgi/tags</tagBase>
+                        <useReleaseProfile>false</useReleaseProfile>
+                        <preparationGoals>clean install</preparationGoals>
+                        <goals>deploy</goals>
+                        <arguments>-Prelease,deploy</arguments>
+                        <autoVersionSubmodules>true</autoVersionSubmodules>
+                        <mavenExecutorId>forked-path</mavenExecutorId>
+                    </configuration>
+                </plugin>
+            </plugins>
+        </pluginManagement>
+    </build>
+
+    <reporting>
+        <plugins>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-surefire-report-plugin</artifactId>
+                <version>2.15</version>
+                <configuration>
+                    <aggregate>true</aggregate>
+                </configuration>
+            </plugin>
+        </plugins>
+    </reporting>
+</project>
diff --git a/trunk/samples/discovery/client/pom.xml b/trunk/samples/discovery/client/pom.xml
new file mode 100644
index 0000000..3d2f96e
--- /dev/null
+++ b/trunk/samples/discovery/client/pom.xml
@@ -0,0 +1,66 @@
+<?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>
+    <groupId>org.apache.cxf.dosgi.samples</groupId>
+    <artifactId>cxf-dosgi-ri-samples-discovery-client</artifactId>
+    <packaging>bundle</packaging>
+    <name>Distributed OSGI Discovery Sample Client Bundle</name>
+    <version>1.6.0</version>
+
+    <parent>
+        <groupId>org.apache.cxf.dosgi.samples</groupId>
+        <artifactId>cxf-dosgi-ri-samples-discovery-parent</artifactId>
+        <version>1.6.0</version>
+    </parent>
+
+    <dependencies>
+        <dependency>
+            <groupId>org.osgi</groupId>
+            <artifactId>org.osgi.core</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.osgi</groupId>
+            <artifactId>org.osgi.compendium</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.cxf.dosgi.samples</groupId>
+            <artifactId>cxf-dosgi-ri-samples-discovery-interface</artifactId>
+            <version>${project.version}</version>
+        </dependency>
+    </dependencies>
+
+    <build>
+        <plugins>
+            <plugin>
+                <groupId>org.apache.felix</groupId>
+                <artifactId>maven-bundle-plugin</artifactId>
+                <configuration>
+                    <instructions>
+                        <Bundle-Name>${project.name}</Bundle-Name>
+                        <Bundle-Description>The client-side
+                            implementation of the Distributed OSGi
+                            Discovery sample</Bundle-Description>
+                        <Bundle-SymbolicName>${project.artifactId}</Bundle-SymbolicName>
+                        <Bundle-Activator>org.apache.cxf.dosgi.samples.discovery.consumer.Activator</Bundle-Activator>
+                        <Import-Package>
+                            org.apache.cxf.dosgi.samples.discovery,
+                            org.osgi.framework,
+                            org.osgi.util.tracker
+                        </Import-Package>
+                        <Private-Package>org.apache.cxf.dosgi.samples.discovery.consumer</Private-Package>
+                    </instructions>
+                </configuration>
+            </plugin>
+        </plugins>
+    </build>
+</project>
diff --git a/trunk/samples/discovery/client/src/main/java/org/apache/cxf/dosgi/samples/discovery/consumer/Activator.java b/trunk/samples/discovery/client/src/main/java/org/apache/cxf/dosgi/samples/discovery/consumer/Activator.java
new file mode 100644
index 0000000..2221116
--- /dev/null
+++ b/trunk/samples/discovery/client/src/main/java/org/apache/cxf/dosgi/samples/discovery/consumer/Activator.java
@@ -0,0 +1,86 @@
+/**
+ * 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.samples.discovery.consumer;
+
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.Executors;
+import java.util.concurrent.ScheduledExecutorService;
+import java.util.concurrent.ScheduledFuture;
+import java.util.concurrent.TimeUnit;
+
+import org.apache.cxf.dosgi.samples.discovery.DisplayService;
+import org.osgi.framework.BundleActivator;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.ServiceReference;
+import org.osgi.util.tracker.ServiceTracker;
+
+public class Activator implements BundleActivator {
+
+    private ServiceTracker tracker;
+    private Map<DisplayService, String> displays = new ConcurrentHashMap<DisplayService, String>();
+    private ScheduledExecutorService scheduler;
+    private ScheduledFuture<?> handle;
+
+    public void start(BundleContext bc) throws Exception {
+        tracker = new ServiceTracker(bc, DisplayService.class.getName(), null) {
+
+            public Object addingService(ServiceReference reference) {
+                Object svc = super.addingService(reference);
+                if (svc instanceof DisplayService) {
+                    DisplayService d = (DisplayService) svc;
+                    System.out.println("Adding display: " + d.getID() + " (" + d + ")");
+                    displays.put(d, d.getID());
+                }
+                return svc;
+            }
+
+            public void removedService(ServiceReference reference, Object service) {
+                String value = displays.remove(service);
+                System.out.println("Removed display: " + value);
+                super.removedService(reference, service);
+            }
+        };
+        tracker.open();
+
+        scheduler = Executors.newScheduledThreadPool(1);
+        Runnable printer = new Runnable() {
+            int counter;
+            public void run() {
+                counter++;
+                String text = "some text " + counter;
+                System.out.println("Sending text to displays: " + text);
+                for (Entry<DisplayService, String> entry : displays.entrySet()) {
+                    try {
+                        entry.getKey().displayText(text);
+                    } catch (Throwable th) {
+                        System.out.println("Could not send message to display: " + entry.getValue());
+                    }
+                }
+            }
+        };
+        handle = scheduler.scheduleAtFixedRate(printer, 5, 5, TimeUnit.SECONDS);
+    }
+
+    public void stop(BundleContext bc) throws Exception {
+        handle.cancel(true);
+        tracker.close();
+    }
+}
diff --git a/trunk/samples/discovery/impl/pom.xml b/trunk/samples/discovery/impl/pom.xml
new file mode 100644
index 0000000..37e1fc8
--- /dev/null
+++ b/trunk/samples/discovery/impl/pom.xml
@@ -0,0 +1,61 @@
+<?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>
+    <groupId>org.apache.cxf.dosgi.samples</groupId>
+    <artifactId>cxf-dosgi-ri-samples-discovery-impl</artifactId>
+    <packaging>bundle</packaging>
+    <name>Distributed OSGI Discovery Sample Implementation Bundle</name>
+    <version>1.6.0</version>
+
+    <parent>
+        <groupId>org.apache.cxf.dosgi.samples</groupId>
+        <artifactId>cxf-dosgi-ri-samples-discovery-parent</artifactId>
+        <version>1.6.0</version>
+    </parent>
+
+    <dependencies>
+        <dependency>
+            <groupId>org.osgi</groupId>
+            <artifactId>org.osgi.core</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.cxf.dosgi.samples</groupId>
+            <artifactId>cxf-dosgi-ri-samples-discovery-interface</artifactId>
+            <version>${project.version}</version>
+        </dependency>
+    </dependencies>
+
+    <build>
+        <plugins>
+            <plugin>
+                <groupId>org.apache.felix</groupId>
+                <artifactId>maven-bundle-plugin</artifactId>
+                <configuration>
+                    <instructions>
+                        <Bundle-Name>${project.name}</Bundle-Name>
+                        <Bundle-Description>The server-side
+                            implementation of the Distributed OSGi
+                            Discovery sample</Bundle-Description>
+                        <Bundle-SymbolicName>${project.artifactId}</Bundle-SymbolicName>
+                        <Bundle-Activator>org.apache.cxf.dosgi.samples.discovery.impl.Activator</Bundle-Activator>
+                        <Import-Package>
+                            org.apache.cxf.dosgi.samples.discovery,
+                            org.osgi.framework
+                        </Import-Package>
+                        <Private-Package>org.apache.cxf.dosgi.samples.discovery.impl</Private-Package>
+                    </instructions>
+                </configuration>
+            </plugin>
+        </plugins>
+    </build>
+</project>
diff --git a/trunk/samples/discovery/impl/src/main/java/org/apache/cxf/dosgi/samples/discovery/impl/Activator.java b/trunk/samples/discovery/impl/src/main/java/org/apache/cxf/dosgi/samples/discovery/impl/Activator.java
new file mode 100644
index 0000000..f9c972a
--- /dev/null
+++ b/trunk/samples/discovery/impl/src/main/java/org/apache/cxf/dosgi/samples/discovery/impl/Activator.java
@@ -0,0 +1,71 @@
+/**
+ * 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.samples.discovery.impl;
+
+import java.io.IOException;
+import java.net.InetAddress;
+import java.net.ServerSocket;
+import java.net.UnknownHostException;
+import java.util.Dictionary;
+import java.util.Hashtable;
+
+import org.apache.cxf.dosgi.samples.discovery.DisplayService;
+import org.osgi.framework.BundleActivator;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.ServiceRegistration;
+
+public class Activator implements BundleActivator {
+
+    private ServiceRegistration reg;
+
+    public void start(BundleContext bc) throws Exception {
+        Dictionary<String, Object> props = new Hashtable<String, Object>();
+
+        String host = getHostName();
+        int port = getPort();
+
+        props.put("service.exported.interfaces", "*");
+        props.put("service.exported.configs", "org.apache.cxf.ws");
+        props.put("org.apache.cxf.ws.address", getAddress(host, port)); // old obsolete value
+        props.put("endpoint.id", getAddress(host, port));
+
+        reg = bc.registerService(DisplayService.class.getName(),
+                new DisplayServiceImpl(host + ":" + port), props);
+    }
+
+    private static String getAddress(String host, int port) {
+        return "http://" + host + ":" + port + "/display";
+    }
+
+    private static String getHostName() {
+        try {
+            return InetAddress.getLocalHost().getCanonicalHostName();
+        } catch (UnknownHostException e) {
+            return "localhost";
+        }
+    }
+
+    private static int getPort() throws IOException {
+        return new ServerSocket(0).getLocalPort();
+    }
+
+    public void stop(BundleContext bc) throws Exception {
+        reg.unregister();
+    }
+}
diff --git a/trunk/samples/discovery/impl/src/main/java/org/apache/cxf/dosgi/samples/discovery/impl/DisplayServiceImpl.java b/trunk/samples/discovery/impl/src/main/java/org/apache/cxf/dosgi/samples/discovery/impl/DisplayServiceImpl.java
new file mode 100644
index 0000000..bd84a62
--- /dev/null
+++ b/trunk/samples/discovery/impl/src/main/java/org/apache/cxf/dosgi/samples/discovery/impl/DisplayServiceImpl.java
@@ -0,0 +1,40 @@
+/**
+ * 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.samples.discovery.impl;
+
+import org.apache.cxf.dosgi.samples.discovery.DisplayService;
+
+public class DisplayServiceImpl implements DisplayService {
+
+    private final String id;
+
+    public DisplayServiceImpl(String id) {
+        this.id = id;
+        System.out.println("Created DisplayService [" + id + "]");
+    }
+
+    public boolean displayText(String text) {
+        System.out.println("DisplayService [" + id + "]: " + text);
+        return true;
+    }
+
+    public String getID() {
+        return id;
+    }
+}
diff --git a/trunk/samples/discovery/interface/pom.xml b/trunk/samples/discovery/interface/pom.xml
new file mode 100644
index 0000000..e89593f
--- /dev/null
+++ b/trunk/samples/discovery/interface/pom.xml
@@ -0,0 +1,52 @@
+<?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>
+  <groupId>org.apache.cxf.dosgi.samples</groupId>
+  <artifactId>cxf-dosgi-ri-samples-discovery-interface</artifactId>
+  <packaging>bundle</packaging>
+  <name>Distributed OSGI Discovery Sample Interface Bundle</name>
+  <version>1.6.0</version>
+
+  <parent>
+    <groupId>org.apache.cxf.dosgi.samples</groupId>
+    <artifactId>cxf-dosgi-ri-samples-discovery-parent</artifactId>
+    <version>1.6.0</version>
+  </parent>
+
+  <build>
+    <plugins>
+      <plugin>
+        <groupId>org.apache.felix</groupId>
+        <artifactId>maven-bundle-plugin</artifactId>
+        <configuration>
+          <instructions>
+            <Bundle-Name>${project.name}</Bundle-Name>
+            <Bundle-Description>The interfaces of the Distributed OSGi Discovery sample</Bundle-Description>
+            <Bundle-SymbolicName>${project.artifactId}</Bundle-SymbolicName>
+            <Import-Package />
+            <Export-Package>org.apache.cxf.dosgi.samples.discovery</Export-Package>
+          </instructions>
+        </configuration>
+      </plugin>
+    </plugins>
+  </build>
+</project>
diff --git a/trunk/samples/discovery/interface/src/main/java/org/apache/cxf/dosgi/samples/discovery/DisplayService.java b/trunk/samples/discovery/interface/src/main/java/org/apache/cxf/dosgi/samples/discovery/DisplayService.java
new file mode 100644
index 0000000..f05cef5
--- /dev/null
+++ b/trunk/samples/discovery/interface/src/main/java/org/apache/cxf/dosgi/samples/discovery/DisplayService.java
@@ -0,0 +1,24 @@
+/**
+ * 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.samples.discovery;
+
+public interface DisplayService {
+    boolean displayText(String text);
+    String getID();
+}
diff --git a/trunk/samples/discovery/pom.xml b/trunk/samples/discovery/pom.xml
new file mode 100644
index 0000000..da83970
--- /dev/null
+++ b/trunk/samples/discovery/pom.xml
@@ -0,0 +1,42 @@
+<?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>
+    <groupId>org.apache.cxf.dosgi.samples</groupId>
+    <artifactId>cxf-dosgi-ri-samples-discovery-parent</artifactId>
+    <packaging>pom</packaging>
+    <name>Distributed OSGI Discovery Sample</name>
+    <version>1.6.0</version>
+
+    <parent>
+      <groupId>org.apache.cxf.dosgi</groupId>
+      <artifactId>cxf-dosgi-ri-parent</artifactId>
+      <version>1.6.0</version>
+      <relativePath>../../parent/pom.xml</relativePath>
+    </parent>
+
+    <modules>
+      <module>interface</module>
+      <module>impl</module>
+      <module>client</module>
+    </modules>
+
+</project>
diff --git a/trunk/samples/ds/client/pom.xml b/trunk/samples/ds/client/pom.xml
new file mode 100644
index 0000000..89265e1
--- /dev/null
+++ b/trunk/samples/ds/client/pom.xml
@@ -0,0 +1,63 @@
+<?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>
+    <groupId>org.apache.cxf.dosgi.samples</groupId>
+    <artifactId>cxf-dosgi-ri-samples-ds-client</artifactId>
+    <packaging>bundle</packaging>
+    <name>Distributed OSGI Declarative Services Sample Client Bundle</name>
+    <version>1.6.0</version>
+
+    <parent>
+        <groupId>org.apache.cxf.dosgi.samples</groupId>
+        <artifactId>cxf-dosgi-ri-samples-ds-parent</artifactId>
+        <version>1.6.0</version>
+    </parent>
+
+    <dependencies>
+        <dependency>
+            <groupId>org.osgi</groupId>
+            <artifactId>org.osgi.core</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.osgi</groupId>
+            <artifactId>org.osgi.compendium</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.cxf.dosgi.samples</groupId>
+            <artifactId>cxf-dosgi-ri-samples-ds-interface</artifactId>
+            <version>${project.version}</version>
+        </dependency>
+    </dependencies>
+
+    <build>
+        <plugins>
+            <plugin>
+                <groupId>org.apache.felix</groupId>
+                <artifactId>maven-bundle-plugin</artifactId>
+                <configuration>
+                    <instructions>
+                        <Bundle-Name>${project.name}</Bundle-Name>
+                        <Bundle-Description>The client-side
+                            implementation of the Distributed OSGi with
+                            Declarative Services sample</Bundle-Description>
+                        <Bundle-SymbolicName>${project.artifactId}</Bundle-SymbolicName>
+                        <Bundle-Activator>org.apache.cxf.dosgi.samples.ds.consumer.Activator</Bundle-Activator>
+                        <Import-Package>*</Import-Package>
+                        <Private-Package>org.apache.cxf.dosgi.samples.ds.consumer</Private-Package>
+                        <Service-Component>OSGI-INF/component.xml</Service-Component>
+                    </instructions>
+                </configuration>
+            </plugin>
+        </plugins>
+    </build>
+</project>
diff --git a/trunk/samples/ds/client/src/main/java/org/apache/cxf/dosgi/samples/ds/consumer/Activator.java b/trunk/samples/ds/client/src/main/java/org/apache/cxf/dosgi/samples/ds/consumer/Activator.java
new file mode 100644
index 0000000..304493d
--- /dev/null
+++ b/trunk/samples/ds/client/src/main/java/org/apache/cxf/dosgi/samples/ds/consumer/Activator.java
@@ -0,0 +1,45 @@
+/**

+ * 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.samples.ds.consumer;

+

+import org.apache.cxf.dosgi.samples.ds.AdderService;

+import org.osgi.framework.BundleActivator;

+import org.osgi.framework.BundleContext;

+import org.osgi.util.tracker.ServiceTracker;

+

+/**

+ * This Activator simply registers a service tracker to indicate its interest in the

+ * AdderService which causes the service to get registered by the Listener Hook.

+ * It is a workaround for the problem that the current ListenerHook is incompatible

+ * with the Equinox DS implementation which doesn't specify a filter when looking up

+ * a service. See also DOSGI-73.

+ */

+public class Activator implements BundleActivator {

+

+    private ServiceTracker tracker;

+

+    public void start(BundleContext context) throws Exception {

+        tracker = new ServiceTracker(context, AdderService.class.getName(), null);

+        tracker.open();

+    }

+

+    public void stop(BundleContext context) throws Exception {

+        tracker.close();

+    }

+}

diff --git a/trunk/samples/ds/client/src/main/java/org/apache/cxf/dosgi/samples/ds/consumer/AdderConsumer.java b/trunk/samples/ds/client/src/main/java/org/apache/cxf/dosgi/samples/ds/consumer/AdderConsumer.java
new file mode 100644
index 0000000..060ed42
--- /dev/null
+++ b/trunk/samples/ds/client/src/main/java/org/apache/cxf/dosgi/samples/ds/consumer/AdderConsumer.java
@@ -0,0 +1,39 @@
+/**
+ * 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.samples.ds.consumer;
+
+import org.apache.cxf.dosgi.samples.ds.AdderService;
+
+public class AdderConsumer {
+
+    private AdderService adder;
+
+    public void bindAdder(AdderService a) {
+        adder = a;
+    }
+
+    public void unbindAdder(AdderService a) {
+        adder = null;
+    }
+
+    public void start() {
+        System.out.println("Declarative Service consumer component.");
+        System.out.println("Using adder service: 1 + 1 = " + adder.add(1, 1));
+    }
+}
diff --git a/trunk/samples/ds/client/src/main/resources/OSGI-INF/component.xml b/trunk/samples/ds/client/src/main/resources/OSGI-INF/component.xml
new file mode 100644
index 0000000..31b91f7
--- /dev/null
+++ b/trunk/samples/ds/client/src/main/resources/OSGI-INF/component.xml
@@ -0,0 +1,20 @@
+<?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.
+  -->
+<scr:component xmlns:scr="http://www.osgi.org/xmlns/scr/v1.1.0" name="DS Consumer Sample" activate="start">
+   <implementation class="org.apache.cxf.dosgi.samples.ds.consumer.AdderConsumer"/>
+   <reference interface="org.apache.cxf.dosgi.samples.ds.AdderService" name="AdderService" cardinality="1..1" policy="dynamic" bind="bindAdder" unbind="unbindAdder"/>
+</scr:component>
+
diff --git a/trunk/samples/ds/client/src/main/resources/OSGI-INF/remote-service/remote-services.xml b/trunk/samples/ds/client/src/main/resources/OSGI-INF/remote-service/remote-services.xml
new file mode 100644
index 0000000..e1f0b21
--- /dev/null
+++ b/trunk/samples/ds/client/src/main/resources/OSGI-INF/remote-service/remote-services.xml
@@ -0,0 +1,26 @@
+<?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.
+  -->
+<endpoint-descriptions xmlns="http://www.osgi.org/xmlns/rsa/v1.0.0">
+  <endpoint-description>
+    <property name="objectClass">
+      <array>
+        <value>org.apache.cxf.dosgi.samples.ds.AdderService</value>
+      </array>
+    </property>
+    <property name="endpoint.id">http://localhost:9090/adder</property>
+    <property name="service.imported.configs">org.apache.cxf.ws</property>
+  </endpoint-description>
+</endpoint-descriptions>
diff --git a/trunk/samples/ds/impl/pom.xml b/trunk/samples/ds/impl/pom.xml
new file mode 100644
index 0000000..26f2c6e
--- /dev/null
+++ b/trunk/samples/ds/impl/pom.xml
@@ -0,0 +1,60 @@
+<?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>
+  <groupId>org.apache.cxf.dosgi.samples</groupId>
+  <artifactId>cxf-dosgi-ri-samples-ds-impl</artifactId>
+  <packaging>bundle</packaging>
+  <name>Distributed OSGI Declarative Services Sample Implementation Bundle</name>
+  <version>1.6.0</version>
+
+  <parent>
+    <groupId>org.apache.cxf.dosgi.samples</groupId>
+    <artifactId>cxf-dosgi-ri-samples-ds-parent</artifactId>
+    <version>1.6.0</version>
+  </parent>
+
+  <dependencies>
+    <dependency>
+      <groupId>org.apache.cxf.dosgi.samples</groupId>
+      <artifactId>cxf-dosgi-ri-samples-ds-interface</artifactId>
+      <version>${project.version}</version>
+    </dependency>
+  </dependencies>
+
+  <build>
+    <plugins>
+      <plugin>
+        <groupId>org.apache.felix</groupId>
+        <artifactId>maven-bundle-plugin</artifactId>
+        <configuration>
+          <instructions>
+            <Bundle-Name>${project.name}</Bundle-Name>
+            <Bundle-Description>The server-side implementation of the Distributed OSGi with Declarative Services sample</Bundle-Description>
+            <Bundle-SymbolicName>${project.artifactId}</Bundle-SymbolicName>
+            <Import-Package>org.apache.cxf.dosgi.samples.ds</Import-Package>
+            <Private-Package>org.apache.cxf.dosgi.samples.ds.impl</Private-Package>
+            <Service-Component>OSGI-INF/component.xml</Service-Component>
+          </instructions>
+        </configuration>
+      </plugin>
+    </plugins>
+  </build>
+</project>
diff --git a/trunk/samples/ds/impl/src/main/java/org/apache/cxf/dosgi/samples/ds/impl/AdderServiceImpl.java b/trunk/samples/ds/impl/src/main/java/org/apache/cxf/dosgi/samples/ds/impl/AdderServiceImpl.java
new file mode 100644
index 0000000..0d1fcba
--- /dev/null
+++ b/trunk/samples/ds/impl/src/main/java/org/apache/cxf/dosgi/samples/ds/impl/AdderServiceImpl.java
@@ -0,0 +1,30 @@
+/**
+ * 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.samples.ds.impl;
+
+import org.apache.cxf.dosgi.samples.ds.AdderService;
+
+public class AdderServiceImpl implements AdderService {
+
+    public int add(int a, int b) {
+        int result = a + b;
+        System.out.println("Adder service invoked: " + a + " + " + b + " = " + result);
+        return result;
+    }
+}
diff --git a/trunk/samples/ds/impl/src/main/resources/OSGI-INF/component.xml b/trunk/samples/ds/impl/src/main/resources/OSGI-INF/component.xml
new file mode 100644
index 0000000..3687b78
--- /dev/null
+++ b/trunk/samples/ds/impl/src/main/resources/OSGI-INF/component.xml
@@ -0,0 +1,26 @@
+<?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.
+  -->
+<scr:component xmlns:scr="http://www.osgi.org/xmlns/scr/v1.1.0" name="DS Service Sample">
+  <implementation class="org.apache.cxf.dosgi.samples.ds.impl.AdderServiceImpl"/>
+
+  <property name="service.exported.interfaces" value="*" />
+  <property name="service.exported.configs" value="org.apache.cxf.ws" />
+  <property name="org.apache.cxf.ws.address" value="http://localhost:9090/adder" />
+
+  <service>
+    <provide interface="org.apache.cxf.dosgi.samples.ds.AdderService"/>
+  </service>
+</scr:component>
diff --git a/trunk/samples/ds/interface/pom.xml b/trunk/samples/ds/interface/pom.xml
new file mode 100644
index 0000000..c6f45d3
--- /dev/null
+++ b/trunk/samples/ds/interface/pom.xml
@@ -0,0 +1,52 @@
+<?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>
+  <groupId>org.apache.cxf.dosgi.samples</groupId>
+  <artifactId>cxf-dosgi-ri-samples-ds-interface</artifactId>
+  <packaging>bundle</packaging>
+  <name>Distributed OSGI Declarative Services Sample Interface Bundle</name>
+  <version>1.6.0</version>
+
+  <parent>
+    <groupId>org.apache.cxf.dosgi.samples</groupId>
+    <artifactId>cxf-dosgi-ri-samples-ds-parent</artifactId>
+    <version>1.6.0</version>
+  </parent>
+
+  <build>
+    <plugins>
+      <plugin>
+        <groupId>org.apache.felix</groupId>
+        <artifactId>maven-bundle-plugin</artifactId>
+        <configuration>
+          <instructions>
+            <Bundle-Name>${project.name}</Bundle-Name>
+            <Bundle-Description>The interfaces of the Distributed OSGi with Declarative Services sample</Bundle-Description>
+            <Bundle-SymbolicName>${project.artifactId}</Bundle-SymbolicName>
+            <Import-Package />
+            <Export-Package>org.apache.cxf.dosgi.samples.ds</Export-Package>
+          </instructions>
+        </configuration>
+      </plugin>
+    </plugins>
+  </build>
+</project>
diff --git a/trunk/samples/ds/interface/src/main/java/org/apache/cxf/dosgi/samples/ds/AdderService.java b/trunk/samples/ds/interface/src/main/java/org/apache/cxf/dosgi/samples/ds/AdderService.java
new file mode 100644
index 0000000..f5e77fc
--- /dev/null
+++ b/trunk/samples/ds/interface/src/main/java/org/apache/cxf/dosgi/samples/ds/AdderService.java
@@ -0,0 +1,23 @@
+/**
+ * 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.samples.ds;
+
+public interface AdderService {
+    int add(int a, int b);
+}
diff --git a/trunk/samples/ds/pom.xml b/trunk/samples/ds/pom.xml
new file mode 100644
index 0000000..e1ee1a3
--- /dev/null
+++ b/trunk/samples/ds/pom.xml
@@ -0,0 +1,41 @@
+<?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>
+    <groupId>org.apache.cxf.dosgi.samples</groupId>
+    <artifactId>cxf-dosgi-ri-samples-ds-parent</artifactId>
+    <packaging>pom</packaging>
+    <name>Distributed OSGI Declarative Services Sample</name>
+    <version>1.6.0</version>
+
+    <parent>
+      <groupId>org.apache.cxf.dosgi</groupId>
+      <artifactId>cxf-dosgi-ri-parent</artifactId>
+      <version>1.6.0</version>
+      <relativePath>../../parent/pom.xml</relativePath>
+    </parent>
+
+    <modules>
+      <module>interface</module>
+      <module>impl</module>
+      <module>client</module>
+    </modules>
+
+</project>
diff --git a/trunk/samples/greeter/client/pom.xml b/trunk/samples/greeter/client/pom.xml
new file mode 100644
index 0000000..83a8bd2
--- /dev/null
+++ b/trunk/samples/greeter/client/pom.xml
@@ -0,0 +1,77 @@
+<?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>
+    <groupId>org.apache.cxf.dosgi.samples</groupId>
+    <artifactId>cxf-dosgi-ri-samples-greeter-client</artifactId>
+    <packaging>bundle</packaging>
+    <name>Distributed OSGI Greeter Bundle Client</name>
+    <version>1.6.0</version>
+
+    <parent>
+      <groupId>org.apache.cxf.dosgi</groupId>
+      <artifactId>cxf-dosgi-ri-parent</artifactId>
+      <version>1.6.0</version>
+      <relativePath>../../../parent/pom.xml</relativePath>
+    </parent>
+
+    <properties>
+        <bundle.import.package>*</bundle.import.package>
+        <bundle.private.package>org.apache.cxf.dosgi.samples.greeter.client</bundle.private.package>
+    </properties>
+
+    <dependencies>
+        <dependency>
+            <groupId>org.apache.cxf.dosgi.samples</groupId>
+            <artifactId>cxf-dosgi-ri-samples-greeter-interface</artifactId>
+            <version>${project.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>org.osgi</groupId>
+            <artifactId>org.osgi.core</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.osgi</groupId>
+            <artifactId>org.osgi.compendium</artifactId>
+        </dependency>
+    </dependencies>
+
+    <build>
+      <plugins>
+        <plugin>
+                <groupId>org.apache.felix</groupId>
+                <artifactId>maven-bundle-plugin</artifactId>
+                <configuration>
+                    <instructions>
+                        <Bundle-Name>CXF Distributed OSGi Greeter Demo Client Bundle</Bundle-Name>
+                        <Bundle-Description>The client-side implementation of the Distributed OSGi Greeter demo</Bundle-Description>
+                        <Bundle-SymbolicName>${project.artifactId}</Bundle-SymbolicName>
+                        <Bundle-Activator>org.apache.cxf.dosgi.samples.greeter.client.Activator</Bundle-Activator>
+                        <Import-Package>${bundle.import.package}</Import-Package>
+                        <Private-Package>${bundle.private.package}</Private-Package>
+                        <DynamicImport-Package>org.apache.cxf.dosgi.dsw.qos,org.apache.cxf</DynamicImport-Package>
+                    </instructions>
+                </configuration>
+            </plugin>
+         </plugins>
+    </build>
+
+</project>
diff --git a/trunk/samples/greeter/client/src/main/java/org/apache/cxf/dosgi/samples/greeter/client/Activator.java b/trunk/samples/greeter/client/src/main/java/org/apache/cxf/dosgi/samples/greeter/client/Activator.java
new file mode 100644
index 0000000..6f46760
--- /dev/null
+++ b/trunk/samples/greeter/client/src/main/java/org/apache/cxf/dosgi/samples/greeter/client/Activator.java
@@ -0,0 +1,96 @@
+/**
+ * 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.samples.greeter.client;
+
+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;
+import org.osgi.framework.BundleActivator;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.ServiceReference;
+import org.osgi.util.tracker.ServiceTracker;
+
+public class Activator implements BundleActivator {
+
+    private ServiceTracker tracker;
+
+    public void start(final BundleContext bc) {
+        tracker = new ServiceTracker(bc, GreeterService.class.getName(), null) {
+            @Override
+            public Object addingService(ServiceReference reference) {
+                Object service = super.addingService(reference);
+                if (service instanceof GreeterService) {
+                    useService((GreeterService) service);
+                }
+                return service;
+            }
+        };
+        tracker.open();
+    }
+
+    protected void useService(final GreeterService greeter) {
+        Thread t = new Thread(new Runnable() {
+            public void run() {
+                greeterUI(greeter);
+            }
+        });
+        t.start();
+    }
+
+    private void greeterUI(final GreeterService greeter) {
+        while (true) {
+            System.out.println("*** Opening greeter client dialog ***");
+            Object gd = getGreeterData();
+            if (gd instanceof String) {
+                System.out.println("*** Invoking greeter ***");
+                Map<GreetingPhrase, String> result = greeter.greetMe((String) gd);
+
+                System.out.println("greetMe(\"" + gd + "\") returns:");
+                for (Map.Entry<GreetingPhrase, String> greeting : result.entrySet()) {
+                    System.out.println("  " + greeting.getKey().getPhrase()
+                            + " " + greeting.getValue());
+                }
+            } else if (gd instanceof GreeterData) {
+                System.out.println("*** Invoking greeter ***");
+                try {
+                    GreetingPhrase[] result = greeter.greetMe((GreeterData) gd);
+                    System.out.println("greetMe(\"" + gd + "\") returns:");
+                    for (GreetingPhrase phrase : result) {
+                        System.out.println("  " + phrase.getPhrase());
+                    }
+                } catch (GreeterException ex) {
+                    System.out.println("GreeterException: " + ex.toString());
+                }
+            }
+        }
+    }
+
+    private static Object getGreeterData() {
+        GreeterDialog gd = new GreeterDialog();
+        gd.setVisible(true);
+        return gd.getSelection();
+    }
+
+    public void stop(BundleContext bc) throws Exception {
+        tracker.close();
+    }
+}
diff --git a/trunk/samples/greeter/client/src/main/java/org/apache/cxf/dosgi/samples/greeter/client/GreeterDataImpl.java b/trunk/samples/greeter/client/src/main/java/org/apache/cxf/dosgi/samples/greeter/client/GreeterDataImpl.java
new file mode 100644
index 0000000..368be36
--- /dev/null
+++ b/trunk/samples/greeter/client/src/main/java/org/apache/cxf/dosgi/samples/greeter/client/GreeterDataImpl.java
@@ -0,0 +1,46 @@
+/**
+ * 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.samples.greeter.client;
+
+import org.apache.cxf.dosgi.samples.greeter.GreeterData;
+
+public class GreeterDataImpl implements GreeterData {
+
+    private final String name;
+    private final int age;
+    private final boolean exception;
+
+    public GreeterDataImpl(String n, int a, boolean b) {
+        name = n;
+        age = a;
+        exception = b;
+    }
+
+    public String getName() {
+        return name;
+    }
+
+    public int getAge() {
+        return age;
+    }
+
+    public boolean isException() {
+        return exception;
+    }
+}
diff --git a/trunk/samples/greeter/client/src/main/java/org/apache/cxf/dosgi/samples/greeter/client/GreeterDialog.java b/trunk/samples/greeter/client/src/main/java/org/apache/cxf/dosgi/samples/greeter/client/GreeterDialog.java
new file mode 100644
index 0000000..3983a82
--- /dev/null
+++ b/trunk/samples/greeter/client/src/main/java/org/apache/cxf/dosgi/samples/greeter/client/GreeterDialog.java
@@ -0,0 +1,204 @@
+/**
+ * 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.samples.greeter.client;
+
+import java.awt.Component;
+import java.awt.FlowLayout;
+import java.awt.Frame;
+import java.awt.GridBagConstraints;
+import java.awt.GridBagLayout;
+import java.awt.Insets;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+
+import javax.swing.BoxLayout;
+import javax.swing.ButtonGroup;
+import javax.swing.JButton;
+import javax.swing.JCheckBox;
+import javax.swing.JDialog;
+import javax.swing.JLabel;
+import javax.swing.JPanel;
+import javax.swing.JRadioButton;
+import javax.swing.JTextField;
+import javax.swing.event.ChangeEvent;
+import javax.swing.event.ChangeListener;
+
+public class GreeterDialog extends JDialog {
+
+    private static final long serialVersionUID = 1L;
+
+    JTextField name1field;
+    JTextField name2field;
+    JTextField ageTextField;
+    JCheckBox throwExCB;
+    Object selection;
+
+    public GreeterDialog() {
+        super((Frame) null, "Invoke Remote Greeter Service", true);
+
+        JPanel panel = new JPanel();
+        panel.setLayout(new BoxLayout(panel, BoxLayout.Y_AXIS));
+        setContentPane(panel);
+
+        final JRadioButton rb1 = new JRadioButton("invoke: Map<GreetingPhrase, String> greetMe(String name);");
+        rb1.setSelected(true);
+        rb1.setAlignmentX(Component.LEFT_ALIGNMENT);
+        panel.add(rb1);
+
+        final JPanel simplePanel = createFirstOptionPanel();
+        rb1.addChangeListener(new ChangeListener() {
+            public void stateChanged(ChangeEvent e) {
+                enablePanel(simplePanel, rb1.isSelected());
+            }
+        });
+        panel.add(simplePanel);
+        panel.add(new JLabel(" ")); // add a spacer
+
+        final JRadioButton rb2
+            = new JRadioButton("invoke: GreetingPhrase[] greetMe(GreeterData data) throws GreeterException;");
+        rb2.setAlignmentX(Component.LEFT_ALIGNMENT);
+        panel.add(rb2);
+
+        final JPanel complexPanel = createSecondOptionPanel();
+
+        rb2.addChangeListener(new ChangeListener() {
+            public void stateChanged(ChangeEvent e) {
+                enablePanel(complexPanel, rb2.isSelected());
+            }
+        });
+
+        panel.add(complexPanel);
+        enablePanel(complexPanel, false);
+
+        JPanel buttons = new JPanel(new FlowLayout(FlowLayout.CENTER));
+        buttons.setAlignmentX(Component.LEFT_ALIGNMENT);
+
+        JButton b1 = new JButton("Invoke");
+        buttons.add(b1);
+
+        b1.addActionListener(new ActionListener() {
+            public void actionPerformed(ActionEvent e) {
+                if (rb1.isSelected()) {
+                    selection = name1field.getText();
+                } else {
+                    selection = new GreeterDataImpl(name2field.getText(),
+                                                    new Integer(ageTextField.getText()),
+                                                    throwExCB.isSelected());
+                }
+
+                setVisible(false);
+            }
+        });
+
+        panel.add(buttons);
+
+        ButtonGroup bg = new ButtonGroup();
+        bg.add(rb1);
+        bg.add(rb2);
+
+        pack();
+        setLocationRelativeTo(null); // centers frame on screen
+    }
+
+    private JPanel createFirstOptionPanel() {
+        final JPanel simplePanel = new JPanel(new GridBagLayout());
+        simplePanel.setAlignmentX(Component.LEFT_ALIGNMENT);
+        GridBagConstraints c1 = new GridBagConstraints();
+
+        JLabel lb1 = new JLabel("Name: ");
+        c1.weightx = 0.0;
+        c1.gridx = 0;
+        c1.gridy = 0;
+        c1.insets = new Insets(0, 25, 0, 0);
+        c1.anchor = GridBagConstraints.LINE_START;
+        simplePanel.add(lb1, c1);
+
+        name1field = new JTextField(20);
+        c1.weightx = 0.2;
+        c1.gridx = 1;
+        c1.gridy = 0;
+        c1.insets = new Insets(0, 10, 0, 0);
+        c1.anchor = GridBagConstraints.LINE_START;
+        simplePanel.add(name1field, c1);
+        return simplePanel;
+    }
+    private JPanel createSecondOptionPanel() {
+        final JPanel complexPanel = new JPanel(new GridBagLayout());
+        complexPanel.setAlignmentX(Component.LEFT_ALIGNMENT);
+        GridBagConstraints c2 = new GridBagConstraints();
+
+        JLabel lb2 = new JLabel("Name: ");
+        c2.weightx = 0.0;
+        c2.gridx = 0;
+        c2.gridy = 0;
+        c2.insets = new Insets(0, 25, 0, 0);
+        c2.anchor = GridBagConstraints.LINE_START;
+        complexPanel.add(lb2, c2);
+
+        name2field = new JTextField(20);
+        c2.weightx = 0.2;
+        c2.gridx = 1;
+        c2.gridy = 0;
+        c2.insets = new Insets(0, 10, 0, 0);
+        c2.anchor = GridBagConstraints.LINE_START;
+        complexPanel.add(name2field, c2);
+
+        JLabel lb3 = new JLabel("Age: ");
+        c2.weightx = 0.0;
+        c2.gridx = 0;
+        c2.gridy = 1;
+        c2.insets = new Insets(0, 25, 0, 0);
+        c2.anchor = GridBagConstraints.LINE_START;
+        complexPanel.add(lb3, c2);
+
+        ageTextField = new JTextField(7);
+        c2.weightx = 0.2;
+        c2.gridx = 1;
+        c2.gridy = 1;
+        c2.insets = new Insets(0, 10, 0, 0);
+        c2.anchor = GridBagConstraints.LINE_START;
+        complexPanel.add(ageTextField, c2);
+
+        throwExCB = new JCheckBox("Throw Exception");
+        c2.weightx = 0.0;
+        c2.gridx = 0;
+        c2.gridy = 2;
+        c2.gridwidth = 2;
+        c2.insets = new Insets(0, 22, 0, 0);
+        c2.anchor = GridBagConstraints.LINE_START;
+        complexPanel.add(throwExCB, c2);
+        return complexPanel;
+    }
+
+    public Object getSelection() {
+        return selection;
+    }
+
+    private static void enablePanel(JPanel panel, boolean b) {
+        for (Component c : panel.getComponents()) {
+            c.setEnabled(b);
+        }
+    }
+
+    public static void main(String ... args) {
+        GreeterDialog gd = new GreeterDialog();
+        gd.setVisible(true);
+        System.exit(0);
+    }
+}
diff --git a/trunk/samples/greeter/client/src/main/resources/OSGI-INF/cxf/intents/intent-map.xml b/trunk/samples/greeter/client/src/main/resources/OSGI-INF/cxf/intents/intent-map.xml
new file mode 100644
index 0000000..026bf13
--- /dev/null
+++ b/trunk/samples/greeter/client/src/main/resources/OSGI-INF/cxf/intents/intent-map.xml
@@ -0,0 +1,75 @@
+<?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.
+-->
+
+<beans xmlns="http://www.springframework.org/schema/beans"
+       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+       xmlns:p="http://cxf.apache.org/policy"
+       xmlns:wsp="http://www.w3.org/ns/ws-policy"
+       xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd"
+       xmlns:http="http://cxf.apache.org/transports/http/configuration"
+       xmlns:wsrm-policy="http://schemas.xmlsoap.org/ws/2005/02/rm/policy"
+       xsi:schemaLocation="
+       http://cxf.apache.org/policy http://cxf.apache.org/schemas/policy.xsd
+       http://www.w3.org/ns/ws-policy http://www.w3.org/2007/02/ws-policy.xsd
+       http://cxf.apache.org/transports/http/configuration http://cxf.apache.org/schemas/configuration/http-conf.xsd
+       http://schemas.xmlsoap.org/ws/2005/02/rm/policy http://schemas.xmlsoap.org/ws/2005/02/rm/wsrm-policy.xsd
+       http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
+
+    <bean id="intentMap" class="org.apache.cxf.dosgi.dsw.qos.IntentMap">
+       <property name="intents">
+         <map>
+           <entry key="reliability" value-ref="reliableMessaging"/>
+           <entry key="decoupled" value-ref="decoupledAddressing"/>
+         </map>
+       </property>
+    </bean>
+
+    <p:policies id="reliableMessaging">
+        <wsp:PolicyReference URI="#ReliabilityPolicy"/>
+        <wsp:PolicyReference URI="#DecoupledPolicy"/>
+        <wsp:PolicyReference URI="#AddressingPolicy"/>
+    </p:policies>
+
+    <p:policies id="decoupledAddressing">
+        <wsp:PolicyReference URI="#DecoupledPolicy"/>
+        <wsp:PolicyReference URI="#AddressingPolicy"/>
+    </p:policies>
+
+    <wsp:Policy wsu:Id="ReliabilityPolicy">
+        <wsrm-policy:RMAssertion>
+            <wsrm-policy:BaseRetransmissionInterval Milliseconds="4000"/>
+            <wsrm-policy:AcknowledgementInterval Milliseconds="2000" />
+        </wsrm-policy:RMAssertion>
+    </wsp:Policy>
+
+    <wsp:Policy wsu:Id="DecoupledPolicy">
+        <wsp:ExactlyOne>
+            <http:client DecoupledEndpoint="http://localhost:9970/decoupled_endpoint"/>
+        </wsp:ExactlyOne>
+    </wsp:Policy>
+
+    <wsp:Policy wsu:Id="AddressingPolicy"
+        xmlns:wsam="http://www.w3.org/2007/02/addressing/metadata">
+        <wsam:Addressing>
+            <wsp:Policy />
+        </wsam:Addressing>
+    </wsp:Policy>
+
+</beans>
diff --git a/trunk/samples/greeter/client/src/main/resources/OSGI-INF/remote-service/remote-services.xml b/trunk/samples/greeter/client/src/main/resources/OSGI-INF/remote-service/remote-services.xml
new file mode 100644
index 0000000..af3486e
--- /dev/null
+++ b/trunk/samples/greeter/client/src/main/resources/OSGI-INF/remote-service/remote-services.xml
@@ -0,0 +1,27 @@
+<?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.
+  -->
+<endpoint-descriptions xmlns="http://www.osgi.org/xmlns/rsa/v1.0.0">
+  <endpoint-description>
+    <property name="objectClass">
+      <array>
+        <value>org.apache.cxf.dosgi.samples.greeter.GreeterService</value>
+      </array>
+    </property>
+    <property name="endpoint.id">http://localhost:9090/greeter</property>
+    <property name="service.imported.configs">org.apache.cxf.ws</property>
+  </endpoint-description>
+</endpoint-descriptions>
+
diff --git a/trunk/samples/greeter/impl/pom.xml b/trunk/samples/greeter/impl/pom.xml
new file mode 100644
index 0000000..83581e5
--- /dev/null
+++ b/trunk/samples/greeter/impl/pom.xml
@@ -0,0 +1,76 @@
+<?xml version='1.0' encoding='UTF-8' ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements. See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership. The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License. You may obtain a copy of the License at
+
+  http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied. See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+    <groupId>org.apache.cxf.dosgi.samples</groupId>
+    <artifactId>cxf-dosgi-ri-samples-greeter-impl</artifactId>
+    <packaging>bundle</packaging>
+    <name>Distributed OSGI Greeter Implementation Bundle</name>
+    <version>1.6.0</version>
+
+    <parent>
+      <groupId>org.apache.cxf.dosgi</groupId>
+      <artifactId>cxf-dosgi-ri-parent</artifactId>
+      <version>1.6.0</version>
+      <relativePath>../../../parent/pom.xml</relativePath>
+    </parent>
+
+    <properties>
+        <bundle.import.package>*</bundle.import.package>
+        <bundle.private.package>org.apache.cxf.dosgi.samples.greeter.impl</bundle.private.package>
+    </properties>
+
+    <dependencies>
+        <dependency>
+            <groupId>org.osgi</groupId>
+            <artifactId>org.osgi.core</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.osgi</groupId>
+            <artifactId>org.osgi.compendium</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.cxf.dosgi.samples</groupId>
+            <artifactId>cxf-dosgi-ri-samples-greeter-interface</artifactId>
+            <version>${project.version}</version>
+        </dependency>
+    </dependencies>
+
+    <build>
+      <plugins>
+        <plugin>
+                <groupId>org.apache.felix</groupId>
+                <artifactId>maven-bundle-plugin</artifactId>
+                <configuration>
+                    <instructions>
+                        <Bundle-Name>CXF Distributed OSGi Greeter Demo Service Implementation Bundle</Bundle-Name>
+                        <Bundle-Description>The server-side implementation of the CXF Distributed OSGi Greeter demo</Bundle-Description>
+                        <Bundle-SymbolicName>${project.artifactId}</Bundle-SymbolicName>
+                        <Bundle-Activator>org.apache.cxf.dosgi.samples.greeter.impl.Activator</Bundle-Activator>
+                        <Import-Package>${bundle.import.package}</Import-Package>
+                        <Private-Package>${bundle.private.package}</Private-Package>
+                        <DynamicImport-Package>org.apache.cxf.dosgi.dsw.qos,org.apache.cxf</DynamicImport-Package>
+                    </instructions>
+                </configuration>
+            </plugin>
+         </plugins>
+    </build>
+
+</project>
diff --git a/trunk/samples/greeter/impl/src/main/java/org/apache/cxf/dosgi/samples/greeter/impl/Activator.java b/trunk/samples/greeter/impl/src/main/java/org/apache/cxf/dosgi/samples/greeter/impl/Activator.java
new file mode 100644
index 0000000..9bbbf66
--- /dev/null
+++ b/trunk/samples/greeter/impl/src/main/java/org/apache/cxf/dosgi/samples/greeter/impl/Activator.java
@@ -0,0 +1,47 @@
+/**
+ * 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.samples.greeter.impl;
+
+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.framework.ServiceRegistration;
+
+public class Activator implements BundleActivator {
+
+    private ServiceRegistration registration;
+
+    public void start(BundleContext bc) throws Exception {
+        Dictionary<String, String> props = new Hashtable<String, String>();
+
+        props.put("service.exported.interfaces", "*");
+        props.put("service.exported.configs", "org.apache.cxf.ws");
+        props.put("org.apache.cxf.ws.address", "http://localhost:9090/greeter");
+
+        registration = bc.registerService(GreeterService.class.getName(),
+                                          new GreeterServiceImpl(), props);
+    }
+
+    public void stop(BundleContext bc) throws Exception {
+        registration.unregister();
+    }
+}
diff --git a/trunk/samples/greeter/impl/src/main/java/org/apache/cxf/dosgi/samples/greeter/impl/GreeterServiceImpl.java b/trunk/samples/greeter/impl/src/main/java/org/apache/cxf/dosgi/samples/greeter/impl/GreeterServiceImpl.java
new file mode 100644
index 0000000..6e6a4af
--- /dev/null
+++ b/trunk/samples/greeter/impl/src/main/java/org/apache/cxf/dosgi/samples/greeter/impl/GreeterServiceImpl.java
@@ -0,0 +1,61 @@
+/**
+ * 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.samples.greeter.impl;
+
+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 class GreeterServiceImpl implements GreeterService {
+
+    public Map<GreetingPhrase, String> greetMe(String name) {
+        System.out.println("Invoking: greetMe(" + name + ")");
+
+        Map<GreetingPhrase, String> greetings = new HashMap<GreetingPhrase, String>();
+
+        greetings.put(new GreetingPhrase("Hello"), name);
+        greetings.put(new GreetingPhrase("Hoi"), name);
+        greetings.put(new GreetingPhrase("Hola"), name);
+        greetings.put(new GreetingPhrase("Bonjour"), name);
+
+        return greetings;
+    }
+
+    public GreetingPhrase[] greetMe(GreeterData gd) throws GreeterException {
+        if (gd.isException()) {
+            System.out.println("Throwing custom exception from: greetMe(" + gd.getName() + ")");
+            throw new GreeterException(gd.getName());
+        }
+
+        String details = gd.getName() + "(" + gd.getAge() + ")";
+        System.out.println("Invoking: greetMe(" + details + ")");
+
+        GreetingPhrase[] greetings = new GreetingPhrase[] {
+            new GreetingPhrase("Howdy " + details),
+            new GreetingPhrase("Hallo " + details),
+            new GreetingPhrase("Ni hao " + details)
+        };
+
+        return greetings;
+    }
+}
diff --git a/trunk/samples/greeter/interface/pom.xml b/trunk/samples/greeter/interface/pom.xml
new file mode 100644
index 0000000..e7b35fe
--- /dev/null
+++ b/trunk/samples/greeter/interface/pom.xml
@@ -0,0 +1,72 @@
+<?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>
+    <groupId>org.apache.cxf.dosgi.samples</groupId>
+    <artifactId>cxf-dosgi-ri-samples-greeter-interface</artifactId>
+    <packaging>bundle</packaging>
+    <name>Distributed OSGI Greeter Interface Bundle</name>
+    <version>1.6.0</version>
+
+    <parent>
+      <groupId>org.apache.cxf.dosgi</groupId>
+      <artifactId>cxf-dosgi-ri-parent</artifactId>
+      <version>1.6.0</version>
+      <relativePath>../../../parent/pom.xml</relativePath>
+    </parent>
+
+    <properties>
+        <bundle.import.package>*</bundle.import.package>
+        <bundle.export.package>org.apache.cxf.dosgi.samples.greeter</bundle.export.package>
+    </properties>
+
+    <dependencies>
+        <dependency>
+           <groupId>junit</groupId>
+           <artifactId>junit</artifactId>
+           <scope>test</scope>
+        </dependency>
+        <dependency>
+           <groupId>org.easymock</groupId>
+           <artifactId>easymockclassextension</artifactId>
+           <scope>test</scope>
+         </dependency>
+    </dependencies>
+
+    <build>
+      <plugins>
+        <plugin>
+                <groupId>org.apache.felix</groupId>
+                <artifactId>maven-bundle-plugin</artifactId>
+                <configuration>
+                    <instructions>
+                        <Bundle-Name>CXF Distributed OSGi Greeter Demo Interface Bundle</Bundle-Name>
+                        <Bundle-Description>The interfaces of the CXF Distributed OSGi Greeter demo</Bundle-Description>
+                        <Bundle-SymbolicName>${project.artifactId}</Bundle-SymbolicName>
+                        <Import-Package>${bundle.import.package}</Import-Package>
+                        <Export-Package>${bundle.export.package}</Export-Package>
+                    </instructions>
+                </configuration>
+            </plugin>
+         </plugins>
+    </build>
+
+</project>
diff --git a/trunk/samples/greeter/interface/src/main/java/org/apache/cxf/dosgi/samples/greeter/GreeterData.java b/trunk/samples/greeter/interface/src/main/java/org/apache/cxf/dosgi/samples/greeter/GreeterData.java
new file mode 100644
index 0000000..be23cc4
--- /dev/null
+++ b/trunk/samples/greeter/interface/src/main/java/org/apache/cxf/dosgi/samples/greeter/GreeterData.java
@@ -0,0 +1,25 @@
+/**
+ * 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.samples.greeter;
+
+public interface GreeterData {
+    String getName();
+    int getAge();
+    boolean isException();
+}
diff --git a/trunk/samples/greeter/interface/src/main/java/org/apache/cxf/dosgi/samples/greeter/GreeterException.java b/trunk/samples/greeter/interface/src/main/java/org/apache/cxf/dosgi/samples/greeter/GreeterException.java
new file mode 100644
index 0000000..ebc58d1
--- /dev/null
+++ b/trunk/samples/greeter/interface/src/main/java/org/apache/cxf/dosgi/samples/greeter/GreeterException.java
@@ -0,0 +1,45 @@
+/**

+ * 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.samples.greeter;

+

+public class GreeterException extends Exception {

+

+    private static final long serialVersionUID = 1L;

+    private String name;

+

+    public GreeterException() {

+    }

+

+    public GreeterException(String name) {

+        this.name = name;

+    }

+

+    public String getName() {

+        return name;

+    }

+

+    public void setName(String theName) {

+        name = theName;

+    }

+

+    @Override

+    public String toString() {

+        return "GreeterService can not greet " + name;

+    }

+}

diff --git a/trunk/samples/greeter/interface/src/main/java/org/apache/cxf/dosgi/samples/greeter/GreeterService.java b/trunk/samples/greeter/interface/src/main/java/org/apache/cxf/dosgi/samples/greeter/GreeterService.java
new file mode 100644
index 0000000..1a0d0e0
--- /dev/null
+++ b/trunk/samples/greeter/interface/src/main/java/org/apache/cxf/dosgi/samples/greeter/GreeterService.java
@@ -0,0 +1,27 @@
+/**
+ * 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.samples.greeter;
+
+import java.util.Map;
+
+public interface GreeterService {
+
+    Map<GreetingPhrase, String> greetMe(String name);
+    GreetingPhrase[] greetMe(GreeterData name) throws GreeterException;
+}
diff --git a/trunk/samples/greeter/interface/src/main/java/org/apache/cxf/dosgi/samples/greeter/GreetingPhrase.java b/trunk/samples/greeter/interface/src/main/java/org/apache/cxf/dosgi/samples/greeter/GreetingPhrase.java
new file mode 100644
index 0000000..857ed70
--- /dev/null
+++ b/trunk/samples/greeter/interface/src/main/java/org/apache/cxf/dosgi/samples/greeter/GreetingPhrase.java
@@ -0,0 +1,50 @@
+/**
+ * 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.samples.greeter;
+
+public class GreetingPhrase {
+
+    private String phrase;
+
+    public GreetingPhrase() {
+    }
+
+    public GreetingPhrase(String phrase) {
+        this.phrase = phrase;
+    }
+
+    public void setPhrase(String thePhrase) {
+        this.phrase = thePhrase;
+    }
+
+    public String getPhrase() {
+        return phrase;
+    }
+
+    @Override
+    public int hashCode() {
+        return phrase.hashCode();
+    }
+
+    @Override
+    public boolean equals(Object other) {
+        return GreetingPhrase.class.isAssignableFrom(other.getClass())
+                && phrase.equals(((GreetingPhrase) other).phrase);
+    }
+}
diff --git a/trunk/samples/greeter/pom.xml b/trunk/samples/greeter/pom.xml
new file mode 100644
index 0000000..d398d7c
--- /dev/null
+++ b/trunk/samples/greeter/pom.xml
@@ -0,0 +1,42 @@
+<?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>
+    <groupId>org.apache.cxf.dosgi.samples</groupId>
+    <artifactId>cxf-dosgi-ri-samples-greeter-parent</artifactId>
+    <packaging>pom</packaging>
+    <name>Distributed OSGI Greeter Bundles</name>
+    <version>1.6.0</version>
+
+    <parent>
+      <groupId>org.apache.cxf.dosgi</groupId>
+      <artifactId>cxf-dosgi-ri-parent</artifactId>
+      <version>1.6.0</version>
+      <relativePath>../../parent/pom.xml</relativePath>
+    </parent>
+
+    <modules>
+      <module>interface</module>
+      <module>impl</module>
+      <module>client</module>
+    </modules>
+
+</project>
diff --git a/trunk/samples/greeter_rest/client/pom.xml b/trunk/samples/greeter_rest/client/pom.xml
new file mode 100644
index 0000000..9be90ea
--- /dev/null
+++ b/trunk/samples/greeter_rest/client/pom.xml
@@ -0,0 +1,76 @@
+<?xml version='1.0' encoding='UTF-8' ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements. See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership. The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License. You may obtain a copy of the License at
+
+  http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied. See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+    <groupId>org.apache.cxf.dosgi.samples</groupId>
+    <artifactId>cxf-dosgi-ri-samples-greeter-rest-client</artifactId>
+    <packaging>bundle</packaging>
+    <name>Distributed OSGI Greeter Bundle Client</name>
+    <version>1.6.0</version>
+
+    <parent>
+      <groupId>org.apache.cxf.dosgi</groupId>
+      <artifactId>cxf-dosgi-ri-parent</artifactId>
+      <version>1.6.0</version>
+      <relativePath>../../../parent/pom.xml</relativePath>
+    </parent>
+
+    <properties>
+        <bundle.import.package>javax.ws.rs.*,*</bundle.import.package>
+        <bundle.private.package>org.apache.cxf.dosgi.samples.greeter.client.rest</bundle.private.package>
+    </properties>
+
+    <dependencies>
+        <dependency>
+            <groupId>org.apache.cxf.dosgi.samples</groupId>
+            <artifactId>cxf-dosgi-ri-samples-greeter-rest-interface</artifactId>
+            <version>${project.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>org.osgi</groupId>
+            <artifactId>org.osgi.core</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.osgi</groupId>
+            <artifactId>org.osgi.compendium</artifactId>
+        </dependency>
+    </dependencies>
+
+    <build>
+      <plugins>
+        <plugin>
+                <groupId>org.apache.felix</groupId>
+                <artifactId>maven-bundle-plugin</artifactId>
+                <configuration>
+                    <instructions>
+                        <Bundle-Name>CXF Distributed OSGi Greeter REST Demo Client Bundle</Bundle-Name>
+                        <Bundle-Description>The client-side implementation of the Distributed OSGi Greeter REST demo</Bundle-Description>
+                        <Bundle-SymbolicName>${project.artifactId}</Bundle-SymbolicName>
+                        <Bundle-Activator>org.apache.cxf.dosgi.samples.greeter.client.rest.Activator</Bundle-Activator>
+                        <Import-Package>${bundle.import.package}</Import-Package>
+                        <Private-Package>${bundle.private.package}</Private-Package>
+                        <DynamicImport-Package>org.apache.cxf.dosgi.dsw.qos,org.apache.cxf</DynamicImport-Package>
+                    </instructions>
+                </configuration>
+            </plugin>
+         </plugins>
+    </build>
+
+</project>
diff --git a/trunk/samples/greeter_rest/client/src/main/java/org/apache/cxf/dosgi/samples/greeter/client/rest/Activator.java b/trunk/samples/greeter_rest/client/src/main/java/org/apache/cxf/dosgi/samples/greeter/client/rest/Activator.java
new file mode 100644
index 0000000..667060f
--- /dev/null
+++ b/trunk/samples/greeter_rest/client/src/main/java/org/apache/cxf/dosgi/samples/greeter/client/rest/Activator.java
@@ -0,0 +1,132 @@
+/**
+ * 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.samples.greeter.client.rest;
+
+import javax.swing.JOptionPane;
+
+import org.apache.cxf.dosgi.samples.greeter.rest.GreeterException;
+import org.apache.cxf.dosgi.samples.greeter.rest.GreeterInfo;
+import org.apache.cxf.dosgi.samples.greeter.rest.GreeterService;
+import org.apache.cxf.dosgi.samples.greeter.rest.GreeterService2;
+import org.apache.cxf.dosgi.samples.greeter.rest.GreetingPhrase;
+import org.osgi.framework.BundleActivator;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.ServiceReference;
+import org.osgi.util.tracker.ServiceTracker;
+
+public class Activator implements BundleActivator {
+
+    private ServiceTracker tracker;
+    private ServiceTracker tracker2;
+
+    public void start(final BundleContext bc) {
+        tracker = new ServiceTracker(bc, GreeterService.class.getName(), null) {
+            @Override
+            public Object addingService(ServiceReference reference) {
+                Object service = super.addingService(reference);
+                if (service instanceof GreeterService) {
+                    useGreeterService((GreeterService) service);
+                }
+                return service;
+            }
+        };
+        tracker.open();
+
+        tracker2 = new ServiceTracker(bc, GreeterService2.class.getName(), null) {
+            @Override
+            public Object addingService(ServiceReference reference) {
+                Object service = super.addingService(reference);
+                if (service instanceof GreeterService2) {
+                    useGreeterService2((GreeterService2) service);
+                }
+                return service;
+            }
+        };
+        tracker2.open();
+    }
+
+    protected void useGreeterService(final GreeterService greeter) {
+        Thread t = new Thread(new Runnable() {
+            public void run() {
+                greeterUI(greeter);
+            }
+        });
+        t.start();
+    }
+
+    protected void useGreeterService2(final GreeterService2 greeter) {
+        Thread t = new Thread(new Runnable() {
+            public void run() {
+                greeter2UI(greeter);
+            }
+        });
+        t.start();
+    }
+
+    private void greeterUI(final GreeterService greeter) {
+        while (true) {
+            System.out.println("*** Opening greeter client dialog ***");
+            String name = JOptionPane.showInputDialog("Enter name:");
+            if (name == null) {
+                break;
+            } else {
+                System.out.println("*** Invoking greeter ***");
+                try {
+                    GreeterInfo info = greeter.greetMe(name);
+
+                    System.out.println("greetMe(\"" + name + "\") returns:");
+                    for (GreetingPhrase greeting: info.getGreetings()) {
+                        System.out.println("  " + greeting.getPhrase()
+                                + " " + greeting.getName());
+                    }
+                } catch (GreeterException ex) {
+                    System.out.println("GreeterException: " + ex.toString());
+                }
+            }
+        }
+    }
+
+    private void greeter2UI(final GreeterService2 greeter) {
+        while (true) {
+            System.out.println("*** Opening greeter2 client dialog ***");
+            String name = JOptionPane.showInputDialog("Greeter2: Enter name");
+            if (name == null) {
+                break;
+            } else {
+                System.out.println("*** Invoking greeter2 ***");
+                try {
+                    GreeterInfo info = greeter.greetMe(name);
+
+                    System.out.println("greetMe(\"" + name + "\") returns:");
+                    for (GreetingPhrase greeting: info.getGreetings()) {
+                        System.out.println("  " + greeting.getPhrase()
+                                + " " + greeting.getName());
+                    }
+                } catch (GreeterException ex) {
+                    System.out.println("GreeterException: " + ex.toString());
+                }
+            }
+        }
+    }
+
+    public void stop(BundleContext bc) throws Exception {
+        tracker.close();
+        tracker2.close();
+    }
+}
diff --git a/trunk/samples/greeter_rest/client/src/main/resources/OSGI-INF/remote-service/remote-services.xml b/trunk/samples/greeter_rest/client/src/main/resources/OSGI-INF/remote-service/remote-services.xml
new file mode 100644
index 0000000..1b2ec65
--- /dev/null
+++ b/trunk/samples/greeter_rest/client/src/main/resources/OSGI-INF/remote-service/remote-services.xml
@@ -0,0 +1,31 @@
+<?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.
+  -->
+<service-descriptions xmlns="http://www.osgi.org/xmlns/sd/v1.0.0">
+  <service-description>
+    <provide interface="org.apache.cxf.dosgi.samples.greeter.rest.GreeterService" />
+    <property name="service.exported.interfaces">*</property>
+    <property name="service.exported.configs">org.apache.cxf.rs</property>
+    <property name="service.exported.intents">HTTP</property>
+    <property name="org.apache.cxf.rs.address">http://localhost:8080/greeter</property>
+  </service-description>
+  <service-description>
+    <provide interface="org.apache.cxf.dosgi.samples.greeter.rest.GreeterService2" />
+    <property name="service.exported.interfaces">*</property>
+    <property name="service.exported.configs">org.apache.cxf.rs</property>
+    <property name="service.exported.intents">HTTP</property>
+    <property name="org.apache.cxf.rs.address">http://localhost:8080/greeter2</property>
+  </service-description>
+</service-descriptions>
diff --git a/trunk/samples/greeter_rest/impl/pom.xml b/trunk/samples/greeter_rest/impl/pom.xml
new file mode 100644
index 0000000..b180322
--- /dev/null
+++ b/trunk/samples/greeter_rest/impl/pom.xml
@@ -0,0 +1,77 @@
+<?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>
+    <groupId>org.apache.cxf.dosgi.samples</groupId>
+    <artifactId>cxf-dosgi-ri-samples-greeter-rest-impl</artifactId>
+    <packaging>bundle</packaging>
+    <name>Distributed OSGI Greeter Implementation Bundle</name>
+    <version>1.6.0</version>
+
+    <parent>
+      <groupId>org.apache.cxf.dosgi</groupId>
+      <artifactId>cxf-dosgi-ri-parent</artifactId>
+      <version>1.6.0</version>
+      <relativePath>../../../parent/pom.xml</relativePath>
+    </parent>
+
+    <properties>
+        <bundle.import.package>javax.ws.rs.*,*</bundle.import.package>
+        <bundle.private.package>org.apache.cxf.dosgi.samples.greeter.impl.rest</bundle.private.package>
+    </properties>
+
+    <dependencies>
+        <dependency>
+            <groupId>org.osgi</groupId>
+            <artifactId>org.osgi.core</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.osgi</groupId>
+            <artifactId>org.osgi.compendium</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.cxf.dosgi.samples</groupId>
+            <artifactId>cxf-dosgi-ri-samples-greeter-rest-interface</artifactId>
+            <version>${project.version}</version>
+        </dependency>
+    </dependencies>
+
+    <build>
+      <plugins>
+        <plugin>
+                <groupId>org.apache.felix</groupId>
+                <artifactId>maven-bundle-plugin</artifactId>
+                <configuration>
+                    <instructions>
+                        <Bundle-Name>CXF Distributed OSGi Greeter Demo Service REST Implementation Bundle</Bundle-Name>
+                        <Bundle-Description>The server-side implementation of the CXF Distributed OSGi Greeter REST demo</Bundle-Description>
+                        <Bundle-SymbolicName>${project.artifactId}</Bundle-SymbolicName>
+                        <Bundle-Activator>org.apache.cxf.dosgi.samples.greeter.impl.rest.Activator</Bundle-Activator>
+                        <Import-Package>${bundle.import.package}</Import-Package>
+                        <Private-Package>${bundle.private.package}</Private-Package>
+                        <DynamicImport-Package>org.apache.cxf.dosgi.dsw.qos,org.apache.cxf</DynamicImport-Package>
+                    </instructions>
+                </configuration>
+            </plugin>
+         </plugins>
+    </build>
+
+</project>
diff --git a/trunk/samples/greeter_rest/impl/src/main/java/org/apache/cxf/dosgi/samples/greeter/impl/rest/Activator.java b/trunk/samples/greeter_rest/impl/src/main/java/org/apache/cxf/dosgi/samples/greeter/impl/rest/Activator.java
new file mode 100644
index 0000000..5ee239b
--- /dev/null
+++ b/trunk/samples/greeter_rest/impl/src/main/java/org/apache/cxf/dosgi/samples/greeter/impl/rest/Activator.java
@@ -0,0 +1,59 @@
+/**
+ * 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.samples.greeter.impl.rest;
+
+import java.util.Dictionary;
+import java.util.Hashtable;
+
+import org.apache.cxf.dosgi.samples.greeter.rest.GreeterService;
+import org.apache.cxf.dosgi.samples.greeter.rest.GreeterService2;
+import org.osgi.framework.BundleActivator;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.ServiceRegistration;
+
+public class Activator implements BundleActivator {
+
+    private ServiceRegistration registration;
+    private ServiceRegistration registration2;
+
+    public void start(BundleContext bc) throws Exception {
+        Dictionary<String, Object> props = getProperties("/greeter");
+        registration = bc.registerService(GreeterService.class.getName(),
+                                          new GreeterServiceImpl(), props);
+
+        props = getProperties("/greeter2");
+        registration2 = bc.registerService(GreeterService2.class.getName(),
+                                          new GreeterServiceImpl2(), props);
+    }
+
+    private Dictionary<String, Object> getProperties(String address) {
+        Dictionary<String, Object> props = new Hashtable<String, Object>();
+
+        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.httpservice.context", address);
+        return props;
+    }
+
+    public void stop(BundleContext bc) throws Exception {
+        registration.unregister();
+        registration2.unregister();
+    }
+}
diff --git a/trunk/samples/greeter_rest/impl/src/main/java/org/apache/cxf/dosgi/samples/greeter/impl/rest/GreeterServiceImpl.java b/trunk/samples/greeter_rest/impl/src/main/java/org/apache/cxf/dosgi/samples/greeter/impl/rest/GreeterServiceImpl.java
new file mode 100644
index 0000000..cf8df84
--- /dev/null
+++ b/trunk/samples/greeter_rest/impl/src/main/java/org/apache/cxf/dosgi/samples/greeter/impl/rest/GreeterServiceImpl.java
@@ -0,0 +1,49 @@
+/**
+ * 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.samples.greeter.impl.rest;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.cxf.dosgi.samples.greeter.rest.GreeterException;
+import org.apache.cxf.dosgi.samples.greeter.rest.GreeterInfo;
+import org.apache.cxf.dosgi.samples.greeter.rest.GreeterService;
+import org.apache.cxf.dosgi.samples.greeter.rest.GreetingPhrase;
+
+public class GreeterServiceImpl implements GreeterService {
+
+    private static final String STRANGER_NAME = "Stranger";
+
+    public GreeterInfo greetMe(String name) throws GreeterException {
+        System.out.println("Invoking: greetMe(" + name + ")");
+
+        if (name.equals(STRANGER_NAME)) {
+            throw new GreeterException(name);
+        }
+
+        GreeterInfo info = new GreeterInfo();
+        List<GreetingPhrase> list = new ArrayList<GreetingPhrase>();
+        list.add(new GreetingPhrase("Hello", name));
+        list.add(new GreetingPhrase("Hoi", name));
+        list.add(new GreetingPhrase("Hola", name));
+        list.add(new GreetingPhrase("Bonjour", name));
+        info.setGreetings(list);
+        return info;
+    }
+}
diff --git a/trunk/samples/greeter_rest/impl/src/main/java/org/apache/cxf/dosgi/samples/greeter/impl/rest/GreeterServiceImpl2.java b/trunk/samples/greeter_rest/impl/src/main/java/org/apache/cxf/dosgi/samples/greeter/impl/rest/GreeterServiceImpl2.java
new file mode 100644
index 0000000..83731c5
--- /dev/null
+++ b/trunk/samples/greeter_rest/impl/src/main/java/org/apache/cxf/dosgi/samples/greeter/impl/rest/GreeterServiceImpl2.java
@@ -0,0 +1,33 @@
+/**
+ * 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.samples.greeter.impl.rest;
+
+import org.apache.cxf.dosgi.samples.greeter.rest.GreeterException;
+import org.apache.cxf.dosgi.samples.greeter.rest.GreeterInfo;
+import org.apache.cxf.dosgi.samples.greeter.rest.GreeterService2;
+
+public class GreeterServiceImpl2 implements GreeterService2 {
+
+    private GreeterServiceImpl greeter = new GreeterServiceImpl();
+
+    public GreeterInfo greetMe(String name) throws GreeterException {
+        System.out.println("Delegating from GreeterServiceImpl2 to GreeterServiceImpl");
+        return greeter.greetMe(name);
+    }
+}
diff --git a/trunk/samples/greeter_rest/impl2/pom.xml b/trunk/samples/greeter_rest/impl2/pom.xml
new file mode 100644
index 0000000..2c9ebe7
--- /dev/null
+++ b/trunk/samples/greeter_rest/impl2/pom.xml
@@ -0,0 +1,77 @@
+<?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>
+    <groupId>org.apache.cxf.dosgi.samples</groupId>
+    <artifactId>cxf-dosgi-ri-samples-greeter-rest-impl2</artifactId>
+    <packaging>bundle</packaging>
+    <name>Distributed OSGI Greeter Implementation2 Bundle</name>
+    <version>1.6.0</version>
+
+    <parent>
+      <groupId>org.apache.cxf.dosgi</groupId>
+      <artifactId>cxf-dosgi-ri-parent</artifactId>
+      <version>1.6.0</version>
+      <relativePath>../../../parent/pom.xml</relativePath>
+    </parent>
+
+    <properties>
+        <bundle.import.package>javax.ws.rs.*,*</bundle.import.package>
+        <bundle.private.package>org.apache.cxf.dosgi.samples.greeter.impl2.rest</bundle.private.package>
+    </properties>
+
+    <dependencies>
+        <dependency>
+            <groupId>org.osgi</groupId>
+            <artifactId>org.osgi.core</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.osgi</groupId>
+            <artifactId>org.osgi.compendium</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.cxf.dosgi.samples</groupId>
+            <artifactId>cxf-dosgi-ri-samples-greeter-rest-interface</artifactId>
+            <version>${project.version}</version>
+        </dependency>
+    </dependencies>
+
+    <build>
+      <plugins>
+        <plugin>
+                <groupId>org.apache.felix</groupId>
+                <artifactId>maven-bundle-plugin</artifactId>
+                <configuration>
+                    <instructions>
+                        <Bundle-Name>CXF Distributed OSGi Greeter Demo Service REST Implementation2 Bundle</Bundle-Name>
+                        <Bundle-Description>The 2nd server-side implementation of the CXF Distributed OSGi Greeter REST demo</Bundle-Description>
+                        <Bundle-SymbolicName>${project.artifactId}</Bundle-SymbolicName>
+                        <Bundle-Activator>org.apache.cxf.dosgi.samples.greeter.impl2.rest.Activator</Bundle-Activator>
+                        <Import-Package>${bundle.import.package}</Import-Package>
+                        <Private-Package>${bundle.private.package}</Private-Package>
+                        <DynamicImport-Package>org.apache.cxf.dosgi.dsw.qos,org.apache.cxf</DynamicImport-Package>
+                    </instructions>
+                </configuration>
+            </plugin>
+         </plugins>
+    </build>
+
+</project>
diff --git a/trunk/samples/greeter_rest/impl2/src/main/java/org/apache/cxf/dosgi/samples/greeter/impl2/rest/Activator.java b/trunk/samples/greeter_rest/impl2/src/main/java/org/apache/cxf/dosgi/samples/greeter/impl2/rest/Activator.java
new file mode 100644
index 0000000..6076701
--- /dev/null
+++ b/trunk/samples/greeter_rest/impl2/src/main/java/org/apache/cxf/dosgi/samples/greeter/impl2/rest/Activator.java
@@ -0,0 +1,53 @@
+/**
+ * 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.samples.greeter.impl2.rest;
+
+import java.util.Dictionary;
+import java.util.Hashtable;
+
+import org.apache.cxf.dosgi.samples.greeter.rest.GreeterService;
+import org.osgi.framework.BundleActivator;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.ServiceRegistration;
+
+public class Activator implements BundleActivator {
+
+    private ServiceRegistration registration;
+
+    public void start(BundleContext bc) throws Exception {
+        Dictionary<String, Object> props = getProperties("/rest");
+        registration = bc.registerService(GreeterService.class.getName(),
+                                          new GreeterServiceImpl2(), props);
+    }
+
+    private Dictionary<String, Object> getProperties(String address) {
+        Dictionary<String, Object> props = new Hashtable<String, Object>();
+
+        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.httpservice.context", address);
+        props.put("org.apache.cxf.rs.address", "/service");
+        return props;
+    }
+
+    public void stop(BundleContext bc) throws Exception {
+        registration.unregister();
+    }
+}
diff --git a/trunk/samples/greeter_rest/impl2/src/main/java/org/apache/cxf/dosgi/samples/greeter/impl2/rest/GreeterServiceImpl2.java b/trunk/samples/greeter_rest/impl2/src/main/java/org/apache/cxf/dosgi/samples/greeter/impl2/rest/GreeterServiceImpl2.java
new file mode 100644
index 0000000..2b0881f
--- /dev/null
+++ b/trunk/samples/greeter_rest/impl2/src/main/java/org/apache/cxf/dosgi/samples/greeter/impl2/rest/GreeterServiceImpl2.java
@@ -0,0 +1,49 @@
+/**
+ * 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.samples.greeter.impl2.rest;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.cxf.dosgi.samples.greeter.rest.GreeterException;
+import org.apache.cxf.dosgi.samples.greeter.rest.GreeterInfo;
+import org.apache.cxf.dosgi.samples.greeter.rest.GreeterService;
+import org.apache.cxf.dosgi.samples.greeter.rest.GreetingPhrase;
+
+public class GreeterServiceImpl2 implements GreeterService {
+
+    private static final String STRANGER_NAME = "Stranger";
+
+    public GreeterInfo greetMe(String name) throws GreeterException {
+        System.out.println("Invoking from GreeterServiceImpl2: greetMe(" + name + ")");
+
+        if (name.equals(STRANGER_NAME)) {
+            throw new GreeterException(name);
+        }
+
+        GreeterInfo info = new GreeterInfo();
+        List<GreetingPhrase> list = new ArrayList<GreetingPhrase>();
+        list.add(new GreetingPhrase("Hello", name));
+        list.add(new GreetingPhrase("Hoi", name));
+        list.add(new GreetingPhrase("Hola", name));
+        list.add(new GreetingPhrase("Bonjour", name));
+        info.setGreetings(list);
+        return info;
+    }
+}
diff --git a/trunk/samples/greeter_rest/interface/pom.xml b/trunk/samples/greeter_rest/interface/pom.xml
new file mode 100644
index 0000000..a7d9985
--- /dev/null
+++ b/trunk/samples/greeter_rest/interface/pom.xml
@@ -0,0 +1,81 @@
+<?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>
+    <groupId>org.apache.cxf.dosgi.samples</groupId>
+    <artifactId>cxf-dosgi-ri-samples-greeter-rest-interface</artifactId>
+    <packaging>bundle</packaging>
+    <name>Distributed OSGI Greeter Rest Interface Bundle</name>
+    <version>1.6.0</version>
+
+    <parent>
+      <groupId>org.apache.cxf.dosgi</groupId>
+      <artifactId>cxf-dosgi-ri-parent</artifactId>
+      <version>1.6.0</version>
+      <relativePath>../../../parent/pom.xml</relativePath>
+    </parent>
+
+    <properties>
+        <bundle.import.package>javax.ws.rs,javax.xml.bind.annotation,*</bundle.import.package>
+        <bundle.export.package>org.apache.cxf.dosgi.samples.greeter.rest</bundle.export.package>
+    </properties>
+
+    <dependencies>
+        <dependency>
+           <groupId>junit</groupId>
+           <artifactId>junit</artifactId>
+           <scope>test</scope>
+        </dependency>
+        <dependency>
+           <groupId>org.easymock</groupId>
+           <artifactId>easymockclassextension</artifactId>
+           <scope>test</scope>
+        </dependency>
+        <dependency>
+          <groupId>org.apache.servicemix.specs</groupId>
+          <artifactId>org.apache.servicemix.specs.jsr339-api-m10</artifactId>
+          <version>${servicemix.specs.version}</version>
+        </dependency>
+        <dependency>
+          <groupId>org.apache.servicemix.specs</groupId>
+          <artifactId>org.apache.servicemix.specs.jaxb-api-2.1</artifactId>
+          <version>${servicemix.specs.version}</version>
+        </dependency>
+    </dependencies>
+
+    <build>
+      <plugins>
+        <plugin>
+                <groupId>org.apache.felix</groupId>
+                <artifactId>maven-bundle-plugin</artifactId>
+                <configuration>
+                    <instructions>
+                        <Bundle-Name>CXF Distributed OSGi Greeter REST Demo Interface Bundle</Bundle-Name>
+                        <Bundle-Description>The interfaces of the CXF Distributed OSGi Greeter REST demo</Bundle-Description>
+                        <Bundle-SymbolicName>${project.artifactId}</Bundle-SymbolicName>
+                        <Import-Package>${bundle.import.package}</Import-Package>
+                        <Export-Package>${bundle.export.package}</Export-Package>
+                    </instructions>
+                </configuration>
+            </plugin>
+         </plugins>
+    </build>
+
+</project>
diff --git a/trunk/samples/greeter_rest/interface/src/main/java/org/apache/cxf/dosgi/samples/greeter/rest/GreeterException.java b/trunk/samples/greeter_rest/interface/src/main/java/org/apache/cxf/dosgi/samples/greeter/rest/GreeterException.java
new file mode 100644
index 0000000..fb83637
--- /dev/null
+++ b/trunk/samples/greeter_rest/interface/src/main/java/org/apache/cxf/dosgi/samples/greeter/rest/GreeterException.java
@@ -0,0 +1,45 @@
+/**
+ * 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.samples.greeter.rest;
+
+public class GreeterException extends Exception {
+
+    private static final long serialVersionUID = 1L;
+    private String name;
+
+    public GreeterException() {
+    }
+
+    public GreeterException(String name) {
+        this.name = name;
+    }
+
+    public String getName() {
+        return name;
+    }
+
+    public void setName(String theName) {
+        name = theName;
+    }
+
+    @Override
+    public String toString() {
+        return "GreeterService can not greet " + name;
+    }
+}
diff --git a/trunk/samples/greeter_rest/interface/src/main/java/org/apache/cxf/dosgi/samples/greeter/rest/GreeterInfo.java b/trunk/samples/greeter_rest/interface/src/main/java/org/apache/cxf/dosgi/samples/greeter/rest/GreeterInfo.java
new file mode 100644
index 0000000..6dba206
--- /dev/null
+++ b/trunk/samples/greeter_rest/interface/src/main/java/org/apache/cxf/dosgi/samples/greeter/rest/GreeterInfo.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.samples.greeter.rest;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.xml.bind.annotation.XmlRootElement;
+@XmlRootElement
+public class GreeterInfo {
+
+    private List<GreetingPhrase> greetings = new ArrayList<GreetingPhrase>();
+
+    public void setGreetings(List<GreetingPhrase> list) {
+        greetings = list;
+    }
+
+    public List<GreetingPhrase> getGreetings() {
+        return greetings;
+    }
+}
diff --git a/trunk/samples/greeter_rest/interface/src/main/java/org/apache/cxf/dosgi/samples/greeter/rest/GreeterService.java b/trunk/samples/greeter_rest/interface/src/main/java/org/apache/cxf/dosgi/samples/greeter/rest/GreeterService.java
new file mode 100644
index 0000000..7e67bd4
--- /dev/null
+++ b/trunk/samples/greeter_rest/interface/src/main/java/org/apache/cxf/dosgi/samples/greeter/rest/GreeterService.java
@@ -0,0 +1,31 @@
+/**
+ * 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.samples.greeter.rest;
+
+import javax.ws.rs.GET;
+import javax.ws.rs.Path;
+import javax.ws.rs.PathParam;
+
+@Path("greeter")
+public interface GreeterService {
+
+    @GET
+    @Path("greeting/{name}")
+    GreeterInfo greetMe(@PathParam("name") String name) throws GreeterException;
+}
diff --git a/trunk/samples/greeter_rest/interface/src/main/java/org/apache/cxf/dosgi/samples/greeter/rest/GreeterService2.java b/trunk/samples/greeter_rest/interface/src/main/java/org/apache/cxf/dosgi/samples/greeter/rest/GreeterService2.java
new file mode 100644
index 0000000..453157c
--- /dev/null
+++ b/trunk/samples/greeter_rest/interface/src/main/java/org/apache/cxf/dosgi/samples/greeter/rest/GreeterService2.java
@@ -0,0 +1,24 @@
+/**
+ * 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.samples.greeter.rest;
+
+public interface GreeterService2 {
+
+    GreeterInfo greetMe(String name) throws GreeterException;
+}
diff --git a/trunk/samples/greeter_rest/interface/src/main/java/org/apache/cxf/dosgi/samples/greeter/rest/GreetingPhrase.java b/trunk/samples/greeter_rest/interface/src/main/java/org/apache/cxf/dosgi/samples/greeter/rest/GreetingPhrase.java
new file mode 100644
index 0000000..545e091
--- /dev/null
+++ b/trunk/samples/greeter_rest/interface/src/main/java/org/apache/cxf/dosgi/samples/greeter/rest/GreetingPhrase.java
@@ -0,0 +1,64 @@
+/**
+ * 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.samples.greeter.rest;
+
+import javax.xml.bind.annotation.XmlRootElement;
+
+@XmlRootElement
+public class GreetingPhrase {
+
+    private String phrase;
+    private String name;
+
+    public GreetingPhrase() {
+    }
+
+    public GreetingPhrase(String phrase, String name) {
+        this.phrase = phrase;
+        this.name = name;
+    }
+
+    public void setPhrase(String thePhrase) {
+        this.phrase = thePhrase;
+    }
+
+    public String getPhrase() {
+        return phrase;
+    }
+
+    public void setName(String theName) {
+        this.name = theName;
+    }
+
+    public String getName() {
+        return name;
+    }
+
+    @Override
+    public int hashCode() {
+        return phrase.hashCode() + 37 * name.hashCode();
+    }
+
+    @Override
+    public boolean equals(Object other) {
+        return GreetingPhrase.class.isAssignableFrom(other.getClass())
+                && phrase.equals(((GreetingPhrase) other).phrase)
+                && name.equals(((GreetingPhrase) other).name);
+    }
+}
diff --git a/trunk/samples/greeter_rest/interface/src/main/resources/OSGI-INF/cxf/jaxrs/GreeterService2-model.xml b/trunk/samples/greeter_rest/interface/src/main/resources/OSGI-INF/cxf/jaxrs/GreeterService2-model.xml
new file mode 100644
index 0000000..2c4da17
--- /dev/null
+++ b/trunk/samples/greeter_rest/interface/src/main/resources/OSGI-INF/cxf/jaxrs/GreeterService2-model.xml
@@ -0,0 +1,7 @@
+<model xmlns="http://cxf.apache.org/jaxrs">
+ <resource name="org.apache.cxf.dosgi.samples.greeter.rest.GreeterService2" path="greeter">
+    <operation name="greetMe" verb="GET" path="greeting/{name}">
+       <param name="name" type="PATH"/>
+    </operation>
+ </resource>
+</model>
diff --git a/trunk/samples/greeter_rest/pom.xml b/trunk/samples/greeter_rest/pom.xml
new file mode 100644
index 0000000..f2f5feb
--- /dev/null
+++ b/trunk/samples/greeter_rest/pom.xml
@@ -0,0 +1,43 @@
+<?xml version='1.0' encoding='UTF-8' ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements. See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership. The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License. You may obtain a copy of the License at
+
+  http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied. See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+
+    <modelVersion>4.0.0</modelVersion>
+    <groupId>org.apache.cxf.dosgi.samples</groupId>
+    <artifactId>cxf-dosgi-ri-samples-greeter-rest-parent</artifactId>
+    <packaging>pom</packaging>
+    <name>Distributed OSGI Greeter Rest Bundles</name>
+    <version>1.6.0</version>
+
+    <parent>
+      <groupId>org.apache.cxf.dosgi</groupId>
+      <artifactId>cxf-dosgi-ri-parent</artifactId>
+      <version>1.6.0</version>
+      <relativePath>../../parent/pom.xml</relativePath>
+    </parent>
+
+    <modules>
+      <module>interface</module>
+      <module>impl</module>
+      <module>impl2</module>
+      <module>client</module>
+    </modules>
+
+</project>
diff --git a/trunk/samples/pom.xml b/trunk/samples/pom.xml
new file mode 100644
index 0000000..89f9e69
--- /dev/null
+++ b/trunk/samples/pom.xml
@@ -0,0 +1,45 @@
+<?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>
+    <groupId>org.apache.cxf.dosgi.samples</groupId>
+    <artifactId>cxf-dosgi-ri-samples</artifactId>
+    <version>1.6.0</version>
+    <packaging>pom</packaging>
+    <name>Distributed OSGI RI Sample Bundles</name>
+    <url>http://cxf.apache.org/</url>
+
+    <parent>
+      <groupId>org.apache.cxf.dosgi</groupId>
+      <artifactId>cxf-dosgi-ri-parent</artifactId>
+      <version>1.6.0</version>
+      <relativePath>../parent/pom.xml</relativePath>
+    </parent>
+
+    <modules>
+      <module>greeter</module>
+      <module>greeter_rest</module>
+      <module>spring_dm</module>
+      <module>ds</module>
+      <module>discovery</module>
+      <module>security_filter</module>
+    </modules>
+</project>
diff --git a/trunk/samples/security_filter/pom.xml b/trunk/samples/security_filter/pom.xml
new file mode 100644
index 0000000..c68a0e9
--- /dev/null
+++ b/trunk/samples/security_filter/pom.xml
@@ -0,0 +1,73 @@
+<?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>
+    <groupId>org.apache.cxf.dosgi.samples</groupId>
+    <artifactId>cxf-dosgi-ri-samples-security</artifactId>
+    <packaging>bundle</packaging>
+    <name>Distributed OSGI Security Sample Bundle</name>
+    <version>1.6.0</version>
+
+    <parent>
+        <groupId>org.apache.cxf.dosgi</groupId>
+        <artifactId>cxf-dosgi-ri-parent</artifactId>
+        <version>1.6.0</version>
+        <relativePath>../../parent/pom.xml</relativePath>
+    </parent>
+
+    <dependencies>
+        <dependency>
+            <groupId>org.osgi</groupId>
+            <artifactId>org.osgi.core</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.osgi</groupId>
+            <artifactId>org.osgi.compendium</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.geronimo.specs</groupId>
+            <artifactId>geronimo-servlet_${servlet.version}_spec</artifactId>
+            <version>1.0</version>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.servicemix.specs</groupId>
+            <artifactId>org.apache.servicemix.specs.jsr311-api-1.0</artifactId>
+            <version>${servicemix.specs.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>org.slf4j</groupId>
+            <artifactId>slf4j-api</artifactId>
+        </dependency>
+    </dependencies>
+
+    <build>
+        <plugins>
+            <plugin>
+                <groupId>org.apache.felix</groupId>
+                <artifactId>maven-bundle-plugin</artifactId>
+                <configuration>
+                    <instructions>
+                        <Bundle-Name>${project.name}</Bundle-Name>
+                        <Bundle-Description>An example Distributed OSGi
+                            endpoint that passes requests through a
+                            security filter</Bundle-Description>
+                        <Bundle-SymbolicName>${project.artifactId}</Bundle-SymbolicName>
+                        <Private-Package>org.apache.cxf.dosgi.samples.security</Private-Package>
+                        <Bundle-Activator>org.apache.cxf.dosgi.samples.security.Activator</Bundle-Activator>
+                    </instructions>
+                </configuration>
+            </plugin>
+        </plugins>
+    </build>
+
+</project>
diff --git a/trunk/samples/security_filter/src/main/java/org/apache/cxf/dosgi/samples/security/Activator.java b/trunk/samples/security_filter/src/main/java/org/apache/cxf/dosgi/samples/security/Activator.java
new file mode 100644
index 0000000..2514106
--- /dev/null
+++ b/trunk/samples/security_filter/src/main/java/org/apache/cxf/dosgi/samples/security/Activator.java
@@ -0,0 +1,65 @@
+/**
+ * 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.samples.security;
+
+import java.util.Dictionary;
+import java.util.Hashtable;
+
+import javax.servlet.Filter;
+
+import org.osgi.framework.BundleActivator;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.ServiceRegistration;
+
+/**
+ * Registers a REST endpoint and a servlet filter to control access to the
+ * endpoint.
+ */
+public class Activator implements BundleActivator {
+
+    private ServiceRegistration restRegistration;
+    private ServiceRegistration filterRegistration;
+
+    public void start(BundleContext bundleContext) throws Exception {
+        // Register a rest endpoint
+        Dictionary<String, Object> restProps = new Hashtable<String, Object>();
+        restProps.put("service.exported.interfaces", SecureRestEndpoint.class.getName());
+        restProps.put("service.exported.configs", "org.apache.cxf.rs");
+        restProps.put("org.apache.cxf.rs.httpservice.context", "/secure");
+        restRegistration = bundleContext.registerService(SecureRestEndpoint.class.getName(),
+                                                         new SecureRestEndpoint(), restProps);
+
+        // Register a servlet filter (this could be done in another OSGi bundle,
+        // too)
+        Dictionary<String, Object> filterProps = new Hashtable<String, Object>();
+        filterProps.put("org.apache.cxf.httpservice.filter", Boolean.TRUE);
+        // Pax-Web whiteboard (if deployed) will attempt to apply this filter to
+        // servlets by name or URL, and will complain
+        // if neither servletName or urlPatterns are specified. The felix http
+        // service whiteboard may do something similar.
+        filterProps.put("servletNames", "none");
+        filterRegistration = bundleContext.registerService(Filter.class.getName(),
+                                                           new SampleSecurityFilter(), filterProps);
+    }
+
+    public void stop(BundleContext bundleContext) throws Exception {
+        restRegistration.unregister();
+        filterRegistration.unregister();
+    }
+}
diff --git a/trunk/samples/security_filter/src/main/java/org/apache/cxf/dosgi/samples/security/SampleSecurityFilter.java b/trunk/samples/security_filter/src/main/java/org/apache/cxf/dosgi/samples/security/SampleSecurityFilter.java
new file mode 100644
index 0000000..bfc8504
--- /dev/null
+++ b/trunk/samples/security_filter/src/main/java/org/apache/cxf/dosgi/samples/security/SampleSecurityFilter.java
@@ -0,0 +1,61 @@
+/**
+ * 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.samples.security;
+
+import java.io.IOException;
+
+import javax.servlet.Filter;
+import javax.servlet.FilterChain;
+import javax.servlet.FilterConfig;
+import javax.servlet.ServletException;
+import javax.servlet.ServletRequest;
+import javax.servlet.ServletResponse;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * A filter that requires a query string of "secure" to invoke the protected
+ * resource.
+ */
+public class SampleSecurityFilter implements Filter {
+
+    private static final Logger LOG = LoggerFactory.getLogger(SampleSecurityFilter.class);
+
+    public void destroy() {
+        LOG.info("destroy()");
+    }
+
+    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
+        throws IOException, ServletException {
+        if ("secure".equals(((HttpServletRequest)request).getQueryString())) {
+            LOG.info("Access granted");
+            chain.doFilter(request, response);
+        } else {
+            LOG.warn("Access denied");
+            ((HttpServletResponse)response).sendError(HttpServletResponse.SC_FORBIDDEN);
+        }
+    }
+
+    public void init(FilterConfig config) throws ServletException {
+        LOG.info("init()");
+    }
+}
diff --git a/trunk/samples/security_filter/src/main/java/org/apache/cxf/dosgi/samples/security/SecureRestEndpoint.java b/trunk/samples/security_filter/src/main/java/org/apache/cxf/dosgi/samples/security/SecureRestEndpoint.java
new file mode 100644
index 0000000..8c066ac
--- /dev/null
+++ b/trunk/samples/security_filter/src/main/java/org/apache/cxf/dosgi/samples/security/SecureRestEndpoint.java
@@ -0,0 +1,35 @@
+/**
+ * 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.samples.security;
+
+import javax.ws.rs.GET;
+import javax.ws.rs.Path;
+import javax.ws.rs.Produces;
+import javax.ws.rs.core.MediaType;
+
+@Path("/")
+public class SecureRestEndpoint {
+
+    @GET
+    @Path("hello")
+    @Produces(MediaType.TEXT_PLAIN)
+    public String sayHello() {
+        return "Hello and congratulations, you made it past the security filter";
+    }
+}
diff --git a/trunk/samples/spring_dm/client/pom.xml b/trunk/samples/spring_dm/client/pom.xml
new file mode 100644
index 0000000..9f689e4
--- /dev/null
+++ b/trunk/samples/spring_dm/client/pom.xml
@@ -0,0 +1,60 @@
+<?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>
+  <groupId>org.apache.cxf.dosgi.samples</groupId>
+  <artifactId>cxf-dosgi-ri-samples-spring-dm-client</artifactId>
+  <packaging>bundle</packaging>
+  <name>Distributed OSGI Spring-DM Sample Client Bundle</name>
+  <version>1.6.0</version>
+
+  <parent>
+    <groupId>org.apache.cxf.dosgi.samples</groupId>
+    <artifactId>cxf-dosgi-ri-samples-spring-dm-parent</artifactId>
+    <version>1.6.0</version>
+  </parent>
+
+  <dependencies>
+    <dependency>
+      <groupId>org.apache.cxf.dosgi.samples</groupId>
+      <artifactId>cxf-dosgi-ri-samples-spring-dm-interface</artifactId>
+      <version>${project.version}</version>
+    </dependency>
+  </dependencies>
+
+  <build>
+    <plugins>
+      <plugin>
+        <groupId>org.apache.felix</groupId>
+        <artifactId>maven-bundle-plugin</artifactId>
+        <configuration>
+          <instructions>
+            <Bundle-Name>CXF Distributed OSGi Spring-DM Sample Client Bundle</Bundle-Name>
+            <Bundle-Description>The client-side implementation of the Distributed OSGi with Spring-DM sample</Bundle-Description>
+            <Bundle-SymbolicName>${project.artifactId}</Bundle-SymbolicName>
+            <Import-Package>org.apache.cxf.dosgi.samples.springdm</Import-Package>
+            <Private-Package>org.apache.cxf.dosgi.samples.springdm.client</Private-Package>
+          </instructions>
+        </configuration>
+      </plugin>
+    </plugins>
+  </build>
+</project>
diff --git a/trunk/samples/spring_dm/client/src/main/java/org/apache/cxf/dosgi/samples/springdm/client/DinnerServiceConsumer.java b/trunk/samples/spring_dm/client/src/main/java/org/apache/cxf/dosgi/samples/springdm/client/DinnerServiceConsumer.java
new file mode 100644
index 0000000..8fe34c8
--- /dev/null
+++ b/trunk/samples/spring_dm/client/src/main/java/org/apache/cxf/dosgi/samples/springdm/client/DinnerServiceConsumer.java
@@ -0,0 +1,38 @@
+/**
+ * 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.samples.springdm.client;
+
+import org.apache.cxf.dosgi.samples.springdm.DinnerService;
+import org.apache.cxf.dosgi.samples.springdm.Restaurant;
+
+public class DinnerServiceConsumer {
+
+    DinnerService dinnerService;
+
+    public void setDinnerService(DinnerService ds) {
+        dinnerService = ds;
+    }
+
+    public void start() {
+        System.out.println("Found the following restaurants:");
+        for (Restaurant r : dinnerService.findRestaurants("nice and not too expensive!")) {
+            System.out.format("  %s (%s) Rating: %d\n", r.getName(), r.getAddress(), r.getRating());
+        }
+    }
+}
diff --git a/trunk/samples/spring_dm/client/src/main/resources/META-INF/spring/client-spring.xml b/trunk/samples/spring_dm/client/src/main/resources/META-INF/spring/client-spring.xml
new file mode 100644
index 0000000..252df7b
--- /dev/null
+++ b/trunk/samples/spring_dm/client/src/main/resources/META-INF/spring/client-spring.xml
@@ -0,0 +1,31 @@
+<?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.
+-->
+<beans xmlns="http://www.springframework.org/schema/beans"
+  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+  xmlns:osgi="http://www.springframework.org/schema/osgi"
+  xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
+                      http://www.springframework.org/schema/osgi http://www.springframework.org/schema/osgi/spring-osgi.xsd">
+  <osgi:reference id="dinnerServiceRef" interface="org.apache.cxf.dosgi.samples.springdm.DinnerService"/>
+
+  <bean class="org.apache.cxf.dosgi.samples.springdm.client.DinnerServiceConsumer"
+        init-method="start">
+    <property name="dinnerService" ref="dinnerServiceRef"/>
+  </bean>
+</beans>
diff --git a/trunk/samples/spring_dm/client/src/main/resources/OSGI-INF/remote-service/remote-services.xml b/trunk/samples/spring_dm/client/src/main/resources/OSGI-INF/remote-service/remote-services.xml
new file mode 100644
index 0000000..19c44db
--- /dev/null
+++ b/trunk/samples/spring_dm/client/src/main/resources/OSGI-INF/remote-service/remote-services.xml
@@ -0,0 +1,29 @@
+<!--
+  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.
+-->
+<endpoint-descriptions xmlns="http://www.osgi.org/xmlns/rsa/v1.0.0">
+  <endpoint-description>
+    <property name="objectClass">
+      <array>
+        <value>org.apache.cxf.dosgi.samples.springdm.DinnerService</value>
+      </array>
+    </property>
+    <property name="endpoint.id">http://localhost:9000/org/apache/cxf/dosgi/samples/springdm/DinnerService</property>
+    <property name="service.imported.configs">org.apache.cxf.ws</property>
+  </endpoint-description>
+</endpoint-descriptions>
diff --git a/trunk/samples/spring_dm/impl/pom.xml b/trunk/samples/spring_dm/impl/pom.xml
new file mode 100644
index 0000000..9571883
--- /dev/null
+++ b/trunk/samples/spring_dm/impl/pom.xml
@@ -0,0 +1,60 @@
+<?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>
+  <groupId>org.apache.cxf.dosgi.samples</groupId>
+  <artifactId>cxf-dosgi-ri-samples-spring-dm-impl</artifactId>
+  <packaging>bundle</packaging>
+  <name>Distributed OSGI Spring-DM Sample Implementation Bundle</name>
+  <version>1.6.0</version>
+
+  <parent>
+    <groupId>org.apache.cxf.dosgi.samples</groupId>
+    <artifactId>cxf-dosgi-ri-samples-spring-dm-parent</artifactId>
+    <version>1.6.0</version>
+  </parent>
+
+  <dependencies>
+    <dependency>
+      <groupId>org.apache.cxf.dosgi.samples</groupId>
+      <artifactId>cxf-dosgi-ri-samples-spring-dm-interface</artifactId>
+      <version>${project.version}</version>
+    </dependency>
+  </dependencies>
+
+  <build>
+    <plugins>
+      <plugin>
+        <groupId>org.apache.felix</groupId>
+        <artifactId>maven-bundle-plugin</artifactId>
+        <configuration>
+          <instructions>
+            <Bundle-Name>CXF Distributed OSGi Spring-DM Sample Implementation Bundle</Bundle-Name>
+            <Bundle-Description>The server-side implementation of the Distributed OSGi with Spring-DM sample</Bundle-Description>
+            <Bundle-SymbolicName>${project.artifactId}</Bundle-SymbolicName>
+            <Import-Package>org.apache.cxf.dosgi.samples.springdm</Import-Package>
+            <Private-Package>org.apache.cxf.dosgi.samples.springdm.impl</Private-Package>
+          </instructions>
+        </configuration>
+      </plugin>
+    </plugins>
+  </build>
+</project>
diff --git a/trunk/samples/spring_dm/impl/src/main/java/org/apache/cxf/dosgi/samples/springdm/impl/DinnerServiceImpl.java b/trunk/samples/spring_dm/impl/src/main/java/org/apache/cxf/dosgi/samples/springdm/impl/DinnerServiceImpl.java
new file mode 100644
index 0000000..e98e192
--- /dev/null
+++ b/trunk/samples/spring_dm/impl/src/main/java/org/apache/cxf/dosgi/samples/springdm/impl/DinnerServiceImpl.java
@@ -0,0 +1,39 @@
+/**
+ * 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.samples.springdm.impl;
+
+import java.util.Arrays;
+import java.util.List;
+
+import org.apache.cxf.dosgi.samples.springdm.DinnerService;
+import org.apache.cxf.dosgi.samples.springdm.Restaurant;
+
+public class DinnerServiceImpl implements DinnerService {
+
+    List<Restaurant> restaurants = Arrays.asList(
+        new Restaurant("Jojo's", "1 food way", 3),
+        new Restaurant("Boohaa's", "95 forage ave", 1),
+        new Restaurant("MicMac", "Plastic Plaza", 1)
+    );
+
+    public List<Restaurant> findRestaurants(String query) {
+        System.out.println("Hey! Someone's using the Dinner Service! Query: " + query);
+        return restaurants;
+    }
+}
diff --git a/trunk/samples/spring_dm/impl/src/main/resources/META-INF/spring/spring.xml b/trunk/samples/spring_dm/impl/src/main/resources/META-INF/spring/spring.xml
new file mode 100644
index 0000000..7c798c4
--- /dev/null
+++ b/trunk/samples/spring_dm/impl/src/main/resources/META-INF/spring/spring.xml
@@ -0,0 +1,32 @@
+<?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.
+-->
+<beans xmlns="http://www.springframework.org/schema/beans"
+  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+  xmlns:osgi="http://www.springframework.org/schema/osgi"
+  xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
+                      http://www.springframework.org/schema/osgi http://www.springframework.org/schema/osgi/spring-osgi.xsd">
+  <osgi:service interface="org.apache.cxf.dosgi.samples.springdm.DinnerService">
+    <osgi:service-properties>
+      <entry key="service.exported.interfaces" value="*" />
+    </osgi:service-properties>
+
+    <bean class="org.apache.cxf.dosgi.samples.springdm.impl.DinnerServiceImpl" />
+  </osgi:service>
+</beans>
diff --git a/trunk/samples/spring_dm/interface/pom.xml b/trunk/samples/spring_dm/interface/pom.xml
new file mode 100644
index 0000000..4c2dd88
--- /dev/null
+++ b/trunk/samples/spring_dm/interface/pom.xml
@@ -0,0 +1,52 @@
+<?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>
+  <groupId>org.apache.cxf.dosgi.samples</groupId>
+  <artifactId>cxf-dosgi-ri-samples-spring-dm-interface</artifactId>
+  <packaging>bundle</packaging>
+  <name>Distributed OSGI Spring-DM Sample Interface Bundle</name>
+  <version>1.6.0</version>
+
+  <parent>
+    <groupId>org.apache.cxf.dosgi.samples</groupId>
+    <artifactId>cxf-dosgi-ri-samples-spring-dm-parent</artifactId>
+    <version>1.6.0</version>
+  </parent>
+
+  <build>
+    <plugins>
+      <plugin>
+        <groupId>org.apache.felix</groupId>
+        <artifactId>maven-bundle-plugin</artifactId>
+        <configuration>
+          <instructions>
+            <Bundle-Name>CXF Distributed OSGi Spring-DM Sample Interface Bundle</Bundle-Name>
+            <Bundle-Description>The interfaces of the Distributed OSGi with Spring-DM sample</Bundle-Description>
+            <Bundle-SymbolicName>${project.artifactId}</Bundle-SymbolicName>
+            <Import-Package />
+            <Export-Package>org.apache.cxf.dosgi.samples.springdm</Export-Package>
+          </instructions>
+        </configuration>
+      </plugin>
+    </plugins>
+  </build>
+</project>
diff --git a/trunk/samples/spring_dm/interface/src/main/java/org/apache/cxf/dosgi/samples/springdm/DinnerService.java b/trunk/samples/spring_dm/interface/src/main/java/org/apache/cxf/dosgi/samples/springdm/DinnerService.java
new file mode 100644
index 0000000..da296b3
--- /dev/null
+++ b/trunk/samples/spring_dm/interface/src/main/java/org/apache/cxf/dosgi/samples/springdm/DinnerService.java
@@ -0,0 +1,25 @@
+/**
+ * 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.samples.springdm;
+
+import java.util.List;
+
+public interface DinnerService {
+    List<Restaurant> findRestaurants(String searchQuery);
+}
diff --git a/trunk/samples/spring_dm/interface/src/main/java/org/apache/cxf/dosgi/samples/springdm/Restaurant.java b/trunk/samples/spring_dm/interface/src/main/java/org/apache/cxf/dosgi/samples/springdm/Restaurant.java
new file mode 100644
index 0000000..f6f06b1
--- /dev/null
+++ b/trunk/samples/spring_dm/interface/src/main/java/org/apache/cxf/dosgi/samples/springdm/Restaurant.java
@@ -0,0 +1,59 @@
+/**
+ * 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.samples.springdm;
+
+public class Restaurant {
+
+    private String name;
+    private String address;
+    private int rating;
+
+    public Restaurant() {
+    }
+
+    public Restaurant(String name, String address, int rating) {
+        this.name = name;
+        this.address = address;
+        this.rating = rating;
+    }
+
+    public String getAddress() {
+        return address;
+    }
+
+    public String getName() {
+        return name;
+    }
+
+    public int getRating() {
+        return rating;
+    }
+
+    public void setName(String name) {
+        this.name = name;
+    }
+
+    public void setAddress(String address) {
+        this.address = address;
+    }
+
+    public void setRating(int rating) {
+        this.rating = rating;
+    }
+}
diff --git a/trunk/samples/spring_dm/pom.xml b/trunk/samples/spring_dm/pom.xml
new file mode 100644
index 0000000..f40a8e6
--- /dev/null
+++ b/trunk/samples/spring_dm/pom.xml
@@ -0,0 +1,41 @@
+<?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>
+    <groupId>org.apache.cxf.dosgi.samples</groupId>
+    <artifactId>cxf-dosgi-ri-samples-spring-dm-parent</artifactId>
+    <packaging>pom</packaging>
+    <name>Distributed OSGI Spring-DM Sample</name>
+    <version>1.6.0</version>
+
+    <parent>
+      <groupId>org.apache.cxf.dosgi</groupId>
+      <artifactId>cxf-dosgi-ri-parent</artifactId>
+      <version>1.6.0</version>
+      <relativePath>../../parent/pom.xml</relativePath>
+    </parent>
+
+    <modules>
+      <module>interface</module>
+      <module>impl</module>
+      <module>client</module>
+    </modules>
+</project>
diff --git a/trunk/systests2/common/pom.xml b/trunk/systests2/common/pom.xml
new file mode 100644
index 0000000..5c9ef18
--- /dev/null
+++ b/trunk/systests2/common/pom.xml
@@ -0,0 +1,108 @@
+<?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.6.0</version>
+        <relativePath>../../parent/pom.xml</relativePath>
+    </parent>
+
+    <groupId>org.apache.cxf.dosgi.systests</groupId>
+    <artifactId>cxf-dosgi-ri-systests2-common</artifactId>
+    <packaging>bundle</packaging>
+
+    <name>Distributed OSGi System Tests Common Classes</name>
+
+    <dependencies>
+        <dependency>
+            <groupId>org.osgi</groupId>
+            <artifactId>org.osgi.core</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.osgi</groupId>
+            <artifactId>org.osgi.compendium</artifactId>
+        </dependency>
+
+        <dependency>
+           <groupId>org.ops4j.pax.tinybundles</groupId>
+           <artifactId>tinybundles</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.cxf</groupId>
+            <artifactId>cxf-rt-core</artifactId>
+            <version>${cxf.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.cxf</groupId>
+            <artifactId>cxf-rt-frontend-jaxws</artifactId>
+            <version>${cxf.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.cxf</groupId>
+            <artifactId>cxf-rt-databinding-aegis</artifactId>
+            <version>${cxf.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.cxf.dosgi.samples</groupId>
+            <artifactId>cxf-dosgi-ri-samples-greeter-impl</artifactId>
+            <version>${project.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.cxf.dosgi.samples</groupId>
+            <artifactId>cxf-dosgi-ri-samples-greeter-interface</artifactId>
+            <version>${project.version}</version>
+        </dependency>
+
+        <dependency>
+            <groupId>junit</groupId>
+            <artifactId>junit</artifactId>
+            <scope>provided</scope>
+        </dependency>
+    </dependencies>
+
+    <build>
+        <plugins>
+            <plugin>
+                <groupId>org.apache.felix</groupId>
+                <artifactId>maven-bundle-plugin</artifactId>
+                <extensions>true</extensions>
+                <configuration>
+                    <excludeDependencies>true</excludeDependencies>
+                    <instructions>
+                        <Bundle-Name>Bundle containing common code for the CXF DOSGi system tests</Bundle-Name>
+                        <Bundle-SymbolicName>${project.artifactId}</Bundle-SymbolicName>
+                        <Bundle-Vendor>The Apache Software Foundation</Bundle-Vendor>
+                        <!-- The TinyBundles are only used during the 'configure' stage and are therefore not
+                             needed at runtime.
+                             Other imports marked as optional as not all tests have the same dependencies. -->
+                        <Import-Package>
+                            !org.ops4j.pax.swissbox.tinybundles.*,
+                            *;resolution:=optional
+                        </Import-Package>
+                        <Export-Package>*</Export-Package>
+                    </instructions>
+                </configuration>
+            </plugin>
+        </plugins>
+    </build>
+</project>
diff --git a/trunk/systests2/common/src/main/java/org/apache/cxf/dosgi/systests2/common/test1/GreeterDataImpl.java b/trunk/systests2/common/src/main/java/org/apache/cxf/dosgi/systests2/common/test1/GreeterDataImpl.java
new file mode 100644
index 0000000..31f2988
--- /dev/null
+++ b/trunk/systests2/common/src/main/java/org/apache/cxf/dosgi/systests2/common/test1/GreeterDataImpl.java
@@ -0,0 +1,39 @@
+/**
+ * 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.common.test1;
+
+import org.apache.cxf.dosgi.samples.greeter.GreeterData;
+
+public class GreeterDataImpl implements GreeterData {
+
+    public int getAge() {
+        // TODO Auto-generated method stub
+        return 0;
+    }
+
+    public String getName() {
+        // TODO Auto-generated method stub
+        return null;
+    }
+
+    public boolean isException() {
+        // TODO Auto-generated method stub
+        return false;
+    }
+}
diff --git a/trunk/systests2/common/src/main/java/org/apache/cxf/dosgi/systests2/common/test1/MyActivator.java b/trunk/systests2/common/src/main/java/org/apache/cxf/dosgi/systests2/common/test1/MyActivator.java
new file mode 100644
index 0000000..6740725
--- /dev/null
+++ b/trunk/systests2/common/src/main/java/org/apache/cxf/dosgi/systests2/common/test1/MyActivator.java
@@ -0,0 +1,45 @@
+/**
+ * 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.common.test1;
+
+import org.osgi.framework.BundleActivator;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.Filter;
+import org.osgi.util.tracker.ServiceTracker;
+
+public class MyActivator implements BundleActivator {
+
+    private ServiceTracker startTracker;
+    private ServiceTracker tracker;
+
+    public void start(final BundleContext bc) throws Exception {
+        Filter filter = bc.createFilter("(&(objectClass=java.lang.Object)(testName=test1))");
+        tracker = new MyServiceTracker(bc);
+
+        // The start tracker waits until a service from the test class is set before the
+        // 'MyServiceTracker' is activated.
+        startTracker = new StartServiceTracker(bc, filter, tracker);
+        startTracker.open();
+    }
+
+    public void stop(BundleContext bc) throws Exception {
+        startTracker.close();
+        tracker.close();
+    }
+}
diff --git a/trunk/systests2/common/src/main/java/org/apache/cxf/dosgi/systests2/common/test1/MyServiceTracker.java b/trunk/systests2/common/src/main/java/org/apache/cxf/dosgi/systests2/common/test1/MyServiceTracker.java
new file mode 100644
index 0000000..8cc1e42
--- /dev/null
+++ b/trunk/systests2/common/src/main/java/org/apache/cxf/dosgi/systests2/common/test1/MyServiceTracker.java
@@ -0,0 +1,77 @@
+/**
+ * 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.common.test1;
+
+import java.util.Dictionary;
+import java.util.Hashtable;
+import java.util.Map;
+
+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.osgi.framework.BundleContext;
+import org.osgi.framework.ServiceReference;
+import org.osgi.util.tracker.ServiceTracker;
+
+public class MyServiceTracker extends ServiceTracker {
+
+    private static StringBuffer invocationResult = new StringBuffer();
+
+    public MyServiceTracker(BundleContext context) {
+        super(context, GreeterService.class.getName(), null);
+    }
+
+    public Object addingService(ServiceReference reference) {
+        Object svc = super.addingService(reference);
+        if (svc instanceof GreeterService) {
+            System.out.println("[client] Got a GreeterService...");
+            invokeGreeter((GreeterService) svc);
+        }
+        return svc;
+    }
+
+    public static String getResult() {
+        return invocationResult.toString();
+    }
+
+    private void invokeGreeter(GreeterService svc) {
+        try {
+            Map<GreetingPhrase, String> result = svc.greetMe("OSGi");
+            for (Map.Entry<GreetingPhrase, String> e : result.entrySet()) {
+                GreetingPhrase key = e.getKey();
+                invocationResult.append(key.getPhrase());
+                invocationResult.append(e.getValue());
+            }
+            try {
+                svc.greetMe(new GreeterDataImpl());
+            } catch (GreeterException ex) {
+                invocationResult.append(";exception");
+            }
+            Dictionary<String, Object> props = new Hashtable<String, Object>();
+            props.put("result", invocationResult.toString());
+            props.put("testResult", "test1");
+
+            System.out.println("[client] Successfully invoked remote service. Registering test response service...");
+            context.registerService(String.class.getName(), "test1", props);
+        } catch (Exception x) {
+            System.err.println("[client] Error during remote service invocation:");
+            x.printStackTrace(System.err);
+        }
+    }
+}
\ No newline at end of file
diff --git a/trunk/systests2/common/src/main/java/org/apache/cxf/dosgi/systests2/common/test1/StartServiceTracker.java b/trunk/systests2/common/src/main/java/org/apache/cxf/dosgi/systests2/common/test1/StartServiceTracker.java
new file mode 100644
index 0000000..40319ec
--- /dev/null
+++ b/trunk/systests2/common/src/main/java/org/apache/cxf/dosgi/systests2/common/test1/StartServiceTracker.java
@@ -0,0 +1,41 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.cxf.dosgi.systests2.common.test1;
+
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.Filter;
+import org.osgi.framework.ServiceReference;
+import org.osgi.util.tracker.ServiceTracker;
+
+public class StartServiceTracker extends ServiceTracker {
+
+    private ServiceTracker tracker;
+
+    public StartServiceTracker(BundleContext context, Filter filter, ServiceTracker tracker) {
+        super(context, filter, null);
+        this.tracker = tracker;
+    }
+
+    @Override
+    public Object addingService(ServiceReference reference) {
+        System.out.println("Test object available, so starting the service client tracker...");
+        tracker.open();
+        return super.addingService(reference);
+    }
+}
diff --git a/trunk/systests2/common/src/main/java/org/apache/cxf/dosgi/systests2/common/test2/Test2Service.java b/trunk/systests2/common/src/main/java/org/apache/cxf/dosgi/systests2/common/test2/Test2Service.java
new file mode 100644
index 0000000..806cdc9
--- /dev/null
+++ b/trunk/systests2/common/src/main/java/org/apache/cxf/dosgi/systests2/common/test2/Test2Service.java
@@ -0,0 +1,23 @@
+/**
+ * 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.common.test2;
+
+public interface Test2Service {
+    String getRemoteStackTrace();
+}
diff --git a/trunk/systests2/common/src/main/java/org/apache/cxf/dosgi/systests2/common/test2/client/ClientActivator.java b/trunk/systests2/common/src/main/java/org/apache/cxf/dosgi/systests2/common/test2/client/ClientActivator.java
new file mode 100644
index 0000000..0efd943
--- /dev/null
+++ b/trunk/systests2/common/src/main/java/org/apache/cxf/dosgi/systests2/common/test2/client/ClientActivator.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.systests2.common.test2.client;
+
+import org.osgi.framework.BundleActivator;
+import org.osgi.framework.BundleContext;
+import org.osgi.util.tracker.ServiceTracker;
+
+public class ClientActivator implements BundleActivator {
+
+    private ServiceTracker tracker;
+
+    public void start(final BundleContext bc) throws Exception {
+        tracker = new Test2ServiceTracker(bc);
+        tracker.open();
+    }
+
+    public void stop(BundleContext bc) throws Exception {
+        tracker.close();
+    }
+}
diff --git a/trunk/systests2/common/src/main/java/org/apache/cxf/dosgi/systests2/common/test2/client/Test2ServiceTracker.java b/trunk/systests2/common/src/main/java/org/apache/cxf/dosgi/systests2/common/test2/client/Test2ServiceTracker.java
new file mode 100644
index 0000000..5933e21
--- /dev/null
+++ b/trunk/systests2/common/src/main/java/org/apache/cxf/dosgi/systests2/common/test2/client/Test2ServiceTracker.java
@@ -0,0 +1,72 @@
+/**
+ * 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.common.test2.client;
+
+import java.util.Dictionary;
+import java.util.Hashtable;
+
+import org.apache.cxf.dosgi.systests2.common.test2.Test2Service;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.Filter;
+import org.osgi.framework.InvalidSyntaxException;
+import org.osgi.framework.ServiceReference;
+import org.osgi.util.tracker.ServiceTracker;
+
+public class Test2ServiceTracker extends ServiceTracker {
+
+    public Test2ServiceTracker(BundleContext context) {
+        super(context, getFilter(context), null);
+    }
+
+    private static Filter getFilter(BundleContext context) {
+        Filter f = null;
+        try {
+            // It's very important that the service.imported condition is there too
+            // otherwise the tracker will make a local 'direct' invocation on the service.
+            // The service.imported forces a proxy lookup.
+            f = context.createFilter("(&(objectClass=" + Test2Service.class.getName() + ")(service.imported=*))");
+        } catch (InvalidSyntaxException e) {
+            e.printStackTrace();
+        }
+        return f;
+    }
+
+    @Override
+    public Object addingService(ServiceReference reference) {
+        Object svc = super.addingService(reference);
+        if (svc instanceof Test2Service) {
+            System.out.println("*** Ref: " + reference);
+            for (String key : reference.getPropertyKeys()) {
+                System.out.println("  " + key + "-" + reference.getProperty(key));
+            }
+
+            invokeRemoteTestService(context, (Test2Service) svc);
+        }
+        return svc;
+    }
+
+    private void invokeRemoteTestService(BundleContext bc, Test2Service svc) {
+        String res = svc.getRemoteStackTrace();
+
+        Dictionary<String, Object> props = new Hashtable<String, Object>();
+        props.put("result", res);
+        props.put("testResult", "test2");
+        bc.registerService(String.class.getName(), "test2", props);
+    }
+}
diff --git a/trunk/systests2/common/src/main/java/org/apache/cxf/dosgi/systests2/common/test2/server/ServerActivator.java b/trunk/systests2/common/src/main/java/org/apache/cxf/dosgi/systests2/common/test2/server/ServerActivator.java
new file mode 100644
index 0000000..315b250
--- /dev/null
+++ b/trunk/systests2/common/src/main/java/org/apache/cxf/dosgi/systests2/common/test2/server/ServerActivator.java
@@ -0,0 +1,53 @@
+/**
+ * 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.common.test2.server;
+
+import java.net.ServerSocket;
+import java.util.Dictionary;
+import java.util.Hashtable;
+
+import org.apache.cxf.dosgi.systests2.common.test2.Test2Service;
+import org.osgi.framework.BundleActivator;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.ServiceRegistration;
+
+public class ServerActivator implements BundleActivator {
+
+    private ServiceRegistration reg;
+
+    public void start(BundleContext bc) throws Exception {
+        Test2Service svc = new Test2ServiceImpl();
+
+        // Dynamically assign a free port
+        int freePort = new ServerSocket(0).getLocalPort();
+        String url = "http://localhost:" + freePort + "/test2";
+        System.out.println("*** Server using URL: " + url);
+
+        Dictionary<String, Object> props = new Hashtable<String, Object>();
+        props.put("service.exported.interfaces", "*");
+        props.put("service.exported.configs", "org.apache.cxf.ws");
+        props.put("endpoint.id", url);
+
+        reg = bc.registerService(Test2Service.class.getName(), svc, props);
+    }
+
+    public void stop(BundleContext bc) throws Exception {
+        reg.unregister();
+    }
+}
diff --git a/trunk/systests2/common/src/main/java/org/apache/cxf/dosgi/systests2/common/test2/server/Test2ServiceImpl.java b/trunk/systests2/common/src/main/java/org/apache/cxf/dosgi/systests2/common/test2/server/Test2ServiceImpl.java
new file mode 100644
index 0000000..c03f572
--- /dev/null
+++ b/trunk/systests2/common/src/main/java/org/apache/cxf/dosgi/systests2/common/test2/server/Test2ServiceImpl.java
@@ -0,0 +1,36 @@
+/**
+ * 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.common.test2.server;
+
+import java.io.PrintWriter;
+import java.io.StringWriter;
+
+import org.apache.cxf.dosgi.systests2.common.test2.Test2Service;
+
+public class Test2ServiceImpl implements Test2Service {
+
+    public String getRemoteStackTrace() {
+        Throwable th = new Throwable("Throwable created on the server");
+        StringWriter sw = new StringWriter();
+        PrintWriter pw = new PrintWriter(sw);
+        th.printStackTrace(pw);
+
+        return sw.toString();
+    }
+}
diff --git a/trunk/systests2/common/src/main/resources/rs-test1.xml b/trunk/systests2/common/src/main/resources/rs-test1.xml
new file mode 100644
index 0000000..7392d24
--- /dev/null
+++ b/trunk/systests2/common/src/main/resources/rs-test1.xml
@@ -0,0 +1,28 @@
+<?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.
+  -->
+<endpoint-descriptions xmlns="http://www.osgi.org/xmlns/rsa/v1.0.0"
+  xmlns:other="http://www.acme.org/xmlns/other/v1.0.0">
+  <endpoint-description>
+    <property name="objectClass">
+      <array>
+        <value>org.apache.cxf.dosgi.samples.greeter.GreeterService</value>
+      </array>
+    </property>
+    <property name="endpoint.id">http://localhost:9191/grrr</property>
+    <property name="service.imported.configs">org.apache.cxf.ws</property>
+  </endpoint-description>
+</endpoint-descriptions>
+
diff --git a/trunk/systests2/multi-bundle/pom.xml b/trunk/systests2/multi-bundle/pom.xml
new file mode 100644
index 0000000..cafdd73
--- /dev/null
+++ b/trunk/systests2/multi-bundle/pom.xml
@@ -0,0 +1,258 @@
+<?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.6.0</version>
+        <relativePath>../../parent/pom.xml</relativePath>
+    </parent>
+
+    <groupId>org.apache.cxf.dosgi.systests</groupId>
+    <artifactId>cxf-dosgi-ri-systests2-multibundle</artifactId>
+    <packaging>jar</packaging>
+
+    <name>Distributed OSGi System Tests Multi-Bundle</name>
+    
+    <!-- 
+        When changing code make sure to run the distro before testing
+        or you will be testing the old code.
+     
+     -->
+
+    <dependencies>
+        <dependency>
+            <groupId>org.apache.geronimo.specs</groupId>
+            <artifactId>geronimo-atinject_1.0_spec</artifactId>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.ops4j.pax.exam</groupId>
+            <artifactId>pax-exam-junit4</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.ops4j.pax.exam</groupId>
+            <artifactId>pax-exam-inject</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.ops4j.pax.exam</groupId>
+            <artifactId>pax-exam-container-forked</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.ops4j.pax.exam</groupId>
+            <artifactId>pax-exam-link-mvn</artifactId>
+            <scope>test</scope>
+        </dependency>
+        
+        <dependency>
+            <groupId>org.ops4j.pax.url</groupId>
+            <artifactId>pax-url-aether</artifactId>
+            <version>1.6.0</version>
+        </dependency>
+
+        <dependency>
+            <groupId>org.eclipse</groupId>
+            <artifactId>org.eclipse.osgi</artifactId>
+        </dependency>
+        <!-- 
+        <dependency>
+            <groupId>org.apache.felix</groupId>
+            <artifactId>org.apache.felix.framework</artifactId>
+            <scope>test</scope>
+        </dependency>
+         -->
+
+        <dependency>
+            <groupId>org.apache.cxf.dosgi.systests</groupId>
+            <artifactId>cxf-dosgi-ri-systests2-common</artifactId>
+            <version>${project.version}</version>
+            <scope>test</scope>
+        </dependency>
+
+        <dependency>
+            <groupId>org.apache.cxf</groupId>
+            <artifactId>cxf-api</artifactId>
+            <version>${cxf.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.cxf</groupId>
+            <artifactId>cxf-rt-core</artifactId>
+            <version>${cxf.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.cxf</groupId>
+            <artifactId>cxf-rt-bindings-soap</artifactId>
+            <version>${cxf.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.cxf</groupId>
+            <artifactId>cxf-rt-transports-http-jetty</artifactId>
+            <version>${cxf.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.cxf</groupId>
+            <artifactId>cxf-rt-frontend-jaxrs</artifactId>
+            <version>${cxf.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.zookeeper</groupId>
+            <artifactId>zookeeper</artifactId>
+            <version>${zookeeper.version}</version>
+            <exclusions>
+                <exclusion>
+                    <groupId>com.sun.jdmk</groupId>
+                    <artifactId>jmxtools</artifactId>
+                </exclusion>
+                <exclusion>
+                    <groupId>com.sun.jmx</groupId>
+                    <artifactId>jmxri</artifactId>
+                </exclusion>
+                <exclusion>
+                    <groupId>log4j</groupId>
+                    <artifactId>log4j</artifactId>
+                </exclusion>
+            </exclusions>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.cxf.dosgi</groupId>
+            <artifactId>cxf-dosgi-ri-discovery-distributed-zookeeper-server</artifactId>
+            <version>${project.version}</version>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.cxf.dosgi.samples</groupId>
+            <artifactId>cxf-dosgi-ri-samples-greeter-impl</artifactId>
+            <version>${project.version}</version>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.cxf.dosgi.samples</groupId>
+            <artifactId>cxf-dosgi-ri-samples-greeter-interface</artifactId>
+            <version>${project.version}</version>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.cxf.dosgi.samples</groupId>
+            <artifactId>cxf-dosgi-ri-samples-greeter-rest-impl</artifactId>
+            <version>${project.version}</version>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.cxf.dosgi.samples</groupId>
+            <artifactId>cxf-dosgi-ri-samples-greeter-rest-interface</artifactId>
+            <version>${project.version}</version>
+            <scope>test</scope>
+        </dependency>
+
+        <dependency>
+            <groupId>junit</groupId>
+            <artifactId>junit</artifactId>
+            <scope>test</scope>
+        </dependency>
+        
+        <dependency>
+        	<groupId>org.apache.cxf.services.xkms</groupId>
+        	<artifactId>cxf-services-xkms-features</artifactId>
+        	<version>${cxf.version}</version>
+        	<type>xml</type>
+        </dependency>
+        <dependency>
+        	<groupId>org.apache.cxf.services.xkms</groupId>
+        	<artifactId>cxf-services-xkms-common</artifactId>
+        	<version>${cxf.version}</version>
+        	<scope>test</scope>
+        </dependency>
+        <dependency>
+        	<groupId>org.apache.cxf.services.xkms</groupId>
+        	<artifactId>cxf-services-xkms-client</artifactId>
+        	<version>${cxf.version}</version>
+        	<scope>test</scope>
+        </dependency>
+    </dependencies>
+
+    <build>
+        <plugins>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-dependency-plugin</artifactId>
+                <executions>
+                    <execution>
+                        <id>unpack</id>
+                        <phase>generate-resources</phase>
+                        <goals>
+                            <goal>unpack</goal>
+                        </goals>
+                        <configuration>
+                            <artifactItems>
+                                <artifactItem>
+                                    <groupId>org.apache.cxf.dosgi</groupId>
+                                    <artifactId>cxf-dosgi-ri-multibundle-distribution</artifactId>
+                                    <version>${project.version}</version>
+                                    <type>zip</type>
+                                    <classifier>dir</classifier>
+                                </artifactItem>
+                            </artifactItems>
+                        </configuration>
+                    </execution>
+                </executions>
+            </plugin>
+
+            <!-- use pax exam maven plugin -->
+
+            <!-- Note: settings and dependencies for the final osgi runtime 
+                (TESTS) are just used in TestCases that annotated with this: @RunWith( MavenConfiguredJUnit4TestRunner.class 
+                ) All other testcases will use their own settings/provisioning inside @Configure 
+                Methods. -->
+            <plugin>
+                <groupId>org.ops4j.pax.exam</groupId>
+                <artifactId>maven-paxexam-plugin</artifactId>
+                <executions>
+                    <execution>
+                        <id>generate-config</id>
+                        <goals>
+                            <goal>generate-config</goal>
+                            <goal>generate-depends-file</goal>
+                        </goals>
+                    </execution>
+                </executions>
+                <configuration>
+                    <options>
+                        <platform>equinox</platform>
+                        <profiles>log</profiles>
+                    </options>
+                </configuration>
+            </plugin>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-surefire-plugin</artifactId>
+                <configuration>
+                    <systemPropertyVariables>
+                        <!-- <org.apache.cxf.dosgi.test.debug.port>5005</org.apache.cxf.dosgi.test.debug.port> 
+                            <org.apache.cxf.dosgi.test.serviceWaitTimeout>180</org.apache.cxf.dosgi.test.serviceWaitTimeout> -->
+                        <java.util.logging.config.file>${project.build.directory}/test-classes/logging.properties</java.util.logging.config.file>
+                    </systemPropertyVariables>
+                </configuration>
+            </plugin>
+        </plugins>
+    </build>
+</project>
diff --git a/trunk/systests2/multi-bundle/src/test/java/org/apache/cxf/dosgi/systests2/multi/AbstractDosgiTest.java b/trunk/systests2/multi-bundle/src/test/java/org/apache/cxf/dosgi/systests2/multi/AbstractDosgiTest.java
new file mode 100644
index 0000000..4f4f9ea
--- /dev/null
+++ b/trunk/systests2/multi-bundle/src/test/java/org/apache/cxf/dosgi/systests2/multi/AbstractDosgiTest.java
@@ -0,0 +1,157 @@
+/**
+ * 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.ConnectException;
+import java.net.HttpURLConnection;
+import java.net.InetSocketAddress;
+import java.net.MalformedURLException;
+import java.net.ServerSocket;
+import java.net.Socket;
+import java.net.URL;
+import java.util.Collection;
+import java.util.concurrent.TimeoutException;
+
+import org.apache.cxf.aegis.databinding.AegisDatabinding;
+import org.apache.cxf.dosgi.samples.greeter.GreeterService;
+import org.apache.cxf.frontend.ClientProxyFactoryBean;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.ServiceReference;
+
+public class AbstractDosgiTest {
+
+    private static final int TIMEOUT = 20;
+
+    /**
+     * Sleeps for a short interval, throwing an exception if timeout has been reached.
+     * Used to facilitate a retry interval with timeout when used in a loop.
+     *
+     * @param startTime the start time of the entire operation in milliseconds
+     * @param timeout the timeout duration for the entire operation in seconds
+     * @param message the error message to use when timeout occurs
+     * @throws InterruptedException if interrupted while sleeping
+     */
+    private static void sleepOrTimeout(long startTime, long timeout, String message) throws
+            InterruptedException, TimeoutException {
+        timeout *= 1000; // seconds to millis
+        long elapsed = System.currentTimeMillis() - startTime;
+        long remaining = timeout - elapsed;
+        if (remaining <= 0) {
+            throw new TimeoutException(message);
+        }
+        long interval = Math.min(remaining, 1000);
+        Thread.sleep(interval);
+    }
+
+    @SuppressWarnings({
+        "rawtypes", "unchecked"
+    })
+    protected ServiceReference waitService(BundleContext bc, Class cls, String filter, int timeout)
+        throws Exception {
+        System.out.println("Waiting for service: " + cls + " " + filter);
+        long startTime = System.currentTimeMillis();
+        while (true) {
+            Collection refs = bc.getServiceReferences(cls, filter);
+            if (refs != null && refs.size() > 0) {
+                return (ServiceReference)refs.iterator().next();
+            }
+            sleepOrTimeout(startTime, timeout, "Service not found: " + cls + " " + filter);
+        }
+    }
+
+    protected void waitPort(int port) throws Exception {
+        System.out.println("Waiting for server to appear on port: " + port);
+        long startTime = System.currentTimeMillis();
+        while (true) {
+            Socket s = null;
+            try {
+                s = new Socket((String)null, port);
+                // yep, its available
+                return;
+            } catch (IOException e) {
+                sleepOrTimeout(startTime, TIMEOUT, "Timeout waiting for port " + port);
+            } finally {
+                if (s != null) {
+                    try {
+                        s.close();
+                    } catch (IOException e) {
+                        // ignore
+                    }
+                }
+            }
+        }
+    }
+
+    protected GreeterService createGreeterServiceProxy(String serviceUri) {
+        ClientProxyFactoryBean factory = new ClientProxyFactoryBean();
+        factory.setServiceClass(GreeterService.class);
+        factory.setAddress(serviceUri);
+        factory.getServiceFactory().setDataBinding(new AegisDatabinding());
+        return (GreeterService)factory.create();
+    }
+
+    protected Bundle getBundleByName(BundleContext bc, String name) {
+        for (Bundle bundle : bc.getBundles()) {
+            if (bundle.getSymbolicName().equals(name)) {
+                return bundle;
+            }
+        }
+        return null;
+    }
+
+    protected int getFreePort() throws IOException {
+        ServerSocket socket = new ServerSocket();
+        try {
+            socket.setReuseAddress(true); // enables quickly reopening socket on same port
+            socket.bind(new InetSocketAddress(0)); // zero finds a free port
+            return socket.getLocalPort();
+        } finally {
+            socket.close();
+        }
+    }
+
+    protected void waitWebPage(String urlSt) throws InterruptedException, TimeoutException {
+        System.out.println("Waiting for url " + urlSt);
+        HttpURLConnection con = null;
+        long startTime = System.currentTimeMillis();
+        while (true) {
+            try {
+                URL url = new URL(urlSt);
+                con = (HttpURLConnection)url.openConnection();
+                int status = con.getResponseCode();
+                if (status == 200) {
+                    return;
+                }
+            } catch (ConnectException e) {
+                // Ignore connection refused
+            } catch (MalformedURLException e) {
+                throw new RuntimeException(e.getMessage(), e);
+            } catch (IOException e) {
+                throw new RuntimeException(e.getMessage(), e);
+            } finally {
+                if (con != null) {
+                    con.disconnect();
+                }
+            }
+            sleepOrTimeout(startTime, TIMEOUT, "Timeout waiting for web page " + urlSt);
+        }
+    }
+}
diff --git a/trunk/systests2/multi-bundle/src/test/java/org/apache/cxf/dosgi/systests2/multi/MultiBundleTools.java b/trunk/systests2/multi-bundle/src/test/java/org/apache/cxf/dosgi/systests2/multi/MultiBundleTools.java
new file mode 100644
index 0000000..48e87ac
--- /dev/null
+++ b/trunk/systests2/multi-bundle/src/test/java/org/apache/cxf/dosgi/systests2/multi/MultiBundleTools.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.systests2.multi;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.net.URL;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+import java.util.Properties;
+import java.util.TreeMap;
+import java.util.jar.Attributes;
+import java.util.jar.JarInputStream;
+import java.util.jar.Manifest;
+
+import org.ops4j.pax.exam.CoreOptions;
+import org.ops4j.pax.exam.Option;
+
+public final class MultiBundleTools {
+
+    private MultiBundleTools() {
+    }
+    
+    private static Properties getProps(File distroDir) throws FileNotFoundException, IOException {
+        Properties p = new Properties();
+        File confFile = new File(distroDir, "conf/felix.config.properties.append");
+        p.load(new FileInputStream(confFile));
+        return p;
+    }
+
+    private static int getDistroBundles(File distroDir,
+                                        Properties props, 
+                                        Map<Integer, String> bundles) throws Exception {
+        int startLevel = Integer.parseInt(props.getProperty("org.osgi.framework.startlevel.beginning"));
+        for (int i = 0; i <= startLevel; i++) {
+            String val = props.getProperty("felix.auto.start." + i);
+            if (val != null) {
+                if (val.startsWith("file:")) {
+                    File fullDir = new File(distroDir, val.substring("file:".length()));
+                    bundles.put(i, fullDir.toURI().toASCIIString());
+                } else {
+                    if (!val.contains("org.osgi.compendium")) {
+                        // We're skipping that one as it's pulled in explicitly in the test
+                        bundles.put(i, val);
+                    }
+                }
+            }
+        }
+        return startLevel + 1; // Add 1 to start level to be on the safe side
+    }
+
+    private static File getRootDirectory() {
+        String resourceName = "/" + MultiBundleTools.class.getName().replace('.', '/') + ".class";
+        URL curURL = MultiBundleTools.class.getResource(resourceName);
+        File curFile = new File(curURL.getFile());
+        String curString = curFile.getAbsolutePath();
+        File curBase = new File(curString.substring(0, curString.length() - resourceName.length()));
+        return curBase.getParentFile().getParentFile();
+    }
+
+    private static Option[] getDistroBundleOptions() throws Exception {
+        Map<Integer, String> bundles = new TreeMap<Integer, String>();
+        File root = getRootDirectory();
+        File depRoot = new File(root, "target/dependency");
+        File distroDir = depRoot.listFiles()[0];
+        Properties props = getProps(distroDir);
+        getDistroBundles(distroDir, props, bundles);
+        List<Option> opts = new ArrayList<Option>();
+        
+        /*
+        String sysPackagesValue = props.getProperty("org.osgi.framework.system.packages");
+        opts.add(CoreOptions.frameworkProperty("org.osgi.framework.system.packages")
+                 .value(sysPackagesValue));
+        */
+
+        for (Map.Entry<Integer, String> entry : bundles.entrySet()) {
+            String bundleUri = entry.getValue();
+            URL bundleURL = new URL(bundleUri);
+            JarInputStream bundleJar = new JarInputStream(bundleURL.openStream());
+            Manifest manifest = bundleJar.getManifest();
+            Attributes host = manifest.getAttributes("Fragment-Host");
+            if (host != null) {
+                System.out.println(bundleUri);
+            }
+            bundleJar.close();
+            
+            opts.add(CoreOptions.bundle(bundleUri));
+        }
+        System.out.println(opts);
+        return opts.toArray(new Option[opts.size()]);
+    }
+
+    public static Option getDistroWithDiscovery() throws Exception {
+        return getDistro();
+    }
+
+    public static Option getDistro() throws Exception {
+        return CoreOptions.composite(getDistroBundleOptions());
+    }
+}
diff --git a/trunk/systests2/multi-bundle/src/test/java/org/apache/cxf/dosgi/systests2/multi/TestCustomIntent.java b/trunk/systests2/multi-bundle/src/test/java/org/apache/cxf/dosgi/systests2/multi/TestCustomIntent.java
new file mode 100644
index 0000000..2200567
--- /dev/null
+++ b/trunk/systests2/multi-bundle/src/test/java/org/apache/cxf/dosgi/systests2/multi/TestCustomIntent.java
@@ -0,0 +1,110 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.cxf.dosgi.systests2.multi;
+
+import java.io.InputStream;
+import java.util.Map;
+
+import javax.inject.Inject;
+
+import junit.framework.Assert;
+
+import org.apache.cxf.dosgi.samples.greeter.GreeterService;
+import org.apache.cxf.dosgi.samples.greeter.GreetingPhrase;
+import org.apache.cxf.dosgi.systests2.multi.customintent.AddGreetingPhraseInterceptor;
+import org.apache.cxf.dosgi.systests2.multi.customintent.CustomFeature;
+import org.apache.cxf.dosgi.systests2.multi.customintent.CustomIntentActivator;
+import org.apache.cxf.dosgi.systests2.multi.customintent.service.EmptyGreeterService;
+import org.apache.cxf.dosgi.systests2.multi.customintent.service.GreeterServiceWithCustomIntentActivator;
+import org.apache.cxf.frontend.ClientProxyFactoryBean;
+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 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.streamBundle;
+import static org.ops4j.pax.exam.CoreOptions.systemProperty;
+
+@RunWith(PaxExam.class)
+public class TestCustomIntent extends AbstractDosgiTest {
+
+    @Inject
+    BundleContext bundleContext;
+
+    protected static InputStream getCustomIntentBundle() {
+        return TinyBundles.bundle()
+                .add(CustomIntentActivator.class)
+                .add(CustomFeature.class)
+                .add(AddGreetingPhraseInterceptor.class)
+                .set(Constants.BUNDLE_SYMBOLICNAME, "CustomIntent")
+                .set(Constants.BUNDLE_ACTIVATOR, CustomIntentActivator.class.getName()).build(TinyBundles.withBnd());
+    }
+
+    protected static InputStream getServiceBundle() {
+        return TinyBundles.bundle()
+                .add(GreeterServiceWithCustomIntentActivator.class)
+                .add(EmptyGreeterService.class)
+                .set(Constants.BUNDLE_SYMBOLICNAME, "EmptyGreeterService")
+                .set(Constants.BUNDLE_ACTIVATOR, GreeterServiceWithCustomIntentActivator.class.getName())
+                .build(TinyBundles.withBnd());
+    }
+
+    @Configuration
+    public static Option[] configure() throws Exception {
+        return new Option[] {
+                MultiBundleTools.getDistro(),
+                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.systests")
+                    .artifactId("cxf-dosgi-ri-systests2-common").versionAsInProject(),
+                streamBundle(getCustomIntentBundle()).noStart(),
+                provision(getServiceBundle()),
+                frameworkStartLevel(100) };
+    }
+
+    @Test
+    public void testCustomIntent() throws Exception {
+        // There should be warnings of unsatisfied intent myIntent in the log at debug level
+        Thread.sleep(2000);
+        getBundleByName(bundleContext, "CustomIntent").start();
+        waitPort(9090);
+
+        ClassLoader cl = Thread.currentThread().getContextClassLoader();
+        Thread.currentThread().setContextClassLoader(ClientProxyFactoryBean.class.getClassLoader());
+        try {
+            GreeterService greeterService = createGreeterServiceProxy("http://localhost:9090/greeter");
+            Map<GreetingPhrase, String> result = greeterService.greetMe("Chris");
+            Assert.assertEquals(1, result.size());
+            GreetingPhrase phrase = result.keySet().iterator().next();
+            Assert.assertEquals("Hi from custom intent", phrase.getPhrase());
+        } finally {
+            Thread.currentThread().setContextClassLoader(cl);
+        }
+    }
+}
diff --git a/trunk/systests2/multi-bundle/src/test/java/org/apache/cxf/dosgi/systests2/multi/TestDiscoveryExport.java b/trunk/systests2/multi-bundle/src/test/java/org/apache/cxf/dosgi/systests2/multi/TestDiscoveryExport.java
new file mode 100644
index 0000000..84cf342
--- /dev/null
+++ b/trunk/systests2/multi-bundle/src/test/java/org/apache/cxf/dosgi/systests2/multi/TestDiscoveryExport.java
@@ -0,0 +1,110 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.cxf.dosgi.systests2.multi;
+
+import java.io.IOException;
+import java.util.Dictionary;
+import java.util.Hashtable;
+
+import javax.inject.Inject;
+
+import junit.framework.Assert;
+
+import org.apache.zookeeper.ZooKeeper;
+import org.apache.zookeeper.data.Stat;
+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.osgi.framework.BundleContext;
+import org.osgi.service.cm.ConfigurationAdmin;
+
+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 TestDiscoveryExport extends AbstractDosgiTest {
+
+    private static final String GREETER_ZOOKEEPER_NODE
+        = "/osgi/service_registry/org/apache/cxf/dosgi/samples/greeter/GreeterService/localhost#9090##greeter";
+
+    @Inject
+    BundleContext bundleContext;
+
+    @Inject
+    ConfigurationAdmin configAdmin;
+
+    @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 testDiscoveryExport() throws Exception {
+        final int zkPort = getFreePort();
+        System.out.println("*** Port for ZooKeeper Server: " + zkPort);
+        updateZkServerConfig(zkPort, configAdmin);
+        updateZkClientConfig(zkPort, configAdmin);
+        ZooKeeper zk = new ZooKeeper("localhost:" + zkPort, 1000, null);
+        assertNodeExists(zk, GREETER_ZOOKEEPER_NODE, 14000);
+        zk.close();
+    }
+
+    private void assertNodeExists(ZooKeeper zk, String zNode, int timeout) {
+        long endTime = System.currentTimeMillis() + timeout;
+        Stat stat = null;
+        while (stat == null && System.currentTimeMillis() < endTime) {
+            try {
+                stat = zk.exists(zNode, null);
+                Thread.sleep(200);
+            } catch (Exception e) {
+                // Ignore
+            }
+        }
+        Assert.assertNotNull("ZooKeeper node " + zNode + " was not found", stat);
+    }
+
+    protected void updateZkClientConfig(final int zkPort, ConfigurationAdmin cadmin) throws IOException {
+        Dictionary<String, Object> cliProps = new Hashtable<String, Object>();
+        cliProps.put("zookeeper.host", "127.0.0.1");
+        cliProps.put("zookeeper.port", "" + zkPort);
+        cadmin.getConfiguration("org.apache.cxf.dosgi.discovery.zookeeper", null).update(cliProps);
+    }
+
+    protected void updateZkServerConfig(final int zkPort, ConfigurationAdmin cadmin) throws IOException {
+        Dictionary<String, Object> svrProps = new Hashtable<String, Object>();
+        svrProps.put("clientPort", zkPort);
+        cadmin.getConfiguration("org.apache.cxf.dosgi.discovery.zookeeper.server", null).update(svrProps);
+    }
+}
diff --git a/trunk/systests2/multi-bundle/src/test/java/org/apache/cxf/dosgi/systests2/multi/TestExportRestService.java b/trunk/systests2/multi-bundle/src/test/java/org/apache/cxf/dosgi/systests2/multi/TestExportRestService.java
new file mode 100644
index 0000000..3330c00
--- /dev/null
+++ b/trunk/systests2/multi-bundle/src/test/java/org/apache/cxf/dosgi/systests2/multi/TestExportRestService.java
@@ -0,0 +1,93 @@
+/**
+ * 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 javax.inject.Inject;
+
+import org.apache.cxf.dosgi.systests2.multi.rest.RestTranslate;
+import org.apache.cxf.dosgi.systests2.multi.rest.RestTranslateImpl;
+import org.apache.cxf.dosgi.systests2.multi.rest.TranslateActivator;
+import org.apache.cxf.jaxrs.client.WebClient;
+import org.junit.Assert;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.ops4j.pax.exam.Configuration;
+import org.ops4j.pax.exam.CoreOptions;
+import org.ops4j.pax.exam.Option;
+import org.ops4j.pax.exam.junit.PaxExam;
+import org.ops4j.pax.tinybundles.core.TinyBundles;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.Constants;
+
+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 TestExportRestService extends AbstractDosgiTest {
+
+    @Inject
+    BundleContext bundleContext;
+    
+    String webPort = "9091";
+
+    @Configuration
+    public Option[] configure() throws Exception {
+        return new Option[] {
+                MultiBundleTools.getDistroWithDiscovery(),
+                systemProperty("org.osgi.service.http.port").value(webPort),
+                systemProperty("org.ops4j.pax.logging.DefaultServiceLog.level").value("INFO"),
+                mavenBundle().groupId("org.apache.cxf.dosgi.samples")
+                    .artifactId("cxf-dosgi-ri-samples-greeter-interface").versionAsInProject(),
+                CoreOptions.junitBundles(),
+                provision(getServiceBundle()),
+                frameworkStartLevel(100),
+                //CoreOptions.vmOption("-Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=5005")
+        };
+    }
+    
+    private InputStream getServiceBundle() {
+        return TinyBundles.bundle()
+                .add(RestTranslate.class)
+                .add(RestTranslateImpl.class)
+                .add(TranslateActivator.class)
+                .set(Constants.BUNDLE_SYMBOLICNAME, "RestTranslate")
+                .set(Constants.BUNDLE_ACTIVATOR, TranslateActivator.class.getName())
+                .build(TinyBundles.withBnd());
+    }
+
+    /**
+     * FIXME This test fails.. 
+     */
+    @Test
+    public void testEndpointAvailable() throws Exception {
+        waitWebPage("http://localhost:" + webPort + "/cxf/translate");
+        try {
+            WebClient client = WebClient.create("http://localhost:" + webPort + "/cxf/translate/hello");
+            String result = client.get(String.class);
+            Assert.assertEquals("hallo", result);
+        } catch (Exception e) {
+            e.printStackTrace();
+            throw new RuntimeException(e.getMessage());
+        }
+    }
+}
diff --git a/trunk/systests2/multi-bundle/src/test/java/org/apache/cxf/dosgi/systests2/multi/TestExportService.java b/trunk/systests2/multi-bundle/src/test/java/org/apache/cxf/dosgi/systests2/multi/TestExportService.java
new file mode 100644
index 0000000..77248bc
--- /dev/null
+++ b/trunk/systests2/multi-bundle/src/test/java/org/apache/cxf/dosgi/systests2/multi/TestExportService.java
@@ -0,0 +1,141 @@
+/**
+ * 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.inject.Inject;
+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 org.osgi.framework.BundleContext;
+
+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 {
+
+    @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.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 {
+        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;
+        }
+    }
+}
diff --git a/trunk/systests2/multi-bundle/src/test/java/org/apache/cxf/dosgi/systests2/multi/TestImportService.java b/trunk/systests2/multi-bundle/src/test/java/org/apache/cxf/dosgi/systests2/multi/TestImportService.java
new file mode 100644
index 0000000..0f8b0b8
--- /dev/null
+++ b/trunk/systests2/multi-bundle/src/test/java/org/apache/cxf/dosgi/systests2/multi/TestImportService.java
@@ -0,0 +1,154 @@
+/**
+ * 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", "20")),
+                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
+        ServerFactoryBean factory = new ServerFactoryBean();
+        factory.setServiceClass(GreeterService.class);
+        factory.setAddress("http://localhost:9191/grrr");
+        factory.getServiceFactory().setDataBinding(new AegisDatabinding());
+        factory.setServiceBean(new TestGreeter());
+
+        Server server = null;
+        ClassLoader cl = Thread.currentThread().getContextClassLoader();
+        try {
+            Thread.currentThread().setContextClassLoader(ServerFactoryBean.class.getClassLoader());
+            server = factory.create();
+
+            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();
+            }
+            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");
+        }
+    }
+}
diff --git a/trunk/systests2/multi-bundle/src/test/java/org/apache/cxf/dosgi/systests2/multi/customintent/AddGreetingPhraseInterceptor.java b/trunk/systests2/multi-bundle/src/test/java/org/apache/cxf/dosgi/systests2/multi/customintent/AddGreetingPhraseInterceptor.java
new file mode 100644
index 0000000..a3a19be
--- /dev/null
+++ b/trunk/systests2/multi-bundle/src/test/java/org/apache/cxf/dosgi/systests2/multi/customintent/AddGreetingPhraseInterceptor.java
@@ -0,0 +1,44 @@
+/**
+ * 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);
+    }
+}
diff --git a/trunk/systests2/multi-bundle/src/test/java/org/apache/cxf/dosgi/systests2/multi/customintent/CustomFeature.java b/trunk/systests2/multi-bundle/src/test/java/org/apache/cxf/dosgi/systests2/multi/customintent/CustomFeature.java
new file mode 100644
index 0000000..abac14f
--- /dev/null
+++ b/trunk/systests2/multi-bundle/src/test/java/org/apache/cxf/dosgi/systests2/multi/customintent/CustomFeature.java
@@ -0,0 +1,33 @@
+/**
+ * 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);
+    }
+}
diff --git a/trunk/systests2/multi-bundle/src/test/java/org/apache/cxf/dosgi/systests2/multi/customintent/CustomIntentActivator.java b/trunk/systests2/multi-bundle/src/test/java/org/apache/cxf/dosgi/systests2/multi/customintent/CustomIntentActivator.java
new file mode 100644
index 0000000..ca4efda
--- /dev/null
+++ b/trunk/systests2/multi-bundle/src/test/java/org/apache/cxf/dosgi/systests2/multi/customintent/CustomIntentActivator.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.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 {
+    }
+}
diff --git a/trunk/systests2/multi-bundle/src/test/java/org/apache/cxf/dosgi/systests2/multi/customintent/service/EmptyGreeterService.java b/trunk/systests2/multi-bundle/src/test/java/org/apache/cxf/dosgi/systests2/multi/customintent/service/EmptyGreeterService.java
new file mode 100644
index 0000000..2c0108d
--- /dev/null
+++ b/trunk/systests2/multi-bundle/src/test/java/org/apache/cxf/dosgi/systests2/multi/customintent/service/EmptyGreeterService.java
@@ -0,0 +1,41 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.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>();
+    }
+}
diff --git a/trunk/systests2/multi-bundle/src/test/java/org/apache/cxf/dosgi/systests2/multi/customintent/service/GreeterServiceWithCustomIntentActivator.java b/trunk/systests2/multi-bundle/src/test/java/org/apache/cxf/dosgi/systests2/multi/customintent/service/GreeterServiceWithCustomIntentActivator.java
new file mode 100644
index 0000000..bcf6016
--- /dev/null
+++ b/trunk/systests2/multi-bundle/src/test/java/org/apache/cxf/dosgi/systests2/multi/customintent/service/GreeterServiceWithCustomIntentActivator.java
@@ -0,0 +1,42 @@
+/**
+ * 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 {
+    }
+}
diff --git a/trunk/systests2/multi-bundle/src/test/java/org/apache/cxf/dosgi/systests2/multi/rest/RestTranslate.java b/trunk/systests2/multi-bundle/src/test/java/org/apache/cxf/dosgi/systests2/multi/rest/RestTranslate.java
new file mode 100644
index 0000000..3a55c0e
--- /dev/null
+++ b/trunk/systests2/multi-bundle/src/test/java/org/apache/cxf/dosgi/systests2/multi/rest/RestTranslate.java
@@ -0,0 +1,34 @@
+/**
+ * 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);
+
+}
diff --git a/trunk/systests2/multi-bundle/src/test/java/org/apache/cxf/dosgi/systests2/multi/rest/RestTranslateImpl.java b/trunk/systests2/multi-bundle/src/test/java/org/apache/cxf/dosgi/systests2/multi/rest/RestTranslateImpl.java
new file mode 100644
index 0000000..640b0c9
--- /dev/null
+++ b/trunk/systests2/multi-bundle/src/test/java/org/apache/cxf/dosgi/systests2/multi/rest/RestTranslateImpl.java
@@ -0,0 +1,41 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.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);
+    }
+}
diff --git a/trunk/systests2/multi-bundle/src/test/java/org/apache/cxf/dosgi/systests2/multi/rest/TranslateActivator.java b/trunk/systests2/multi-bundle/src/test/java/org/apache/cxf/dosgi/systests2/multi/rest/TranslateActivator.java
new file mode 100644
index 0000000..1c48fb5
--- /dev/null
+++ b/trunk/systests2/multi-bundle/src/test/java/org/apache/cxf/dosgi/systests2/multi/rest/TranslateActivator.java
@@ -0,0 +1,40 @@
+/**
+ * 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 {
+    }
+}
diff --git a/trunk/systests2/multi-bundle/src/test/resources/log4j.properties b/trunk/systests2/multi-bundle/src/test/resources/log4j.properties
new file mode 100644
index 0000000..2f206d5
--- /dev/null
+++ b/trunk/systests2/multi-bundle/src/test/resources/log4j.properties
@@ -0,0 +1,13 @@
+# 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
diff --git a/trunk/systests2/pom.xml b/trunk/systests2/pom.xml
new file mode 100644
index 0000000..c357058
--- /dev/null
+++ b/trunk/systests2/pom.xml
@@ -0,0 +1,42 @@
+<?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.6.0</version>
+        <relativePath>../parent/pom.xml</relativePath>
+    </parent>
+
+    <groupId>org.apache.cxf.dosgi.systests</groupId>
+    <artifactId>cxf-dosgi-ri-systests2</artifactId>
+    <version>1.6.0</version>
+    <packaging>pom</packaging>
+
+    <name>Distributed OSGi System Tests</name>
+
+    <modules>
+        <module>common</module>
+        <module>multi-bundle</module>
+    </modules>
+</project>
diff --git a/trunk/tck/apply-to-tck.sh.template b/trunk/tck/apply-to-tck.sh.template
new file mode 100755
index 0000000..b6d4455
--- /dev/null
+++ b/trunk/tck/apply-to-tck.sh.template
@@ -0,0 +1,15 @@
+#This script pretends the current build to be the same as the version in the R5 TCK repo.
+#This puts the wrong version numbers on the files copied to the repo, so it could be improved
+#but it keeps changes to a minimum.
+#
+#Run this script before executing the CT tests to get the CT tests to run with the current CXF DOSGi build
+
+TCK_HOME=... the osgi build clone root directory...
+ZOOKEEPER_JAR=... the zookeeper server jar, can be obtained from a zookeeper download...
+cp $ZOOKEEPER_JAR $TCK_HOME/licensed/repo/org.apache.cxf.dosgi.discovery.zookeeper/org.apache.cxf.dosgi.discovery.zookeeper-1.2.0.jar
+
+cp org.osgi.impl.service.remoteserviceadmin-4.3.0.lib $TCK_HOME/cnf/repo/org.osgi.impl.service.remoteserviceadmin
+
+cp ../distribution/single-bundle/target/cxf-dosgi-ri-singlebundle-distribution-1.5-SNAPSHOT.jar $TCK_HOME/licensed/repo/org.apache.cxf.dosgi.singlebundle/org.apache.cxf.dosgi.singlebundle-1.3.1.jar
+cp ../discovery/distributed/zookeeper-server/target/cxf-dosgi-ri-discovery-distributed-zookeeper-server-1.5-SNAPSHOT.jar $TCK_HOME/licensed/repo/org.apache.cxf.dosgi.discovery.server/org.apache.cxf.dosgi.discovery.server-1.2.0.jar
+cp ../discovery/distributed/zookeeper-server-config/target/cxf-dosgi-ri-discovery-distributed-zookeeper-server-config-1.5-SNAPSHOT.jar $TCK_HOME/licensed/repo/org.apache.cxf.dosgi.discovery.server.config/org.apache.cxf.dosgi.discovery.server.config-1.2.0.jar
diff --git a/trunk/tck/org.osgi.impl.service.remoteserviceadmin-4.3.0.lib b/trunk/tck/org.osgi.impl.service.remoteserviceadmin-4.3.0.lib
new file mode 100644
index 0000000..66a532c
--- /dev/null
+++ b/trunk/tck/org.osgi.impl.service.remoteserviceadmin-4.3.0.lib
@@ -0,0 +1,5 @@
+org.apache.cxf.dosgi.singlebundle; version=1.3.1
+com.springsource.org.apache.log4j; version=1.2.15
+slf4j.api; version=1.6.1
+slf4j.nop; version=1.6.1
+