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:04 UTC
[05/50] [abbrv] aries-rsa git commit: [DOSGI-229] Use separate
bundles for API and RSA impl. Remove dynamic import
[DOSGI-229] Use separate bundles for API and RSA impl. Remove dynamic import
Project: http://git-wip-us.apache.org/repos/asf/aries-rsa/repo
Commit: http://git-wip-us.apache.org/repos/asf/aries-rsa/commit/4ed2614d
Tree: http://git-wip-us.apache.org/repos/asf/aries-rsa/tree/4ed2614d
Diff: http://git-wip-us.apache.org/repos/asf/aries-rsa/diff/4ed2614d
Branch: refs/heads/master
Commit: 4ed2614db3d5ac7550b6738811014dae404282b1
Parents: 84f6be4
Author: Christian Schneider <ch...@die-schneider.net>
Authored: Tue Mar 8 00:47:16 2016 +0100
Committer: Christian Schneider <ch...@die-schneider.net>
Committed: Tue Mar 8 00:47:16 2016 +0100
----------------------------------------------------------------------
.../features/src/main/resources/features.xml | 2 +
dsw/cxf-dosgi-provider-api/pom.xml | 64 +++
.../cxf/dosgi/dsw/api/DistributionProvider.java | 54 ++
.../org/apache/cxf/dosgi/dsw/api/Endpoint.java | 27 +
.../dsw/api/IntentUnsatisfiedException.java | 35 ++
dsw/cxf-dosgi-rsa/pom.xml | 71 +++
.../apache/cxf/dosgi/dsw/service/Activator.java | 37 ++
.../dosgi/dsw/service/ClientServiceFactory.java | 106 ++++
.../service/DistributionProviderTracker.java | 67 +++
.../cxf/dosgi/dsw/service/EventAdminHelper.java | 151 +++++
.../cxf/dosgi/dsw/service/EventProducer.java | 114 ++++
.../dosgi/dsw/service/ExportReferenceImpl.java | 77 +++
.../dsw/service/ExportRegistrationImpl.java | 152 +++++
.../dsw/service/ImportRegistrationImpl.java | 230 ++++++++
.../dsw/service/RemoteServiceAdminCore.java | 553 +++++++++++++++++++
.../dsw/service/RemoteServiceAdminInstance.java | 99 ++++
.../dsw/service/RemoteServiceadminFactory.java | 51 ++
.../cxf/dosgi/dsw/service/StringPlus.java | 72 +++
.../dsw/service/ClientServiceFactoryTest.java | 88 +++
.../dosgi/dsw/service/EventProducerTest.java | 189 +++++++
.../dsw/service/ImportRegistrationImplTest.java | 178 ++++++
.../dsw/service/RemoteServiceAdminCoreTest.java | 491 ++++++++++++++++
.../cxf/dosgi/dsw/service/StringPlusTest.java | 63 +++
dsw/cxf-dsw/pom.xml | 12 +-
.../org/apache/cxf/dosgi/dsw/Activator.java | 8 +-
.../cxf/dosgi/dsw/api/DistributionProvider.java | 54 --
.../org/apache/cxf/dosgi/dsw/api/Endpoint.java | 27 -
.../dsw/api/IntentUnsatisfiedException.java | 35 --
.../dosgi/dsw/service/ClientServiceFactory.java | 106 ----
.../cxf/dosgi/dsw/service/EventAdminHelper.java | 151 -----
.../cxf/dosgi/dsw/service/EventProducer.java | 114 ----
.../dosgi/dsw/service/ExportReferenceImpl.java | 77 ---
.../dsw/service/ExportRegistrationImpl.java | 152 -----
.../dsw/service/ImportRegistrationImpl.java | 230 --------
.../cxf/dosgi/dsw/service/PackageFinder.java | 47 --
.../dsw/service/RemoteServiceAdminCore.java | 549 ------------------
.../dsw/service/RemoteServiceAdminInstance.java | 99 ----
.../dsw/service/RemoteServiceadminFactory.java | 51 --
.../cxf/dosgi/dsw/service/StringPlus.java | 72 ---
.../org/apache/cxf/dosgi/dsw/ActivatorTest.java | 4 +-
.../dsw/service/ClientServiceFactoryTest.java | 90 ---
.../service/DistributionProviderImplTest.java | 124 -----
.../dosgi/dsw/service/EventProducerTest.java | 189 -------
.../dsw/service/ImportRegistrationImplTest.java | 178 ------
.../dsw/service/RemoteServiceAdminCoreTest.java | 491 ----------------
.../cxf/dosgi/dsw/service/StringPlusTest.java | 63 ---
dsw/pom.xml | 2 +
47 files changed, 2983 insertions(+), 2913 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/aries-rsa/blob/4ed2614d/distribution/features/src/main/resources/features.xml
----------------------------------------------------------------------
diff --git a/distribution/features/src/main/resources/features.xml b/distribution/features/src/main/resources/features.xml
index 1c19381..b39562b 100644
--- a/distribution/features/src/main/resources/features.xml
+++ b/distribution/features/src/main/resources/features.xml
@@ -24,6 +24,8 @@
<feature>cxf-http</feature>
<feature>http</feature>
<bundle start-level="8">mvn:${project.groupId}/cxf-dosgi-ri-osgi-api/${project.version}</bundle>
+ <bundle>mvn:${project.groupId}/cxf-dosgi-ri-provider-api/${project.version}</bundle>
+ <bundle>mvn:${project.groupId}/cxf-dosgi-ri-rsa/${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>
http://git-wip-us.apache.org/repos/asf/aries-rsa/blob/4ed2614d/dsw/cxf-dosgi-provider-api/pom.xml
----------------------------------------------------------------------
diff --git a/dsw/cxf-dosgi-provider-api/pom.xml b/dsw/cxf-dosgi-provider-api/pom.xml
new file mode 100644
index 0000000..9b248fb
--- /dev/null
+++ b/dsw/cxf-dosgi-provider-api/pom.xml
@@ -0,0 +1,64 @@
+<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/xsd/maven-4.0.0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+
+ <parent>
+ <groupId>org.apache.cxf.dosgi</groupId>
+ <artifactId>cxf-dosgi-ri-parent</artifactId>
+ <version>1.8-SNAPSHOT</version>
+ <relativePath>../../parent/pom.xml</relativePath>
+ </parent>
+ <artifactId>cxf-dosgi-ri-provider-api</artifactId>
+ <packaging>bundle</packaging>
+ <name>Distributed OSGI Distributed Software Modules</name>
+
+ <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>junit</groupId>
+ <artifactId>junit</artifactId>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.easymock</groupId>
+ <artifactId>easymockclassextension</artifactId>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.slf4j</groupId>
+ <artifactId>slf4j-jdk14</artifactId>
+ <version>1.7.14</version>
+ </dependency>
+ </dependencies>
+
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>maven-bundle-plugin</artifactId>
+ <extensions>true</extensions>
+ <configuration>
+ <instructions>
+ <Bundle-SymbolicName>${project.artifactId}</Bundle-SymbolicName>
+ </instructions>
+ </configuration>
+ </plugin>
+ </plugins>
+ </build>
+</project>
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/aries-rsa/blob/4ed2614d/dsw/cxf-dosgi-provider-api/src/main/java/org/apache/cxf/dosgi/dsw/api/DistributionProvider.java
----------------------------------------------------------------------
diff --git a/dsw/cxf-dosgi-provider-api/src/main/java/org/apache/cxf/dosgi/dsw/api/DistributionProvider.java b/dsw/cxf-dosgi-provider-api/src/main/java/org/apache/cxf/dosgi/dsw/api/DistributionProvider.java
new file mode 100644
index 0000000..c7328db
--- /dev/null
+++ b/dsw/cxf-dosgi-provider-api/src/main/java/org/apache/cxf/dosgi/dsw/api/DistributionProvider.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.api;
+
+import java.util.Map;
+
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.ServiceReference;
+import org.osgi.service.remoteserviceadmin.EndpointDescription;
+
+@SuppressWarnings("rawtypes")
+public interface DistributionProvider {
+
+ String[] getSupportedTypes();
+
+ /**
+ * @param sref reference of the service to be exported
+ * @param effectiveProperties combined properties of the service and additional properties from rsa
+ * @param exportedInterface name of the interface to be exported
+ * @return closeable Endpoint that represents the service that is exposed to the outside world
+ */
+ Endpoint exportService(ServiceReference<?> sref,
+ Map<String, Object> effectiveProperties,
+ Class[] exportedInterfaces);
+
+ /**
+ * @param sref reference of the service offered to the requesting bundle
+ * @param interfaces interfaces of the service to proxy
+ * @param endpoint description of the remote endpoint
+ * @return service proxy to be given to the requesting bundle
+ * @throws IntentUnsatisfiedException
+ */
+ Object importEndpoint(BundleContext consumerContext,
+ Class[] interfaces,
+ EndpointDescription endpoint)
+ throws IntentUnsatisfiedException;
+
+}
http://git-wip-us.apache.org/repos/asf/aries-rsa/blob/4ed2614d/dsw/cxf-dosgi-provider-api/src/main/java/org/apache/cxf/dosgi/dsw/api/Endpoint.java
----------------------------------------------------------------------
diff --git a/dsw/cxf-dosgi-provider-api/src/main/java/org/apache/cxf/dosgi/dsw/api/Endpoint.java b/dsw/cxf-dosgi-provider-api/src/main/java/org/apache/cxf/dosgi/dsw/api/Endpoint.java
new file mode 100644
index 0000000..f45b562
--- /dev/null
+++ b/dsw/cxf-dosgi-provider-api/src/main/java/org/apache/cxf/dosgi/dsw/api/Endpoint.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.api;
+
+import java.io.Closeable;
+
+import org.osgi.service.remoteserviceadmin.EndpointDescription;
+
+public interface Endpoint extends Closeable {
+ EndpointDescription description();
+}
http://git-wip-us.apache.org/repos/asf/aries-rsa/blob/4ed2614d/dsw/cxf-dosgi-provider-api/src/main/java/org/apache/cxf/dosgi/dsw/api/IntentUnsatisfiedException.java
----------------------------------------------------------------------
diff --git a/dsw/cxf-dosgi-provider-api/src/main/java/org/apache/cxf/dosgi/dsw/api/IntentUnsatisfiedException.java b/dsw/cxf-dosgi-provider-api/src/main/java/org/apache/cxf/dosgi/dsw/api/IntentUnsatisfiedException.java
new file mode 100644
index 0000000..4e27938
--- /dev/null
+++ b/dsw/cxf-dosgi-provider-api/src/main/java/org/apache/cxf/dosgi/dsw/api/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.api;
+
+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;
+ }
+}
http://git-wip-us.apache.org/repos/asf/aries-rsa/blob/4ed2614d/dsw/cxf-dosgi-rsa/pom.xml
----------------------------------------------------------------------
diff --git a/dsw/cxf-dosgi-rsa/pom.xml b/dsw/cxf-dosgi-rsa/pom.xml
new file mode 100644
index 0000000..3327135
--- /dev/null
+++ b/dsw/cxf-dosgi-rsa/pom.xml
@@ -0,0 +1,71 @@
+<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/xsd/maven-4.0.0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+ <parent>
+ <groupId>org.apache.cxf.dosgi</groupId>
+ <artifactId>cxf-dosgi-ri-parent</artifactId>
+ <version>1.8-SNAPSHOT</version>
+ <relativePath>../../parent/pom.xml</relativePath>
+ </parent>
+ <artifactId>cxf-dosgi-ri-rsa</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>
+
+ <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.dosgi</groupId>
+ <artifactId>cxf-dosgi-provider-api</artifactId>
+ <version>${project.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>
+ <dependency>
+ <groupId>org.slf4j</groupId>
+ <artifactId>slf4j-jdk14</artifactId>
+ <version>1.7.14</version>
+ </dependency>
+ </dependencies>
+
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>maven-bundle-plugin</artifactId>
+ <extensions>true</extensions>
+ <configuration>
+ <instructions>
+ <Bundle-SymbolicName>${project.artifactId}</Bundle-SymbolicName>
+ <Bundle-Activator>org.apache.cxf.dosgi.dsw.service.Activator</Bundle-Activator>
+ </instructions>
+ </configuration>
+ </plugin>
+ </plugins>
+ </build>
+</project>
+</project>
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/aries-rsa/blob/4ed2614d/dsw/cxf-dosgi-rsa/src/main/java/org/apache/cxf/dosgi/dsw/service/Activator.java
----------------------------------------------------------------------
diff --git a/dsw/cxf-dosgi-rsa/src/main/java/org/apache/cxf/dosgi/dsw/service/Activator.java b/dsw/cxf-dosgi-rsa/src/main/java/org/apache/cxf/dosgi/dsw/service/Activator.java
new file mode 100644
index 0000000..4c4d7ad
--- /dev/null
+++ b/dsw/cxf-dosgi-rsa/src/main/java/org/apache/cxf/dosgi/dsw/service/Activator.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.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/4ed2614d/dsw/cxf-dosgi-rsa/src/main/java/org/apache/cxf/dosgi/dsw/service/ClientServiceFactory.java
----------------------------------------------------------------------
diff --git a/dsw/cxf-dosgi-rsa/src/main/java/org/apache/cxf/dosgi/dsw/service/ClientServiceFactory.java b/dsw/cxf-dosgi-rsa/src/main/java/org/apache/cxf/dosgi/dsw/service/ClientServiceFactory.java
new file mode 100644
index 0000000..b482b64
--- /dev/null
+++ b/dsw/cxf-dosgi-rsa/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.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.ServiceFactory;
+import org.osgi.framework.ServiceRegistration;
+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();
+ try {
+ LOG.debug("getService() from serviceFactory for {}", interfaceNames);
+ final List<Class<?>> interfaces = new ArrayList<Class<?>>();
+ for (String ifaceName : interfaceNames) {
+ interfaces.add(requestingBundle.loadClass(ifaceName));
+ }
+ Object proxy = AccessController.doPrivileged(new PrivilegedAction<Object>() {
+ public Object run() {
+ Class<?>[] ifAr = interfaces.toArray(new Class[]{});
+ return handler.importEndpoint(requestingBundle.getBundleContext(), 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/4ed2614d/dsw/cxf-dosgi-rsa/src/main/java/org/apache/cxf/dosgi/dsw/service/DistributionProviderTracker.java
----------------------------------------------------------------------
diff --git a/dsw/cxf-dosgi-rsa/src/main/java/org/apache/cxf/dosgi/dsw/service/DistributionProviderTracker.java b/dsw/cxf-dosgi-rsa/src/main/java/org/apache/cxf/dosgi/dsw/service/DistributionProviderTracker.java
new file mode 100644
index 0000000..7dd31b7
--- /dev/null
+++ b/dsw/cxf-dosgi-rsa/src/main/java/org/apache/cxf/dosgi/dsw/service/DistributionProviderTracker.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.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);
+ Bundle apiBundle = FrameworkUtil.getBundle(DistributionProvider.class);
+ RemoteServiceAdminCore rsaCore = new RemoteServiceAdminCore(context,
+ apiBundle.getBundleContext(),
+ 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);
+ }
+
+ @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/4ed2614d/dsw/cxf-dosgi-rsa/src/main/java/org/apache/cxf/dosgi/dsw/service/EventAdminHelper.java
----------------------------------------------------------------------
diff --git a/dsw/cxf-dosgi-rsa/src/main/java/org/apache/cxf/dosgi/dsw/service/EventAdminHelper.java b/dsw/cxf-dosgi-rsa/src/main/java/org/apache/cxf/dosgi/dsw/service/EventAdminHelper.java
new file mode 100644
index 0000000..4868efa
--- /dev/null
+++ b/dsw/cxf-dosgi-rsa/src/main/java/org/apache/cxf/dosgi/dsw/service/EventAdminHelper.java
@@ -0,0 +1,151 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT 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/4ed2614d/dsw/cxf-dosgi-rsa/src/main/java/org/apache/cxf/dosgi/dsw/service/EventProducer.java
----------------------------------------------------------------------
diff --git a/dsw/cxf-dosgi-rsa/src/main/java/org/apache/cxf/dosgi/dsw/service/EventProducer.java b/dsw/cxf-dosgi-rsa/src/main/java/org/apache/cxf/dosgi/dsw/service/EventProducer.java
new file mode 100644
index 0000000..26a46ab
--- /dev/null
+++ b/dsw/cxf-dosgi-rsa/src/main/java/org/apache/cxf/dosgi/dsw/service/EventProducer.java
@@ -0,0 +1,114 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT 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/4ed2614d/dsw/cxf-dosgi-rsa/src/main/java/org/apache/cxf/dosgi/dsw/service/ExportReferenceImpl.java
----------------------------------------------------------------------
diff --git a/dsw/cxf-dosgi-rsa/src/main/java/org/apache/cxf/dosgi/dsw/service/ExportReferenceImpl.java b/dsw/cxf-dosgi-rsa/src/main/java/org/apache/cxf/dosgi/dsw/service/ExportReferenceImpl.java
new file mode 100644
index 0000000..497aa9c
--- /dev/null
+++ b/dsw/cxf-dosgi-rsa/src/main/java/org/apache/cxf/dosgi/dsw/service/ExportReferenceImpl.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.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/4ed2614d/dsw/cxf-dosgi-rsa/src/main/java/org/apache/cxf/dosgi/dsw/service/ExportRegistrationImpl.java
----------------------------------------------------------------------
diff --git a/dsw/cxf-dosgi-rsa/src/main/java/org/apache/cxf/dosgi/dsw/service/ExportRegistrationImpl.java b/dsw/cxf-dosgi-rsa/src/main/java/org/apache/cxf/dosgi/dsw/service/ExportRegistrationImpl.java
new file mode 100644
index 0000000..d80bd40
--- /dev/null
+++ b/dsw/cxf-dosgi-rsa/src/main/java/org/apache/cxf/dosgi/dsw/service/ExportRegistrationImpl.java
@@ -0,0 +1,152 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT 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/4ed2614d/dsw/cxf-dosgi-rsa/src/main/java/org/apache/cxf/dosgi/dsw/service/ImportRegistrationImpl.java
----------------------------------------------------------------------
diff --git a/dsw/cxf-dosgi-rsa/src/main/java/org/apache/cxf/dosgi/dsw/service/ImportRegistrationImpl.java b/dsw/cxf-dosgi-rsa/src/main/java/org/apache/cxf/dosgi/dsw/service/ImportRegistrationImpl.java
new file mode 100644
index 0000000..2b896db
--- /dev/null
+++ b/dsw/cxf-dosgi-rsa/src/main/java/org/apache/cxf/dosgi/dsw/service/ImportRegistrationImpl.java
@@ -0,0 +1,230 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT 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/4ed2614d/dsw/cxf-dosgi-rsa/src/main/java/org/apache/cxf/dosgi/dsw/service/RemoteServiceAdminCore.java
----------------------------------------------------------------------
diff --git a/dsw/cxf-dosgi-rsa/src/main/java/org/apache/cxf/dosgi/dsw/service/RemoteServiceAdminCore.java b/dsw/cxf-dosgi-rsa/src/main/java/org/apache/cxf/dosgi/dsw/service/RemoteServiceAdminCore.java
new file mode 100644
index 0000000..aa6e4ee
--- /dev/null
+++ b/dsw/cxf-dosgi-rsa/src/main/java/org/apache/cxf/dosgi/dsw/service/RemoteServiceAdminCore.java
@@ -0,0 +1,553 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT 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.api.DistributionProvider;
+import org.apache.cxf.dosgi.dsw.api.Endpoint;
+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());
+ Endpoint endpoint = provider.exportService(serviceReference, serviceProperties, 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) {
+ 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[] exportedInterfaces
+ = StringPlus.normalize(serviceProperties.get(RemoteConstants.SERVICE_EXPORTED_INTERFACES));
+ if (exportedInterfaces == null || exportedInterfaces.length == 0) {
+ throw new IllegalArgumentException("service is missing the service.exported.interfaces property");
+ }
+
+ List<String> interfaces = new ArrayList<String>(1);
+ if (exportedInterfaces.length == 1 && "*".equals(exportedInterfaces[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(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));
+ }
+
+ Collections.addAll(interfaces, 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);
+ }
+ }
+
+ 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;
+ }
+}
http://git-wip-us.apache.org/repos/asf/aries-rsa/blob/4ed2614d/dsw/cxf-dosgi-rsa/src/main/java/org/apache/cxf/dosgi/dsw/service/RemoteServiceAdminInstance.java
----------------------------------------------------------------------
diff --git a/dsw/cxf-dosgi-rsa/src/main/java/org/apache/cxf/dosgi/dsw/service/RemoteServiceAdminInstance.java b/dsw/cxf-dosgi-rsa/src/main/java/org/apache/cxf/dosgi/dsw/service/RemoteServiceAdminInstance.java
new file mode 100644
index 0000000..fc3a67e
--- /dev/null
+++ b/dsw/cxf-dosgi-rsa/src/main/java/org/apache/cxf/dosgi/dsw/service/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.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.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/4ed2614d/dsw/cxf-dosgi-rsa/src/main/java/org/apache/cxf/dosgi/dsw/service/RemoteServiceadminFactory.java
----------------------------------------------------------------------
diff --git a/dsw/cxf-dosgi-rsa/src/main/java/org/apache/cxf/dosgi/dsw/service/RemoteServiceadminFactory.java b/dsw/cxf-dosgi-rsa/src/main/java/org/apache/cxf/dosgi/dsw/service/RemoteServiceadminFactory.java
new file mode 100644
index 0000000..968ff16
--- /dev/null
+++ b/dsw/cxf-dosgi-rsa/src/main/java/org/apache/cxf/dosgi/dsw/service/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.cxf.dosgi.dsw.service;
+
+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);
+ }
+}