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

[47/50] [abbrv] aries-rsa git commit: Switching to aries package names

http://git-wip-us.apache.org/repos/asf/aries-rsa/blob/5f4c6604/rsa/src/main/java/org/apache/aries/rsa/core/RemoteServiceAdminCore.java
----------------------------------------------------------------------
diff --git a/rsa/src/main/java/org/apache/aries/rsa/core/RemoteServiceAdminCore.java b/rsa/src/main/java/org/apache/aries/rsa/core/RemoteServiceAdminCore.java
new file mode 100644
index 0000000..60da887
--- /dev/null
+++ b/rsa/src/main/java/org/apache/aries/rsa/core/RemoteServiceAdminCore.java
@@ -0,0 +1,590 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.aries.rsa.core;
+
+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.aries.rsa.spi.DistributionProvider;
+import org.apache.aries.rsa.spi.Endpoint;
+import org.apache.aries.rsa.util.EndpointHelper;
+import org.apache.aries.rsa.util.StringPlus;
+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 ServiceListener exportedServiceListener;
+    private DistributionProvider provider;
+    private BundleContext apictx;
+
+    public RemoteServiceAdminCore(BundleContext context, BundleContext apiContext, DistributionProvider provider) {
+        this.bctx = context;
+        this.apictx = apiContext;
+        this.eventProducer = new EventProducer(bctx);
+        this.provider = provider;
+        // 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 + "=*)";
+            context.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 = getProperties(serviceReference);
+        if (additionalProperties != null) {
+            overlayProperties(serviceProperties, additionalProperties);
+        }
+        Map<String, Object> key = makeKey(serviceProperties);
+
+        List<String> interfaceNames = getInterfaceNames(serviceProperties);
+
+        if (isImportedService(serviceReference)) {
+            return Collections.emptyList();
+        }
+
+        List<ExportRegistration> exportRegs = getExistingAndLock(key, interfaceNames);
+        if (exportRegs != null) {
+            return exportRegs;
+        }
+
+        try {
+            ExportRegistration exportReg = exportService(interfaceNames, serviceReference, serviceProperties);
+            exportRegs = new ArrayList<>();
+            exportRegs.add(exportReg);
+            store(key, exportRegs);
+            return exportRegs;
+        } finally {
+            unlock(key);
+        }
+    }
+
+    private void store(Map<String, Object> key, List<ExportRegistration> exportRegs) {
+        if (!exportRegs.isEmpty()) {
+            // enlist initial export registrations in global list of exportRegistrations
+            synchronized (exportedServices) {
+                exportedServices.put(key, new ArrayList<ExportRegistration>(exportRegs));
+            }
+            eventProducer.publishNotification(exportRegs);
+        }
+    }
+
+    private void unlock(Map<String, Object> key) {
+        synchronized (exportedServices) {
+            if (exportedServices.get(key) == exportInProgress) {
+                exportedServices.remove(key);
+            }
+            exportedServices.notifyAll(); // in any case, always notify waiting threads
+        }
+    }
+
+    private List<ExportRegistration> getExistingAndLock(Map<String, Object> key, List<String> interfaces) {
+        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);
+        }
+        return null;
+    }
+
+    private ExportRegistration exportService(List<String> interfaceNames,
+            ServiceReference<?> serviceReference, Map<String, Object> serviceProperties) {
+        LOG.info("interfaces selected for export: " + interfaceNames);
+        try {
+            Class<?>[] interfaces = getInterfaces(interfaceNames, serviceReference.getBundle());
+            Map<String, Object> eprops = createEndpointProps(serviceProperties, interfaces);
+            BundleContext serviceContext = serviceReference.getBundle().getBundleContext();
+            
+            // TODO unget service when export is destroyed
+            Object serviceO = serviceContext.getService(serviceReference);
+            Endpoint endpoint = provider.exportService(serviceO, serviceContext, eprops, interfaces);
+            return new ExportRegistrationImpl(serviceReference, endpoint, this);
+        } catch (Exception e) {
+            return new ExportRegistrationImpl(this, e);
+        }
+    }
+    
+    private Class<?>[] getInterfaces(List<String> interfaceNames, 
+                                         Bundle serviceBundle) throws ClassNotFoundException {
+        List<Class<?>> interfaces = new ArrayList<>();
+        for (String interfaceName : interfaceNames) {
+            interfaces.add(serviceBundle.loadClass(interfaceName));
+        }
+        return interfaces.toArray(new Class[]{});
+    }
+
+    /**
+     * 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> getInterfaceNames(Map<String, Object> serviceProperties) {
+        List<String> providedInterfaces = StringPlus.normalize(serviceProperties.get(org.osgi.framework.Constants.OBJECTCLASS));
+        if (providedInterfaces == null || providedInterfaces.isEmpty()) {
+            throw new IllegalArgumentException("service is missing the objectClass property");
+        }
+
+        List<String> exportedInterfaces
+            = StringPlus.normalize(serviceProperties.get(RemoteConstants.SERVICE_EXPORTED_INTERFACES));
+        if (exportedInterfaces == null || exportedInterfaces.isEmpty()) {
+            throw new IllegalArgumentException("service is missing the service.exported.interfaces property");
+        }
+
+        List<String> interfaces = new ArrayList<String>(1);
+        if (exportedInterfaces.size() == 1 && "*".equals(exportedInterfaces.get(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)
+            interfaces.addAll(providedInterfaces);
+        } else {
+            List<String> providedList = providedInterfaces;
+            List<String> allowedList = exportedInterfaces;
+            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));
+            }
+
+            interfaces.addAll(exportedInterfaces);
+        }
+        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 isImportedService(ServiceReference<?> sref) {
+        return sref.getProperty(RemoteConstants.SERVICE_IMPORTED) != 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;
+            }
+
+            if (determineConfigTypesForImport(endpoint).size() == 0) {
+                LOG.info("No matching handler can be found for remote endpoint {}.", endpoint.getId());
+                return null;
+            }
+            
+            // TODO: somehow select the interfaces that should be imported ---> job of the TopologyManager?
+            List<String> matchingInterfaces = endpoint.getInterfaces();
+            
+            if (matchingInterfaces.size() == 0) {
+                LOG.info("No matching interfaces found for remote endpoint {}.", endpoint.getId());
+                return null;
+            }
+            
+            LOG.info("Importing service {} with interfaces {} using handler {}.", 
+                     endpoint.getId(), endpoint.getInterfaces(), provider.getClass());
+
+            ImportRegistrationImpl imReg = exposeServiceFactory(matchingInterfaces.get(0), endpoint, provider);
+            if (imRegs == null) {
+                imRegs = new ArrayList<ImportRegistrationImpl>();
+                importedServices.put(endpoint, imRegs);
+            }
+            imRegs.add(imReg);
+            eventProducer.publishNotification(imReg);
+            return imReg;
+        }
+    }
+    
+    private List<String> determineConfigTypesForImport(EndpointDescription endpoint) {
+        List<String> remoteConfigurationTypes = endpoint.getConfigurationTypes();
+
+        List<String> usableConfigurationTypes = new ArrayList<String>();
+        for (String ct : provider.getSupportedTypes()) {
+            if (remoteConfigurationTypes.contains(ct)) {
+                usableConfigurationTypes.add(ct);
+            }
+        }
+
+        if (usableConfigurationTypes.size() == 0) {
+            LOG.info("Ignoring endpoint {} as it has no compatible configuration types: {}.",
+                 endpoint.getId(), remoteConfigurationTypes);
+        }
+        return usableConfigurationTypes;
+    }
+
+    protected ImportRegistrationImpl exposeServiceFactory(String interfaceName,
+                                            EndpointDescription epd,
+                                            DistributionProvider handler) {
+        ImportRegistrationImpl imReg = new ImportRegistrationImpl(epd, this);
+        try {
+            EndpointDescription endpoint = imReg.getImportedEndpointDescription();
+            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(endpoint, handler, imReg);
+            imReg.setClientServiceFactory(csf);
+            
+            /**
+             *  Export the factory using the api context as it has very few imports.
+             *  If the bundle publishing the factory does not import the service interface
+             *  package then the factory is visible for all consumers which we want.
+             */
+            ServiceRegistration<?> csfReg = apictx.registerService(interfaceName, csf, serviceProps);
+            imReg.setImportedServiceRegistration(csfReg);
+        } 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);
+        }
+        return imReg;
+    }
+
+    /**
+     * 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()) {
+                    ExportRegistration exportRegistration = regs.iterator().next();
+                    if (exportRegistration.getException() == null) {
+                        Bundle regBundle = exportRegistration.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);
+    }
+
+    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
+     */
+    private 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;
+    }
+    
+    protected Map<String, Object> createEndpointProps(Map<String, Object> effectiveProps, 
+                                                      Class<?>[] ifaces) {
+        Map<String, Object> props = new HashMap<String, Object>();
+        copyEndpointProperties(effectiveProps, props);
+        props.remove(org.osgi.framework.Constants.SERVICE_ID);
+        EndpointHelper.addObjectClass(props, ifaces);
+        props.put(RemoteConstants.ENDPOINT_SERVICE_ID, effectiveProps.get(org.osgi.framework.Constants.SERVICE_ID));
+        String frameworkUUID = bctx.getProperty(org.osgi.framework.Constants.FRAMEWORK_UUID);
+        props.put(RemoteConstants.ENDPOINT_FRAMEWORK_UUID, frameworkUUID);
+        for (Class<?> iface : ifaces) {
+            String pkg = iface.getPackage().getName();
+            props.put(RemoteConstants.ENDPOINT_PACKAGE_VERSION_ + pkg, PackageUtil.getVersion(iface, bctx));
+        }
+        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) {
+            String skey = entry.getKey();
+            if (!skey.startsWith(".")) {
+                endpointProps.put(skey, entry.getValue());
+            }
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/aries-rsa/blob/5f4c6604/rsa/src/main/java/org/apache/aries/rsa/core/RemoteServiceAdminInstance.java
----------------------------------------------------------------------
diff --git a/rsa/src/main/java/org/apache/aries/rsa/core/RemoteServiceAdminInstance.java b/rsa/src/main/java/org/apache/aries/rsa/core/RemoteServiceAdminInstance.java
new file mode 100644
index 0000000..1b1c8da
--- /dev/null
+++ b/rsa/src/main/java/org/apache/aries/rsa/core/RemoteServiceAdminInstance.java
@@ -0,0 +1,99 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.aries.rsa.core;
+
+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.osgi.framework.BundleContext;
+import org.osgi.framework.Constants;
+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;
+
+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) {
+        String frameworkUUID = bctx.getProperty(Constants.FRAMEWORK_UUID);
+        checkPermission(new EndpointPermission(endpoint, frameworkUUID, 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();
+        }
+    }
+
+    private void checkPermission(EndpointPermission permission) {
+        SecurityManager sm = System.getSecurityManager();
+        if (sm != null) {
+            sm.checkPermission(permission);
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/aries-rsa/blob/5f4c6604/rsa/src/main/java/org/apache/aries/rsa/core/RemoteServiceadminFactory.java
----------------------------------------------------------------------
diff --git a/rsa/src/main/java/org/apache/aries/rsa/core/RemoteServiceadminFactory.java b/rsa/src/main/java/org/apache/aries/rsa/core/RemoteServiceadminFactory.java
new file mode 100644
index 0000000..51abb65
--- /dev/null
+++ b/rsa/src/main/java/org/apache/aries/rsa/core/RemoteServiceadminFactory.java
@@ -0,0 +1,51 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.aries.rsa.core;
+
+import org.osgi.framework.Bundle;
+import org.osgi.framework.ServiceFactory;
+import org.osgi.framework.ServiceRegistration;
+import org.osgi.service.remoteserviceadmin.RemoteServiceAdmin;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class RemoteServiceadminFactory implements ServiceFactory<RemoteServiceAdmin> {
+
+    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 RemoteServiceAdmin getService(Bundle b, ServiceRegistration<RemoteServiceAdmin> 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<RemoteServiceAdmin> sreg,
+                                          RemoteServiceAdmin serviceObject) {
+        LOG.debug("RemoteServiceAdmin ServiceInstance removed for Bundle {}", b.getSymbolicName());
+        instances--;
+        ((RemoteServiceAdminInstance)serviceObject).close(instances == 0);
+    }
+}

http://git-wip-us.apache.org/repos/asf/aries-rsa/blob/5f4c6604/rsa/src/main/java/org/apache/cxf/dosgi/dsw/service/Activator.java
----------------------------------------------------------------------
diff --git a/rsa/src/main/java/org/apache/cxf/dosgi/dsw/service/Activator.java b/rsa/src/main/java/org/apache/cxf/dosgi/dsw/service/Activator.java
deleted file mode 100644
index 4c4d7ad..0000000
--- a/rsa/src/main/java/org/apache/cxf/dosgi/dsw/service/Activator.java
+++ /dev/null
@@ -1,37 +0,0 @@
-/**
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-package org.apache.cxf.dosgi.dsw.service;
-
-import org.osgi.framework.BundleActivator;
-import org.osgi.framework.BundleContext;
-
-public class Activator implements BundleActivator {
-
-    private DistributionProviderTracker tracker;
-
-    public void start(BundleContext bundlecontext) throws Exception {
-        tracker = new DistributionProviderTracker(bundlecontext);
-        tracker.open();
-    }
-
-    public void stop(BundleContext context) throws Exception {
-        tracker.close();
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/aries-rsa/blob/5f4c6604/rsa/src/main/java/org/apache/cxf/dosgi/dsw/service/ClientServiceFactory.java
----------------------------------------------------------------------
diff --git a/rsa/src/main/java/org/apache/cxf/dosgi/dsw/service/ClientServiceFactory.java b/rsa/src/main/java/org/apache/cxf/dosgi/dsw/service/ClientServiceFactory.java
deleted file mode 100644
index 7c292db..0000000
--- a/rsa/src/main/java/org/apache/cxf/dosgi/dsw/service/ClientServiceFactory.java
+++ /dev/null
@@ -1,110 +0,0 @@
-/**
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-package org.apache.cxf.dosgi.dsw.service;
-
-import java.security.AccessController;
-import java.security.PrivilegedAction;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.List;
-
-import org.apache.cxf.dosgi.dsw.api.DistributionProvider;
-import org.apache.cxf.dosgi.dsw.api.IntentUnsatisfiedException;
-import org.osgi.framework.Bundle;
-import org.osgi.framework.BundleContext;
-import org.osgi.framework.ServiceFactory;
-import org.osgi.framework.ServiceRegistration;
-import org.osgi.framework.wiring.BundleWiring;
-import org.osgi.service.remoteserviceadmin.EndpointDescription;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-@SuppressWarnings("rawtypes")
-public class ClientServiceFactory implements ServiceFactory {
-
-    private static final Logger LOG = LoggerFactory.getLogger(ClientServiceFactory.class);
-
-    private EndpointDescription endpoint;
-    private DistributionProvider handler;
-    private ImportRegistrationImpl importRegistration;
-
-    private boolean closeable;
-    private int serviceCounter;
-
-    public ClientServiceFactory(EndpointDescription endpoint,
-                                DistributionProvider handler, ImportRegistrationImpl ir) {
-        this.endpoint = endpoint;
-        this.handler = handler;
-        this.importRegistration = ir;
-    }
-
-    public Object getService(final Bundle requestingBundle, final ServiceRegistration sreg) {
-        List<String> interfaceNames = endpoint.getInterfaces();
-        final BundleContext consumerContext = requestingBundle.getBundleContext();
-        final ClassLoader consumerLoader = requestingBundle.adapt(BundleWiring.class).getClassLoader();
-        try {
-            LOG.debug("getService() from serviceFactory for {}", interfaceNames);
-            final List<Class<?>> interfaces = new ArrayList<Class<?>>();
-            for (String ifaceName : interfaceNames) {
-                interfaces.add(consumerLoader.loadClass(ifaceName));
-            }
-            Object proxy = AccessController.doPrivileged(new PrivilegedAction<Object>() {
-                public Object run() {
-                    Class<?>[] ifAr = interfaces.toArray(new Class[]{});
-                    return handler.importEndpoint(consumerLoader, consumerContext, ifAr, endpoint);
-                }
-            });
-
-            synchronized (this) {
-                serviceCounter++;
-            }
-            return proxy;
-        } catch (IntentUnsatisfiedException iue) {
-            LOG.info("Did not create proxy for {} because intent {} could not be satisfied",
-                    interfaceNames, iue.getIntent());
-        } catch (Exception e) {
-            LOG.warn("Problem creating a remote proxy for {}", interfaceNames, 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();
-        }
-    }
-}

http://git-wip-us.apache.org/repos/asf/aries-rsa/blob/5f4c6604/rsa/src/main/java/org/apache/cxf/dosgi/dsw/service/DistributionProviderTracker.java
----------------------------------------------------------------------
diff --git a/rsa/src/main/java/org/apache/cxf/dosgi/dsw/service/DistributionProviderTracker.java b/rsa/src/main/java/org/apache/cxf/dosgi/dsw/service/DistributionProviderTracker.java
deleted file mode 100644
index 675fcc6..0000000
--- a/rsa/src/main/java/org/apache/cxf/dosgi/dsw/service/DistributionProviderTracker.java
+++ /dev/null
@@ -1,73 +0,0 @@
-/**
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-package org.apache.cxf.dosgi.dsw.service;
-
-import java.util.Dictionary;
-import java.util.Hashtable;
-
-import org.apache.cxf.dosgi.dsw.api.DistributionProvider;
-import org.osgi.framework.Bundle;
-import org.osgi.framework.BundleContext;
-import org.osgi.framework.FrameworkUtil;
-import org.osgi.framework.ServiceReference;
-import org.osgi.framework.ServiceRegistration;
-import org.osgi.service.remoteserviceadmin.RemoteServiceAdmin;
-import org.osgi.util.tracker.ServiceTracker;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-@SuppressWarnings("rawtypes")
-public class DistributionProviderTracker extends ServiceTracker<DistributionProvider, ServiceRegistration> {
-    private static final Logger LOG = LoggerFactory.getLogger(Activator.class);
-
-    public DistributionProviderTracker(BundleContext context) {
-        super(context, DistributionProvider.class, null);
-    }
-
-    @Override
-    public ServiceRegistration addingService(ServiceReference<DistributionProvider> reference) {
-        LOG.debug("RemoteServiceAdmin Implementation is starting up");
-        DistributionProvider provider = context.getService(reference);
-        BundleContext apiContext = getAPIContext();
-        RemoteServiceAdminCore rsaCore = new RemoteServiceAdminCore(context, 
-                                                                    apiContext, 
-                                                                    provider);
-        RemoteServiceadminFactory rsaf = new RemoteServiceadminFactory(rsaCore);
-        Dictionary<String, Object> props = new Hashtable<String, Object>();
-        props.put("remote.intents.supported", reference.getProperty("remote.intents.supported"));
-        props.put("remote.configs.supported", reference.getProperty("remote.configs.supported"));
-        LOG.info("Registering RemoteServiceAdmin for provider " + provider.getClass().getName());
-        return context.registerService(RemoteServiceAdmin.class.getName(), rsaf, props);
-    }
-
-    protected BundleContext getAPIContext() {
-        Bundle apiBundle = FrameworkUtil.getBundle(DistributionProvider.class);
-        BundleContext apiContext = apiBundle.getBundleContext();
-        return apiContext;
-    }
-    
-    @Override
-    public void removedService(ServiceReference<DistributionProvider> reference,
-                               ServiceRegistration reg) {
-        LOG.debug("RemoteServiceAdmin Implementation is shutting down now");
-        reg.unregister();
-        super.removedService(reference, reg);
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/aries-rsa/blob/5f4c6604/rsa/src/main/java/org/apache/cxf/dosgi/dsw/service/EventAdminHelper.java
----------------------------------------------------------------------
diff --git a/rsa/src/main/java/org/apache/cxf/dosgi/dsw/service/EventAdminHelper.java b/rsa/src/main/java/org/apache/cxf/dosgi/dsw/service/EventAdminHelper.java
deleted file mode 100644
index 4868efa..0000000
--- a/rsa/src/main/java/org/apache/cxf/dosgi/dsw/service/EventAdminHelper.java
+++ /dev/null
@@ -1,151 +0,0 @@
-/**
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-package org.apache.cxf.dosgi.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;
-
-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);
-    }
-
-    @SuppressWarnings({
-     "rawtypes", "unchecked"
-    })
-    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 <K, V> void setIfNotNull(Map<K, V> map, K key, V val) {
-        if (val != null) {
-            map.put(key, val);
-        }
-    }
-
-    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;
-    }
-}

http://git-wip-us.apache.org/repos/asf/aries-rsa/blob/5f4c6604/rsa/src/main/java/org/apache/cxf/dosgi/dsw/service/EventProducer.java
----------------------------------------------------------------------
diff --git a/rsa/src/main/java/org/apache/cxf/dosgi/dsw/service/EventProducer.java b/rsa/src/main/java/org/apache/cxf/dosgi/dsw/service/EventProducer.java
deleted file mode 100644
index 26a46ab..0000000
--- a/rsa/src/main/java/org/apache/cxf/dosgi/dsw/service/EventProducer.java
+++ /dev/null
@@ -1,114 +0,0 @@
-/**
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-package org.apache.cxf.dosgi.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");
-        }
-    }
-
-    @SuppressWarnings({
-     "rawtypes", "unchecked"
-    })
-    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);
-        }
-    }
-}

http://git-wip-us.apache.org/repos/asf/aries-rsa/blob/5f4c6604/rsa/src/main/java/org/apache/cxf/dosgi/dsw/service/ExportReferenceImpl.java
----------------------------------------------------------------------
diff --git a/rsa/src/main/java/org/apache/cxf/dosgi/dsw/service/ExportReferenceImpl.java b/rsa/src/main/java/org/apache/cxf/dosgi/dsw/service/ExportReferenceImpl.java
deleted file mode 100644
index 497aa9c..0000000
--- a/rsa/src/main/java/org/apache/cxf/dosgi/dsw/service/ExportReferenceImpl.java
+++ /dev/null
@@ -1,77 +0,0 @@
-/**
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-package org.apache.cxf.dosgi.dsw.service;
-
-import org.osgi.framework.ServiceReference;
-import org.osgi.service.remoteserviceadmin.EndpointDescription;
-import org.osgi.service.remoteserviceadmin.ExportReference;
-
-@SuppressWarnings("rawtypes")
-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;
-    }
-}

http://git-wip-us.apache.org/repos/asf/aries-rsa/blob/5f4c6604/rsa/src/main/java/org/apache/cxf/dosgi/dsw/service/ExportRegistrationImpl.java
----------------------------------------------------------------------
diff --git a/rsa/src/main/java/org/apache/cxf/dosgi/dsw/service/ExportRegistrationImpl.java b/rsa/src/main/java/org/apache/cxf/dosgi/dsw/service/ExportRegistrationImpl.java
deleted file mode 100644
index d80bd40..0000000
--- a/rsa/src/main/java/org/apache/cxf/dosgi/dsw/service/ExportRegistrationImpl.java
+++ /dev/null
@@ -1,152 +0,0 @@
-/**
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-package org.apache.cxf.dosgi.dsw.service;
-
-import java.io.Closeable;
-import java.io.IOException;
-import java.util.Arrays;
-import java.util.Map;
-import java.util.Set;
-
-import org.apache.cxf.dosgi.dsw.api.Endpoint;
-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;
-
-@SuppressWarnings("rawtypes")
-public class ExportRegistrationImpl implements ExportRegistration {
-
-    private static final Logger LOG = LoggerFactory.getLogger(ExportRegistrationImpl.class);
-
-    private final RemoteServiceAdminCore rsaCore;
-    private final ExportReferenceImpl exportReference;
-    private final Closeable server;
-    private final Throwable exception;
-
-    private final ExportRegistrationImpl parent;
-    private int instanceCount;
-    private volatile boolean closed;
-
-    private ExportRegistrationImpl(ExportRegistrationImpl parent, RemoteServiceAdminCore rsaCore,
-            ExportReferenceImpl exportReference, Closeable 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, Endpoint endpoint, RemoteServiceAdminCore rsaCore) {
-        this(null, rsaCore, new ExportReferenceImpl(sref, endpoint.description()), endpoint, null);
-    }
-
-    // create a new (parent) instance which failed to be exported with the given exception
-    public ExportRegistrationImpl(RemoteServiceAdminCore rsaCore, Throwable exception) {
-        this(null, rsaCore, null, null, exception);
-    }
-
-    private void ensureParent() {
-        if (parent != this) {
-            throw new IllegalStateException("this method may only be called on the parent");
-        }
-    }
-
-    public ExportReference getExportReference() {
-        if (exportReference == null) {
-            throw new IllegalStateException(getException());
-        }
-        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) {
-                    try {
-                        server.close();
-                    } catch (IOException e) {
-                        LOG.warn("Error closing ExportRegistration", e);
-                    }
-                }
-            }
-        }
-    }
-
-    @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;
-    }
-}

http://git-wip-us.apache.org/repos/asf/aries-rsa/blob/5f4c6604/rsa/src/main/java/org/apache/cxf/dosgi/dsw/service/ImportRegistrationImpl.java
----------------------------------------------------------------------
diff --git a/rsa/src/main/java/org/apache/cxf/dosgi/dsw/service/ImportRegistrationImpl.java b/rsa/src/main/java/org/apache/cxf/dosgi/dsw/service/ImportRegistrationImpl.java
deleted file mode 100644
index 2b896db..0000000
--- a/rsa/src/main/java/org/apache/cxf/dosgi/dsw/service/ImportRegistrationImpl.java
+++ /dev/null
@@ -1,230 +0,0 @@
-/**
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-package org.apache.cxf.dosgi.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;
-
-@SuppressWarnings("rawtypes")
-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;
-    }
-}

http://git-wip-us.apache.org/repos/asf/aries-rsa/blob/5f4c6604/rsa/src/main/java/org/apache/cxf/dosgi/dsw/service/PackageUtil.java
----------------------------------------------------------------------
diff --git a/rsa/src/main/java/org/apache/cxf/dosgi/dsw/service/PackageUtil.java b/rsa/src/main/java/org/apache/cxf/dosgi/dsw/service/PackageUtil.java
deleted file mode 100644
index effcef1..0000000
--- a/rsa/src/main/java/org/apache/cxf/dosgi/dsw/service/PackageUtil.java
+++ /dev/null
@@ -1,85 +0,0 @@
-/**
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-package org.apache.cxf.dosgi.dsw.service;
-
-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.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-@SuppressWarnings("deprecation")
-public final class PackageUtil {
-
-    public static final Logger LOG = LoggerFactory.getLogger(PackageUtil.class);
-
-    private PackageUtil() {
-    }
-
-    /**
-     * 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<PackageAdmin> paRef = bc.getServiceReference(PackageAdmin.class);
-        if (paRef != null) {
-            PackageAdmin pa = 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: {}", (Object)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";
-    }
-}