summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorrfeng <rfeng@13f79535-47bb-0310-9956-ffa450edef68>2009-07-24 17:53:23 +0000
committerrfeng <rfeng@13f79535-47bb-0310-9956-ffa450edef68>2009-07-24 17:53:23 +0000
commit61fd7d871ecc003913e6bc31670e47d5e7eb4097 (patch)
treeb3fba81202522ccf530c97467a312d1e4f4f0afb
parentf233e515188f75286b600ed5d4d567b6a3203b2f (diff)
Add the support for dynamic OSGi remote service import and export based on OSGi properties
Add two samples to demonstrate the OSGi property driven remote services git-svn-id: http://svn.us.apache.org/repos/asf/tuscany@797580 13f79535-47bb-0310-9956-ffa450edef68
-rwxr-xr-xjava/sca/modules/implementation-osgi/META-INF/MANIFEST.MF4
-rw-r--r--java/sca/modules/implementation-osgi/src/main/java/org/apache/tuscany/sca/implementation/osgi/xml/ServiceDescriptionsProcessor.java46
-rw-r--r--java/sca/modules/implementation-osgi/src/test/java/org/apache/tuscany/sca/implementation/osgi/xml/ServiceDescriptionsTestCase.java21
-rw-r--r--java/sca/modules/node-impl-osgi/META-INF/MANIFEST.MF4
-rw-r--r--java/sca/modules/node-impl-osgi/src/main/java/org/apache/tuscany/sca/dosgi/discovery/AbstractDiscoveryService.java344
-rw-r--r--java/sca/modules/node-impl-osgi/src/main/java/org/apache/tuscany/sca/dosgi/discovery/DiscoveredServiceNotificationImpl.java67
-rw-r--r--java/sca/modules/node-impl-osgi/src/main/java/org/apache/tuscany/sca/dosgi/discovery/EndpointDescription.java69
-rw-r--r--java/sca/modules/node-impl-osgi/src/main/java/org/apache/tuscany/sca/dosgi/discovery/EndpointPublication.java63
-rw-r--r--java/sca/modules/node-impl-osgi/src/main/java/org/apache/tuscany/sca/dosgi/discovery/LocalDiscoveryService.java122
-rw-r--r--java/sca/modules/node-impl-osgi/src/main/java/org/apache/tuscany/sca/dosgi/discovery/ServiceEndpointDescriptionImpl.java135
-rw-r--r--java/sca/modules/node-impl-osgi/src/main/java/org/apache/tuscany/sca/node/osgi/impl/NodeActivator.java26
-rw-r--r--java/sca/modules/node-impl-osgi/src/main/java/org/apache/tuscany/sca/node/osgi/impl/OSGiServiceExporter.java58
-rw-r--r--java/sca/modules/node-impl-osgi/src/main/java/org/apache/tuscany/sca/node/osgi/impl/OSGiServiceImporter.java121
-rw-r--r--java/sca/modules/node-impl-osgi/src/main/java/org/apache/tuscany/sca/osgi/service/discovery/impl/AbstractDiscoveryService.java280
-rw-r--r--java/sca/modules/node-impl-osgi/src/main/java/org/apache/tuscany/sca/osgi/service/discovery/impl/Discovery.java (renamed from java/sca/modules/node-impl-osgi/src/main/java/org/osgi/service/discovery/Discovery.java)40
-rw-r--r--java/sca/modules/node-impl-osgi/src/main/java/org/apache/tuscany/sca/osgi/service/discovery/impl/DiscoveryActivator.java (renamed from java/sca/modules/node-impl-osgi/src/main/java/org/apache/tuscany/sca/dosgi/discovery/DiscoveryActivator.java)11
-rw-r--r--java/sca/modules/node-impl-osgi/src/main/java/org/apache/tuscany/sca/osgi/service/discovery/impl/DomainDiscoveryService.java (renamed from java/sca/modules/node-impl-osgi/src/main/java/org/apache/tuscany/sca/dosgi/discovery/DomainDiscoveryService.java)59
-rw-r--r--java/sca/modules/node-impl-osgi/src/main/java/org/apache/tuscany/sca/osgi/service/discovery/impl/LocalDiscoveryService.java208
-rw-r--r--java/sca/modules/node-impl-osgi/src/main/java/org/apache/tuscany/sca/osgi/service/remoteadmin/EndpointDescription.java146
-rw-r--r--java/sca/modules/node-impl-osgi/src/main/java/org/apache/tuscany/sca/osgi/service/remoteadmin/EndpointListener.java101
-rw-r--r--java/sca/modules/node-impl-osgi/src/main/java/org/apache/tuscany/sca/osgi/service/remoteadmin/EndpointPermission.java172
-rw-r--r--java/sca/modules/node-impl-osgi/src/main/java/org/apache/tuscany/sca/osgi/service/remoteadmin/ExportRegistration.java71
-rw-r--r--java/sca/modules/node-impl-osgi/src/main/java/org/apache/tuscany/sca/osgi/service/remoteadmin/ImportRegistration.java70
-rw-r--r--java/sca/modules/node-impl-osgi/src/main/java/org/apache/tuscany/sca/osgi/service/remoteadmin/RemoteAdmin.java101
-rw-r--r--java/sca/modules/node-impl-osgi/src/main/java/org/apache/tuscany/sca/osgi/service/remoteadmin/RemoteAdminEvent.java148
-rw-r--r--java/sca/modules/node-impl-osgi/src/main/java/org/apache/tuscany/sca/osgi/service/remoteadmin/RemoteAdminListener.java36
-rw-r--r--java/sca/modules/node-impl-osgi/src/main/java/org/apache/tuscany/sca/osgi/service/remoteadmin/RemoteConstants.java143
-rw-r--r--java/sca/modules/node-impl-osgi/src/main/java/org/apache/tuscany/sca/osgi/service/remoteadmin/impl/EndpointDescriptionImpl.java150
-rw-r--r--java/sca/modules/node-impl-osgi/src/main/java/org/apache/tuscany/sca/osgi/service/remoteadmin/impl/EndpointIntrospector.java (renamed from java/sca/modules/implementation-osgi/src/main/java/org/apache/tuscany/sca/implementation/osgi/introspection/ExportedServiceIntrospector.java)118
-rw-r--r--java/sca/modules/node-impl-osgi/src/main/java/org/apache/tuscany/sca/osgi/service/remoteadmin/impl/ExportRegistrationImpl.java89
-rw-r--r--java/sca/modules/node-impl-osgi/src/main/java/org/apache/tuscany/sca/osgi/service/remoteadmin/impl/ImportRegistrationImpl.java92
-rw-r--r--java/sca/modules/node-impl-osgi/src/main/java/org/apache/tuscany/sca/osgi/service/remoteadmin/impl/RemoteAdminHelper.java86
-rw-r--r--java/sca/modules/node-impl-osgi/src/main/java/org/apache/tuscany/sca/osgi/service/remoteadmin/impl/RemoteAdminImpl.java144
-rw-r--r--java/sca/modules/node-impl-osgi/src/main/java/org/apache/tuscany/sca/osgi/service/remoteadmin/impl/RemoteControllerImpl.java403
-rw-r--r--java/sca/modules/node-impl-osgi/src/main/java/org/osgi/service/discovery/DiscoveredServiceNotification.java107
-rw-r--r--java/sca/modules/node-impl-osgi/src/main/java/org/osgi/service/discovery/DiscoveredServiceTracker.java81
-rw-r--r--java/sca/modules/node-impl-osgi/src/main/java/org/osgi/service/discovery/ServiceEndpointDescription.java128
-rw-r--r--java/sca/modules/node-impl-osgi/src/main/java/org/osgi/service/discovery/ServicePublication.java147
-rw-r--r--java/sca/samples/dosgi-calculator-operations/src/main/java/calculator/dosgi/operations/impl/OperationsActivator.java2
-rw-r--r--java/sca/samples/dosgi-calculator/OSGI-INF/sca/bundle.composite11
-rw-r--r--java/sca/samples/dosgi-calculator/OSGI-INF/sca/calculator-service.bindings2
-rw-r--r--java/sca/samples/dosgi-calculator/src/main/java/calculator/dosgi/impl/CalculatorActivator.java4
-rw-r--r--java/sca/samples/dosgi-calculator/src/main/java/calculator/dosgi/impl/CalculatorServiceImpl.java9
-rw-r--r--java/sca/samples/dosgi-dynamic-calculator-operations/LICENSE205
-rw-r--r--java/sca/samples/dosgi-dynamic-calculator-operations/META-INF/MANIFEST.MF22
-rw-r--r--java/sca/samples/dosgi-dynamic-calculator-operations/NOTICE6
-rw-r--r--java/sca/samples/dosgi-dynamic-calculator-operations/OSGI-INF/add-component.xml25
-rw-r--r--java/sca/samples/dosgi-dynamic-calculator-operations/OSGI-INF/blueprint/operations-module.xml40
-rw-r--r--java/sca/samples/dosgi-dynamic-calculator-operations/OSGI-INF/divide-component.xml25
-rw-r--r--java/sca/samples/dosgi-dynamic-calculator-operations/OSGI-INF/multiply-component.xml25
-rw-r--r--java/sca/samples/dosgi-dynamic-calculator-operations/OSGI-INF/sca/add-service.bindings23
-rw-r--r--java/sca/samples/dosgi-dynamic-calculator-operations/OSGI-INF/sca/divide-service.bindings23
-rw-r--r--java/sca/samples/dosgi-dynamic-calculator-operations/OSGI-INF/sca/multiply-service.bindings23
-rw-r--r--java/sca/samples/dosgi-dynamic-calculator-operations/OSGI-INF/sca/subtract-service.bindings23
-rw-r--r--java/sca/samples/dosgi-dynamic-calculator-operations/OSGI-INF/subtract-component.xml25
-rw-r--r--java/sca/samples/dosgi-dynamic-calculator-operations/README183
-rw-r--r--java/sca/samples/dosgi-dynamic-calculator-operations/pom.xml134
-rw-r--r--java/sca/samples/dosgi-dynamic-calculator-operations/src/main/java/calculator/dosgi/operations/AddService.java31
-rw-r--r--java/sca/samples/dosgi-dynamic-calculator-operations/src/main/java/calculator/dosgi/operations/DivideService.java31
-rw-r--r--java/sca/samples/dosgi-dynamic-calculator-operations/src/main/java/calculator/dosgi/operations/MultiplyService.java31
-rw-r--r--java/sca/samples/dosgi-dynamic-calculator-operations/src/main/java/calculator/dosgi/operations/SubtractService.java31
-rw-r--r--java/sca/samples/dosgi-dynamic-calculator-operations/src/main/java/calculator/dosgi/operations/impl/AddServiceImpl.java37
-rw-r--r--java/sca/samples/dosgi-dynamic-calculator-operations/src/main/java/calculator/dosgi/operations/impl/DivideServiceImpl.java37
-rw-r--r--java/sca/samples/dosgi-dynamic-calculator-operations/src/main/java/calculator/dosgi/operations/impl/MultiplyServiceImpl.java37
-rw-r--r--java/sca/samples/dosgi-dynamic-calculator-operations/src/main/java/calculator/dosgi/operations/impl/OperationsActivator.java94
-rw-r--r--java/sca/samples/dosgi-dynamic-calculator-operations/src/main/java/calculator/dosgi/operations/impl/SubtractServiceImpl.java37
-rw-r--r--java/sca/samples/dosgi-dynamic-calculator-operations/src/test/java/calculator/dosgi/operations/test/OSGiTestUtils.java105
-rw-r--r--java/sca/samples/dosgi-dynamic-calculator-operations/src/test/java/calculator/dosgi/operations/test/OperationsNode.java43
-rw-r--r--java/sca/samples/dosgi-dynamic-calculator-operations/src/test/java/calculator/dosgi/operations/test/OperationsOSGiNodeTestCase.java104
-rw-r--r--java/sca/samples/dosgi-dynamic-calculator/LICENSE205
-rw-r--r--java/sca/samples/dosgi-dynamic-calculator/META-INF/MANIFEST.MF20
-rw-r--r--java/sca/samples/dosgi-dynamic-calculator/NOTICE6
-rw-r--r--java/sca/samples/dosgi-dynamic-calculator/OSGI-INF/blueprint/calculator-module.xml43
-rw-r--r--java/sca/samples/dosgi-dynamic-calculator/OSGI-INF/calculator-component.xml36
-rw-r--r--java/sca/samples/dosgi-dynamic-calculator/OSGI-INF/remote-service/calculator-service-descriptions.xml (renamed from java/sca/samples/dosgi-calculator/OSGI-INF/remote-service/calculator-service-descriptions.xml)48
-rw-r--r--java/sca/samples/dosgi-dynamic-calculator/OSGI-INF/sca/calculator-service.bindings24
-rw-r--r--java/sca/samples/dosgi-dynamic-calculator/README155
-rw-r--r--java/sca/samples/dosgi-dynamic-calculator/dosgi-calculator.pngbin0 -> 85103 bytes
-rw-r--r--java/sca/samples/dosgi-dynamic-calculator/pom.xml139
-rw-r--r--java/sca/samples/dosgi-dynamic-calculator/src/main/java/calculator/dosgi/CalculatorService.java36
-rw-r--r--java/sca/samples/dosgi-dynamic-calculator/src/main/java/calculator/dosgi/impl/CalculatorActivator.java78
-rw-r--r--java/sca/samples/dosgi-dynamic-calculator/src/main/java/calculator/dosgi/impl/CalculatorServiceDSImpl.java114
-rw-r--r--java/sca/samples/dosgi-dynamic-calculator/src/main/java/calculator/dosgi/impl/CalculatorServiceImpl.java105
-rw-r--r--java/sca/samples/dosgi-dynamic-calculator/src/main/java/calculator/dosgi/operations/AddService.java31
-rw-r--r--java/sca/samples/dosgi-dynamic-calculator/src/main/java/calculator/dosgi/operations/DivideService.java31
-rw-r--r--java/sca/samples/dosgi-dynamic-calculator/src/main/java/calculator/dosgi/operations/MultiplyService.java31
-rw-r--r--java/sca/samples/dosgi-dynamic-calculator/src/main/java/calculator/dosgi/operations/SubtractService.java31
-rw-r--r--java/sca/samples/dosgi-dynamic-calculator/src/main/java/calculator/rmi/OperationsRMIServer.java93
-rw-r--r--java/sca/samples/dosgi-dynamic-calculator/src/main/java/calculator/rmi/OperationsRMIServer_Stub.java132
-rw-r--r--java/sca/samples/dosgi-dynamic-calculator/src/main/java/calculator/rmi/OperationsRemote.java37
-rw-r--r--java/sca/samples/dosgi-dynamic-calculator/src/test/java/calculator/dosgi/test/CalculatorNode.java43
-rw-r--r--java/sca/samples/dosgi-dynamic-calculator/src/test/java/calculator/dosgi/test/CalculatorOSGiNodeTestCase.java144
-rw-r--r--java/sca/samples/dosgi-dynamic-calculator/src/test/java/calculator/dosgi/test/OSGiTestUtils.java105
-rw-r--r--java/sca/samples/pom.xml3
94 files changed, 5890 insertions, 1439 deletions
diff --git a/java/sca/modules/implementation-osgi/META-INF/MANIFEST.MF b/java/sca/modules/implementation-osgi/META-INF/MANIFEST.MF
index c6921b4c4e..f417c651b2 100755
--- a/java/sca/modules/implementation-osgi/META-INF/MANIFEST.MF
+++ b/java/sca/modules/implementation-osgi/META-INF/MANIFEST.MF
@@ -19,7 +19,6 @@ Import-Package: javax.xml.namespace,
org.apache.tuscany.sca.contribution.resolver;version="2.0.0",
org.apache.tuscany.sca.core;version="2.0.0",
org.apache.tuscany.sca.implementation.osgi;version="2.0.0",
- org.apache.tuscany.sca.implementation.osgi.introspection;version="2.0.0",
org.apache.tuscany.sca.interfacedef;version="2.0.0",
org.apache.tuscany.sca.interfacedef.java;version="2.0.0",
org.apache.tuscany.sca.interfacedef.java.impl;version="2.0.0",
@@ -32,6 +31,5 @@ Import-Package: javax.xml.namespace,
org.osgi.service.packageadmin;version="1.2.0",
org.osgi.util.tracker;version="1.3.3"
Bundle-DocURL: http://www.apache.org/
-Export-Package: org.apache.tuscany.sca.implementation.osgi;version="2.0.0",
- org.apache.tuscany.sca.implementation.osgi.introspection;version="2.0.0"
+Export-Package: org.apache.tuscany.sca.implementation.osgi;version="2.0.0"
Bundle-RequiredExecutionEnvironment: J2SE-1.5,JavaSE-1.6
diff --git a/java/sca/modules/implementation-osgi/src/main/java/org/apache/tuscany/sca/implementation/osgi/xml/ServiceDescriptionsProcessor.java b/java/sca/modules/implementation-osgi/src/main/java/org/apache/tuscany/sca/implementation/osgi/xml/ServiceDescriptionsProcessor.java
index bef07d159d..38e2730df8 100644
--- a/java/sca/modules/implementation-osgi/src/main/java/org/apache/tuscany/sca/implementation/osgi/xml/ServiceDescriptionsProcessor.java
+++ b/java/sca/modules/implementation-osgi/src/main/java/org/apache/tuscany/sca/implementation/osgi/xml/ServiceDescriptionsProcessor.java
@@ -19,16 +19,21 @@
package org.apache.tuscany.sca.implementation.osgi.xml;
+import java.util.StringTokenizer;
+
import javax.xml.namespace.QName;
import javax.xml.stream.XMLStreamConstants;
import javax.xml.stream.XMLStreamException;
import javax.xml.stream.XMLStreamReader;
import javax.xml.stream.XMLStreamWriter;
+import org.apache.tuscany.sca.contribution.processor.BaseStAXArtifactProcessor;
+import org.apache.tuscany.sca.contribution.processor.ContributionReadException;
import org.apache.tuscany.sca.contribution.processor.ContributionResolveException;
import org.apache.tuscany.sca.contribution.processor.ContributionWriteException;
import org.apache.tuscany.sca.contribution.processor.StAXArtifactProcessor;
import org.apache.tuscany.sca.contribution.resolver.ModelResolver;
+import org.apache.tuscany.sca.core.ExtensionPointRegistry;
import org.apache.tuscany.sca.core.FactoryExtensionPoint;
import org.apache.tuscany.sca.implementation.osgi.ServiceDescription;
import org.apache.tuscany.sca.implementation.osgi.ServiceDescriptions;
@@ -56,16 +61,22 @@ import org.apache.tuscany.sca.monitor.Monitor;
</service-description>
</service-descriptions>
*/
-public class ServiceDescriptionsProcessor implements StAXArtifactProcessor<ServiceDescriptions> {
+public class ServiceDescriptionsProcessor extends BaseStAXArtifactProcessor implements
+ StAXArtifactProcessor<ServiceDescriptions> {
private ServiceDescriptionsFactory factory;
+ private StAXArtifactProcessor processor;
private Monitor monitor;
- public ServiceDescriptionsProcessor(FactoryExtensionPoint modelFactories, Monitor monitor) {
+ public ServiceDescriptionsProcessor(ExtensionPointRegistry registry,
+ StAXArtifactProcessor processor,
+ Monitor monitor) {
this.monitor = monitor;
+ this.processor = processor;
+ FactoryExtensionPoint modelFactories = registry.getExtensionPoint(FactoryExtensionPoint.class);
this.factory = modelFactories.getFactory(ServiceDescriptionsFactory.class);
}
- public ServiceDescriptions read(XMLStreamReader reader) throws XMLStreamException {
+ public ServiceDescriptions read(XMLStreamReader reader) throws XMLStreamException, ContributionReadException {
int event = reader.getEventType();
ServiceDescriptions sds = factory.createServiceDescriptions();
ServiceDescription sd = null;
@@ -112,7 +123,18 @@ public class ServiceDescriptionsProcessor implements StAXArtifactProcessor<Servi
} else if ("Boolean".equals(propType)) {
prop = Boolean.valueOf(propValue);
}
+ if (propName.endsWith(".intents")) {
+ prop = toQNames(reader, propValue);
+ }
sd.getProperties().put(propName, prop);
+ } else {
+ name = reader.getName();
+ if (!ServiceDescriptions.SERVICE_DESCRIPTIONS_QNAME.equals(name)) {
+ Object ext = processor.read(reader);
+ if (sd != null) {
+ sd.getProperties().put(name.toString(), ext);
+ }
+ }
}
break;
case XMLStreamConstants.END_ELEMENT:
@@ -134,6 +156,24 @@ public class ServiceDescriptionsProcessor implements StAXArtifactProcessor<Servi
}
}
+ /**
+ * Convert ns1:e1 ns2:e2 to {http://ns1}e1 {http://ns2}e2
+ * @param reader
+ * @param value
+ * @return
+ */
+ private String toQNames(XMLStreamReader reader, String value) {
+ if (value == null) {
+ return null;
+ }
+ StringBuffer sb = new StringBuffer();
+ for (StringTokenizer tokens = new StringTokenizer(value, " \t\n\r\f,"); tokens.hasMoreTokens();) {
+ QName qname = getQNameValue(reader, tokens.nextToken());
+ sb.append(qname.toString()).append(' ');
+ }
+ return sb.toString().trim();
+ }
+
public QName getArtifactType() {
return ServiceDescriptions.SERVICE_DESCRIPTIONS_QNAME;
}
diff --git a/java/sca/modules/implementation-osgi/src/test/java/org/apache/tuscany/sca/implementation/osgi/xml/ServiceDescriptionsTestCase.java b/java/sca/modules/implementation-osgi/src/test/java/org/apache/tuscany/sca/implementation/osgi/xml/ServiceDescriptionsTestCase.java
index d6728f8e1f..e0284b9219 100644
--- a/java/sca/modules/implementation-osgi/src/test/java/org/apache/tuscany/sca/implementation/osgi/xml/ServiceDescriptionsTestCase.java
+++ b/java/sca/modules/implementation-osgi/src/test/java/org/apache/tuscany/sca/implementation/osgi/xml/ServiceDescriptionsTestCase.java
@@ -25,8 +25,11 @@ import java.util.List;
import javax.xml.stream.XMLInputFactory;
import javax.xml.stream.XMLStreamReader;
+import org.apache.tuscany.sca.contribution.processor.ExtensibleStAXArtifactProcessor;
+import org.apache.tuscany.sca.contribution.processor.StAXArtifactProcessor;
+import org.apache.tuscany.sca.contribution.processor.StAXArtifactProcessorExtensionPoint;
import org.apache.tuscany.sca.core.DefaultExtensionPointRegistry;
-import org.apache.tuscany.sca.core.DefaultFactoryExtensionPoint;
+import org.apache.tuscany.sca.core.ExtensionPointRegistry;
import org.apache.tuscany.sca.implementation.osgi.ServiceDescription;
import org.junit.AfterClass;
import org.junit.Assert;
@@ -40,7 +43,7 @@ public class ServiceDescriptionsTestCase {
private static final String xml =
"<?xml version=\"1.0\" encoding=\"UTF-8\"?>"
+ "<service-descriptions xmlns=\"http://www.osgi.org/xmlns/sd/v1.0.0\" "
- +"xmlns:sca=\"http://docs.oasis-open.org/ns/opencsa/sca/200903\">"
+ + "xmlns:sca=\"http://docs.oasis-open.org/ns/opencsa/sca/200903\">"
+ "<service-description>"
+ "<provide interface=\"calculator.operations.AddService\"/>"
+ "<property name=\"service.intents\">sca:SOAP sca:HTTP</property>"
@@ -62,9 +65,10 @@ public class ServiceDescriptionsTestCase {
+ "<property name=\"osgi.remote.configuration.sca.reference\">"
+ "subtractService"
+ "</property>"
- + "</service-description>"
+ + "</service-description>"
+ "</service-descriptions>";
+ private static ServiceDescriptionsProcessor processor;
private static XMLStreamReader reader;
/**
@@ -72,15 +76,20 @@ public class ServiceDescriptionsTestCase {
*/
@BeforeClass
public static void setUpBeforeClass() throws Exception {
+ ExtensionPointRegistry extensionPoints = new DefaultExtensionPointRegistry();
+
XMLInputFactory factory = XMLInputFactory.newInstance();
+ StAXArtifactProcessorExtensionPoint staxProcessors =
+ extensionPoints.getExtensionPoint(StAXArtifactProcessorExtensionPoint.class);
+ StAXArtifactProcessor staxProcessor = new ExtensibleStAXArtifactProcessor(staxProcessors, factory, null, null);
+
+ processor = new ServiceDescriptionsProcessor(extensionPoints, staxProcessor, null);
+
reader = factory.createXMLStreamReader(new StringReader(xml));
}
@Test
public void testLoad() throws Exception {
- ServiceDescriptionsProcessor processor =
- new ServiceDescriptionsProcessor(new DefaultFactoryExtensionPoint(new DefaultExtensionPointRegistry()),
- null);
List<ServiceDescription> descriptions = processor.read(reader);
Assert.assertEquals(2, descriptions.size());
System.out.println(descriptions);
diff --git a/java/sca/modules/node-impl-osgi/META-INF/MANIFEST.MF b/java/sca/modules/node-impl-osgi/META-INF/MANIFEST.MF
index d950198a5e..71a5f1ae46 100644
--- a/java/sca/modules/node-impl-osgi/META-INF/MANIFEST.MF
+++ b/java/sca/modules/node-impl-osgi/META-INF/MANIFEST.MF
@@ -23,13 +23,13 @@ Import-Package: javax.xml.namespace,
org.apache.tuscany.sca.definitions.xml;version="2.0.0",
org.apache.tuscany.sca.extensibility.equinox;version="2.0.0",
org.apache.tuscany.sca.implementation.osgi;version="2.0.0",
- org.apache.tuscany.sca.implementation.osgi.introspection;version="2.0.0",
org.apache.tuscany.sca.interfacedef;version="2.0.0",
org.apache.tuscany.sca.interfacedef.java;version="2.0.0",
org.apache.tuscany.sca.monitor;version="2.0.0",
org.apache.tuscany.sca.node;version="2.0.0",
org.apache.tuscany.sca.node.configuration;version="2.0.0",
org.apache.tuscany.sca.node.impl;version="2.0.0",
+ org.apache.tuscany.sca.osgi.service.remoteadmin;version="2.0.0",
org.apache.tuscany.sca.policy;version="2.0.0",
org.apache.tuscany.sca.provider;version="2.0.0",
org.apache.tuscany.sca.runtime;version="2.0.0",
@@ -44,4 +44,4 @@ Bundle-SymbolicName: org.apache.tuscany.sca.node.osgi.impl
Bundle-DocURL: http://www.apache.org/
Bundle-RequiredExecutionEnvironment: J2SE-1.5,JavaSE-1.6
Bundle-ActivationPolicy: lazy
-Export-Package: org.osgi.service.discovery;version="1.0"
+Export-Package: org.apache.tuscany.sca.osgi.service.remoteadmin;version="2.0.0"
diff --git a/java/sca/modules/node-impl-osgi/src/main/java/org/apache/tuscany/sca/dosgi/discovery/AbstractDiscoveryService.java b/java/sca/modules/node-impl-osgi/src/main/java/org/apache/tuscany/sca/dosgi/discovery/AbstractDiscoveryService.java
deleted file mode 100644
index fa60ed0ed2..0000000000
--- a/java/sca/modules/node-impl-osgi/src/main/java/org/apache/tuscany/sca/dosgi/discovery/AbstractDiscoveryService.java
+++ /dev/null
@@ -1,344 +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.tuscany.sca.dosgi.discovery;
-
-import static org.osgi.service.discovery.DiscoveredServiceNotification.AVAILABLE;
-import static org.osgi.service.discovery.DiscoveredServiceTracker.FILTER_MATCH_CRITERIA;
-import static org.osgi.service.discovery.DiscoveredServiceTracker.INTERFACE_MATCH_CRITERIA;
-
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.Dictionary;
-import java.util.HashMap;
-import java.util.Hashtable;
-import java.util.Iterator;
-import java.util.List;
-import java.util.Map;
-import java.util.concurrent.ConcurrentHashMap;
-import java.util.logging.Logger;
-
-import org.apache.tuscany.sca.assembly.Endpoint;
-import org.apache.tuscany.sca.core.ExtensionPointRegistry;
-import org.apache.tuscany.sca.node.NodeFactory;
-import org.apache.tuscany.sca.node.impl.NodeFactoryImpl;
-import org.osgi.framework.Bundle;
-import org.osgi.framework.BundleContext;
-import org.osgi.framework.Filter;
-import org.osgi.framework.InvalidSyntaxException;
-import org.osgi.framework.ServiceReference;
-import org.osgi.framework.ServiceRegistration;
-import org.osgi.service.discovery.DiscoveredServiceNotification;
-import org.osgi.service.discovery.DiscoveredServiceTracker;
-import org.osgi.service.discovery.Discovery;
-import org.osgi.service.discovery.ServiceEndpointDescription;
-import org.osgi.service.discovery.ServicePublication;
-import org.osgi.util.tracker.ServiceTracker;
-
-/**
- *
- */
-public abstract class AbstractDiscoveryService implements Discovery {
- private final static Logger logger = Logger.getLogger(AbstractDiscoveryService.class.getName());
-
- protected BundleContext context;
- protected ExtensionPointRegistry registry;
-
- private Map<String, List<DiscoveredServiceTracker>> filtersToTrackers =
- new HashMap<String, List<DiscoveredServiceTracker>>();
- private Map<String, List<DiscoveredServiceTracker>> interfacesToTrackers =
- new HashMap<String, List<DiscoveredServiceTracker>>();
- // this is effectively a set which allows for multiple service descriptions with the
- // same interface name but different properties and takes care of itself with respect to concurrency
- protected Map<ServiceEndpointDescription, Bundle> servicesInfo =
- new ConcurrentHashMap<ServiceEndpointDescription, Bundle>();
- private Map<DiscoveredServiceTracker, Collection<String>> trackersToFilters =
- new HashMap<DiscoveredServiceTracker, Collection<String>>();
- private Map<DiscoveredServiceTracker, Collection<String>> trackersToInterfaces =
- new HashMap<DiscoveredServiceTracker, Collection<String>>();
- private ServiceTracker trackerTracker;
-
- public AbstractDiscoveryService(BundleContext context) {
- super();
- this.context = context;
-
- // track the registration of DiscoveredServiceTrackers
- trackerTracker = new ServiceTracker(context, DiscoveredServiceTracker.class.getName(), null) {
- public Object addingService(ServiceReference reference) {
- Object result = super.addingService(reference);
- cacheTracker(reference, result);
- return result;
- }
-
- public void modifiedService(ServiceReference reference, Object service) {
- super.modifiedService(reference, service);
- updateTracker(reference, service);
- }
-
- public void removedService(ServiceReference reference, Object service) {
- super.removedService(reference, service);
- clearTracker(service);
- }
- };
-
- trackerTracker.open();
-
- }
-
- public void stop() {
- trackerTracker.close();
- }
-
- protected ExtensionPointRegistry getExtensionPointRegistry() {
- NodeFactoryImpl factory = (NodeFactoryImpl) NodeFactory.newInstance();
- factory.init();
- ServiceTracker tracker = new ServiceTracker(context, ExtensionPointRegistry.class.getName(), null);
- tracker.open();
- // tracker.waitForService(1000);
- registry = (ExtensionPointRegistry)tracker.getService();
- tracker.close();
- return registry;
- }
-
- private synchronized void cacheTracker(ServiceReference reference, Object service) {
- if (service instanceof DiscoveredServiceTracker) {
- DiscoveredServiceTracker tracker = (DiscoveredServiceTracker)service;
- Collection<String> interfaces =
- addTracker(reference, tracker, INTERFACE_MATCH_CRITERIA, interfacesToTrackers, trackersToInterfaces);
- Collection<String> filters =
- addTracker(reference, tracker, FILTER_MATCH_CRITERIA, filtersToTrackers, trackersToFilters);
-
- triggerCallbacks(null, interfaces, tracker, false);
- triggerCallbacks(null, filters, tracker, true);
- }
- }
-
- private synchronized void clearTracker(Object service) {
- if (service instanceof DiscoveredServiceTracker) {
- removeTracker((DiscoveredServiceTracker)service, interfacesToTrackers, trackersToInterfaces);
- removeTracker((DiscoveredServiceTracker)service, filtersToTrackers, trackersToFilters);
- }
- }
-
- private synchronized void updateTracker(ServiceReference reference, Object service) {
- if (service instanceof DiscoveredServiceTracker) {
- DiscoveredServiceTracker tracker = (DiscoveredServiceTracker)service;
- logger.info("updating tracker: " + tracker);
- Collection<String> oldInterfaces = removeTracker(tracker, interfacesToTrackers, trackersToInterfaces);
- Collection<String> oldFilters = removeTracker(tracker, filtersToTrackers, trackersToFilters);
-
- Collection<String> newInterfaces =
- addTracker(reference, tracker, INTERFACE_MATCH_CRITERIA, interfacesToTrackers, trackersToInterfaces);
- Collection<String> newFilters =
- addTracker(reference, tracker, FILTER_MATCH_CRITERIA, filtersToTrackers, trackersToFilters);
-
- triggerCallbacks(oldInterfaces, newInterfaces, tracker, false);
- triggerCallbacks(oldFilters, newFilters, tracker, true);
- }
- }
-
- private void triggerCallbacks(Collection<String> oldInterest,
- Collection<String> newInterest,
- DiscoveredServiceTracker tracker,
- boolean isFilter) {
- // compute delta between old & new interfaces/filters and
- // trigger callbacks for any entries in servicesInfo that
- // match any *additional* interface/filters
- Collection<String> deltaInterest = new ArrayList<String>();
- if (!isEmpty(newInterest)) {
- if (isEmpty(oldInterest)) {
- deltaInterest.addAll(newInterest);
- } else {
- Iterator<String> i = newInterest.iterator();
- while (i.hasNext()) {
- String next = (String)i.next();
- if (!oldInterest.contains(next)) {
- deltaInterest.add(next);
- }
- }
- }
- }
-
- if (servicesInfo.size() > 0) {
- logger.info("search for matches to trigger callbacks with delta: " + deltaInterest);
- } else {
- logger.info("nothing to search for matches to trigger callbacks with delta: " + deltaInterest);
- }
- Iterator<String> i = deltaInterest.iterator();
- while (i.hasNext()) {
- String next = i.next();
- for (ServiceEndpointDescription sd : servicesInfo.keySet()) {
- triggerCallbacks(tracker, next, isFilter, sd, AVAILABLE);
- }
- }
- }
-
- private void triggerCallbacks(DiscoveredServiceTracker tracker,
- String toMatch,
- boolean isFilter,
- ServiceEndpointDescription sd,
- int type) {
- logger.fine("check if string: " + toMatch
- + (isFilter ? " matches " : " contained by ")
- + sd.getProvidedInterfaces());
-
- DiscoveredServiceNotification notification =
- isFilter ? (filterMatches(toMatch, sd) ? new DiscoveredServiceNotificationImpl(sd, true, toMatch, type)
- : null) : (sd.getProvidedInterfaces().contains(toMatch)
- ? new DiscoveredServiceNotificationImpl(sd, false, toMatch, type) : null);
-
- if (notification != null) {
- tracker.serviceChanged(notification);
- }
- }
-
- private boolean filterMatches(String filterValue, ServiceEndpointDescription sd) {
- Filter filter = createFilter(filterValue);
- return filter != null ? filter.match(getServiceProperties(null, sd)) : false;
- }
-
- private Filter createFilter(String filterValue) {
-
- if (filterValue == null) {
- return null;
- }
-
- try {
- return context.createFilter(filterValue);
- } catch (InvalidSyntaxException ex) {
- System.out.println("Invalid filter expression " + filterValue);
- } catch (Exception ex) {
- System.out.println("Problem creating a Filter from " + filterValue);
- }
- return null;
- }
-
- @SuppressWarnings("unchecked")
- private Dictionary<String, Object> getServiceProperties(String interfaceName, ServiceEndpointDescription sd) {
- Dictionary<String, Object> d = new Hashtable<String, Object>(sd.getProperties());
-
- String[] interfaceNames = getProvidedInterfaces(sd, interfaceName);
- if (interfaceNames != null) {
- d.put(INTERFACE_MATCH_CRITERIA, interfaceNames);
- }
- return d;
- }
-
- @SuppressWarnings("unchecked")
- private static String[] getProvidedInterfaces(ServiceEndpointDescription sd, String interfaceName) {
-
- Collection<String> interfaceNames = sd.getProvidedInterfaces();
- if (interfaceName == null) {
- return null;
- }
-
- Iterator<String> iNames = interfaceNames.iterator();
- while (iNames.hasNext()) {
- if (iNames.next().equals(interfaceName)) {
- return new String[] {interfaceName};
- }
- }
- return null;
- }
-
- static Collection<String> removeTracker(DiscoveredServiceTracker tracker,
- Map<String, List<DiscoveredServiceTracker>> forwardMap,
- Map<DiscoveredServiceTracker, Collection<String>> reverseMap) {
- Collection<String> collection = reverseMap.get(tracker);
- if (!isEmpty(collection)) {
- reverseMap.remove(tracker);
- Iterator<String> i = collection.iterator();
- while (i.hasNext()) {
- String element = i.next();
- if (forwardMap.containsKey(element)) {
- forwardMap.get(element).remove(tracker);
- } else {
- // if the element wasn't on the forwardmap, its a new element and
- // shouldn't be returned as part of the collection of old ones
- i.remove();
- }
- }
- }
- return collection;
- }
-
- private static boolean isEmpty(Collection<?> c) {
- return c == null || c.isEmpty();
- }
-
- @SuppressWarnings("unchecked")
- static Collection<String> addTracker(ServiceReference reference,
- DiscoveredServiceTracker tracker,
- String property,
- Map<String, List<DiscoveredServiceTracker>> forwardMap,
- Map<DiscoveredServiceTracker, Collection<String>> reverseMap) {
- Collection<String> collection = (Collection<String>)reference.getProperty(property);
- logger.info("adding tracker: " + tracker
- + " collection: "
- + collection
- + " registered against prop: "
- + property);
- if (!isEmpty(collection)) {
- reverseMap.put(tracker, new ArrayList<String>(collection));
- Iterator<String> i = collection.iterator();
- while (i.hasNext()) {
- String element = i.next();
- if (forwardMap.containsKey(element)) {
- forwardMap.get(element).add(tracker);
- } else {
- List<DiscoveredServiceTracker> trackerList = new ArrayList<DiscoveredServiceTracker>();
- trackerList.add(tracker);
- forwardMap.put(element, trackerList);
- }
- }
- }
- return collection;
- }
-
- protected void discoveredServiceChanged(ServiceEndpointDescription sd, int type) {
- for (Map.Entry<DiscoveredServiceTracker, Collection<String>> entry : trackersToInterfaces.entrySet()) {
- for (String match : entry.getValue()) {
- triggerCallbacks(entry.getKey(), match, false, sd, type);
- }
- }
- for (Map.Entry<DiscoveredServiceTracker, Collection<String>> entry : trackersToFilters.entrySet()) {
- for (String match : entry.getValue()) {
- triggerCallbacks(entry.getKey(), match, true, sd, type);
- }
- }
- }
-
- /**
- * Publish the OSGi services that are exposed to SCA. For SCA, the replicated endpoint registry
- * serves are the discovery protocol. The OSGi services are added to endpoint registry first before
- * the ServicePublication services are registered so that othe Discovery services can see them.
- * @param ref
- * @param endpoint
- * @return
- */
- protected ServiceRegistration localServicePublished(ServiceReference ref, Endpoint endpoint) {
- EndpointPublication publication = new EndpointPublication(ref, endpoint);
- ServiceRegistration registration =
- ref.getBundle().getBundleContext().registerService(ServicePublication.class.getName(),
- publication,
- publication.getProperties());
- return registration;
- }
-
-}
diff --git a/java/sca/modules/node-impl-osgi/src/main/java/org/apache/tuscany/sca/dosgi/discovery/DiscoveredServiceNotificationImpl.java b/java/sca/modules/node-impl-osgi/src/main/java/org/apache/tuscany/sca/dosgi/discovery/DiscoveredServiceNotificationImpl.java
deleted file mode 100644
index a50721fbfc..0000000000
--- a/java/sca/modules/node-impl-osgi/src/main/java/org/apache/tuscany/sca/dosgi/discovery/DiscoveredServiceNotificationImpl.java
+++ /dev/null
@@ -1,67 +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.tuscany.sca.dosgi.discovery;
-
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.HashSet;
-
-import org.osgi.service.discovery.DiscoveredServiceNotification;
-import org.osgi.service.discovery.ServiceEndpointDescription;
-
-public class DiscoveredServiceNotificationImpl implements DiscoveredServiceNotification {
-
- private ServiceEndpointDescription discription;
- private Collection<String> interfaces;
- private Collection<String> filters;
- private int type;
-
- public DiscoveredServiceNotificationImpl(ServiceEndpointDescription sd, boolean isFilter, String match, int type) {
- this.discription = sd;
- if (isFilter) {
- filters = new ArrayList<String>();
- filters.add(match);
- interfaces = Collections.emptySet();
- } else {
- interfaces = new HashSet<String>();
- interfaces.add(match);
- filters = Collections.emptyList();
- }
-
- this.type = type;
- }
-
- public ServiceEndpointDescription getServiceEndpointDescription() {
- return discription;
- }
-
- public int getType() {
- return type;
- }
-
- public Collection<String> getInterfaces() {
- return interfaces;
- }
-
- public Collection<String> getFilters() {
- return filters;
- }
-}
diff --git a/java/sca/modules/node-impl-osgi/src/main/java/org/apache/tuscany/sca/dosgi/discovery/EndpointDescription.java b/java/sca/modules/node-impl-osgi/src/main/java/org/apache/tuscany/sca/dosgi/discovery/EndpointDescription.java
deleted file mode 100644
index 5cdb0a4a8a..0000000000
--- a/java/sca/modules/node-impl-osgi/src/main/java/org/apache/tuscany/sca/dosgi/discovery/EndpointDescription.java
+++ /dev/null
@@ -1,69 +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.tuscany.sca.dosgi.discovery;
-
-import static org.osgi.service.discovery.ServicePublication.ENDPOINT_ID;
-import static org.osgi.service.discovery.ServicePublication.ENDPOINT_LOCATION;
-
-import java.net.URI;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.Map;
-
-import org.apache.tuscany.sca.assembly.ComponentService;
-import org.apache.tuscany.sca.assembly.Endpoint;
-import org.apache.tuscany.sca.interfacedef.Interface;
-import org.apache.tuscany.sca.interfacedef.InterfaceContract;
-import org.apache.tuscany.sca.interfacedef.java.JavaInterface;
-
-/**
- *
- */
-public class EndpointDescription extends ServiceEndpointDescriptionImpl {
- public EndpointDescription(Endpoint endpoint) {
- super(Collections.singleton(getInterfaceName(endpoint)), getServiceProperties(endpoint));
- }
-
- static String getInterfaceName(Endpoint endpoint) {
- ComponentService service = endpoint.getService();
- if (service == null) {
- return null;
- }
- InterfaceContract contract = service.getInterfaceContract();
- if (contract == null) {
- return null;
- }
- Interface intf = contract.getInterface();
- if (intf instanceof JavaInterface) {
- JavaInterface javaInterface = (JavaInterface)intf;
- return javaInterface.getName();
- }
-
- return null;
- }
-
- static Map<String, Object> getServiceProperties(Endpoint endpoint) {
- Map<String, Object> serviceProps = new HashMap<String, Object>();
- serviceProps.put(ENDPOINT_ID, endpoint.getURI());
- serviceProps.put(ENDPOINT_LOCATION, URI.create(endpoint.getBinding().getURI()));
- // TODO: Populate the properties from the Endpoint object
- return serviceProps;
- }
-}
diff --git a/java/sca/modules/node-impl-osgi/src/main/java/org/apache/tuscany/sca/dosgi/discovery/EndpointPublication.java b/java/sca/modules/node-impl-osgi/src/main/java/org/apache/tuscany/sca/dosgi/discovery/EndpointPublication.java
deleted file mode 100644
index 4c7cbee649..0000000000
--- a/java/sca/modules/node-impl-osgi/src/main/java/org/apache/tuscany/sca/dosgi/discovery/EndpointPublication.java
+++ /dev/null
@@ -1,63 +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.tuscany.sca.dosgi.discovery;
-
-import java.util.Collections;
-import java.util.Dictionary;
-import java.util.Hashtable;
-import java.util.Map;
-
-import org.apache.tuscany.sca.assembly.Endpoint;
-import org.osgi.framework.ServiceReference;
-import org.osgi.service.discovery.ServicePublication;
-
-/**
- * Publication of an SCA endpoint
- */
-public class EndpointPublication implements ServicePublication {
- private Endpoint endpoint;
- private ServiceReference reference;
-
- /**
- * Create a publication for the endpoint
- * @param reference The OSGi service reference for the given endpoint. The SCA endpoint
- * is pointing to a local service in the OSGi service registry
- */
- public EndpointPublication(ServiceReference reference, Endpoint endpoint) {
- super();
- this.reference = reference;
- this.endpoint = endpoint;
- }
-
- public ServiceReference getReference() {
- return reference;
- }
-
- public Dictionary<String, Object> getProperties() {
- Dictionary<String, Object> props = new Hashtable<String, Object>();
- Map<String, Object> serviceProps = EndpointDescription.getServiceProperties(endpoint);
- props.put(SERVICE_PROPERTIES, serviceProps);
- // TODO: Populate the properties from the Endpoint object
- String name = EndpointDescription.getInterfaceName(endpoint);
- props.put(ENDPOINT_INTERFACE_NAME, Collections.singleton(name));
- return props;
- }
-
-}
diff --git a/java/sca/modules/node-impl-osgi/src/main/java/org/apache/tuscany/sca/dosgi/discovery/LocalDiscoveryService.java b/java/sca/modules/node-impl-osgi/src/main/java/org/apache/tuscany/sca/dosgi/discovery/LocalDiscoveryService.java
deleted file mode 100644
index 543298600d..0000000000
--- a/java/sca/modules/node-impl-osgi/src/main/java/org/apache/tuscany/sca/dosgi/discovery/LocalDiscoveryService.java
+++ /dev/null
@@ -1,122 +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.tuscany.sca.dosgi.discovery;
-
-import static org.osgi.framework.Bundle.ACTIVE;
-import static org.osgi.framework.BundleEvent.STARTED;
-import static org.osgi.framework.BundleEvent.STOPPING;
-import static org.osgi.service.discovery.DiscoveredServiceNotification.AVAILABLE;
-import static org.osgi.service.discovery.DiscoveredServiceNotification.UNAVAILABLE;
-
-import java.util.Collections;
-import java.util.Enumeration;
-import java.util.Iterator;
-import java.util.List;
-import java.util.Map;
-import java.util.Map.Entry;
-
-import org.apache.tuscany.sca.implementation.osgi.ServiceDescriptions;
-import org.osgi.framework.Bundle;
-import org.osgi.framework.BundleContext;
-import org.osgi.framework.BundleEvent;
-import org.osgi.framework.BundleListener;
-import org.osgi.service.discovery.ServiceEndpointDescription;
-
-public class LocalDiscoveryService extends AbstractDiscoveryService implements BundleListener {
-
- public LocalDiscoveryService(BundleContext context) {
- super(context);
- init();
- }
-
- private void init() {
- context.addBundleListener(this);
- getExtensionPointRegistry();
- processExistingBundles();
- }
-
- public void bundleChanged(BundleEvent event) {
- switch (event.getType()) {
- case STARTED:
- discover(event.getBundle());
- break;
- case STOPPING:
- removeServicesDeclaredInBundle(event.getBundle());
- break;
- }
- }
-
- private void processExistingBundles() {
- Bundle[] bundles = context.getBundles();
- if (bundles == null) {
- return;
- }
-
- for (Bundle b : bundles) {
- if (b.getState() == ACTIVE) {
- discover(b);
- }
- }
- }
-
- private void discover(Bundle b) {
- String path = (String)b.getHeaders().get(ServiceDescriptions.REMOTE_SERVICE_HEADER);
- if (path == null) {
- Enumeration files = b.findEntries(ServiceDescriptions.REMOTE_SERVICE_FOLDER, "*.xml", false);
- if (files == null || !files.hasMoreElements()) {
- return;
- }
- }
-
- ServiceDescriptions descriptions = null;
-
- // TODO: Use SCA contribution to load the service discription files
- List<ServiceEndpointDescription> refs = Collections.emptyList();
- for (ServiceEndpointDescription sed : refs) {
- servicesInfo.put(sed, b);
- serviceDescriptionAdded(sed);
- }
- // throw new RuntimeException("To be implemented");
- }
-
- private void removeServicesDeclaredInBundle(Bundle bundle) {
- for (Iterator<Map.Entry<ServiceEndpointDescription, Bundle>> i = servicesInfo.entrySet().iterator(); i
- .hasNext();) {
- Entry<ServiceEndpointDescription, Bundle> entry = i.next();
- if (entry.getValue().equals(bundle)) {
- serviceDescriptionRemoved(entry.getKey());
- i.remove();
- }
- }
- }
-
- private void serviceDescriptionAdded(ServiceEndpointDescription sd) {
- discoveredServiceChanged(sd, AVAILABLE);
- }
-
- private void serviceDescriptionRemoved(ServiceEndpointDescription sd) {
- discoveredServiceChanged(sd, UNAVAILABLE);
- }
-
- public void stop() {
- context.removeBundleListener(this);
- super.stop();
- }
-
-}
diff --git a/java/sca/modules/node-impl-osgi/src/main/java/org/apache/tuscany/sca/dosgi/discovery/ServiceEndpointDescriptionImpl.java b/java/sca/modules/node-impl-osgi/src/main/java/org/apache/tuscany/sca/dosgi/discovery/ServiceEndpointDescriptionImpl.java
deleted file mode 100644
index cd3b8e7543..0000000000
--- a/java/sca/modules/node-impl-osgi/src/main/java/org/apache/tuscany/sca/dosgi/discovery/ServiceEndpointDescriptionImpl.java
+++ /dev/null
@@ -1,135 +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.tuscany.sca.dosgi.discovery;
-
-import static org.osgi.service.discovery.ServicePublication.ENDPOINT_ID;
-import static org.osgi.service.discovery.ServicePublication.ENDPOINT_LOCATION;
-import static org.osgi.service.discovery.ServicePublication.SERVICE_INTERFACE_NAME;
-
-import java.net.URI;
-import java.net.URISyntaxException;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.HashSet;
-import java.util.Map;
-import java.util.Set;
-import java.util.logging.Logger;
-
-import org.osgi.service.discovery.ServiceEndpointDescription;
-
-public class ServiceEndpointDescriptionImpl implements ServiceEndpointDescription {
-
- private static final Logger logger = Logger.getLogger(ServiceEndpointDescriptionImpl.class.getName());
-
- private Set<String> interfaces;
- private Map<String, Object> properties;
-
- public ServiceEndpointDescriptionImpl(Collection<String> interfaceNames) {
- this(interfaceNames, Collections.<String, Object> singletonMap(SERVICE_INTERFACE_NAME,
- interfaceNames));
- }
-
- public ServiceEndpointDescriptionImpl(Collection<String> interfaceNames, Map<String, Object> remoteProperties) {
- this.interfaces = new HashSet<String>(interfaceNames);
- this.properties = remoteProperties;
- }
-
- public ServiceEndpointDescriptionImpl(String interfaceName) {
- this(Collections.singleton(interfaceName));
- }
-
- @Override
- public boolean equals(Object obj) {
- if (this == obj)
- return true;
- if (obj == null)
- return false;
- if (getClass() != obj.getClass())
- return false;
- ServiceEndpointDescriptionImpl other = (ServiceEndpointDescriptionImpl)obj;
- if (interfaces == null) {
- if (other.interfaces != null)
- return false;
- } else if (!interfaces.equals(other.interfaces))
- return false;
- if (properties == null) {
- if (other.properties != null)
- return false;
- } else if (!properties.equals(other.properties))
- return false;
- return true;
- }
-
- public String getEndpointID() {
- Object val = properties.get(ENDPOINT_ID);
- if (val == null) {
- return null;
- } else {
- return val.toString();
- }
- }
-
- public String getEndpointInterfaceName(String interfaceName) {
- return interfaceName;
- }
-
- public URI getLocation() {
- Object value = properties.get(ENDPOINT_LOCATION);
- if (value == null) {
- return null;
- }
-
- try {
- return new URI(value.toString());
- } catch (URISyntaxException ex) {
- logger.warning("Service document URL is malformed : " + value.toString());
- }
-
- return null;
- }
-
- public Map<String, Object> getProperties() {
- return Collections.unmodifiableMap(properties);
- }
-
- public Object getProperty(String key) {
- return properties.get(key);
- }
-
- public Collection<String> getPropertyKeys() {
- return getProperties().keySet();
- }
-
- public Collection<String> getProvidedInterfaces() {
- return interfaces;
- }
-
- public String getVersion(String interfaceName) {
- return "0.0";
- }
-
- @Override
- public int hashCode() {
- final int prime = 31;
- int result = 1;
- result = prime * result + ((interfaces == null) ? 0 : interfaces.hashCode());
- result = prime * result + ((properties == null) ? 0 : properties.hashCode());
- return result;
- }
-}
diff --git a/java/sca/modules/node-impl-osgi/src/main/java/org/apache/tuscany/sca/node/osgi/impl/NodeActivator.java b/java/sca/modules/node-impl-osgi/src/main/java/org/apache/tuscany/sca/node/osgi/impl/NodeActivator.java
index 00b0b680be..10667a3509 100644
--- a/java/sca/modules/node-impl-osgi/src/main/java/org/apache/tuscany/sca/node/osgi/impl/NodeActivator.java
+++ b/java/sca/modules/node-impl-osgi/src/main/java/org/apache/tuscany/sca/node/osgi/impl/NodeActivator.java
@@ -21,7 +21,9 @@ package org.apache.tuscany.sca.node.osgi.impl;
import static org.apache.tuscany.sca.node.osgi.impl.NodeManager.isSCABundle;
-import org.apache.tuscany.sca.dosgi.discovery.DiscoveryActivator;
+import org.apache.tuscany.sca.osgi.service.discovery.impl.DiscoveryActivator;
+import org.apache.tuscany.sca.osgi.service.remoteadmin.impl.RemoteAdminImpl;
+import org.apache.tuscany.sca.osgi.service.remoteadmin.impl.RemoteControllerImpl;
import org.osgi.framework.Bundle;
import org.osgi.framework.BundleActivator;
import org.osgi.framework.BundleContext;
@@ -37,7 +39,8 @@ public class NodeActivator implements BundleActivator, SynchronousBundleListener
private NodeManager manager;
private DiscoveryActivator discoveryActivator = new DiscoveryActivator();
- private OSGiServiceExporter exporter;
+ private RemoteAdminImpl remoteAdmin;
+ private RemoteControllerImpl controller;
private void init() {
synchronized (this) {
@@ -57,8 +60,14 @@ public class NodeActivator implements BundleActivator, SynchronousBundleListener
// FIXME: We should try to avoid aggressive initialization
init();
- exporter = new OSGiServiceExporter(context);
- exporter.start();
+ remoteAdmin = new RemoteAdminImpl(context);
+ remoteAdmin.start();
+
+ controller = new RemoteControllerImpl(context);
+ controller.start();
+
+// exporter = new OSGiServiceExporter(context);
+// exporter.start();
discoveryActivator.start(context);
@@ -80,10 +89,15 @@ public class NodeActivator implements BundleActivator, SynchronousBundleListener
public void stop(BundleContext context) throws Exception {
context.removeBundleListener(this);
bundleContext = null;
- exporter.stop();
- exporter = null;
+ controller.stop();
+ controller = null;
+// exporter.stop();
+// exporter = null;
discoveryActivator.stop(context);
discoveryActivator = null;
+
+ remoteAdmin.stop();
+ remoteAdmin = null;
}
public static BundleContext getBundleContext() {
diff --git a/java/sca/modules/node-impl-osgi/src/main/java/org/apache/tuscany/sca/node/osgi/impl/OSGiServiceExporter.java b/java/sca/modules/node-impl-osgi/src/main/java/org/apache/tuscany/sca/node/osgi/impl/OSGiServiceExporter.java
index d4a6580842..016c88ba43 100644
--- a/java/sca/modules/node-impl-osgi/src/main/java/org/apache/tuscany/sca/node/osgi/impl/OSGiServiceExporter.java
+++ b/java/sca/modules/node-impl-osgi/src/main/java/org/apache/tuscany/sca/node/osgi/impl/OSGiServiceExporter.java
@@ -19,24 +19,27 @@
package org.apache.tuscany.sca.node.osgi.impl;
-import static org.apache.tuscany.sca.implementation.osgi.OSGiProperty.SERVICE_EXPORTED_CONFIGS;
-import static org.apache.tuscany.sca.implementation.osgi.OSGiProperty.SERVICE_EXPORTED_INTERFACES;
-import static org.apache.tuscany.sca.implementation.osgi.OSGiProperty.SERVICE_IMPORTED;
-
+import java.util.ArrayList;
import java.util.Collections;
+import java.util.List;
+import org.apache.tuscany.sca.assembly.Component;
+import org.apache.tuscany.sca.assembly.ComponentService;
+import org.apache.tuscany.sca.assembly.Endpoint;
import org.apache.tuscany.sca.contribution.Contribution;
import org.apache.tuscany.sca.core.ExtensionPointRegistry;
-import org.apache.tuscany.sca.implementation.osgi.introspection.ExportedServiceIntrospector;
-import org.apache.tuscany.sca.node.Node;
+import org.apache.tuscany.sca.core.LifeCycleListener;
import org.apache.tuscany.sca.node.NodeFactory;
import org.apache.tuscany.sca.node.configuration.NodeConfiguration;
import org.apache.tuscany.sca.node.impl.NodeFactoryImpl;
import org.apache.tuscany.sca.node.impl.NodeImpl;
+import org.apache.tuscany.sca.osgi.service.remoteadmin.EndpointDescription;
+import org.apache.tuscany.sca.osgi.service.remoteadmin.ExportRegistration;
+import org.apache.tuscany.sca.osgi.service.remoteadmin.impl.EndpointDescriptionImpl;
+import org.apache.tuscany.sca.osgi.service.remoteadmin.impl.EndpointIntrospector;
+import org.apache.tuscany.sca.osgi.service.remoteadmin.impl.ExportRegistrationImpl;
import org.osgi.framework.BundleContext;
import org.osgi.framework.Constants;
-import org.osgi.framework.Filter;
-import org.osgi.framework.InvalidSyntaxException;
import org.osgi.framework.ServiceReference;
import org.osgi.util.tracker.ServiceTracker;
import org.osgi.util.tracker.ServiceTrackerCustomizer;
@@ -44,12 +47,12 @@ import org.osgi.util.tracker.ServiceTrackerCustomizer;
/**
* Watching and exporting OSGi services
*/
-public class OSGiServiceExporter implements ServiceTrackerCustomizer {
+public class OSGiServiceExporter implements ServiceTrackerCustomizer, LifeCycleListener {
private ExtensionPointRegistry registry;
private BundleContext context;
private ServiceTracker serviceTracker;
private NodeFactoryImpl nodeFactory;
- private ExportedServiceIntrospector introspector;
+ private EndpointIntrospector introspector;
/**
* @param context
@@ -64,11 +67,13 @@ public class OSGiServiceExporter implements ServiceTrackerCustomizer {
if (nodeFactory == null) {
this.nodeFactory = (NodeFactoryImpl)NodeFactory.newInstance();
this.nodeFactory.init();
- this.introspector = new ExportedServiceIntrospector(getExtensionPointRegistry());
+ this.introspector = new EndpointIntrospector(context, getExtensionPointRegistry());
}
}
public void start() {
+ init();
+ /*
String filterStr =
"(& (" + SERVICE_EXPORTED_CONFIGS
+ "=sca) ("
@@ -83,17 +88,23 @@ public class OSGiServiceExporter implements ServiceTrackerCustomizer {
} catch (InvalidSyntaxException e) {
// Ignore
}
+ */
}
public void stop() {
+ /*
if (serviceTracker != null) {
serviceTracker.close();
serviceTracker = null;
}
+ */
}
public Object addingService(ServiceReference reference) {
- init();
+ return exportService(reference);
+ }
+
+ public List<ExportRegistration> exportService(ServiceReference reference) {
try {
Contribution contribution = introspector.introspect(reference);
if (contribution != null) {
@@ -103,7 +114,17 @@ public class OSGiServiceExporter implements ServiceTrackerCustomizer {
configuration.getExtensions().add(reference.getBundle());
// FIXME: Configure the domain and node URI
NodeImpl node = new NodeImpl(nodeFactory, configuration, Collections.singletonList(contribution));
- return node.start();
+ node.start();
+ List<ExportRegistration> exportedServices = new ArrayList<ExportRegistration>();
+ Component component = contribution.getDeployables().get(0).getComponents().get(0);
+ ComponentService service = component.getServices().get(0);
+ for (Endpoint endpoint : service.getEndpoints()) {
+ EndpointDescription endpointDescription = new EndpointDescriptionImpl(endpoint);
+ ExportRegistration exportRegistration =
+ new ExportRegistrationImpl(node, reference, endpointDescription);
+ exportedServices.add(exportRegistration);
+ }
+ return exportedServices;
} else {
return null;
}
@@ -114,14 +135,15 @@ public class OSGiServiceExporter implements ServiceTrackerCustomizer {
}
public void modifiedService(ServiceReference reference, Object service) {
- Node node = (Node)service;
- node.stop();
- node.start();
+ removedService(reference, service);
+ exportService(reference);
}
public void removedService(ServiceReference reference, Object service) {
- Node node = (Node)service;
- node.stop();
+ List<ExportRegistration> exportedServices = (List<ExportRegistration>)service;
+ for(ExportRegistration exportRegistration: exportedServices) {
+ exportRegistration.close();
+ }
}
protected ExtensionPointRegistry getExtensionPointRegistry() {
diff --git a/java/sca/modules/node-impl-osgi/src/main/java/org/apache/tuscany/sca/node/osgi/impl/OSGiServiceImporter.java b/java/sca/modules/node-impl-osgi/src/main/java/org/apache/tuscany/sca/node/osgi/impl/OSGiServiceImporter.java
new file mode 100644
index 0000000000..7a0f3bbbc0
--- /dev/null
+++ b/java/sca/modules/node-impl-osgi/src/main/java/org/apache/tuscany/sca/node/osgi/impl/OSGiServiceImporter.java
@@ -0,0 +1,121 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT 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.tuscany.sca.node.osgi.impl;
+
+import java.util.Collections;
+
+import org.apache.tuscany.sca.assembly.Component;
+import org.apache.tuscany.sca.assembly.ComponentReference;
+import org.apache.tuscany.sca.contribution.Contribution;
+import org.apache.tuscany.sca.core.ExtensionPointRegistry;
+import org.apache.tuscany.sca.core.LifeCycleListener;
+import org.apache.tuscany.sca.node.Node;
+import org.apache.tuscany.sca.node.NodeFactory;
+import org.apache.tuscany.sca.node.configuration.NodeConfiguration;
+import org.apache.tuscany.sca.node.impl.NodeFactoryImpl;
+import org.apache.tuscany.sca.node.impl.NodeImpl;
+import org.apache.tuscany.sca.osgi.service.remoteadmin.EndpointDescription;
+import org.apache.tuscany.sca.osgi.service.remoteadmin.ImportRegistration;
+import org.apache.tuscany.sca.osgi.service.remoteadmin.impl.EndpointIntrospector;
+import org.apache.tuscany.sca.osgi.service.remoteadmin.impl.ImportRegistrationImpl;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.ServiceReference;
+import org.osgi.util.tracker.ServiceTracker;
+
+/**
+ * Watching and exporting OSGi services
+ */
+public class OSGiServiceImporter implements LifeCycleListener {
+ private ExtensionPointRegistry registry;
+ private BundleContext context;
+ private NodeFactoryImpl nodeFactory;
+ private EndpointIntrospector introspector;
+
+ /**
+ * @param context
+ * @param clazz
+ * @param customizer
+ */
+ public OSGiServiceImporter(BundleContext context) {
+ this.context = context;
+ }
+
+ private synchronized void init() {
+ if (nodeFactory == null) {
+ this.nodeFactory = (NodeFactoryImpl)NodeFactory.newInstance();
+ this.nodeFactory.init();
+ this.introspector = new EndpointIntrospector(context, getExtensionPointRegistry());
+ }
+ }
+
+ public void start() {
+ }
+
+ public void stop() {
+ }
+
+ public ImportRegistration importService(Bundle bundle, EndpointDescription endpointDescription) {
+ init();
+ try {
+ Contribution contribution = introspector.introspect(bundle, endpointDescription);
+ if (contribution != null) {
+
+ NodeConfiguration configuration = nodeFactory.createNodeConfiguration();
+ configuration.setURI("osgi.reference." + endpointDescription.getURI());
+ configuration.getExtensions().add(bundle);
+ // FIXME: Configure the domain and node URI
+ NodeImpl node = new NodeImpl(nodeFactory, configuration, Collections.singletonList(contribution));
+ node.start();
+
+ Component component = contribution.getDeployables().get(0).getComponents().get(0);
+ ComponentReference componentReference = component.getReferences().get(0);
+ ServiceReference serviceReference =
+ context.getServiceReference("(sca.reference=" + component.getURI()
+ + "#reference("
+ + componentReference.getName()
+ + ")");
+ return new ImportRegistrationImpl(node, serviceReference, endpointDescription);
+ } else {
+ return null;
+ }
+ } catch (Exception e) {
+ e.printStackTrace();
+ return null;
+ }
+ }
+
+ public void unimportService(ImportRegistration importRegistration) {
+ Node node = (Node)importRegistration.getImportedService().getProperty("sca.node");
+ node.stop();
+ }
+
+ protected ExtensionPointRegistry getExtensionPointRegistry() {
+ if (registry == null) {
+ ServiceTracker tracker = new ServiceTracker(context, ExtensionPointRegistry.class.getName(), null);
+ tracker.open();
+ // tracker.waitForService(1000);
+ registry = (ExtensionPointRegistry)tracker.getService();
+ tracker.close();
+ }
+ return registry;
+ }
+
+}
diff --git a/java/sca/modules/node-impl-osgi/src/main/java/org/apache/tuscany/sca/osgi/service/discovery/impl/AbstractDiscoveryService.java b/java/sca/modules/node-impl-osgi/src/main/java/org/apache/tuscany/sca/osgi/service/discovery/impl/AbstractDiscoveryService.java
new file mode 100644
index 0000000000..d56b25ef40
--- /dev/null
+++ b/java/sca/modules/node-impl-osgi/src/main/java/org/apache/tuscany/sca/osgi/service/discovery/impl/AbstractDiscoveryService.java
@@ -0,0 +1,280 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT 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.tuscany.sca.osgi.service.discovery.impl;
+
+import static org.apache.tuscany.sca.osgi.service.remoteadmin.EndpointListener.ENDPOINT_LISTENER_SCOPE;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Dictionary;
+import java.util.HashMap;
+import java.util.Hashtable;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+import org.apache.tuscany.sca.core.ExtensionPointRegistry;
+import org.apache.tuscany.sca.core.LifeCycleListener;
+import org.apache.tuscany.sca.node.NodeFactory;
+import org.apache.tuscany.sca.node.impl.NodeFactoryImpl;
+import org.apache.tuscany.sca.osgi.service.remoteadmin.EndpointDescription;
+import org.apache.tuscany.sca.osgi.service.remoteadmin.EndpointListener;
+import org.apache.tuscany.sca.osgi.service.remoteadmin.RemoteConstants;
+import org.apache.tuscany.sca.osgi.service.remoteadmin.impl.RemoteAdminHelper;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.Constants;
+import org.osgi.framework.Filter;
+import org.osgi.framework.ServiceReference;
+import org.osgi.util.tracker.ServiceTracker;
+
+/**
+ *
+ */
+public abstract class AbstractDiscoveryService implements Discovery, LifeCycleListener {
+ protected final static int ADDED = 0x1;
+ protected final static int REMOVED = 0x2;
+ protected final static int MODIFIED = 0x4;
+
+ protected final static Logger logger = Logger.getLogger(AbstractDiscoveryService.class.getName());
+
+ protected BundleContext context;
+ protected ExtensionPointRegistry registry;
+
+ private Map<String, List<EndpointListener>> filtersToListeners = new HashMap<String, List<EndpointListener>>();
+ // this is effectively a set which allows for multiple service descriptions with the
+ // same interface name but different properties and takes care of itself with respect to concurrency
+ protected Map<EndpointDescription, Bundle> servicesInfo = new ConcurrentHashMap<EndpointDescription, Bundle>();
+ private Map<EndpointListener, Collection<String>> listenersToFilters =
+ new HashMap<EndpointListener, Collection<String>>();
+ private ServiceTracker trackerTracker;
+
+ public AbstractDiscoveryService(BundleContext context) {
+ super();
+ this.context = context;
+ }
+
+ public void start() {
+ // track the registration of EndpointListener
+ trackerTracker = new ServiceTracker(this.context, EndpointListener.class.getName(), null) {
+ public Object addingService(ServiceReference reference) {
+ Object result = super.addingService(reference);
+ cacheTracker(reference, result);
+ return result;
+ }
+
+ public void modifiedService(ServiceReference reference, Object service) {
+ super.modifiedService(reference, service);
+ updateTracker(reference, service);
+ }
+
+ public void removedService(ServiceReference reference, Object service) {
+ super.removedService(reference, service);
+ clearTracker(service);
+ }
+ };
+
+ trackerTracker.open();
+ }
+
+ public void stop() {
+ trackerTracker.close();
+ }
+
+ protected ExtensionPointRegistry getExtensionPointRegistry() {
+ NodeFactoryImpl factory = (NodeFactoryImpl)NodeFactory.newInstance();
+ factory.init();
+ ServiceTracker tracker = new ServiceTracker(context, ExtensionPointRegistry.class.getName(), null);
+ tracker.open();
+ // tracker.waitForService(1000);
+ registry = (ExtensionPointRegistry)tracker.getService();
+ tracker.close();
+ return registry;
+ }
+
+ protected Dictionary<String, Object> getProperties() {
+ Dictionary headers = context.getBundle().getHeaders();
+ Hashtable<String, Object> props = new Hashtable<String, Object>();
+ props.put(PRODUCT_NAME, "Apache Tuscany SCA");
+ props.put(PRODUCT_VERSION, headers.get(Constants.BUNDLE_VERSION));
+ props.put(VENDOR_NAME, headers.get(Constants.BUNDLE_VENDOR));
+ props.put(SUPPORTED_PROTOCOLS, new String[] {"local", "sca"});
+ return props;
+ }
+
+ private synchronized void cacheTracker(ServiceReference reference, Object service) {
+ if (service instanceof EndpointListener) {
+ EndpointListener listener = (EndpointListener)service;
+ Collection<String> filters =
+ addTracker(reference, listener, ENDPOINT_LISTENER_SCOPE, filtersToListeners, listenersToFilters);
+
+ triggerCallbacks(null, filters, listener, true);
+ }
+ }
+
+ private synchronized void clearTracker(Object service) {
+ if (service instanceof EndpointListener) {
+ removeTracker((EndpointListener)service, filtersToListeners, listenersToFilters);
+ }
+ }
+
+ private synchronized void updateTracker(ServiceReference reference, Object service) {
+ if (service instanceof EndpointListener) {
+ EndpointListener listener = (EndpointListener)service;
+ if (logger.isLoggable(Level.FINE)) {
+ logger.fine("updating listener: " + listener);
+ }
+ Collection<String> oldFilters = removeTracker(listener, filtersToListeners, listenersToFilters);
+
+ Collection<String> newFilters =
+ addTracker(reference, listener, ENDPOINT_LISTENER_SCOPE, filtersToListeners, listenersToFilters);
+
+ triggerCallbacks(oldFilters, newFilters, listener, true);
+ }
+ }
+
+ private void triggerCallbacks(Collection<String> oldInterest,
+ Collection<String> newInterest,
+ EndpointListener listener,
+ boolean isFilter) {
+ // compute delta between old & new interfaces/filters and
+ // trigger callbacks for any entries in servicesInfo that
+ // match any *additional* interface/filters
+ Collection<String> deltaInterest = new ArrayList<String>();
+ if (newInterest != null && !newInterest.isEmpty()) {
+ if (oldInterest == null || oldInterest.isEmpty()) {
+ deltaInterest.addAll(newInterest);
+ } else {
+ Iterator<String> i = newInterest.iterator();
+ while (i.hasNext()) {
+ String next = (String)i.next();
+ if (!oldInterest.contains(next)) {
+ deltaInterest.add(next);
+ }
+ }
+ }
+ }
+
+ if (logger.isLoggable(Level.FINE)) {
+ if (servicesInfo.size() > 0) {
+ logger.fine("search for matches to trigger callbacks with delta: " + deltaInterest);
+ } else {
+ logger.fine("nothing to search for matches to trigger callbacks with delta: " + deltaInterest);
+ }
+ }
+ Iterator<String> i = deltaInterest.iterator();
+ while (i.hasNext()) {
+ String next = i.next();
+ for (EndpointDescription sd : servicesInfo.keySet()) {
+ triggerCallbacks(listener, next, sd, ADDED);
+ }
+ }
+ }
+
+ private void triggerCallbacks(EndpointListener listener, String matchedFilter, EndpointDescription sd, int type) {
+ switch (type) {
+ case ADDED:
+ listener.addEndpoint(sd, matchedFilter);
+ break;
+ case REMOVED:
+ listener.removeEndpoint(sd);
+ break;
+ case MODIFIED:
+ listener.removeEndpoint(sd);
+ listener.addEndpoint(sd, matchedFilter);
+ break;
+ }
+ }
+
+ private boolean filterMatches(String filterValue, EndpointDescription sd) {
+ Filter filter = RemoteAdminHelper.createFilter(context, filterValue);
+ Hashtable<String, Object> props = new Hashtable<String, Object>(sd.getProperties());
+ // Add two faked properties to make the filter match
+ props.put(Constants.OBJECTCLASS, sd.getInterfaces());
+ props.put(RemoteConstants.SERVICE_IMPORTED, "true");
+ return filter != null ? filter.match(props) : false;
+ }
+
+ static Collection<String> removeTracker(EndpointListener listener,
+ Map<String, List<EndpointListener>> forwardMap,
+ Map<EndpointListener, Collection<String>> reverseMap) {
+ Collection<String> collection = reverseMap.get(listener);
+ if (collection != null && !collection.isEmpty()) {
+ reverseMap.remove(listener);
+ Iterator<String> i = collection.iterator();
+ while (i.hasNext()) {
+ String element = i.next();
+ if (forwardMap.containsKey(element)) {
+ forwardMap.get(element).remove(listener);
+ } else {
+ // if the element wasn't on the forwardmap, its a new element and
+ // shouldn't be returned as part of the collection of old ones
+ i.remove();
+ }
+ }
+ }
+ return collection;
+ }
+
+ @SuppressWarnings("unchecked")
+ static Collection<String> addTracker(ServiceReference reference,
+ EndpointListener listener,
+ String property,
+ Map<String, List<EndpointListener>> forwardMap,
+ Map<EndpointListener, Collection<String>> reverseMap) {
+ Collection<String> collection = RemoteAdminHelper.getStringCollection(reference, property);
+ if (logger.isLoggable(Level.FINE)) {
+ logger.fine("adding listener: " + listener
+ + " collection: "
+ + collection
+ + " registered against prop: "
+ + property);
+ }
+ if (collection != null && !collection.isEmpty()) {
+ reverseMap.put(listener, new ArrayList<String>(collection));
+ Iterator<String> i = collection.iterator();
+ while (i.hasNext()) {
+ String element = i.next();
+ if (forwardMap.containsKey(element)) {
+ forwardMap.get(element).add(listener);
+ } else {
+ List<EndpointListener> trackerList = new ArrayList<EndpointListener>();
+ trackerList.add(listener);
+ forwardMap.put(element, trackerList);
+ }
+ }
+ }
+ return collection;
+ }
+
+ protected void endpointChanged(EndpointDescription sd, int type) {
+ for (Map.Entry<EndpointListener, Collection<String>> entry : listenersToFilters.entrySet()) {
+ for (String filter : entry.getValue()) {
+ if (filterMatches(filter, sd)) {
+ triggerCallbacks(entry.getKey(), filter, sd, type);
+ }
+ }
+ }
+ }
+
+}
diff --git a/java/sca/modules/node-impl-osgi/src/main/java/org/osgi/service/discovery/Discovery.java b/java/sca/modules/node-impl-osgi/src/main/java/org/apache/tuscany/sca/osgi/service/discovery/impl/Discovery.java
index fd99b0282c..3ad1e53fee 100644
--- a/java/sca/modules/node-impl-osgi/src/main/java/org/osgi/service/discovery/Discovery.java
+++ b/java/sca/modules/node-impl-osgi/src/main/java/org/apache/tuscany/sca/osgi/service/discovery/impl/Discovery.java
@@ -1,20 +1,22 @@
/*
- * Copyright (c) OSGi Alliance (2008, 2009). All Rights Reserved.
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
*
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
+ * http://www.apache.org/licenses/LICENSE-2.0
*
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT 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.osgi.service.discovery;
+package org.apache.tuscany.sca.osgi.service.discovery.impl;
/**
* Every Discovery Provider registers a service implementing this interface.
@@ -23,9 +25,7 @@ package org.osgi.service.discovery;
* functionality, its version, vendor, used protocols etc..
* <p>
* Discovery allows to publish services exposed for remote access as well as to
- * search for remote services. Register a {@link ServicePublication} service in
- * order to publish service metadata and or a {@link DiscoveredServiceTracker}
- * service in order to search for remote services.
+ * search for remote services.
* <p>
* Discovery service implementations usually rely on some discovery protocols or
* other information distribution means.
@@ -39,21 +39,21 @@ public interface Discovery {
* <p>
* Value of this property is of type <code>String</code>.
*/
- static final String PRODUCT_NAME = "osgi.remote.discovery.product";
+ String PRODUCT_NAME = "osgi.remote.discovery.product";
/**
* ServiceRegistration property for the version of the Discovery product.
* <p>
* Value of this property is of type <code>String</code>.
*/
- static final String PRODUCT_VERSION = "osgi.remote.discovery.product.version";
+ String PRODUCT_VERSION = "osgi.remote.discovery.product.version";
/**
* ServiceRegistration property for the Discovery product vendor name.
* <p>
* Value of this property is of type <code>String</code>.
*/
- static final String VENDOR_NAME = "osgi.remote.discovery.vendor";
+ String VENDOR_NAME = "osgi.remote.discovery.vendor";
/**
* ServiceRegistration property that lists the discovery protocols used by
@@ -62,5 +62,5 @@ public interface Discovery {
* Value of this property is of type
* <code>Collection (&lt;? extends String&gt;)</code>.
*/
- static final String SUPPORTED_PROTOCOLS = "osgi.remote.discovery.supported_protocols";
+ String SUPPORTED_PROTOCOLS = "osgi.remote.discovery.supported_protocols";
}
diff --git a/java/sca/modules/node-impl-osgi/src/main/java/org/apache/tuscany/sca/dosgi/discovery/DiscoveryActivator.java b/java/sca/modules/node-impl-osgi/src/main/java/org/apache/tuscany/sca/osgi/service/discovery/impl/DiscoveryActivator.java
index 92951321d0..9a48dd25f7 100644
--- a/java/sca/modules/node-impl-osgi/src/main/java/org/apache/tuscany/sca/dosgi/discovery/DiscoveryActivator.java
+++ b/java/sca/modules/node-impl-osgi/src/main/java/org/apache/tuscany/sca/osgi/service/discovery/impl/DiscoveryActivator.java
@@ -16,16 +16,14 @@
* specific language governing permissions and limitations
* under the License.
*/
-package org.apache.tuscany.sca.dosgi.discovery;
+package org.apache.tuscany.sca.osgi.service.discovery.impl;
import java.util.ArrayList;
-import java.util.Hashtable;
import java.util.List;
import org.osgi.framework.BundleActivator;
import org.osgi.framework.BundleContext;
import org.osgi.framework.ServiceRegistration;
-import org.osgi.service.discovery.Discovery;
public class DiscoveryActivator implements BundleActivator {
private List<AbstractDiscoveryService> discoveryServices = new ArrayList<AbstractDiscoveryService>();
@@ -37,12 +35,9 @@ public class DiscoveryActivator implements BundleActivator {
discoveryServices.add(new DomainDiscoveryService(context));
for (AbstractDiscoveryService service : discoveryServices) {
- Hashtable<String, Object> props = new Hashtable<String, Object>();
- props.put(Discovery.PRODUCT_NAME, "Apache Tuscany SCA");
- props.put(Discovery.PRODUCT_VERSION, "2.0.0");
- props.put(Discovery.VENDOR_NAME, "Apache Software Foundation");
+ service.start();
ServiceRegistration registration =
- context.registerService(Discovery.class.getName(), service, props);
+ context.registerService(Discovery.class.getName(), service, service.getProperties());
discoveryServiceRegistrations.add(registration);
}
}
diff --git a/java/sca/modules/node-impl-osgi/src/main/java/org/apache/tuscany/sca/dosgi/discovery/DomainDiscoveryService.java b/java/sca/modules/node-impl-osgi/src/main/java/org/apache/tuscany/sca/osgi/service/discovery/impl/DomainDiscoveryService.java
index 5f63e3c92d..cd091f3258 100644
--- a/java/sca/modules/node-impl-osgi/src/main/java/org/apache/tuscany/sca/dosgi/discovery/DomainDiscoveryService.java
+++ b/java/sca/modules/node-impl-osgi/src/main/java/org/apache/tuscany/sca/osgi/service/discovery/impl/DomainDiscoveryService.java
@@ -17,27 +17,17 @@
* under the License.
*/
-package org.apache.tuscany.sca.dosgi.discovery;
-
-import static org.osgi.service.discovery.DiscoveredServiceNotification.AVAILABLE;
-import static org.osgi.service.discovery.DiscoveredServiceNotification.UNAVAILABLE;
-
-import java.util.Map;
-import java.util.concurrent.ConcurrentHashMap;
+package org.apache.tuscany.sca.osgi.service.discovery.impl;
import org.apache.tuscany.sca.assembly.Endpoint;
import org.apache.tuscany.sca.assembly.Implementation;
import org.apache.tuscany.sca.core.UtilityExtensionPoint;
import org.apache.tuscany.sca.implementation.osgi.OSGiImplementation;
-import org.apache.tuscany.sca.interfacedef.Interface;
-import org.apache.tuscany.sca.interfacedef.java.JavaInterface;
+import org.apache.tuscany.sca.osgi.service.remoteadmin.EndpointDescription;
+import org.apache.tuscany.sca.osgi.service.remoteadmin.impl.EndpointDescriptionImpl;
import org.apache.tuscany.sca.runtime.EndpointListener;
import org.apache.tuscany.sca.runtime.EndpointRegistry;
import org.osgi.framework.BundleContext;
-import org.osgi.framework.InvalidSyntaxException;
-import org.osgi.framework.ServiceReference;
-import org.osgi.framework.ServiceRegistration;
-import org.osgi.service.discovery.ServiceEndpointDescription;
/**
* Discovery service based on the distributed SCA domain
@@ -45,15 +35,12 @@ import org.osgi.service.discovery.ServiceEndpointDescription;
public class DomainDiscoveryService extends AbstractDiscoveryService implements EndpointListener {
private EndpointRegistry endpointRegistry;
- private Map<String, ServiceRegistration> endpointRegistrations =
- new ConcurrentHashMap<String, ServiceRegistration>();
-
public DomainDiscoveryService(BundleContext context) {
super(context);
- init();
}
- private void init() {
+ public void start() {
+ super.start();
getExtensionPointRegistry();
this.endpointRegistry =
registry.getExtensionPoint(UtilityExtensionPoint.class).getUtility(EndpointRegistry.class);
@@ -69,8 +56,8 @@ public class DomainDiscoveryService extends AbstractDiscoveryService implements
OSGiImplementation osgiImpl = (OSGiImplementation)impl;
BundleContext bundleContext = osgiImpl.getBundle().getBundleContext();
+ /*
if (!endpoint.isRemote()) {
-
Interface intf = endpoint.getService().getInterfaceContract().getInterface();
JavaInterface javaInterface = (JavaInterface)intf;
// String filter = getOSGiFilter(provider.getOSGiProperties(service));
@@ -84,27 +71,31 @@ public class DomainDiscoveryService extends AbstractDiscoveryService implements
// Ignore
}
if (ref != null) {
- ServiceRegistration registration = localServicePublished(ref, endpoint);
- endpointRegistrations.put(endpoint.getURI(), registration);
+
}
- } else {
- // Remote endpoints
- ServiceEndpointDescription description = new EndpointDescription(endpoint);
- discoveredServiceChanged(description, AVAILABLE);
+ } else
+ */
+ {
+ // Notify the endpoint listeners
+ EndpointDescription description = createEndpointDescription(endpoint);
+ endpointChanged(description, ADDED);
}
}
+ private EndpointDescription createEndpointDescription(Endpoint endpoint) {
+ EndpointDescription description = new EndpointDescriptionImpl(endpoint);
+ return description;
+ }
+
public void endpointRemoved(Endpoint endpoint) {
+ /*
if (!endpoint.isRemote()) {
- // unregister the ServicePublication here
- ServiceRegistration registration = endpointRegistrations.get(endpoint.getURI());
- if (registration != null) {
- registration.unregister();
- }
- } else {
- // Remote endpoints
- ServiceEndpointDescription description = new EndpointDescription(endpoint);
- discoveredServiceChanged(description, UNAVAILABLE);
+ // export services
+ } else
+ */
+ {
+ EndpointDescription description = createEndpointDescription(endpoint);
+ endpointChanged(description, REMOVED);
}
}
diff --git a/java/sca/modules/node-impl-osgi/src/main/java/org/apache/tuscany/sca/osgi/service/discovery/impl/LocalDiscoveryService.java b/java/sca/modules/node-impl-osgi/src/main/java/org/apache/tuscany/sca/osgi/service/discovery/impl/LocalDiscoveryService.java
new file mode 100644
index 0000000000..0fbcbc8395
--- /dev/null
+++ b/java/sca/modules/node-impl-osgi/src/main/java/org/apache/tuscany/sca/osgi/service/discovery/impl/LocalDiscoveryService.java
@@ -0,0 +1,208 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT 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.tuscany.sca.osgi.service.discovery.impl;
+
+import static org.osgi.framework.Bundle.ACTIVE;
+import static org.osgi.framework.BundleEvent.STARTED;
+import static org.osgi.framework.BundleEvent.STOPPING;
+
+import java.io.InputStream;
+import java.net.URL;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Enumeration;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.logging.Level;
+
+import javax.xml.stream.XMLInputFactory;
+import javax.xml.stream.XMLOutputFactory;
+import javax.xml.stream.XMLStreamReader;
+
+import org.apache.tuscany.sca.assembly.AssemblyFactory;
+import org.apache.tuscany.sca.contribution.processor.ExtensibleStAXArtifactProcessor;
+import org.apache.tuscany.sca.contribution.processor.StAXArtifactProcessor;
+import org.apache.tuscany.sca.contribution.processor.StAXArtifactProcessorExtensionPoint;
+import org.apache.tuscany.sca.core.FactoryExtensionPoint;
+import org.apache.tuscany.sca.core.UtilityExtensionPoint;
+import org.apache.tuscany.sca.implementation.osgi.ServiceDescription;
+import org.apache.tuscany.sca.implementation.osgi.ServiceDescriptions;
+import org.apache.tuscany.sca.monitor.Monitor;
+import org.apache.tuscany.sca.monitor.MonitorFactory;
+import org.apache.tuscany.sca.osgi.service.remoteadmin.EndpointDescription;
+import org.apache.tuscany.sca.osgi.service.remoteadmin.impl.EndpointDescriptionImpl;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.BundleEvent;
+import org.osgi.framework.BundleListener;
+
+public class LocalDiscoveryService extends AbstractDiscoveryService implements BundleListener {
+ private XMLInputFactory xmlInputFactory;
+ private XMLOutputFactory xmlOutputFactory;
+ private AssemblyFactory assemblyFactory;
+ private StAXArtifactProcessor processor;
+
+ public LocalDiscoveryService(BundleContext context) {
+ super(context);
+ }
+
+ public void start() {
+ super.start();
+ context.addBundleListener(this);
+ getExtensionPointRegistry();
+
+ FactoryExtensionPoint factories = registry.getExtensionPoint(FactoryExtensionPoint.class);
+ this.assemblyFactory = factories.getFactory(AssemblyFactory.class);
+ this.xmlInputFactory = factories.getFactory(XMLInputFactory.class);
+ this.xmlOutputFactory = factories.getFactory(XMLOutputFactory.class);
+ StAXArtifactProcessorExtensionPoint processors =
+ registry.getExtensionPoint(StAXArtifactProcessorExtensionPoint.class);
+ UtilityExtensionPoint utilities = this.registry.getExtensionPoint(UtilityExtensionPoint.class);
+ MonitorFactory monitorFactory = utilities.getUtility(MonitorFactory.class);
+ Monitor monitor = null;
+ if (monitorFactory != null) {
+ monitor = monitorFactory.createMonitor();
+ }
+ processor = new ExtensibleStAXArtifactProcessor(processors, xmlInputFactory, xmlOutputFactory, monitor);
+ processExistingBundles();
+ }
+
+ public void bundleChanged(BundleEvent event) {
+ switch (event.getType()) {
+ case STARTED:
+ discover(event.getBundle());
+ break;
+ case STOPPING:
+ removeServicesDeclaredInBundle(event.getBundle());
+ break;
+ }
+ }
+
+ private void processExistingBundles() {
+ Bundle[] bundles = context.getBundles();
+ if (bundles == null) {
+ return;
+ }
+
+ for (Bundle b : bundles) {
+ if (b.getState() == ACTIVE) {
+ discover(b);
+ }
+ }
+ }
+
+ private void discover(Bundle b) {
+ List<URL> urls = findServiceDescriptionsDocuments(b);
+ if (urls == null || urls.isEmpty()) {
+ return;
+ }
+
+ List<ServiceDescription> serviceDescriptions = new ArrayList<ServiceDescription>();
+
+ for (URL url : urls) {
+ ServiceDescriptions descriptions = null;
+ try {
+ descriptions = loadServiceDescriptions(url);
+ } catch (Exception e) {
+ logger.log(Level.SEVERE, e.getMessage(), e);
+ }
+ if (descriptions != null) {
+ serviceDescriptions.addAll(descriptions);
+ }
+ }
+
+ for (ServiceDescription sd : serviceDescriptions) {
+ EndpointDescription sed = createEndpointDescription(sd);
+ servicesInfo.put(sed, b);
+ serviceDescriptionAdded(sed);
+ }
+ }
+
+ private EndpointDescription createEndpointDescription(ServiceDescription sd) {
+ // Endpoint endpoint = assemblyFactory.createEndpoint();
+ EndpointDescription sed = new EndpointDescriptionImpl(sd.getInterfaces(), sd.getProperties());
+ return sed;
+ }
+
+ private List<URL> findServiceDescriptionsDocuments(Bundle b) {
+ List<URL> urls = null;
+ String path = (String)b.getHeaders().get(ServiceDescriptions.REMOTE_SERVICE_HEADER);
+ if (path == null) {
+ Enumeration<URL> files = b.findEntries(ServiceDescriptions.REMOTE_SERVICE_FOLDER, "*.xml", false);
+ if (files == null || !files.hasMoreElements()) {
+ return Collections.emptyList();
+ } else {
+ urls = new ArrayList<URL>();
+ while (files.hasMoreElements()) {
+ urls.add(files.nextElement());
+ }
+ }
+ } else {
+ URL url = b.getEntry(path);
+ if (url != null) {
+ urls = Collections.singletonList(url);
+ } else {
+ urls = Collections.emptyList();
+ }
+ }
+ return urls;
+ }
+
+ private ServiceDescriptions loadServiceDescriptions(URL url) throws Exception {
+ InputStream is = url.openStream();
+ try {
+ XMLStreamReader reader = xmlInputFactory.createXMLStreamReader(is);
+ reader.nextTag();
+ Object model = processor.read(reader);
+ if (model instanceof ServiceDescriptions) {
+ return (ServiceDescriptions)model;
+ } else {
+ return null;
+ }
+ } finally {
+ is.close();
+ }
+ }
+
+ private void removeServicesDeclaredInBundle(Bundle bundle) {
+ for (Iterator<Map.Entry<EndpointDescription, Bundle>> i = servicesInfo.entrySet().iterator(); i.hasNext();) {
+ Entry<EndpointDescription, Bundle> entry = i.next();
+ if (entry.getValue().equals(bundle)) {
+ serviceDescriptionRemoved(entry.getKey());
+ i.remove();
+ }
+ }
+ }
+
+ private void serviceDescriptionAdded(EndpointDescription endpointDescription) {
+ endpointChanged(endpointDescription, ADDED);
+ }
+
+ private void serviceDescriptionRemoved(EndpointDescription endpointDescription) {
+ endpointChanged(endpointDescription, REMOVED);
+ }
+
+ public void stop() {
+ context.removeBundleListener(this);
+ super.stop();
+ }
+
+}
diff --git a/java/sca/modules/node-impl-osgi/src/main/java/org/apache/tuscany/sca/osgi/service/remoteadmin/EndpointDescription.java b/java/sca/modules/node-impl-osgi/src/main/java/org/apache/tuscany/sca/osgi/service/remoteadmin/EndpointDescription.java
new file mode 100644
index 0000000000..482aa62a23
--- /dev/null
+++ b/java/sca/modules/node-impl-osgi/src/main/java/org/apache/tuscany/sca/osgi/service/remoteadmin/EndpointDescription.java
@@ -0,0 +1,146 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.tuscany.sca.osgi.service.remoteadmin;
+
+import java.net.URI;
+import java.util.List;
+import java.util.Map;
+
+import org.osgi.framework.Version;
+
+/**
+ * A description of an endpoint that provides sufficient information for a
+ * compatible distribution provider to create a connection to this endpoint An
+ * Endpoint Description is easy to transfer between different systems. This
+ * allows it to be used as a communications device to convey available endpoint
+ * information to nodes in a network. An Endpoint Description reflects the
+ * perspective of an importer. That is, the property keys have been chosen to
+ * match filters that are created by client bundles that need a service.
+ *
+ * @Immutable
+ */
+public interface EndpointDescription {
+ /**
+ * Returns the configuration types. A distribution provider exports a
+ * service with an endpoint. This endpoint uses some kind of communications
+ * protocol with a set of configuration parameters. There are many different
+ * types but each endpoint is configured by only one configuration type.
+ * However, a distribution provider can be aware of different configuration
+ * types and provide synonyms to increase the change a receiving distributon
+ * provider can create a connection to this endpoint. This value represents
+ * the RemoteConstants.SERVICE_IMPORTED_CONFIGS
+ *
+ * @return Returns The configuration type used for the associated endpoint
+ * and optionally synonyms.
+ */
+ public List<String> getConfigurationTypes();
+
+ /**
+ * Return the list of intents implemented by this endpoint. The intents are
+ * based on the service.intents on an imported service, except for any
+ * intents that are additionally provided by the importing distribution
+ * provider. All qualified intents must have been expanded. The property the
+ * intents come from is RemoteConstants.SERVICE_INTENTS
+ *
+ * @return A list of expanded intents that are provided by this endpoint.
+ */
+ public List<String> getIntents();
+
+ /**
+ * Answer the list of interfaces implemented by the exported service. If
+ * this Endpoint Description does not map to a service, then this List must
+ * be empty. The value of the interfaces is derived from the objectClass
+ * property.
+ *
+ * @return The list of Java interface names accessible by this endpoint
+ */
+ public List<String> getInterfaces();
+
+ /**
+ * Answer the version of the given interface. The version is encoded by
+ * prefixing the given interface name with endpoint.version., and then using
+ * this as a property key. The value must then be the Version object. For
+ * example: endpoint.version.com.acme.Foo
+ *
+ * @param name The name of the interface for which a version is requested
+ * @return Returns The version of the given interface or null if the
+ * interface has no version in this Endpoint Description
+ */
+ public Version getInterfaceVersion(String name);
+
+ /**
+ * Returns An immutable map referring to the properties of this Endpoint
+ * Description.
+ *
+ * @return Returns all endpoint properties.
+ */
+ public Map<String, Object> getProperties();
+
+ /**
+ * Returns the universally unique id for the service exported through this
+ * endpoint. Each service in the OSGi service registry has a universally
+ * unique id. The UUID can be used to detect that two Endpoint Descriptions
+ * really refer to the same registered service instance in some remote
+ * framework. This UUID can be used to filter out duplicate ways of
+ * communicating with the same service. The service UUID is constructed from
+ * two properties. It is first the org.osgi.framework.uuid System property
+ * set by the framework or through configuration. This property must
+ * uniquely represents the UUID of a framework instance. This UUID must not
+ * contain any dots ('.' .). This is suffixed with a dot and then the
+ * service.id service property of the service.
+ * <p>
+ * For example: 72dc5fd9-5f8f-4f8f-9821-9ebb433a5b72.121
+ * <p>
+ * If this Endpoint Description does not map to a remote OSGi service, for
+ * example some web service, then the Endpoint Description must not have a
+ * service UUID. If two endpoints have the same URI, then they must refer to
+ * the same OSGi service.
+ *
+ * @return Returns Unique id of a service or null if this Endpoint
+ * Description does not relate to an OSGi service
+ */
+ public String getRemoteServiceID();
+
+ /**
+ * Returns the endpoint's URI. The URI is an opaque id for an endpoint in
+ * URI form. No two different endpoints must have the same URI, two Endpoint
+ * Descriptions with the same URI must represent the same endpoint. The
+ * value of the URI is stored in the RemoteConstants.ENDPOINT_URI property.
+ *
+ * @return Returns The URI of the endpoint, never null.
+ */
+ public URI getURI();
+
+ /**
+ * Two endpoints are equal if their URIs are equal, the hash code is
+ * therefore derived from the URI.
+ */
+ public int hashCode();
+
+ /**
+ * Two endpoints are equal if their URIs are equal.
+ *
+ * @param other
+ * @return
+ */
+ public boolean equals(Object other);
+
+}
diff --git a/java/sca/modules/node-impl-osgi/src/main/java/org/apache/tuscany/sca/osgi/service/remoteadmin/EndpointListener.java b/java/sca/modules/node-impl-osgi/src/main/java/org/apache/tuscany/sca/osgi/service/remoteadmin/EndpointListener.java
new file mode 100644
index 0000000000..033897ba7b
--- /dev/null
+++ b/java/sca/modules/node-impl-osgi/src/main/java/org/apache/tuscany/sca/osgi/service/remoteadmin/EndpointListener.java
@@ -0,0 +1,101 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT 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.tuscany.sca.osgi.service.remoteadmin;
+
+/**
+ * A whiteboard service that represents a listener for endpoints. An Endpoint
+ * Listener represents a participant in the distributed model that is interested
+ * in Endpoint Descriptions. This whiteboard service can be used in many
+ * different scenarios. However, the primary use case is to allow a remote
+ * controller to be informed of End Point Descriptions available in the network
+ * and inform the network about available End Point Descriptions. Both the
+ * network bundle and the controller bundle register a Endpoint Listener
+ * service. The controller informs the network bundle about End Points that it
+ * creates. The network bundles then uses a protocol like for example SLP to
+ * announce these local end-points to the network. If the network bundle
+ * discovers a new Endpoint through its discovery protocol, then it sends an End
+ * Point Description to all the End Point Listener services that are registered
+ * (except its own) that have specified an interest in that endpoint.
+ * <p>
+ * Endpoint Listener services can express their scope with the service property
+ * ENDPOINT_LISTENER_SCOPE. This service property is a list of filters. An
+ * Endpoint Description should only be given to a Endpoint Listener when there
+ * is at least one filter that matches the Endpoint Description properties.
+ * given to it. This filter model is quite flexible. For example, a discovery
+ * bundle is only interested in locally originating Endpoint Descriptions. The
+ * following filter ensure that it only sees local endpoints.
+ * <p>
+ * (org.osgi.framework.uuid=72dc5fd9-5f8f-4f8f-9821- 9ebb433a5b72)<br>
+ * In the same vein, a controller that is only interested in remote Endpoint
+ * Descriptions can use a filter like:
+ * <p>
+ * (!(org.osgi.framework.uuid=72dc5fd9-5f8f-4f8f-9821-9ebb433a5b72)) <br>
+ * Where in both cases, the given UUID is the UUID of the local framework that
+ * can be found in the Framework properties. The Endpoint Listener’s scope maps
+ * very well to the service hooks. A controller can just register all filters
+ * found from the Listener Hook as its scope. This will automatically provide it
+ * with all known endpoints that match the given scope, without having to
+ * inspect the filter string. In general, when an Endpoint Description is
+ * discovered, it should be dispatched to all registered Endpoint Listener
+ * services. If a new Endpoint Listener is registered, it should be informed
+ * about all currently known Endpoints that match its scope. If a getter of the
+ * Endpoint Listener service is unregistered, then all its registered Endpoint
+ * Description objects must be removed. The Endpoint Listener models a best
+ * effort approach. Participating bundles should do their utmost to keep the
+ * listeners up to date, but implementers should realize that many endpoints
+ * come through unreliable discovery processes.
+ *
+ * @ThreadSafe
+ */
+public interface EndpointListener {
+ /**
+ * Specifies the interest of this listener with filters. This listener is
+ * only interested in Endpoint Descriptions where its properties match the
+ * given filter. The type of this property must be String+.
+ */
+ public static final String ENDPOINT_LISTENER_SCOPE = "endpoint.listener.scope";
+
+ /**
+ * Register an endpoint with this listener. If the endpoint matches one of
+ * the filters registered with the ENDPOINT_LISTENER_SCOPE service property
+ * then this filter should be given as the matchedFilter parameter. When
+ * this service is first registered or it is modified, it should receive all
+ * known endpoints matching the filter.
+ *
+ * @param endpoint The Endpoint Description to be published
+ * @param matchedFilter matchedFilter The filter from the
+ * ENDPOINT_LISTENER_SCOPE that matched the endpoint, must not be
+ * null.
+ */
+ public void addEndpoint(EndpointDescription endpoint, String matchedFilter);
+
+ /**
+ * Remove the registration of an endpoint. If an endpoint that was
+ * registered with the addEndpoint method is no longer available then this
+ * method should be called. This will remove the endpoint from the listener.
+ * It is not necessary to remove endpoints when the service is unregistered
+ * or modified in such a way that not all endpoints match the interest
+ * filter anymore.
+ *
+ * @param endpoint The Endpoint Description that is no longer valid.
+ */
+ public void removeEndpoint(EndpointDescription endpoint);
+}
diff --git a/java/sca/modules/node-impl-osgi/src/main/java/org/apache/tuscany/sca/osgi/service/remoteadmin/EndpointPermission.java b/java/sca/modules/node-impl-osgi/src/main/java/org/apache/tuscany/sca/osgi/service/remoteadmin/EndpointPermission.java
new file mode 100644
index 0000000000..0658fa5ffc
--- /dev/null
+++ b/java/sca/modules/node-impl-osgi/src/main/java/org/apache/tuscany/sca/osgi/service/remoteadmin/EndpointPermission.java
@@ -0,0 +1,172 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT 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.tuscany.sca.osgi.service.remoteadmin;
+
+import java.security.BasicPermission;
+import java.security.Permission;
+import java.security.PermissionCollection;
+
+/**
+ * A bundle’s authority to register or get a service.
+ * <ul>
+ * <li>The register action allows a bundle to register a service on the
+ * specified names.
+ * <li>The get action allows a bundle to detect a service and get it.
+ * EndpointPermission to get the specific service.
+ * </ul>
+ *
+ * @ThreadSafe
+ */
+public final class EndpointPermission extends BasicPermission {
+ private static final long serialVersionUID = 577543263888050488L;
+ /**
+ * The action string get.
+ */
+ public static final String EXPORT = "export";
+ /**
+ * The action string register.
+ */
+ public static final String IMPORT = "import";
+
+ private String actions;
+
+ /**
+ *Create a new EndpointPermission.
+ *
+ * @param name The service class name The name of the service is specified
+ * as a fully qualified class name. Wildcards may be used.
+ * <p>
+ * name ::= <class name> | <class name ending in ".*"> | *
+ * <p>
+ * Examples:
+ * <ul>
+ * <li>org.osgi.service.http.HttpService
+ * <li>org.osgi.service.http.*
+ * <li>*
+ * </ul>
+ * For the get action, the name can also be a filter expression.
+ * The filter gives access to the service properties as well as
+ * the following attributes:
+ * <p>
+ * <ul>
+ * <li>signer - A Distinguished Name chain used to sign the
+ * bundle publishing the service. Wildcards in a DN are not
+ * matched according to the filter string rules, but according to
+ * the rules defined for a DN chain.
+ * <li>location - The location of the bundle publishing the
+ * service.
+ * <li>id - The bundle ID of the bundle publishing the service.
+ * <li>name - The symbolic name of the bundle publishing the
+ * service.
+ * </ul>
+ * Since the above attribute names may conflict with service
+ * property names used by a service, you can prefix an attribute
+ * name with '@' in the filter expression to match against the
+ * service property and not one of the above attributes. Filter
+ * attribute names are processed in a case sensitive manner
+ * unless the attribute references a service property. Service
+ * properties names are case insensitive.
+ * <p>
+ * There are two possible actions: get and register. The get
+ * permission allows the owner of this permission to obtain a
+ * service with this name. The register permission allows the
+ * bundle to register a service under that name.
+ * @param actions actions get,register (canonical order)
+ * @throws IllegalArgumentException – If the specified name is a filter
+ * expression and either the specified action is not get or the
+ * filter has an invalid syntax.
+ */
+ public EndpointPermission(String name, String actions) {
+ super(name);
+ this.actions = actions;
+ }
+
+ /**
+ * Creates a new requested EndpointPermission object to be used by code that
+ * must perform checkPermission for the get action. EndpointPermission
+ * objects created with this constructor cannot be added to a
+ * EndpointPermission permission collection.
+ *
+ * @param endpoint The requested service.
+ * @param actions The action get.
+ * @throws IllegalArgumentException – If the specified action is not get or
+ * reference is null.
+ */
+ public EndpointPermission(EndpointDescription endpoint, String actions) {
+ super(null);
+ this.actions = actions;
+ }
+
+ /**
+ * Determines the equality of two EndpointPermission objects. Checks that
+ * specified object has the same class name and action as this
+ * EndpointPermission. obj The object to test for equality.
+ *
+ * @return true if obj is a EndpointPermission, and has the same class name
+ * and actions as this EndpointPermission object; false otherwise.
+ */
+ public boolean equals(Object obj) {
+ return super.equals(obj);
+ }
+
+ /**
+ * Returns the canonical string representation of the actions. Always
+ * returns present actions in the following order: get, register.
+ *
+ * @return The canonical string representation of the actions.
+ */
+ public String getActions() {
+ return actions;
+ }
+
+ /**
+ * Returns the hash code value for this object. Returns Hash code value for
+ * this object.
+ *
+ * @return
+ */
+ public int hashCode() {
+ return super.hashCode();
+ }
+
+ /**
+ *Determines if a EndpointPermission object "implies" the specified
+ * permission.
+ *
+ * @param p The target permission to check.
+ * @return true if the specified permission is implied by this object; false
+ * otherwise. newPermissionCollection()
+ */
+ public boolean implies(Permission p) {
+ return super.implies(p);
+ }
+
+ /**
+ * Returns a new PermissionCollection object for storing EndpointPermission
+ * objects.
+ *
+ * @return A new PermissionCollection object suitable for storing
+ * EndpointPermission objects.
+ */
+ public PermissionCollection newPermissionCollection() {
+ return super.newPermissionCollection();
+ }
+}
diff --git a/java/sca/modules/node-impl-osgi/src/main/java/org/apache/tuscany/sca/osgi/service/remoteadmin/ExportRegistration.java b/java/sca/modules/node-impl-osgi/src/main/java/org/apache/tuscany/sca/osgi/service/remoteadmin/ExportRegistration.java
new file mode 100644
index 0000000000..49c1d14550
--- /dev/null
+++ b/java/sca/modules/node-impl-osgi/src/main/java/org/apache/tuscany/sca/osgi/service/remoteadmin/ExportRegistration.java
@@ -0,0 +1,71 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.tuscany.sca.osgi.service.remoteadmin;
+
+import org.osgi.framework.ServiceReference;
+
+/**
+ * An Export Registration associates a service to a local endpoint. The Export
+ * Registration can be used to delete the endpoint associated with an this
+ * registration. It is created with the
+ * RemoteAdmin.exportService(ServiceReference) method. When this Export
+ * Registration has been unregistered, the methods must all return null.
+ *
+ * @ThreadSafe
+ */
+public interface ExportRegistration {
+ /**
+ * Delete the local endpoint and disconnect any remote distribution
+ * providers. After this method returns, all the methods must return null.
+ * This method has no effect when the endpoint is already destroyed or being
+ * destroyed.
+ */
+ public void close();
+
+ /**
+ *Return the Endpoint Description that is created for this registration.
+ *
+ * @return the local Endpoint Description
+ */
+ public EndpointDescription getEndpointDescription();
+
+ /**
+ * Exception for any error during the import process. If the Remote Admin
+ * for some reasons is unable to create a registration, then it must return
+ * a Throwable from this method. In this case, all other methods must return
+ * on this interface must thrown an Illegal State Exception. If no error
+ * occurred, this method must return null. The error must be set before this
+ * Import Registration is returned. Asynchronously occurring errors must be
+ * reported to the log.
+ *
+ * @return The exception that occurred during the creation of the
+ * registration or null if no exception occurred.
+ */
+ public Throwable getException();
+
+ /**
+ * Return the service being exported.
+ *
+ * @return The service being exported, must be null when this registration
+ * is unregistered.
+ */
+ public ServiceReference getExportedService();
+}
diff --git a/java/sca/modules/node-impl-osgi/src/main/java/org/apache/tuscany/sca/osgi/service/remoteadmin/ImportRegistration.java b/java/sca/modules/node-impl-osgi/src/main/java/org/apache/tuscany/sca/osgi/service/remoteadmin/ImportRegistration.java
new file mode 100644
index 0000000000..fdf70f849f
--- /dev/null
+++ b/java/sca/modules/node-impl-osgi/src/main/java/org/apache/tuscany/sca/osgi/service/remoteadmin/ImportRegistration.java
@@ -0,0 +1,70 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.tuscany.sca.osgi.service.remoteadmin;
+
+import org.osgi.framework.ServiceReference;
+
+/**
+ * An Import Registration associates an active proxy service to a remote
+ * endpoint. The Import Registration can be used to delete the proxy associated
+ * with an endpoint. It is created with the RemoteAdmin.importService method.
+ *
+ * @ThreadSafe
+ */
+public interface ImportRegistration {
+
+ /**
+ * Unregister this Import Registration. This must close the connection to
+ * the end endpoint unregister the proxy. After this method returns, all
+ * other methods must return null. This method has no effect when the
+ * service is already unregistered or in the process off.
+ */
+ public void close();
+
+ /**
+ * Exception for any error during the import process. If the Remote Admin
+ * for some reasons is unable to create a registration, then it must return
+ * a Throwable from this method. In this case, all other methods must return
+ * on this interface must thrown an Illegal State Exception. If no error
+ * occurred, this method must return null. The error must be set before this
+ * Import Registration is returned. Asynchronously occurring errors must be
+ * reported to the log.
+ *
+ * @return The exception that occurred during the creation of the
+ * registration or null if no exception occurred.
+ */
+ public Throwable getException();
+
+ /**
+ * Answer the associated remote Endpoint Description.
+ *
+ * @return A Endpoint Description for the remote endpoint.
+ */
+ public EndpointDescription getImportedEndpointDescription();
+
+ /**
+ * Answer the associated Service Reference for the proxy to the endpoint.
+ *
+ * @return A Service Reference to the proxy for the endpoint.
+ */
+ public ServiceReference getImportedService();
+
+}
diff --git a/java/sca/modules/node-impl-osgi/src/main/java/org/apache/tuscany/sca/osgi/service/remoteadmin/RemoteAdmin.java b/java/sca/modules/node-impl-osgi/src/main/java/org/apache/tuscany/sca/osgi/service/remoteadmin/RemoteAdmin.java
new file mode 100644
index 0000000000..c1b2f3d826
--- /dev/null
+++ b/java/sca/modules/node-impl-osgi/src/main/java/org/apache/tuscany/sca/osgi/service/remoteadmin/RemoteAdmin.java
@@ -0,0 +1,101 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT 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.tuscany.sca.osgi.service.remoteadmin;
+
+import java.util.Collection;
+import java.util.List;
+import java.util.Map;
+
+import org.osgi.framework.ServiceReference;
+
+/**
+ * A Remote Service Admin manages the import and export of services. A
+ * Distribution Provider can expose a control interface. This interface allows
+ * the a remote controller to control the export and import of services. The API
+ * allows a remote controller to export a service, to import a service, and find
+ * out about the current imports and exports.
+ *
+ * @ThreadSafe
+ */
+
+public interface RemoteAdmin {
+ /**
+ * Export a service to an endpoint. The Remote Service Admin must create an
+ * endpoint that can be used by other Distrbution Providers to connect to
+ * this Remote Service Admin and use the exported service. This method can
+ * return null if the service could not be exported.
+ *
+ * @param ref The Service Reference to export
+ * @return Export Registration that combines the Endpoint Description and
+ * the Service Reference or <code>null</code if the service could
+ * not be exported
+ */
+ public List<ExportRegistration> exportService(ServiceReference ref);
+
+ /**
+ * Export a service to a given endpoint. The Remote Service Admin must
+ * create an endpoint from the given description that can be used by other
+ * Distrbution Providers to connect to this Remote Service Admin and use the
+ * exported service. This method can return null if the service could not be
+ * exported because the endpoint could not be implemented by this Remote
+ * Service Admin.
+ *
+ * @param ref The Service Reference to export
+ * @param properties The properties to create a local endpoint that can be
+ * implemented by this Remote Service Admin. If this is null, the
+ * endpoint will be determined by the properties on the service,
+ * @see exportService(ServiceReference). The properties are the same as
+ * given for an exported service. They are overlaid over any properties
+ * the service defines
+ * @return Export Registration that combines the Endpoint Description and
+ * the Service Reference or <code>null</code if the service could
+ * not be exported
+ */
+ public List<ExportRegistration> exportService(ServiceReference ref, Map<String, Object> properties);
+
+ /**
+ * Answer the currently active Export Registrations.
+ *
+ * @return Returns A collection of Export Registrations that are currently
+ * active.
+ */
+ public Collection<ExportRegistration> getExportedServices();
+
+ /**
+ * Answer the currently active Import Registrations.
+ *
+ * @return Returns A collection of Import Registrations that are currently
+ * active.
+ */
+ public Collection<ImportRegistration> getImportedEndpoints();
+
+ /**
+ * Import a service from an endpoint. The Remote Service Admin must use the
+ * given endpoint to create a proxy. This method can return null if the
+ * service could not be imported.
+ *
+ * @param endpoint The Endpoint Description to be used for import
+ * @return An Import Registration that combines the Endpoint Description and
+ * the Service Reference or <code>null</code if the endpoint could
+ * not be imported
+ */
+ public ImportRegistration importService(EndpointDescription endpoint);
+}
diff --git a/java/sca/modules/node-impl-osgi/src/main/java/org/apache/tuscany/sca/osgi/service/remoteadmin/RemoteAdminEvent.java b/java/sca/modules/node-impl-osgi/src/main/java/org/apache/tuscany/sca/osgi/service/remoteadmin/RemoteAdminEvent.java
new file mode 100644
index 0000000000..02ad9c81fb
--- /dev/null
+++ b/java/sca/modules/node-impl-osgi/src/main/java/org/apache/tuscany/sca/osgi/service/remoteadmin/RemoteAdminEvent.java
@@ -0,0 +1,148 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT 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.tuscany.sca.osgi.service.remoteadmin;
+
+import java.util.EventObject;
+
+import org.osgi.framework.Bundle;
+
+/**
+ * Provides the event information for a Remote Admin event.
+ *
+ * @Immutable
+ */
+public class RemoteAdminEvent extends EventObject {
+ /**
+ * A fatal exporting error occurred. The Export Registration has been
+ * closed.
+ */
+ public final static int EXPORT_ERROR = 0x1;
+
+ /**
+ * Add an export registration. The Remote Services Admin will call this
+ * method when it exports a service. When this service is registered,
+ * the Remote Service Admin must notify the listener of all existing
+ * Export Registrations.
+ */
+ public final static int EXPORT_REGISTRATION = 0x2;
+
+ /**
+ * Remove an export registration. The Remote Services Admin will call
+ * this method when it removes the export of a service.
+ */
+ public final static int EXPORT_UNREGISTRATION = 0x4;
+
+ /**
+ * A problematic situation occurred, the export is still active.
+ */
+ public final static int EXPORT_WARNING = 0x8;
+
+ /**
+ * A fatal importing error occurred. The Import Registration has been
+ * closed.
+ */
+ public final static int IMPORT_ERROR = 0x10;
+
+ /**
+ * Add an import registration. The Remote Services Admin will call this
+ * method when it imports a service. When this service is registered,
+ * the Remote Service Admin must notify the listener of all existing
+ * Import Registrations.
+ */
+ public final static int IMPORT_REGISTRATION = 0x20;
+
+ /**
+ * Remove an import registration. The Remote Services Admin will call
+ * this method when it removes the import of a service.
+ */
+ public final static int IMPORT_UNREGISTRATION = 0x40;
+
+ /**
+ * A problematic situation occurred, the import is still active.
+ */
+ public final static int IMPORT_WARNING = 0x80;
+
+ private static final long serialVersionUID = -6562225073284539118L;
+ private Throwable exception;
+ private ExportRegistration exportRegistration;
+ private ImportRegistration importRegistration;
+ private int type;
+
+ public RemoteAdminEvent(Bundle source, int type, ExportRegistration registration, Throwable exception) {
+ super(source);
+ this.type = type;
+ this.exportRegistration = registration;
+ this.exception = exception;
+ }
+
+ public RemoteAdminEvent(Bundle source, int type, ImportRegistration registration, Throwable exception) {
+ super(source);
+ this.type = type;
+ this.importRegistration = registration;
+ this.exception = exception;
+ }
+
+ /**
+ * Returns the exception
+ *
+ * @return
+ */
+ public Throwable getException() {
+ return exception;
+ }
+
+ /**
+ * Returns the exportRegistration
+ *
+ * @return
+ */
+ public ExportRegistration getExportRegistration() {
+ return exportRegistration;
+ }
+
+ /**
+ * Returns the importRegistration
+ *
+ * @return
+ */
+ public ImportRegistration getImportRegistration() {
+ return importRegistration;
+ }
+
+ /**
+ * Returns the source
+ *
+ * @return
+ */
+ public Bundle getSource() {
+ return (Bundle)source;
+ }
+
+ /**
+ * Returns the type
+ *
+ * @return
+ */
+ public int getType() {
+ return type;
+ }
+
+}
diff --git a/java/sca/modules/node-impl-osgi/src/main/java/org/apache/tuscany/sca/osgi/service/remoteadmin/RemoteAdminListener.java b/java/sca/modules/node-impl-osgi/src/main/java/org/apache/tuscany/sca/osgi/service/remoteadmin/RemoteAdminListener.java
new file mode 100644
index 0000000000..21ffee971f
--- /dev/null
+++ b/java/sca/modules/node-impl-osgi/src/main/java/org/apache/tuscany/sca/osgi/service/remoteadmin/RemoteAdminListener.java
@@ -0,0 +1,36 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.tuscany.sca.osgi.service.remoteadmin;
+
+/**
+ * A Remote Service Admin Listener is notified asynchronously of any export or
+ * import registrations and unregistrations.
+ *
+ * @ThreadSafe
+ */
+public interface RemoteAdminListener {
+ /**
+ * Notify of a remote admin event
+ *
+ * @param event The remote admin event
+ */
+ public void remoteAdminEvent(RemoteAdminEvent event);
+}
diff --git a/java/sca/modules/node-impl-osgi/src/main/java/org/apache/tuscany/sca/osgi/service/remoteadmin/RemoteConstants.java b/java/sca/modules/node-impl-osgi/src/main/java/org/apache/tuscany/sca/osgi/service/remoteadmin/RemoteConstants.java
new file mode 100644
index 0000000000..f55bb030d7
--- /dev/null
+++ b/java/sca/modules/node-impl-osgi/src/main/java/org/apache/tuscany/sca/osgi/service/remoteadmin/RemoteConstants.java
@@ -0,0 +1,143 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT 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.tuscany.sca.osgi.service.remoteadmin;
+
+/**
+ * Provide the definition of the constants used in the Remote Services API.
+ */
+public class RemoteConstants {
+ /**
+ * The property key for the endpoint URI. This is a unique id for an
+ * endpoint following the URI syntax. As far as this specification is
+ * concerned, this unique id is opaque.
+ */
+ public static final String ENDPOINT_URI = "endpoint.uri";
+
+ /**
+ * The key for a framework property that defines the UUID of the framework.
+ * The property must be set by the framework or through configuration before
+ * the VM is started or some bundle. The value must be a Universally Unique
+ * Id, it must not contain any dots ('.' .).
+ */
+ public static final String FRAMEWORK_UUID = "org.osgi.framework.uuid";
+
+ /**
+ * The configuration types supported by this Distribution Provider. Services
+ * that are suitable for distribution list the configuration types that
+ * describe the configuration information for that service in the
+ * SERVICE_EXPORTED_CONFIGS or SERVICE_IMPORTED_CONFIGS property. A
+ * distribution provider must register a service that has this property and
+ * enumerate all configuration types that it supports. The type of this
+ * property String+
+ *
+ * @see SERVICE_EXPORTED_CONFIGS
+ * @see SERVICE_IMPORTED_CONFIGS
+ */
+ public static final String REMOTE_CONFIGS_SUPPORTED = "remote.configs.supported";
+
+ /**
+ * Service property that lists the intents supported by the distribution
+ * provider. Each distribution provider must register a service that has
+ * this property and enumerate all the supported intents, having any
+ * qualified intents expanded. The value of this property is of type
+ * String+.
+ *
+ * @see SERVICE_INTENTS
+ * @see SERVICE_EXPORTED_INTENTS
+ * @see SERVICE_EXPORTED_INTENTS_EXTRA
+ */
+ public static final String REMOTE_INTENTS_SUPPORTED = "remote.intents.supported";
+
+ /**
+ * A list of configuration types that should be used to export the service.
+ * Configuration types can be synonymous or alternatives. In principle, a
+ * distribution provider should create an endpoint for each recognized
+ * configuration type, the deployer is responsible that synonyms do not
+ * clash. Each configuration type has an associated specification that
+ * describes how the configuration data for the exported service is
+ * represented in an OSGi framework. The value of this property is of type
+ * String+.
+ */
+ public static final String SERVICE_EXPORTED_CONFIGS = "service.exported.configs";
+
+ /**
+ * A list of intents that the distribution provider must implement to
+ * distribute the service. Intents listed in this property are reserved for
+ * intents that are critical for the code to function correctly, for
+ * example, ordering of messages. These intents should not be configurable.
+ * The value of this property is of type String+.
+ */
+ public static final String SERVICE_EXPORTED_INTENTS = "service.exported.intents";
+
+ /**
+ * Extra intents configured in addition to the the intents specified in
+ * SERVICE_EXPORTED_INTENTS. These intents are merged with the service.
+ * exported.intents and therefore have the same semantics. They are extra,
+ * so that the SERVICE_EXPORTED_INTENTS can be set by the bundle developer
+ * and this property is then set by the administrator/deployer. Bundles
+ * should make this property configurable, for example through the
+ * Configuration Admin service. The value of this property is of type
+ * String+.
+ */
+ public static final String SERVICE_EXPORTED_INTENTS_EXTRA = "service.exported.intents.extra";
+
+ /**
+ * Defines the interfaces under which this service can be exported. This
+ * list must be a subset of the types listed in the objectClass service
+ * property. The single value of an asterisk ('*' *) indicates all
+ * interfaces in the registration's objectClass property (not classes). It
+ * is highly recommended to only export interfaces and not concrete classes
+ * due to the complexity of creating proxies for some type of classes. The
+ * value of this property is of type String+.
+ */
+ public static final String SERVICE_EXPORTED_INTERFACES = "service.exported.interfaces";
+
+ /**
+ * Must be set by a distribution provider to true when it registers the
+ * end-point proxy as an imported service. Can be used by a bundle to
+ * prevent it from getting an imported service. The value of this property
+ * is not defined, setting it is sufficient.
+ */
+ public static final String SERVICE_IMPORTED = "service.imported";
+
+ /**
+ * The configuration type used to import this services, as described in
+ * SERVICE_EXPORTED_CONFIGS. Any associated properties for this
+ * configuration types must be properly mapped to the importing system. For
+ * example, a URL in these properties must point to a valid resource when
+ * used in the importing framework. Configuration types in this property
+ * must be synonymous. The value of this property is of type String+.
+ */
+ public final String SERVICE_IMPORTED_CONFIGS = "service.imported.configs";
+
+ /**
+ * A list of intents that this service implements. This property has dual
+ * purpose. A bundle can use this service property to notify the
+ * distribution provider that these intents are already implemented by the
+ * exported service object. For an imported service, a distribution provider
+ * must use this property to convey the combined intents of the exporting
+ * service and the intents that the distribution providers add. To export a
+ * service, a distribution provider must recognize all these intents and
+ * expand any qualified intents. The value of this property is of type
+ * String+.
+ */
+ public static final String SERVICE_INTENTS = "service.intents";
+}
diff --git a/java/sca/modules/node-impl-osgi/src/main/java/org/apache/tuscany/sca/osgi/service/remoteadmin/impl/EndpointDescriptionImpl.java b/java/sca/modules/node-impl-osgi/src/main/java/org/apache/tuscany/sca/osgi/service/remoteadmin/impl/EndpointDescriptionImpl.java
new file mode 100644
index 0000000000..6557b185ee
--- /dev/null
+++ b/java/sca/modules/node-impl-osgi/src/main/java/org/apache/tuscany/sca/osgi/service/remoteadmin/impl/EndpointDescriptionImpl.java
@@ -0,0 +1,150 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT 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.tuscany.sca.osgi.service.remoteadmin.impl;
+
+import static org.apache.tuscany.sca.osgi.service.remoteadmin.RemoteConstants.SERVICE_EXPORTED_INTERFACES;
+
+import java.net.URI;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.UUID;
+import java.util.logging.Logger;
+
+import org.apache.tuscany.sca.assembly.Endpoint;
+import org.apache.tuscany.sca.interfacedef.Interface;
+import org.apache.tuscany.sca.interfacedef.java.JavaInterface;
+import org.apache.tuscany.sca.osgi.service.remoteadmin.EndpointDescription;
+import org.apache.tuscany.sca.osgi.service.remoteadmin.RemoteConstants;
+import org.apache.tuscany.sca.policy.Intent;
+import org.osgi.framework.Version;
+
+/**
+ * Implementation of {@link EndpointDescription}
+ */
+public class EndpointDescriptionImpl implements EndpointDescription {
+ private Endpoint endpoint;
+
+ private static final Logger logger = Logger.getLogger(EndpointDescriptionImpl.class.getName());
+
+ private Collection<String> interfaces;
+ private Map<String, Object> properties;
+
+ public EndpointDescriptionImpl(Collection<String> interfaceNames) {
+ this(interfaceNames, Collections.<String, Object> singletonMap(SERVICE_EXPORTED_INTERFACES, interfaceNames));
+ }
+
+ public EndpointDescriptionImpl(Collection<String> interfaceNames, Map<String, Object> remoteProperties) {
+ this.interfaces = new HashSet<String>(interfaceNames);
+ this.properties =
+ remoteProperties == null ? new HashMap<String, Object>() : new HashMap<String, Object>(remoteProperties);
+ this.properties.put(RemoteConstants.SERVICE_EXPORTED_INTERFACES, interfaceNames);
+ this.endpoint = (Endpoint) properties.get(Endpoint.class.getName());
+ }
+
+ public EndpointDescriptionImpl(String interfaceName) {
+ this(Collections.singleton(interfaceName));
+ }
+
+ public EndpointDescriptionImpl(Endpoint endpoint) {
+ this(getInterfaces(endpoint), getProperties(endpoint));
+ this.endpoint = endpoint;
+ }
+
+ /**
+ * @see org.apache.tuscany.sca.osgi.service.remoteadmin.EndpointDescription#getConfigurationTypes()
+ */
+ public List<String> getConfigurationTypes() {
+ return Collections.singletonList("sca");
+ }
+
+ /**
+ * @see org.apache.tuscany.sca.osgi.service.remoteadmin.EndpointDescription#getIntents()
+ */
+ public List<String> getIntents() {
+ List<String> intents = new ArrayList<String>();
+ for (Intent intent : endpoint.getRequiredIntents()) {
+ intents.add(intent.getName().toString());
+ }
+ return intents;
+ }
+
+ /**
+ * @see org.apache.tuscany.sca.osgi.service.remoteadmin.EndpointDescription#getInterfaceVersion(java.lang.String)
+ */
+ public Version getInterfaceVersion(String name) {
+ return Version.emptyVersion;
+ }
+
+ /**
+ * @see org.apache.tuscany.sca.osgi.service.remoteadmin.EndpointDescription#getInterfaces()
+ */
+ public List<String> getInterfaces() {
+ return new ArrayList<String>(interfaces);
+ }
+
+ private static List<String> getInterfaces(Endpoint endpoint) {
+ Interface intf = endpoint.getInterfaceContract().getInterface();
+ JavaInterface javaInterface = (JavaInterface)intf;
+ return Collections.singletonList(javaInterface.getName());
+ }
+
+ /**
+ * @see org.apache.tuscany.sca.osgi.service.remoteadmin.EndpointDescription#getProperties()
+ */
+ public Map<String, Object> getProperties() {
+ return Collections.unmodifiableMap(properties); // endpoint.getService().getExtensions();
+ }
+
+ private static Map<String, Object> getProperties(Endpoint endpoint) {
+ Map<String, Object> props = new HashMap<String, Object>();
+ props.put(RemoteConstants.ENDPOINT_URI, endpoint.getURI());
+ props.put(RemoteConstants.SERVICE_EXPORTED_CONFIGS, new String[] {"sca"});
+ props.put(Endpoint.class.getName(), endpoint);
+ return props;
+ }
+
+ /**
+ * @see org.apache.tuscany.sca.osgi.service.remoteadmin.EndpointDescription#getRemoteServiceID()
+ */
+ public String getRemoteServiceID() {
+ return null; // endpoint.getService().getExtensions();
+ }
+
+ /**
+ * @see org.apache.tuscany.sca.osgi.service.remoteadmin.EndpointDescription#getURI()
+ */
+ public URI getURI() {
+ if (endpoint != null) {
+ return URI.create(endpoint.getURI());
+ } else {
+ return URI.create("urn:" + UUID.randomUUID());
+ }
+ }
+
+ public Endpoint getEndpoint() {
+ return endpoint;
+ }
+
+}
diff --git a/java/sca/modules/implementation-osgi/src/main/java/org/apache/tuscany/sca/implementation/osgi/introspection/ExportedServiceIntrospector.java b/java/sca/modules/node-impl-osgi/src/main/java/org/apache/tuscany/sca/osgi/service/remoteadmin/impl/EndpointIntrospector.java
index 409e14bdd9..59f8d3c07b 100644
--- a/java/sca/modules/implementation-osgi/src/main/java/org/apache/tuscany/sca/implementation/osgi/introspection/ExportedServiceIntrospector.java
+++ b/java/sca/modules/node-impl-osgi/src/main/java/org/apache/tuscany/sca/osgi/service/remoteadmin/impl/EndpointIntrospector.java
@@ -17,15 +17,13 @@
* under the License.
*/
-package org.apache.tuscany.sca.implementation.osgi.introspection;
+package org.apache.tuscany.sca.osgi.service.remoteadmin.impl;
import static org.apache.tuscany.sca.assembly.Base.SCA11_TUSCANY_NS;
-import static org.apache.tuscany.sca.implementation.osgi.OSGiProperty.REMOTE_CONFIG_SCA;
import static org.apache.tuscany.sca.implementation.osgi.OSGiProperty.SCA_BINDINGS;
import static org.apache.tuscany.sca.implementation.osgi.OSGiProperty.SERVICE_EXPORTED_INTENTS;
import static org.apache.tuscany.sca.implementation.osgi.OSGiProperty.SERVICE_EXPORTED_INTENTS_EXTRA;
import static org.apache.tuscany.sca.implementation.osgi.OSGiProperty.SERVICE_EXPORTED_INTERFACES;
-import static org.apache.tuscany.sca.implementation.osgi.OSGiProperty.SERVICE_IMPORTED_CONFIGS;
import static org.osgi.framework.Constants.OBJECTCLASS;
import static org.osgi.framework.Constants.SERVICE_ID;
@@ -37,9 +35,7 @@ import java.net.URL;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
-import java.util.Dictionary;
import java.util.HashMap;
-import java.util.Hashtable;
import java.util.List;
import java.util.Map;
import java.util.UUID;
@@ -57,6 +53,7 @@ import org.apache.tuscany.sca.assembly.Component;
import org.apache.tuscany.sca.assembly.ComponentReference;
import org.apache.tuscany.sca.assembly.ComponentService;
import org.apache.tuscany.sca.assembly.Composite;
+import org.apache.tuscany.sca.assembly.Endpoint;
import org.apache.tuscany.sca.assembly.Reference;
import org.apache.tuscany.sca.assembly.Service;
import org.apache.tuscany.sca.contribution.Contribution;
@@ -81,18 +78,18 @@ import org.apache.tuscany.sca.interfacedef.java.JavaInterfaceContract;
import org.apache.tuscany.sca.interfacedef.java.JavaInterfaceFactory;
import org.apache.tuscany.sca.monitor.Monitor;
import org.apache.tuscany.sca.monitor.MonitorFactory;
+import org.apache.tuscany.sca.osgi.service.remoteadmin.EndpointDescription;
import org.apache.tuscany.sca.policy.Intent;
import org.apache.tuscany.sca.policy.PolicyFactory;
import org.osgi.framework.Bundle;
-import org.osgi.framework.Filter;
-import org.osgi.framework.InvalidSyntaxException;
+import org.osgi.framework.BundleContext;
import org.osgi.framework.ServiceReference;
/**
* Introspect an OSGi Service to create an SCA composite that contains a single component with
* implementation.osgi
*/
-public class ExportedServiceIntrospector {
+public class EndpointIntrospector {
private AssemblyFactory assemblyFactory;
private ContributionFactory contributionFactory;
private OSGiImplementationFactory implementationFactory;
@@ -127,9 +124,10 @@ public class ExportedServiceIntrospector {
}
/**
+ * @param context TODO
* @param registry
*/
- public ExportedServiceIntrospector(ExtensionPointRegistry registry) {
+ public EndpointIntrospector(BundleContext context, ExtensionPointRegistry registry) {
super();
this.registry = registry;
this.factories = registry.getExtensionPoint(FactoryExtensionPoint.class);
@@ -221,7 +219,7 @@ public class ExportedServiceIntrospector {
// The service.id is Long
serviceID.setValue(String.valueOf(reference.getProperty(SERVICE_ID)));
- String id = "osgi.service." + serviceID.getValue();
+ String id = "osgi.service." + UUID.randomUUID();
Composite composite = assemblyFactory.createComposite();
composite.setName(new QName(SCA11_TUSCANY_NS, id));
@@ -293,36 +291,24 @@ public class ExportedServiceIntrospector {
return contribution;
}
- /**
- * Introspect an OSGi filter to create an SCA reference
- *
- * @param bundle
- * @param filterStr
- * @param properties
- * @return
- * @throws Exception
- */
- public Contribution introspect(Bundle bundle, String filterStr, Map<String, Object> properties) throws Exception {
- Filter filter = null;
- try {
- filter = bundle.getBundleContext().createFilter(filterStr);
- } catch (InvalidSyntaxException e) {
- e.printStackTrace();
- return null;
+ public Contribution introspect(Bundle bundle, EndpointDescription endpoint) throws Exception {
+ if (endpoint instanceof EndpointDescriptionImpl) {
+ EndpointDescriptionImpl impl = (EndpointDescriptionImpl)endpoint;
+ Endpoint ep = impl.getEndpoint();
+ if (ep != null) {
+ return introspect(bundle, ep);
+ }
}
+ Map<String, Object> properties = endpoint.getProperties();
+ List<String> remoteInterfaces = endpoint.getInterfaces();
- Dictionary<String, Object> props = new Hashtable<String, Object>();
- props.put(SERVICE_IMPORTED_CONFIGS, new String[] {REMOTE_CONFIG_SCA});
- if (!filter.match(props)) {
- return null;
- }
String id = "osgi.reference." + UUID.randomUUID();
Composite composite = assemblyFactory.createComposite();
composite.setName(new QName(Base.SCA11_TUSCANY_NS, id));
Component component = assemblyFactory.createComponent();
component.setName(id);
- component.setAutowire(Boolean.TRUE);
+ // component.setAutowire(Boolean.TRUE);
composite.getComponents().add(component);
@@ -332,12 +318,7 @@ public class ExportedServiceIntrospector {
component.setImplementation(implementation);
implementation.setUnresolved(false);
- String[] remoteInterfaces = getStrings(properties.get(SERVICE_EXPORTED_INTERFACES));
- if (remoteInterfaces == null || remoteInterfaces.length > 0 && "*".equals(remoteInterfaces[0])) {
- remoteInterfaces = getStrings(properties.get(OBJECTCLASS));
- } else {
- remoteInterfaces = parse(remoteInterfaces);
- }
+ int count = 0;
for (String intf : remoteInterfaces) {
Reference reference = assemblyFactory.createReference();
JavaInterfaceContract interfaceContract = javaInterfaceFactory.createJavaInterfaceContract();
@@ -349,14 +330,13 @@ public class ExportedServiceIntrospector {
.getCallbackClass()));
}
- reference.setName(id);
+ reference.setName("ref" + (count++));
reference.setInterfaceContract(interfaceContract);
- reference.getExtensions().add(filter);
-
implementation.getReferences().add(reference);
ComponentReference componentReference = assemblyFactory.createComponentReference();
+ componentReference.setName(reference.getName());
component.getReferences().add(componentReference);
componentReference.setReference(reference);
componentReference.setWiredByImpl(true);
@@ -368,10 +348,64 @@ public class ExportedServiceIntrospector {
String[] bindingDocuments = getStrings(properties.get(SCA_BINDINGS));
List<Binding> bindings = loadBindings(bundle, bindingDocuments);
+ List<Binding> bindingList = new ArrayList<Binding>(bindings);
+ BindingDescriptions bindingDescriptions =
+ (BindingDescriptions)properties.get(BindingDescriptions.BINDINGS_QNAME.toString());
+ if (bindingDescriptions != null) {
+ bindingList.addAll(bindingDescriptions);
+ }
+
for (ComponentReference componentReference : component.getReferences()) {
componentReference.getRequiredIntents().addAll(intents);
- componentReference.getBindings().addAll(bindings);
+ componentReference.getBindings().addAll(bindingList);
}
+ // FIXME: Should we scan the owning bundle to create the SCA contribution?
+ Contribution contribution = contributionFactory.createContribution();
+ contribution.setURI("urn:" + id);
+ contribution.setLocation(bundle.getEntry("/").toString());
+ contribution.getDeployables().add(composite);
+ ModelResolver modelResolver = new ExtensibleModelResolver(contribution, modelResolvers, factories);
+ contribution.setModelResolver(modelResolver);
+ contribution.setUnresolved(true);
+ return contribution;
+ }
+
+ public Contribution introspect(Bundle bundle, Endpoint endpoint) throws Exception {
+ String id = "osgi.reference." + UUID.randomUUID();
+ Composite composite = assemblyFactory.createComposite();
+ composite.setName(new QName(Base.SCA11_TUSCANY_NS, id));
+
+ Component component = assemblyFactory.createComponent();
+ component.setName(id);
+ // component.setAutowire(Boolean.TRUE);
+
+ composite.getComponents().add(component);
+
+ OSGiImplementation implementation = implementationFactory.createOSGiImplementation();
+
+ implementation.setBundle(bundle);
+ component.setImplementation(implementation);
+ implementation.setUnresolved(false);
+
+ Reference reference = assemblyFactory.createReference();
+ Service service = endpoint.getService().getService();
+ reference.setInterfaceContract(service.getInterfaceContract());
+ reference.setName("ref");
+
+ reference.getBindings().add(endpoint.getBinding());
+
+ /*
+ reference.getRequiredIntents().addAll(service.getRequiredIntents());
+ reference.getPolicySets().addAll(service.getPolicySets());
+ */
+
+ implementation.getReferences().add(reference);
+
+ ComponentReference componentReference = assemblyFactory.createComponentReference();
+ component.getReferences().add(componentReference);
+ componentReference.setReference(reference);
+ componentReference.setName(reference.getName());
+ componentReference.setWiredByImpl(true);
// FIXME: Should we scan the owning bundle to create the SCA contribution?
Contribution contribution = contributionFactory.createContribution();
diff --git a/java/sca/modules/node-impl-osgi/src/main/java/org/apache/tuscany/sca/osgi/service/remoteadmin/impl/ExportRegistrationImpl.java b/java/sca/modules/node-impl-osgi/src/main/java/org/apache/tuscany/sca/osgi/service/remoteadmin/impl/ExportRegistrationImpl.java
new file mode 100644
index 0000000000..d7881681f0
--- /dev/null
+++ b/java/sca/modules/node-impl-osgi/src/main/java/org/apache/tuscany/sca/osgi/service/remoteadmin/impl/ExportRegistrationImpl.java
@@ -0,0 +1,89 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT 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.tuscany.sca.osgi.service.remoteadmin.impl;
+
+import org.apache.tuscany.sca.node.Node;
+import org.apache.tuscany.sca.osgi.service.remoteadmin.EndpointDescription;
+import org.apache.tuscany.sca.osgi.service.remoteadmin.ExportRegistration;
+import org.osgi.framework.ServiceReference;
+
+/**
+ * Implementation of {@link ExportRegistration}
+ */
+public class ExportRegistrationImpl implements ExportRegistration {
+ private Node node;
+ private ServiceReference exportedService;
+ private EndpointDescription endpointDescription;
+ private Throwable exception;
+
+ /**
+ * @param exportedService
+ * @param endpointDescription
+ * @param exception
+ */
+ public ExportRegistrationImpl(Node node,
+ ServiceReference exportedService,
+ EndpointDescription endpointDescription,
+ Throwable exception) {
+ super();
+ this.node = node;
+ this.exportedService = exportedService;
+ this.endpointDescription = endpointDescription;
+ this.exception = exception;
+ }
+
+ /**
+ * @param exportedService
+ * @param endpointDescription
+ */
+ public ExportRegistrationImpl(Node node, ServiceReference exportedService, EndpointDescription endpointDescription) {
+ this(node, exportedService, endpointDescription, null);
+ }
+
+ /**
+ * @see org.apache.tuscany.sca.osgi.service.remoteadmin.ExportRegistration#close()
+ */
+ public void close() {
+ if (node != null) {
+ node.stop();
+ node = null;
+ }
+ exception = null;
+ endpointDescription = null;
+ exportedService = null;
+ }
+
+ public ServiceReference getExportedService() {
+ return exportedService;
+ }
+
+ public EndpointDescription getEndpointDescription() {
+ return endpointDescription;
+ }
+
+ public Throwable getException() {
+ return exception;
+ }
+
+ public Node getNode() {
+ return node;
+ }
+
+}
diff --git a/java/sca/modules/node-impl-osgi/src/main/java/org/apache/tuscany/sca/osgi/service/remoteadmin/impl/ImportRegistrationImpl.java b/java/sca/modules/node-impl-osgi/src/main/java/org/apache/tuscany/sca/osgi/service/remoteadmin/impl/ImportRegistrationImpl.java
new file mode 100644
index 0000000000..fb145a95d0
--- /dev/null
+++ b/java/sca/modules/node-impl-osgi/src/main/java/org/apache/tuscany/sca/osgi/service/remoteadmin/impl/ImportRegistrationImpl.java
@@ -0,0 +1,92 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.tuscany.sca.osgi.service.remoteadmin.impl;
+
+import org.apache.tuscany.sca.node.Node;
+import org.apache.tuscany.sca.osgi.service.remoteadmin.EndpointDescription;
+import org.apache.tuscany.sca.osgi.service.remoteadmin.ImportRegistration;
+import org.osgi.framework.ServiceReference;
+
+/**
+ *
+ */
+public class ImportRegistrationImpl implements ImportRegistration {
+ private Node node;
+ private ServiceReference exportedService;
+ private EndpointDescription endpointDescription;
+ private Throwable exception;
+
+ /**
+ * @param exportedService
+ * @param endpointDescription
+ * @param exception
+ */
+ public ImportRegistrationImpl(Node node,
+ ServiceReference exportedService,
+ EndpointDescription endpointDescription,
+ Throwable exception) {
+ super();
+ this.node = node;
+ this.exportedService = exportedService;
+ this.endpointDescription = endpointDescription;
+ this.exception = exception;
+ }
+
+ /**
+ * @param exportedService
+ * @param endpointDescription
+ */
+ public ImportRegistrationImpl(Node node, ServiceReference exportedService, EndpointDescription endpointDescription) {
+ super();
+ this.node = node;
+ this.exportedService = exportedService;
+ this.endpointDescription = endpointDescription;
+ }
+
+ /**
+ * @see org.apache.tuscany.sca.osgi.service.remoteadmin.ImportRegistration#close()
+ */
+ public void close() {
+ if (node != null) {
+ node.stop();
+ node = null;
+ }
+ exception = null;
+ endpointDescription = null;
+ exportedService = null;
+ }
+
+ public ServiceReference getImportedService() {
+ return exportedService;
+ }
+
+ public EndpointDescription getImportedEndpointDescription() {
+ return endpointDescription;
+ }
+
+ public Throwable getException() {
+ return exception;
+ }
+
+ public Node getNode() {
+ return node;
+ }
+
+}
diff --git a/java/sca/modules/node-impl-osgi/src/main/java/org/apache/tuscany/sca/osgi/service/remoteadmin/impl/RemoteAdminHelper.java b/java/sca/modules/node-impl-osgi/src/main/java/org/apache/tuscany/sca/osgi/service/remoteadmin/impl/RemoteAdminHelper.java
new file mode 100644
index 0000000000..7f467854a0
--- /dev/null
+++ b/java/sca/modules/node-impl-osgi/src/main/java/org/apache/tuscany/sca/osgi/service/remoteadmin/impl/RemoteAdminHelper.java
@@ -0,0 +1,86 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.tuscany.sca.osgi.service.remoteadmin.impl;
+
+import java.util.Arrays;
+import java.util.Collection;
+
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.Filter;
+import org.osgi.framework.InvalidSyntaxException;
+import org.osgi.framework.ServiceReference;
+
+/**
+ *
+ */
+public class RemoteAdminHelper {
+ private RemoteAdminHelper() {
+ }
+
+ /**
+ * In OSGi, the value of String+ can be a single String, String[] or Collection<String>
+ * @param value
+ * @return
+ */
+ public static String[] getStringArray(Object value) {
+ if (value == null) {
+ return null;
+ }
+ if (value instanceof String) {
+ return new String[] {(String)value};
+ } else if (value instanceof Collection) {
+ Collection<String> collection = (Collection)value;
+ return collection.toArray(new String[collection.size()]);
+ }
+ return (String[])value;
+
+ }
+
+ public static Collection<String> getStringCollection(Object value) {
+ String[] values = getStringArray(value);
+ if (values == null) {
+ return null;
+ } else {
+ return Arrays.asList(values);
+ }
+ }
+
+ public static String[] getStringArray(ServiceReference serviceReference, String propertyName) {
+ Object propertyValue = serviceReference.getProperty(propertyName);
+ return getStringArray(propertyValue);
+ }
+
+ public static Collection<String> getStringCollection(ServiceReference serviceReference, String propertyName) {
+ Object propertyValue = serviceReference.getProperty(propertyName);
+ return getStringCollection(propertyValue);
+ }
+
+ public static Filter createFilter(BundleContext context, String filterValue) {
+ if (filterValue == null) {
+ return null;
+ }
+ try {
+ return context.createFilter(filterValue);
+ } catch (InvalidSyntaxException ex) {
+ throw new IllegalArgumentException("Invalid Filter: " + filterValue, ex);
+ }
+ }
+
+}
diff --git a/java/sca/modules/node-impl-osgi/src/main/java/org/apache/tuscany/sca/osgi/service/remoteadmin/impl/RemoteAdminImpl.java b/java/sca/modules/node-impl-osgi/src/main/java/org/apache/tuscany/sca/osgi/service/remoteadmin/impl/RemoteAdminImpl.java
new file mode 100644
index 0000000000..05e59844e9
--- /dev/null
+++ b/java/sca/modules/node-impl-osgi/src/main/java/org/apache/tuscany/sca/osgi/service/remoteadmin/impl/RemoteAdminImpl.java
@@ -0,0 +1,144 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.tuscany.sca.osgi.service.remoteadmin.impl;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.tuscany.sca.node.osgi.impl.OSGiServiceExporter;
+import org.apache.tuscany.sca.node.osgi.impl.OSGiServiceImporter;
+import org.apache.tuscany.sca.osgi.service.remoteadmin.EndpointDescription;
+import org.apache.tuscany.sca.osgi.service.remoteadmin.ExportRegistration;
+import org.apache.tuscany.sca.osgi.service.remoteadmin.ImportRegistration;
+import org.apache.tuscany.sca.osgi.service.remoteadmin.RemoteAdmin;
+import org.apache.tuscany.sca.osgi.service.remoteadmin.RemoteAdminListener;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.ServiceReference;
+import org.osgi.framework.ServiceRegistration;
+import org.osgi.util.tracker.ServiceTracker;
+
+/**
+ * SCA Implementation of {@link RemoteAdmin}
+ */
+public class RemoteAdminImpl implements RemoteAdmin {
+ private BundleContext context;
+ private ServiceRegistration registration;
+ private ServiceTracker listeners;
+
+ private OSGiServiceExporter exporter;
+ private OSGiServiceImporter importer;
+
+ private Collection<ImportRegistration> importedEndpoints = new ArrayList<ImportRegistration>();
+ private Collection<ExportRegistration> exportedServices = new ArrayList<ExportRegistration>();
+
+ public RemoteAdminImpl(BundleContext context) {
+ this.context = context;
+ }
+
+ public void start() {
+ this.exporter = new OSGiServiceExporter(context);
+ this.importer = new OSGiServiceImporter(context);
+ exporter.start();
+ importer.start();
+ registration = context.registerService(RemoteAdmin.class.getName(), this, null);
+ listeners = new ServiceTracker(this.context, RemoteAdminListener.class.getName(), null);
+ listeners.open();
+ }
+
+ public void stop() {
+ if (registration != null) {
+ registration.unregister();
+ registration = null;
+ }
+ if (listeners != null) {
+ listeners.close();
+ listeners = null;
+ }
+ for (ExportRegistration exportRegistration : exportedServices) {
+ exportRegistration.close();
+ }
+ exportedServices.clear();
+ for (ImportRegistration importRegistration : importedEndpoints) {
+ importRegistration.close();
+ }
+ importedEndpoints.clear();
+ if (importer != null) {
+ importer.stop();
+ importer = null;
+ }
+ if (exporter != null) {
+ exporter.stop();
+ exporter = null;
+ }
+ }
+
+ /**
+ * @see org.apache.tuscany.sca.osgi.service.remoteadmin.RemoteAdmin#exportService(org.osgi.framework.ServiceReference)
+ */
+ public List<ExportRegistration> exportService(ServiceReference ref) {
+ List<ExportRegistration> exportRegistrations = exporter.exportService(ref);
+ if (exportRegistrations != null) {
+ exportedServices.addAll(exportRegistrations);
+ }
+ return exportRegistrations;
+ }
+
+ /**
+ * @see org.apache.tuscany.sca.osgi.service.remoteadmin.RemoteAdmin#exportService(org.osgi.framework.ServiceReference,
+ * java.util.Map)
+ */
+ public List<ExportRegistration> exportService(ServiceReference ref, Map<String, Object> properties) {
+ List<ExportRegistration> exportRegistrations = exporter.exportService(ref);
+ if (exportRegistrations != null) {
+ exportedServices.addAll(exportRegistrations);
+ }
+ return exportRegistrations;
+ }
+
+ /**
+ * @see org.apache.tuscany.sca.osgi.service.remoteadmin.RemoteAdmin#getExportedServices()
+ */
+ public Collection<ExportRegistration> getExportedServices() {
+ return exportedServices;
+ }
+
+ /**
+ * @see org.apache.tuscany.sca.osgi.service.remoteadmin.RemoteAdmin#getImportedEndpoints()
+ */
+ public Collection<ImportRegistration> getImportedEndpoints() {
+ return importedEndpoints;
+ }
+
+ /**
+ * @see org.apache.tuscany.sca.osgi.service.remoteadmin.RemoteAdmin#importService(org.apache.tuscany.sca.dosgi.discovery.EndpointDescription)
+ */
+ public ImportRegistration importService(EndpointDescription endpoint) {
+ Bundle bundle = (Bundle) endpoint.getProperties().get(Bundle.class.getName());
+ ImportRegistration importReg = importer.importService(bundle, endpoint);
+ if (importReg != null) {
+ importedEndpoints.add(importReg);
+ }
+ return importReg;
+ }
+
+}
diff --git a/java/sca/modules/node-impl-osgi/src/main/java/org/apache/tuscany/sca/osgi/service/remoteadmin/impl/RemoteControllerImpl.java b/java/sca/modules/node-impl-osgi/src/main/java/org/apache/tuscany/sca/osgi/service/remoteadmin/impl/RemoteControllerImpl.java
new file mode 100644
index 0000000000..b7fe173c85
--- /dev/null
+++ b/java/sca/modules/node-impl-osgi/src/main/java/org/apache/tuscany/sca/osgi/service/remoteadmin/impl/RemoteControllerImpl.java
@@ -0,0 +1,403 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT 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.tuscany.sca.osgi.service.remoteadmin.impl;
+
+import static org.apache.tuscany.sca.implementation.osgi.OSGiProperty.SERVICE_EXPORTED_INTERFACES;
+import static org.apache.tuscany.sca.osgi.service.remoteadmin.RemoteAdminEvent.EXPORT_ERROR;
+import static org.apache.tuscany.sca.osgi.service.remoteadmin.RemoteAdminEvent.EXPORT_REGISTRATION;
+import static org.apache.tuscany.sca.osgi.service.remoteadmin.RemoteAdminEvent.EXPORT_UNREGISTRATION;
+import static org.apache.tuscany.sca.osgi.service.remoteadmin.RemoteAdminEvent.EXPORT_WARNING;
+import static org.apache.tuscany.sca.osgi.service.remoteadmin.RemoteAdminEvent.IMPORT_ERROR;
+import static org.apache.tuscany.sca.osgi.service.remoteadmin.RemoteAdminEvent.IMPORT_REGISTRATION;
+import static org.apache.tuscany.sca.osgi.service.remoteadmin.RemoteAdminEvent.IMPORT_UNREGISTRATION;
+import static org.apache.tuscany.sca.osgi.service.remoteadmin.RemoteAdminEvent.IMPORT_WARNING;
+import static org.apache.tuscany.sca.osgi.service.remoteadmin.RemoteConstants.SERVICE_EXPORTED_CONFIGS;
+import static org.apache.tuscany.sca.osgi.service.remoteadmin.RemoteConstants.SERVICE_IMPORTED;
+
+import java.util.ArrayList;
+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.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.logging.Logger;
+
+import org.apache.tuscany.sca.core.LifeCycleListener;
+import org.apache.tuscany.sca.osgi.service.remoteadmin.EndpointDescription;
+import org.apache.tuscany.sca.osgi.service.remoteadmin.EndpointListener;
+import org.apache.tuscany.sca.osgi.service.remoteadmin.ExportRegistration;
+import org.apache.tuscany.sca.osgi.service.remoteadmin.ImportRegistration;
+import org.apache.tuscany.sca.osgi.service.remoteadmin.RemoteAdmin;
+import org.apache.tuscany.sca.osgi.service.remoteadmin.RemoteAdminEvent;
+import org.apache.tuscany.sca.osgi.service.remoteadmin.RemoteAdminListener;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.Filter;
+import org.osgi.framework.InvalidSyntaxException;
+import org.osgi.framework.ServiceReference;
+import org.osgi.framework.ServiceRegistration;
+import org.osgi.framework.hooks.service.ListenerHook;
+import org.osgi.util.tracker.ServiceTracker;
+import org.osgi.util.tracker.ServiceTrackerCustomizer;
+
+/**
+ * Implementation of Remote Controller
+ */
+public class RemoteControllerImpl implements ListenerHook, RemoteAdminListener, EndpointListener,
+ ServiceTrackerCustomizer, LifeCycleListener /*, EventHook */{
+ private final static Logger logger = Logger.getLogger(RemoteControllerImpl.class.getName());
+ public final static String ENDPOINT_LOCAL = "service.local";
+
+ private BundleContext context;
+ private ServiceTracker remoteAdmins;
+
+ private ServiceRegistration registration;
+ private ServiceRegistration endpointListener;
+
+ private ServiceTracker remotableServices;
+
+ // Service listeners keyed by the filter
+ private MappedCollections<String, ListenerInfo> serviceListeners = new MappedCollections<String, ListenerInfo>();
+
+ private MappedCollections<ServiceReference, ExportRegistration> exportedServices =
+ new MappedCollections<ServiceReference, ExportRegistration>();
+ private MappedCollections<EndpointDescription, ImportRegistration> importedServices =
+ new MappedCollections<EndpointDescription, ImportRegistration>();
+
+ private Filter remotableServiceFilter;
+
+ public RemoteControllerImpl(BundleContext context) {
+ this.context = context;
+ }
+
+ public void start() {
+ String filter =
+ "(& (!(" + SERVICE_IMPORTED
+ + "=*)) ("
+ + SERVICE_EXPORTED_INTERFACES
+ + "=*) ("
+ + SERVICE_EXPORTED_CONFIGS
+ + "=sca) )";
+ try {
+ remotableServiceFilter = context.createFilter(filter);
+ } catch (InvalidSyntaxException e) {
+ // Ignore
+ }
+
+ endpointListener = context.registerService(EndpointListener.class.getName(), this, null);
+ remoteAdmins = new ServiceTracker(this.context, RemoteAdmin.class.getName(), null);
+ remoteAdmins.open();
+
+ // DO NOT register EventHook.class.getName() as it cannot report existing services
+ String interfaceNames[] = new String[] {ListenerHook.class.getName(), RemoteAdminListener.class.getName()};
+ // The registration will trigger the added() method before registration is assigned
+ registration = context.registerService(interfaceNames, this, null);
+
+ remotableServices = new ServiceTracker(context, remotableServiceFilter, this);
+ remotableServices.open(true);
+
+ }
+
+ /**
+ * @see org.osgi.framework.hooks.service.EventHook#event(org.osgi.framework.ServiceEvent,
+ * java.util.Collection)
+ */
+ /*
+ public void event(ServiceEvent event, Collection contexts) {
+ ServiceReference reference = event.getServiceReference();
+ if (!remotableServiceFilter.match(reference)) {
+ // Only export remotable services that are for SCA
+ return;
+ }
+ switch (event.getType()) {
+ case ServiceEvent.REGISTERED:
+ exportService(reference);
+ break;
+ case ServiceEvent.UNREGISTERING:
+ unexportService(reference);
+ break;
+ case ServiceEvent.MODIFIED:
+ case ServiceEvent.MODIFIED_ENDMATCH:
+ // First check if the property changes will impact
+ // Call remote admin to update the service
+ unexportService(reference);
+ exportService(reference);
+ break;
+ }
+ }
+ */
+
+ public Object addingService(ServiceReference reference) {
+ exportService(reference);
+ return reference.getBundle().getBundleContext().getService(reference);
+ }
+
+ public void modifiedService(ServiceReference reference, Object service) {
+ unexportService(reference);
+ exportService(reference);
+ }
+
+ public void removedService(ServiceReference reference, Object service) {
+ unexportService(reference);
+ }
+
+ private void unexportService(ServiceReference reference) {
+ // Call remote admin to unexport the service
+ Collection<ExportRegistration> exportRegistrations = exportedServices.get(reference);
+ if (exportRegistrations != null) {
+ for (Iterator<ExportRegistration> i = exportRegistrations.iterator(); i.hasNext();) {
+ ExportRegistration exported = i.next();
+ exported.close();
+ i.remove();
+ }
+ }
+ }
+
+ private void exportService(ServiceReference reference) {
+ // Call remote admin to export the service
+ Object[] admins = remoteAdmins.getServices();
+ if (admins == null) {
+ // Ignore
+ logger.warning("No RemoteAdmin services are available.");
+ } else {
+ for (Object ra : admins) {
+ RemoteAdmin remoteAdmin = (RemoteAdmin)ra;
+ List<ExportRegistration> exportRegistrations = remoteAdmin.exportService(reference);
+ if (exportRegistrations != null && !exportRegistrations.isEmpty()) {
+ exportedServices.putValue(reference, exportRegistrations);
+ }
+ }
+ }
+ }
+
+ /**
+ * @see org.osgi.framework.hooks.service.ListenerHook#added(java.util.Collection)
+ */
+ public void added(Collection listeners) {
+ Collection<ListenerInfo> listenerInfos = (Collection<ListenerInfo>)listeners;
+ boolean changed = false;
+ for (ListenerInfo l : listenerInfos) {
+ if (!l.isRemoved() && l.getBundleContext() != context) {
+ String key = l.getFilter();
+ if (key == null) {
+ // key = "";
+ // FIXME: It should always match, let's ignore it for now
+ logger.warning("Service listner without a filter is skipped: " + l);
+ continue;
+ }
+ Collection<ListenerInfo> infos = serviceListeners.get(key);
+ if (infos == null) {
+ infos = new HashSet<ListenerInfo>();
+ serviceListeners.put(key, infos);
+ }
+ infos.add(l);
+ changed = true;
+ }
+ }
+ if (changed) {
+ updateEndpointListenerScope();
+ }
+ }
+
+ private void updateEndpointListenerScope() {
+ Set<String> filterSet = serviceListeners.keySet();
+
+ Dictionary<String, Object> props = new Hashtable<String, Object>();
+ props.put(ENDPOINT_LISTENER_SCOPE, filterSet.toArray(new String[filterSet.size()]));
+ endpointListener.setProperties(props);
+ }
+
+ private MappedCollections<Class<?>, ListenerInfo> findServiceListeners(EndpointDescription endpointDescription,
+ String matchedFilter) {
+ // First find all the listeners that have the matching filter
+ Collection<ListenerInfo> listeners = serviceListeners.get(matchedFilter);
+ if (listeners == null) {
+ return null;
+ }
+
+ // Try to partition the listeners by the interface classes
+ List<String> interfaceNames = endpointDescription.getInterfaces();
+ MappedCollections<Class<?>, ListenerInfo> interfaceToListeners =
+ new MappedCollections<Class<?>, ListenerInfo>();
+ for (String i : interfaceNames) {
+ for (ListenerInfo listener : listeners) {
+ try {
+ Class<?> interfaceClass = listener.getBundleContext().getBundle().loadClass(i);
+ interfaceToListeners.putValue(interfaceClass, listener);
+ } catch (ClassNotFoundException e) {
+ // Ignore the listener as it cannot load the interface class
+ }
+ }
+ }
+ return interfaceToListeners;
+ }
+
+ /**
+ * @see org.osgi.framework.hooks.service.ListenerHook#removed(java.util.Collection)
+ */
+ public void removed(Collection listeners) {
+ Collection<ListenerInfo> listenerInfos = (Collection<ListenerInfo>)listeners;
+ boolean changed = false;
+ for (ListenerInfo l : listenerInfos) {
+ if (registration != null && l.getBundleContext() != context) {
+ String key = l.getFilter();
+ if (key == null) {
+ continue;
+ }
+ if (serviceListeners.removeValue(key, l)) {
+ changed = true;
+ }
+ }
+ }
+ if (changed) {
+ updateEndpointListenerScope();
+ }
+ }
+
+ /**
+ * @see org.apache.tuscany.sca.osgi.service.remoteadmin.RemoteAdminListener#remoteAdminEvent(org.apache.tuscany.sca.osgi.service.remoteadmin.RemoteAdminEvent)
+ */
+ public void remoteAdminEvent(RemoteAdminEvent event) {
+ switch (event.getType()) {
+ case EXPORT_ERROR:
+ case EXPORT_REGISTRATION:
+ case EXPORT_UNREGISTRATION:
+ case EXPORT_WARNING:
+ break;
+ case IMPORT_ERROR:
+ case IMPORT_REGISTRATION:
+ case IMPORT_UNREGISTRATION:
+ case IMPORT_WARNING:
+ break;
+ }
+ }
+
+ /**
+ * @see org.apache.tuscany.sca.osgi.service.remoteadmin.EndpointListener#addEndpoint(org.apache.tuscany.sca.osgi.service.remoteadmin.EndpointDescription,
+ * java.lang.String)
+ */
+ public void addEndpoint(EndpointDescription endpoint, String matchedFilter) {
+ importService(endpoint, matchedFilter);
+ }
+
+ /**
+ * @see org.apache.tuscany.sca.osgi.service.remoteadmin.EndpointListener#removeEndpoint(org.apache.tuscany.sca.osgi.service.remoteadmin.EndpointDescription)
+ */
+ public void removeEndpoint(EndpointDescription endpoint) {
+ unimportService(endpoint);
+ }
+
+ private void importService(EndpointDescription endpoint, String matchedFilter) {
+ Object[] admins = remoteAdmins.getServices();
+ if (admins == null) {
+ logger.warning("No RemoteAdmin services are available.");
+ return;
+ }
+
+ MappedCollections<Class<?>, ListenerInfo> interfaceToListeners = findServiceListeners(endpoint, matchedFilter);
+ for (Map.Entry<Class<?>, Collection<ListenerInfo>> e : interfaceToListeners.entrySet()) {
+ Class<?> interfaceClass = e.getKey();
+ Collection<ListenerInfo> listeners = e.getValue();
+ // Get a listener
+ ListenerInfo listener = listeners.iterator().next();
+ Bundle bundle = listener.getBundleContext().getBundle();
+
+ Map<String, Object> props = new HashMap<String, Object>(endpoint.getProperties());
+ props.put(Bundle.class.getName(), bundle);
+ EndpointDescription description =
+ new EndpointDescriptionImpl(Collections.singletonList(interfaceClass.getName()), props);
+
+ if (admins != null) {
+ for (Object ra : admins) {
+ RemoteAdmin remoteAdmin = (RemoteAdmin)ra;
+ ImportRegistration importRegistration = remoteAdmin.importService(description);
+ if (importRegistration != null) {
+ importedServices.putValue(endpoint, importRegistration);
+ }
+ }
+ }
+ }
+ }
+
+ private void unimportService(EndpointDescription endpoint) {
+ // Call remote admin to unimport the service
+ Collection<ImportRegistration> importRegistrations = importedServices.get(endpoint);
+ if (importRegistrations != null) {
+ for (Iterator<ImportRegistration> i = importRegistrations.iterator(); i.hasNext();) {
+ ImportRegistration imported = i.next();
+ imported.close();
+ i.remove();
+ }
+ }
+ }
+
+ public void stop() {
+ remotableServices.close();
+
+ if (registration != null) {
+ registration.unregister();
+ registration = null;
+ }
+ if (remoteAdmins != null) {
+ remoteAdmins.close();
+ remoteAdmins = null;
+ }
+ for (Collection<ListenerInfo> infos : serviceListeners.values()) {
+ }
+ serviceListeners.clear();
+ }
+
+ private static class MappedCollections<K, V> extends HashMap<K, Collection<V>> {
+ private static final long serialVersionUID = -8926174610229029369L;
+
+ public boolean putValue(K key, V value) {
+ Collection<V> collection = get(key);
+ if (collection == null) {
+ collection = new ArrayList<V>();
+ put(key, collection);
+ }
+ return collection.add(value);
+ }
+
+ public boolean putValue(K key, Collection<? extends V> value) {
+ Collection<V> collection = get(key);
+ if (collection == null) {
+ collection = new ArrayList<V>();
+ put(key, collection);
+ }
+ return collection.addAll(value);
+ }
+
+ public boolean removeValue(K key, V value) {
+ Collection<V> collection = get(key);
+ if (collection == null) {
+ return false;
+ }
+ return collection.remove(value);
+ }
+
+ }
+
+}
diff --git a/java/sca/modules/node-impl-osgi/src/main/java/org/osgi/service/discovery/DiscoveredServiceNotification.java b/java/sca/modules/node-impl-osgi/src/main/java/org/osgi/service/discovery/DiscoveredServiceNotification.java
deleted file mode 100644
index d4431954b8..0000000000
--- a/java/sca/modules/node-impl-osgi/src/main/java/org/osgi/service/discovery/DiscoveredServiceNotification.java
+++ /dev/null
@@ -1,107 +0,0 @@
-/*
- * Copyright (c) OSGi Alliance (2008, 2009). All Rights Reserved.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.osgi.service.discovery;
-
-import java.util.Collection;
-
-/**
- * Interface for notification on discovered services.
- * <p>
- * <code>DiscoveredServiceNotification</code> objects are immutable.
- *
- * @Immutable
- */
-public interface DiscoveredServiceNotification {
-
- /**
- * Notification indicating that a service matching the listening criteria
- * has been discovered.
- * <p>
- * The value of <code>AVAILABLE</code> is 0x00000001.
- */
- public final static int AVAILABLE = 0x00000001;
-
- /**
- * Notification indicating that the properties of a previously discovered
- * service have changed.
- * <p>
- * The value of <code>MODIFIED</code> is 0x00000002.
- */
- public final static int MODIFIED = 0x00000002;
-
- /**
- * Notification indicating that a previously discovered service is no longer
- * known to <code>Discovery</code>.
- * <p>
- * The value of <code>UNAVAILABLE</code> is 0x00000004.
- */
- public final static int UNAVAILABLE = 0x00000004;
-
- /**
- * Notification indicating that the properties of a previously discovered
- * service have changed and the new properties no longer match the
- * listener's filter.
- * <p>
- * The value of <code>MODIFIED_ENDMATCH</code> is 0x00000008.
- */
- public final static int MODIFIED_ENDMATCH = 0x00000008;
-
- /**
- * Returns information currently known to <code>Discovery</code> regarding
- * the service endpoint.
- *
- * @return metadata of the service <code>Discovery</code> notifies about. Is
- * never <code>null</code>.
- */
- ServiceEndpointDescription getServiceEndpointDescription();
-
- /**
- * Returns the type of notification. The type values are:
- * <ul>
- * <li>{@link #AVAILABLE}</li>
- * <li>{@link #MODIFIED}</li>
- * <li>{@link #MODIFIED_ENDMATCH}</li>
- * <li>{@link #UNAVAILABLE}</li>
- * </ul>
- *
- * @return Type of notification regarding known service metadata.
- */
- int getType();
-
- /**
- * Returns interface name criteria of the {@link DiscoveredServiceTracker}
- * object matching with the interfaces of the
- * <code>ServiceEndpointDescription</code> and thus caused the notification.
- *
- * @return <code>Collection (&lt;? extends String&gt;)</code> of matching interface name criteria of the
- * <code>DiscoveredServiceTracker</code> object being notified, or
- * an empty collection if notification hasn't been caused by a
- * matching interface name criteria.
- */
- Collection/* <? extends String> */getInterfaces();
-
- /**
- * Returns filters of the <code>DiscoveredServiceTracker</code> object
- * matching with the properties of the
- * <code>ServiceEndpointDescription</code> and thus caused the notification.
- *
- * @return <code>Collection (&lt;? extends String&gt;)</code> of matching filters of the <code>DiscoveredServiceTracker</code>
- * object being notified, or an empty collection if notification
- * hasn't been caused by a matching filter criteria.
- */
- Collection/* <? extends String> */getFilters();
-}
diff --git a/java/sca/modules/node-impl-osgi/src/main/java/org/osgi/service/discovery/DiscoveredServiceTracker.java b/java/sca/modules/node-impl-osgi/src/main/java/org/osgi/service/discovery/DiscoveredServiceTracker.java
deleted file mode 100644
index 0cfa023d95..0000000000
--- a/java/sca/modules/node-impl-osgi/src/main/java/org/osgi/service/discovery/DiscoveredServiceTracker.java
+++ /dev/null
@@ -1,81 +0,0 @@
-/*
- * Copyright (c) OSGi Alliance (2008, 2009). All Rights Reserved.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.osgi.service.discovery;
-
-/**
- * Interface of trackers for discovered remote services.
- * <p>
- * When a service implementing this interface is registered with the framework,
- * then <code>Discovery</code> will notify it about remote services matching one
- * of the provided criteria and will keep notifying it on changes of information
- * known to Discovery regarding this services.
- *
- * <code>Discovery</code> may deliver notifications on discovered services to a
- * <code>DiscoveredServiceTracker</code> out of order and may concurrently call
- * and/or reenter a <code>DiscoveredServiceTracker</code>.
- *
- * @ThreadSafe
- */
-public interface DiscoveredServiceTracker {
-
- /**
- * Optional ServiceRegistration property which contains service interfaces
- * this tracker is interested in.
- * <p>
- * Value of this property is of type
- * <code>Collection (&lt;? extends String&gt;)</code>. May be
- * <code>null</code> or empty.
- */
- public static final String INTERFACE_MATCH_CRITERIA = "osgi.remote.discovery.interest.interfaces";
-
- /**
- * Optional ServiceRegistration property which contains filters for services
- * this tracker is interested in.
- * <p>
- * Note that these filters need to take into account service publication
- * properties which are not necessarily the same as properties under which a
- * service is registered. See {@link ServicePublication} for some standard
- * properties used to publish service metadata.
- * <p>
- * The following sample filter will make <code>Discovery</code> notify the
- * <code>DiscoveredServiceTracker</code> about services providing interface
- * 'my.company.foo' of version '1.0.1.3':
- * <code>"(&amp;(service.interface=my.company.foo)(service.interface.version=my.company.foo|1.0.1.3))"</code>.
- * <p>
- * Value of this property is of type
- * <code>Collection (&lt;? extends String&gt;)</code>. May be
- * <code>null</code>. or empty
- */
- public static final String FILTER_MATCH_CRITERIA = "osgi.remote.discovery.interest.filters";
-
- /**
- * Receives notification that information known to <code>Discovery</code>
- * regarding a remote service has changed.
- * <p>
- * The tracker is only notified about remote services which fulfill the
- * matching criteria, either one of the interfaces or one of the filters,
- * provided as properties of this service.
- * <p>
- * If multiple criteria match, then the tracker is notified about each of
- * them. This can be done either by a single notification callback or by
- * multiple subsequent ones.
- *
- * @param notification the <code>DiscoveredServiceNotification</code> object
- * describing the change. Is never <code>null</code>.
- */
- void serviceChanged(DiscoveredServiceNotification notification);
-}
diff --git a/java/sca/modules/node-impl-osgi/src/main/java/org/osgi/service/discovery/ServiceEndpointDescription.java b/java/sca/modules/node-impl-osgi/src/main/java/org/osgi/service/discovery/ServiceEndpointDescription.java
deleted file mode 100644
index 8f8b5d9f16..0000000000
--- a/java/sca/modules/node-impl-osgi/src/main/java/org/osgi/service/discovery/ServiceEndpointDescription.java
+++ /dev/null
@@ -1,128 +0,0 @@
-/*
- * Copyright (c) OSGi Alliance (2008, 2009). All Rights Reserved.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.osgi.service.discovery;
-
-import java.net.URI;
-import java.util.Collection;
-import java.util.Map;
-
-/**
- * This interface describes an endpoint of a service. This class can be
- * considered as a wrapper around the property map of a published service and
- * its endpoint. It provides an API to conveniently access the most important
- * properties of the service.
- * <p>
- * <code>ServiceEndpointDescription</code> objects are immutable.
- *
- * @Immutable
- */
-public interface ServiceEndpointDescription {
-
- /**
- * Returns the value of the property with key
- * {@link ServicePublication#SERVICE_INTERFACE_NAME}.
- *
- * @return <code>Collection (&lt;? extends String&gt;)</code> of service
- * interface names provided by the advertised service endpoint. The
- * collection is never <code>null</code> or empty but contains at
- * least one service interface.
- */
- Collection /* <? extends String> */getProvidedInterfaces();
-
- /**
- * Returns non-Java endpoint interface name associated with the given
- * interface.
- * <p>
- * Value of the property with key
- * {@link ServicePublication#ENDPOINT_INTERFACE_NAME} is used by this
- * operation.
- *
- * @param interfaceName for which its non-Java endpoint interface name
- * should be returned.
- * @return non-Java endpoint interface name, or <code>null</code> if it
- * hasn't been provided or if given interface name is
- * <code>null</code>.
- */
- String getEndpointInterfaceName(String interfaceName);
-
- /**
- * Returns version of the given interface.
- * <p>
- * Value of the property with key
- * {@link ServicePublication#SERVICE_INTERFACE_VERSION} is used by this
- * operation.
- *
- * @param interfaceName for which its version should be returned.
- * @return Version of given service interface, or <code>null</code> if it
- * hasn't been provided or if given interface name is
- * <code>null</code>.
- */
- String getVersion(String interfaceName);
-
- /**
- * Returns the value of the property with key
- * {@link ServicePublication#ENDPOINT_LOCATION}.
- *
- * @return The url of the service location, or <code>null</code> if it
- * hasn't been provided.
- */
- URI getLocation();
-
- /**
- * Returns the value of the property with key
- * {@link ServicePublication#ENDPOINT_ID}.
- *
- * @return Unique id of service endpoint, or <code>null</code> if it hasn't
- * been provided.
- */
- String getEndpointID();
-
- /**
- * Getter method for the property value of a given key.
- *
- * @param key Name of the property
- * @return The property value, or <code>null</code> if none is found for the
- * given key or if provided key is <code>null</code>.
- */
- Object getProperty(String key);
-
- /**
- * Returns all names of service endpoint properties.
- *
- * @return a <code>Collection (&lt;? extends String&gt;)</code> of property
- * names available in the ServiceEndpointDescription. The collection
- * is never <code>null</code> or empty but contains at least names
- * of mandatory <code>ServicePublication</code> properties. Since
- * <code>ServiceEndpointDescription</code> objects are immutable,
- * the returned collection is also not going to be updated at a
- * later point of time.
- */
- Collection/* <? extends String> */getPropertyKeys();
-
- /**
- * Returns all service endpoint properties.
- *
- * @return all properties of the service as a
- * <code>Map (&lt;String, Object&gt;)</code>. The map is never
- * <code>null</code> or empty but contains at least mandatory
- * <code>ServicePublication</code> properties. Since
- * <code>ServiceEndpointDescription</code> objects are immutable,
- * the returned map is also not going to be updated at a later point
- * of time.
- */
- Map/* <String, Object> */getProperties();
-}
diff --git a/java/sca/modules/node-impl-osgi/src/main/java/org/osgi/service/discovery/ServicePublication.java b/java/sca/modules/node-impl-osgi/src/main/java/org/osgi/service/discovery/ServicePublication.java
deleted file mode 100644
index d490394bc3..0000000000
--- a/java/sca/modules/node-impl-osgi/src/main/java/org/osgi/service/discovery/ServicePublication.java
+++ /dev/null
@@ -1,147 +0,0 @@
-/*
- * Copyright (c) OSGi Alliance (2008, 2009). All Rights Reserved.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.osgi.service.discovery;
-
-import org.osgi.framework.ServiceReference;
-
-/**
- * Register a service implementing the <code>ServicePublication</code> interface
- * in order to publish metadata of a particular service (endpoint) via
- * Discovery. Metadata which has to be published is given in form of properties
- * at registration.
- * <p>
- * In order to update published service metadata, update the properties
- * registered with the <code>ServicePublication</code> service. Depending on
- * Discovery's implementation and underlying protocol it may result in an update
- * or new re-publication of the service.
- * <p>
- * In order to unpublish the previously published service metadata, unregister
- * the <code>ServicePublication</code> service.
- * <p>
- * Please note that providing the {@link #SERVICE_INTERFACE_NAME} property is
- * mandatory when a <code>ServicePublication</code> service is registered. Note
- * also that a Discovery implementation may require provision of additional
- * properties, e.g. some of the standard properties defined below, or may make
- * special use of them in case they are provided. For example an SLP-based
- * Discovery might use the value provided with the {@link #ENDPOINT_LOCATION}
- * property for construction of a SLP-URL used to publish the service.
- * <p>
- * Also important is that it's not guaranteed that after registering a
- * <code>ServicePublication</code> object its service metadata is actually
- * published. Beside the fact that at least one Discovery service has to be
- * present, the provided properties have to be valid, e.g. shouldn't contain
- * case variants of the same key name, and the actual publication via Discovery
- * mechanisms has to succeed.
- *
- * @ThreadSafe
- */
-public interface ServicePublication {
-
- /**
- * Mandatory ServiceRegistration property which contains a collection of
- * full qualified interface names offered by the advertised service
- * endpoint.
- * <p>
- * Value of this property is of type
- * <code>Collection (&lt;? extends String&gt;)</code>.
- */
- public static final String SERVICE_INTERFACE_NAME = "osgi.remote.service.interfaces";
-
- /**
- * Optional ServiceRegistration property which contains a collection of
- * interface names with their associated version attributes separated by
- * {@link #SEPARATOR} e.g. ["my.company.foo|1.3.5", "my.company.zoo|2.3.5"].
- * In case no version has been provided for an interface, Discovery may use
- * the String-value of <code>org.osgi.framework.Version.emptyVersion</code>
- * constant.
- * <p>
- * Value of this property is of type
- * <code>Collection (&lt;? extends String&gt;)</code>, may be
- * <code>null</code> or empty.
- */
- public static final String SERVICE_INTERFACE_VERSION = "osgi.remote.service.interfaces.version";
-
- /**
- * Optional ServiceRegistration property which contains a collection of
- * interface names with their associated (non-Java) endpoint interface names
- * separated by {@link #SEPARATOR} e.g.:<br>
- * ["my.company.foo|MyWebService", "my.company.zoo|MyWebService"].
- * <p>
- * This (non-Java) endpoint interface name is usually a communication
- * protocol specific interface, for instance a web service interface name.
- * Though this information is usually contained in accompanying properties
- * e.g. a wsdl file, Discovery usually doesn't read and interprets such
- * service meta-data. Providing this information explicitly, might allow
- * external non-Java applications find services based on this endpoint
- * interface.
- * <p>
- * Value of this property is of type
- * <code>Collection (&lt;? extends String&gt;)</code>, may be
- * <code>null</code> or empty.
- */
- public static final String ENDPOINT_INTERFACE_NAME = "osgi.remote.endpoint.interfaces";
-
- /**
- * Optional ServiceRegistration property which contains a map of properties
- * of the published service.
- * <p>
- * Property keys are handled in a case insensitive manner (as OSGi Framework
- * does).
- * <p>
- * Value of this property is of type <code>Map (String, Object)</code>, may
- * be <code>null</code> or empty.
- */
- public static final String SERVICE_PROPERTIES = "osgi.remote.discovery.publication.service.properties";
-
- /**
- * Optional property of the published service identifying its location. This
- * property is provided as part of the service property map referenced by
- * the {@link #SERVICE_PROPERTIES} ServiceRegistration property.
- * <p>
- * Value of this property is of type <code>java.net.URI</code>, may be
- * <code>null</code>.
- */
- public static final String ENDPOINT_LOCATION = "osgi.remote.endpoint.location";
-
- /**
- * Optional property of the published service uniquely identifying its
- * endpoint. This property is provided as part of the service property map
- * referenced by the {@link #SERVICE_PROPERTIES} ServiceRegistration
- * property.
- * <p>
- * Value of this property is of type <code>String</code>, may be
- * <code>null</code>.
- */
- public static final String ENDPOINT_ID = "osgi.remote.endpoint.id";
-
- /**
- * Separator constant for association of interface-specific values with the
- * particular interface name. See also {@link #SERVICE_INTERFACE_VERSION}
- * and {@link #ENDPOINT_INTERFACE_NAME} properties which describe such
- * interface-specific values.
- */
- public static final String SEPARATOR = "|";
-
- /**
- * Returns the <code>ServiceReference</code> this publication metadata is
- * associated with.
- *
- * @return the <code>ServiceReference</code> being published. Is never
- * <code>null</code>.
- */
- ServiceReference getReference();
-}
diff --git a/java/sca/samples/dosgi-calculator-operations/src/main/java/calculator/dosgi/operations/impl/OperationsActivator.java b/java/sca/samples/dosgi-calculator-operations/src/main/java/calculator/dosgi/operations/impl/OperationsActivator.java
index 5348d19f34..da2ce9063a 100644
--- a/java/sca/samples/dosgi-calculator-operations/src/main/java/calculator/dosgi/operations/impl/OperationsActivator.java
+++ b/java/sca/samples/dosgi-calculator-operations/src/main/java/calculator/dosgi/operations/impl/OperationsActivator.java
@@ -44,7 +44,7 @@ public class OperationsActivator implements BundleActivator {
logger.info("Starting " + context.getBundle());
Dictionary<String, Object> props = new Hashtable<String, Object>();
-
+
logger.info("Registering " + AddService.class.getName());
props.put("sca.service", "AddComponent#service-name(Add)");
context.registerService(AddService.class.getName(), new AddServiceImpl(), props);
diff --git a/java/sca/samples/dosgi-calculator/OSGI-INF/sca/bundle.composite b/java/sca/samples/dosgi-calculator/OSGI-INF/sca/bundle.composite
index 2bcd44e970..481fd67e09 100644
--- a/java/sca/samples/dosgi-calculator/OSGI-INF/sca/bundle.composite
+++ b/java/sca/samples/dosgi-calculator/OSGI-INF/sca/bundle.composite
@@ -40,17 +40,6 @@
<reference name="divideService">
<tuscany:binding.rmi uri="rmi://localhost:8085/DivideService"/>
</reference>
-
- <!--
- <reference name="addService" target="OperationsComponent/AddService">
- </reference>
- <reference name="subtractService" target="OperationsComponent/SubtractService">
- </reference>
- <reference name="multiplyService" target="OperationsComponent/MultiplyService">
- </reference>
- <reference name="divideService" target="OperationsComponent/DivideService">
- </reference>
- -->
</component>
</composite>
diff --git a/java/sca/samples/dosgi-calculator/OSGI-INF/sca/calculator-service.bindings b/java/sca/samples/dosgi-calculator/OSGI-INF/sca/calculator-service.bindings
index 65a5a76194..90e55f7377 100644
--- a/java/sca/samples/dosgi-calculator/OSGI-INF/sca/calculator-service.bindings
+++ b/java/sca/samples/dosgi-calculator/OSGI-INF/sca/calculator-service.bindings
@@ -17,7 +17,7 @@
* specific language governing permissions and limitations
* under the License.
-->
-<!-- A consumer-side service description file for RFC 119 -->
+<!-- SCA bindings for calculator service -->
<bindings xmlns="http://www.osgi.org/xmlns/sd/v1.0.0"
xmlns:sca="http://docs.oasis-open.org/ns/opencsa/sca/200903">
<sca:binding.ws uri="http://localhost:8086/CalculatorService"/>
diff --git a/java/sca/samples/dosgi-calculator/src/main/java/calculator/dosgi/impl/CalculatorActivator.java b/java/sca/samples/dosgi-calculator/src/main/java/calculator/dosgi/impl/CalculatorActivator.java
index 40388144ee..6b42645f69 100644
--- a/java/sca/samples/dosgi-calculator/src/main/java/calculator/dosgi/impl/CalculatorActivator.java
+++ b/java/sca/samples/dosgi-calculator/src/main/java/calculator/dosgi/impl/CalculatorActivator.java
@@ -59,9 +59,7 @@ public class CalculatorActivator implements BundleActivator {
Dictionary<String, Object> props = new Hashtable<String, Object>();
props.put("sca.service", "CalculatorComponent#service-name(Calculator)");
props.put("calculator", "Calculator");
- props.put("service.exported.configs", new String[] {"sca"});
- props.put("sca.bindings", new String[] {"OSGI-INF/sca/calculator-service.bindings"});
- props.put("service.exported.interfaces", new String[] {"*"});
+
logger.info("Registering " + CalculatorService.class.getName());
CalculatorService calculator = new CalculatorServiceImpl(context);
context.registerService(CalculatorService.class.getName(), calculator, props);
diff --git a/java/sca/samples/dosgi-calculator/src/main/java/calculator/dosgi/impl/CalculatorServiceImpl.java b/java/sca/samples/dosgi-calculator/src/main/java/calculator/dosgi/impl/CalculatorServiceImpl.java
index 932c5fcf15..a9ea37585a 100644
--- a/java/sca/samples/dosgi-calculator/src/main/java/calculator/dosgi/impl/CalculatorServiceImpl.java
+++ b/java/sca/samples/dosgi-calculator/src/main/java/calculator/dosgi/impl/CalculatorServiceImpl.java
@@ -60,6 +60,12 @@ public class CalculatorServiceImpl implements CalculatorService {
}
private <T> T getService(Class<T> cls) {
+ try {
+ // Wait for 10 seconds until the remote services are imported
+ remoteServices.waitForService(10000);
+ } catch (InterruptedException e) {
+ throw new IllegalStateException(cls.getSimpleName() + " is not available");
+ }
Object[] remoteObjects = remoteServices.getServices();
if (remoteObjects != null) {
for (Object s : remoteObjects) {
@@ -70,13 +76,14 @@ public class CalculatorServiceImpl implements CalculatorService {
}
}
Object[] localObjects = localServices.getServices();
- if (localObjects != null)
+ if (localObjects != null) {
for (Object s : localObjects) {
if (cls.isInstance(s)) {
System.out.println("Local service: " + s);
return cls.cast(s);
}
}
+ }
throw new IllegalStateException(cls.getSimpleName() + " is not available");
}
diff --git a/java/sca/samples/dosgi-dynamic-calculator-operations/LICENSE b/java/sca/samples/dosgi-dynamic-calculator-operations/LICENSE
new file mode 100644
index 0000000000..6e529a25c4
--- /dev/null
+++ b/java/sca/samples/dosgi-dynamic-calculator-operations/LICENSE
@@ -0,0 +1,205 @@
+
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+ 1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+ 2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+ 3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+ 4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+ 6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+ 7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+ 8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+ 9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+ END OF TERMS AND CONDITIONS
+
+ APPENDIX: How to apply the Apache License to your work.
+
+ To apply the Apache License to your work, attach the following
+ boilerplate notice, with the fields enclosed by brackets "[]"
+ replaced with your own identifying information. (Don't include
+ the brackets!) The text should be enclosed in the appropriate
+ comment syntax for the file format. We also recommend that a
+ file or class name and description of purpose be included on the
+ same "printed page" as the copyright notice for easier
+ identification within third-party archives.
+
+ Copyright [yyyy] [name of copyright owner]
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+
+
diff --git a/java/sca/samples/dosgi-dynamic-calculator-operations/META-INF/MANIFEST.MF b/java/sca/samples/dosgi-dynamic-calculator-operations/META-INF/MANIFEST.MF
new file mode 100644
index 0000000000..9dee7d5f4a
--- /dev/null
+++ b/java/sca/samples/dosgi-dynamic-calculator-operations/META-INF/MANIFEST.MF
@@ -0,0 +1,22 @@
+Manifest-Version: 1.0
+Export-Package: calculator.dosgi.operations;version="1.0.1"
+Bundle-Version: 1.0.0
+Bundle-Name: calculator.dosgi.dynamic.operations
+Bundle-Activator: calculator.dosgi.operations.impl.OperationsActivator
+Bundle-ManifestVersion: 2
+Import-Package: calculator.dosgi.operations;version="1.0.1",
+ org.oasisopen.sca.annotation;version="2.0.0",
+ org.osgi.framework,
+ org.osgi.service.component;resolution:=optional,
+ org.osgi.service.packageadmin
+Bundle-SymbolicName: calculator.dosgi.dynamic.operations
+Bundle-Vendor: The Apache Software Foundation
+Bundle-ActivationPolicy: lazy
+Eclipse-LazyStart: true
+Bundle-License: http://www.apache.org/licenses/LICENSE-2.0.txt
+Bundle-DocURL: http://www.apache.org/
+Service-Component: OSGI-INF/add-component.xml,
+ OSGI-INF/subtract-component.xml,
+ OSGI-INF/multiply-component.xml,
+ OSGI-INF/divide-component.xml
+Bundle-RequiredExecutionEnvironment: J2SE-1.5,JavaSE-1.6
diff --git a/java/sca/samples/dosgi-dynamic-calculator-operations/NOTICE b/java/sca/samples/dosgi-dynamic-calculator-operations/NOTICE
new file mode 100644
index 0000000000..51042eab05
--- /dev/null
+++ b/java/sca/samples/dosgi-dynamic-calculator-operations/NOTICE
@@ -0,0 +1,6 @@
+${pom.name}
+Copyright (c) 2005 - 2009 The Apache Software Foundation
+
+This product includes software developed by
+The Apache Software Foundation (http://www.apache.org/).
+
diff --git a/java/sca/samples/dosgi-dynamic-calculator-operations/OSGI-INF/add-component.xml b/java/sca/samples/dosgi-dynamic-calculator-operations/OSGI-INF/add-component.xml
new file mode 100644
index 0000000000..99845257ff
--- /dev/null
+++ b/java/sca/samples/dosgi-dynamic-calculator-operations/OSGI-INF/add-component.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+-->
+<scr:component name="AddComponent" xmlns:scr="http://www.osgi.org/xmlns/scr/v1.0.0">
+ <implementation class="calculator.dosgi.operations.impl.AddServiceImpl" />
+ <service>
+ <provide interface="calculator.dosgi.operations.AddService" />
+ </service>
+</scr:component>
diff --git a/java/sca/samples/dosgi-dynamic-calculator-operations/OSGI-INF/blueprint/operations-module.xml b/java/sca/samples/dosgi-dynamic-calculator-operations/OSGI-INF/blueprint/operations-module.xml
new file mode 100644
index 0000000000..f6b5f4690e
--- /dev/null
+++ b/java/sca/samples/dosgi-dynamic-calculator-operations/OSGI-INF/blueprint/operations-module.xml
@@ -0,0 +1,40 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+-->
+<!-- A sample module-context.xml for OSGI RFC 124 (BluePrint Service) -->
+<components xmlns="http://www.osgi.org/xmlns/blueprint/v1.0.0">
+ <component id="AddComponent" class="calculator.dosgi.operations.impl.AddServiceImpl">
+ </component>
+ <component id="SubtractComponent" class="calculator.dosgi.operations.impl.SubtractServiceImpl">
+ </component>
+ <component id="MultiplyComponent" class="calculator.dosgi.operations.impl.MultiplyServiceImpl">
+ </component>
+ <component id="DivideComponent" class="calculator.dosgi.operations.impl.DivideServiceImpl">
+ </component>
+
+ <!-- We can derive the SCA services for the implementation.osgi -->
+ <service id="AddService" ref="AddComponent" interface="calculator.dosgi.operations.AddService">
+ </service>
+ <service id="SubtractService" ref="SubtractComponent" interface="calculator.dosgi.operations.SubtractService">
+ </service>
+ <service id="MultiplyService" ref="MultiplyComponent" interface="calculator.dosgi.operations.MultiplyService">
+ </service>
+ <service id="DivideService" ref="DivideComponent" interface="calculator.dosgi.operations.DivideService">
+ </service>
+</components> \ No newline at end of file
diff --git a/java/sca/samples/dosgi-dynamic-calculator-operations/OSGI-INF/divide-component.xml b/java/sca/samples/dosgi-dynamic-calculator-operations/OSGI-INF/divide-component.xml
new file mode 100644
index 0000000000..322d4daf2f
--- /dev/null
+++ b/java/sca/samples/dosgi-dynamic-calculator-operations/OSGI-INF/divide-component.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+-->
+<scr:component name="DivideComponent" xmlns:scr="http://www.osgi.org/xmlns/scr/v1.0.0">
+ <implementation class="calculator.dosgi.operations.impl.DivideServiceImpl" />
+ <service>
+ <provide interface="calculator.dosgi.operations.DivideService" />
+ </service>
+</scr:component>
diff --git a/java/sca/samples/dosgi-dynamic-calculator-operations/OSGI-INF/multiply-component.xml b/java/sca/samples/dosgi-dynamic-calculator-operations/OSGI-INF/multiply-component.xml
new file mode 100644
index 0000000000..b9ca777bd8
--- /dev/null
+++ b/java/sca/samples/dosgi-dynamic-calculator-operations/OSGI-INF/multiply-component.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+-->
+<scr:component name="MultiplyComponent" xmlns:scr="http://www.osgi.org/xmlns/scr/v1.0.0">
+ <implementation class="calculator.dosgi.operations.impl.MultiplyServiceImpl" />
+ <service>
+ <provide interface="calculator.dosgi.operations.MultiplyService" />
+ </service>
+</scr:component>
diff --git a/java/sca/samples/dosgi-dynamic-calculator-operations/OSGI-INF/sca/add-service.bindings b/java/sca/samples/dosgi-dynamic-calculator-operations/OSGI-INF/sca/add-service.bindings
new file mode 100644
index 0000000000..d51878c562
--- /dev/null
+++ b/java/sca/samples/dosgi-dynamic-calculator-operations/OSGI-INF/sca/add-service.bindings
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License. You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied. See the License for the
+* specific language governing permissions and limitations
+* under the License.
+-->
+<bindings xmlns="http://www.osgi.org/xmlns/sd/v1.0.0"
+ xmlns:tuscany="http://tuscany.apache.org/xmlns/sca/1.1">
+ <tuscany:binding.rmi uri="rmi://localhost:8085/AddService"/>
+</bindings> \ No newline at end of file
diff --git a/java/sca/samples/dosgi-dynamic-calculator-operations/OSGI-INF/sca/divide-service.bindings b/java/sca/samples/dosgi-dynamic-calculator-operations/OSGI-INF/sca/divide-service.bindings
new file mode 100644
index 0000000000..a664456474
--- /dev/null
+++ b/java/sca/samples/dosgi-dynamic-calculator-operations/OSGI-INF/sca/divide-service.bindings
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License. You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied. See the License for the
+* specific language governing permissions and limitations
+* under the License.
+-->
+<bindings xmlns="http://www.osgi.org/xmlns/sd/v1.0.0"
+ xmlns:tuscany="http://tuscany.apache.org/xmlns/sca/1.1">
+ <tuscany:binding.rmi uri="rmi://localhost:8085/DivideService"/>
+</bindings> \ No newline at end of file
diff --git a/java/sca/samples/dosgi-dynamic-calculator-operations/OSGI-INF/sca/multiply-service.bindings b/java/sca/samples/dosgi-dynamic-calculator-operations/OSGI-INF/sca/multiply-service.bindings
new file mode 100644
index 0000000000..fb1b40e39c
--- /dev/null
+++ b/java/sca/samples/dosgi-dynamic-calculator-operations/OSGI-INF/sca/multiply-service.bindings
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License. You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied. See the License for the
+* specific language governing permissions and limitations
+* under the License.
+-->
+<bindings xmlns="http://www.osgi.org/xmlns/sd/v1.0.0"
+ xmlns:tuscany="http://tuscany.apache.org/xmlns/sca/1.1">
+ <tuscany:binding.rmi uri="rmi://localhost:8085/MultiplyService"/>
+</bindings> \ No newline at end of file
diff --git a/java/sca/samples/dosgi-dynamic-calculator-operations/OSGI-INF/sca/subtract-service.bindings b/java/sca/samples/dosgi-dynamic-calculator-operations/OSGI-INF/sca/subtract-service.bindings
new file mode 100644
index 0000000000..2f44802d1f
--- /dev/null
+++ b/java/sca/samples/dosgi-dynamic-calculator-operations/OSGI-INF/sca/subtract-service.bindings
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License. You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied. See the License for the
+* specific language governing permissions and limitations
+* under the License.
+-->
+<bindings xmlns="http://www.osgi.org/xmlns/sd/v1.0.0"
+ xmlns:tuscany="http://tuscany.apache.org/xmlns/sca/1.1">
+ <tuscany:binding.rmi uri="rmi://localhost:8085/SubtractService"/>
+</bindings> \ No newline at end of file
diff --git a/java/sca/samples/dosgi-dynamic-calculator-operations/OSGI-INF/subtract-component.xml b/java/sca/samples/dosgi-dynamic-calculator-operations/OSGI-INF/subtract-component.xml
new file mode 100644
index 0000000000..1472f5a976
--- /dev/null
+++ b/java/sca/samples/dosgi-dynamic-calculator-operations/OSGI-INF/subtract-component.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+-->
+<scr:component name="SubtractComponent" xmlns:scr="http://www.osgi.org/xmlns/scr/v1.0.0">
+ <implementation class="calculator.dosgi.operations.impl.SubtractServiceImpl" />
+ <service>
+ <provide interface="calculator.dosgi.operations.SubtractService" />
+ </service>
+</scr:component>
diff --git a/java/sca/samples/dosgi-dynamic-calculator-operations/README b/java/sca/samples/dosgi-dynamic-calculator-operations/README
new file mode 100644
index 0000000000..9e616c1f50
--- /dev/null
+++ b/java/sca/samples/dosgi-dynamic-calculator-operations/README
@@ -0,0 +1,183 @@
+Distributed OSGi Calculator Sample
+==================================
+This sample implements a distributed calculator using Distributed OSGi (RFC 119) over SCA.
+
+The README in the samples directory (the directory above this) provides
+general instructions about building and running samples. Take a look there
+first.
+
+On Windows, run
+java -jar ..\..\modules\osgi-3.4.0-v20080605-1900.jar -configuration ..\..\features\configuration -clean -console
+
+On *Unix, run
+java -jar ../../modules/osgi-3.4.0-v20080605-1900.jar -configuration ../../features/configuration -clean -console
+
+You should see the osgi console:
+
+osgi>
+
+osgi> Jun 22, 2009 1:32:27 PM org.apache.tuscany.sca.extensibility.equinox.EquinoxServiceDiscoveryActivator start
+INFO: Equinox-based service discoverer is now configured.
+
+You can run "ss" command under the osgi> to see the status of the bundles.
+osgi> ss
+
+Then you can install and start the calculator.dosgi bundle:
+
+osgi> install file:./target/sample-dosgi-calculator-operations.jar
+Bundle id is 181
+
+osgi> start 181
+Jun 22, 2009 2:09:21 PM calculator.dosgi.operations.impl.OperationsActivator sta
+rt
+INFO: Starting file:./target/sample-dosgi-calculator-operations.jar [181]
+Jun 22, 2009 2:09:21 PM calculator.dosgi.operations.impl.OperationsActivator sta
+rt
+INFO: Registering calculator.dosgi.operations.AddService
+Jun 22, 2009 2:09:21 PM calculator.dosgi.operations.impl.OperationsActivator sta
+rt
+INFO: Registering calculator.dosgi.operations.SubtractService
+Jun 22, 2009 2:09:21 PM calculator.dosgi.operations.impl.OperationsActivator sta
+rt
+INFO: Registering calculator.dosgi.operations.MultiplyService
+Jun 22, 2009 2:09:21 PM calculator.dosgi.operations.impl.OperationsActivator sta
+rt
+INFO: Registering calculator.dosgi.operations.DivideService
+Jun 22, 2009 2:09:21 PM calculator.dosgi.operations.impl.OperationsActivator get
+Bundle
+INFO: calculator.dosgi.operations.AddService is loaded by bundle: calculator.dos
+gi.operations
+Jun 22, 2009 2:09:21 PM org.apache.tuscany.sca.node.impl.NodeImpl start
+INFO: Starting node: calculator.dosgi.operations
+Jun 22, 2009 2:09:21 PM org.apache.tuscany.sca.node.impl.NodeFactoryImpl configu
+reNode
+INFO: Loading contribution: bundleentry://181/
+Jun 22, 2009 2:09:21 PM org.apache.tuscany.sca.endpoint.tribes.ReplicatedEndpoin
+tRegistry addEndpoint
+INFO: EndpointRegistry: Add endpoint - Endpoint: URI = OperationsComponent#serv
+ice-binding(AddService/AddService)
+Jun 22, 2009 2:09:21 PM org.apache.tuscany.sca.host.rmi.DefaultRMIHost registerS
+ervice
+INFO: RMI service registered: rmi://localhost:8085/AddService
+Jun 22, 2009 2:09:21 PM org.apache.tuscany.sca.endpoint.tribes.ReplicatedEndpoin
+tRegistry addEndpoint
+INFO: EndpointRegistry: Add endpoint - Endpoint: URI = OperationsComponent#serv
+ice-binding(SubtractService/SubtractService)
+Jun 22, 2009 2:09:21 PM org.apache.tuscany.sca.host.rmi.DefaultRMIHost registerS
+ervice
+INFO: RMI service registered: rmi://localhost:8085/SubtractService
+Jun 22, 2009 2:09:21 PM org.apache.tuscany.sca.endpoint.tribes.ReplicatedEndpoin
+tRegistry addEndpoint
+INFO: EndpointRegistry: Add endpoint - Endpoint: URI = OperationsComponent#serv
+ice-binding(MultiplyService/MultiplyService)
+Jun 22, 2009 2:09:21 PM org.apache.tuscany.sca.host.rmi.DefaultRMIHost registerS
+ervice
+INFO: RMI service registered: rmi://localhost:8085/MultiplyService
+Jun 22, 2009 2:09:21 PM org.apache.tuscany.sca.endpoint.tribes.ReplicatedEndpoin
+tRegistry addEndpoint
+INFO: EndpointRegistry: Add endpoint - Endpoint: URI = OperationsComponent#serv
+ice-binding(DivideService/DivideService)
+Jun 22, 2009 2:09:21 PM org.apache.tuscany.sca.host.rmi.DefaultRMIHost registerS
+ervice
+INFO: RMI service registered: rmi://localhost:8085/DivideService
+
+osgi>
+
+To stop the bundle:
+
+osgi> stop 181
+Jun 22, 2009 2:09:48 PM org.apache.tuscany.sca.node.impl.NodeImpl stop
+INFO: Stopping node: calculator.dosgi.operations
+Jun 22, 2009 2:09:48 PM org.apache.tuscany.sca.endpoint.tribes.ReplicatedEndpoin
+tRegistry removeEndpoint
+INFO: EndpointRegistry: Remove endpoint - Endpoint: URI = OperationsComponent#s
+ervice-binding(AddService/AddService)
+Jun 22, 2009 2:09:48 PM org.apache.tuscany.sca.host.rmi.DefaultRMIHost unregiste
+rService
+INFO: RMI service unregistered: rmi://localhost:8085/AddService
+Jun 22, 2009 2:09:48 PM org.apache.tuscany.sca.endpoint.tribes.ReplicatedEndpoin
+tRegistry removeEndpoint
+INFO: EndpointRegistry: Remove endpoint - Endpoint: URI = OperationsComponent#s
+ervice-binding(SubtractService/SubtractService)
+Jun 22, 2009 2:09:48 PM org.apache.tuscany.sca.host.rmi.DefaultRMIHost unregiste
+rService
+INFO: RMI service unregistered: rmi://localhost:8085/SubtractService
+Jun 22, 2009 2:09:48 PM org.apache.tuscany.sca.endpoint.tribes.ReplicatedEndpoin
+tRegistry removeEndpoint
+INFO: EndpointRegistry: Remove endpoint - Endpoint: URI = OperationsComponent#s
+ervice-binding(MultiplyService/MultiplyService)
+Jun 22, 2009 2:09:48 PM org.apache.tuscany.sca.host.rmi.DefaultRMIHost unregiste
+rService
+INFO: RMI service unregistered: rmi://localhost:8085/MultiplyService
+Jun 22, 2009 2:09:48 PM org.apache.tuscany.sca.endpoint.tribes.ReplicatedEndpoin
+tRegistry removeEndpoint
+INFO: EndpointRegistry: Remove endpoint - Endpoint: URI = OperationsComponent#s
+ervice-binding(DivideService/DivideService)
+Jun 22, 2009 2:09:48 PM org.apache.tuscany.sca.host.rmi.DefaultRMIHost unregiste
+rService
+INFO: RMI service unregistered: rmi://localhost:8085/DivideService
+Jun 22, 2009 2:09:48 PM calculator.dosgi.operations.impl.OperationsActivator sto
+p
+INFO: Stopping file:./target/sample-dosgi-calculator-operations.jar [181]
+
+osgi>
+
+To exit the console, run:
+osgi> exit
+
+Sample Overview
+---------------
+The application consists of two OSGi bundles:
+ * The calculator bundle: It provides the calculator service. The service is implemented by a java class that
+ consumes other services to perform the “add”, “subtract”, “multiply” and “divide” operations.
+ * The operations bundle: It provides the add/subtract/multiply/divide services.
+ (See ../samples/dosgi-calculator-operations)
+
+
+dosgi-calculator-operations/
+ src/
+ main/
+ java/
+ calculator/
+ dosgi/
+ operations/
+ AddService.java - Interface for Add
+ SubtractService.java - Interface for Subtract
+ MultiplyService.java - Interface for Multiply
+ DivideService.java - Interface for Divide
+ impl/
+ OperationsActivator.java - OSGi bundle activator
+ AddServiceImpl.java - Implementation for Add
+ SubtractServiceImpl.java - Implementation for Subtract
+ MultiplyServiceImpl.java - Implementation for Multiply
+ DivideServiceImpl.java - Implementation for Divide
+ resources/
+ META-INF/
+ sca-contribution.xml
+ OSGI-INF/
+ sca/
+ bundle.componentType - The component type for implementation.osgi of this bundle
+ bundle.composite - The composite file
+ test/
+ java/
+ src/
+ calculator/
+ dosgi/
+ operations/
+ test/
+ OperationsOSGiNodeTestCase.java - The JUNIT test case that tests this bundle using a RMI client
+
+ META-INF/
+ MANIFEST.MF - The OSGi manifest for this bundle
+ pom.xml - the Maven build file
+
+
+
+Building And Running The Test Case Using Maven
+-------------------------------------------
+With either the binary or source distributions the sample can be built and run
+using Maven as follows.
+
+cd dosgi-calculator-operations
+mvn
+
diff --git a/java/sca/samples/dosgi-dynamic-calculator-operations/pom.xml b/java/sca/samples/dosgi-dynamic-calculator-operations/pom.xml
new file mode 100644
index 0000000000..037782997f
--- /dev/null
+++ b/java/sca/samples/dosgi-dynamic-calculator-operations/pom.xml
@@ -0,0 +1,134 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+-->
+<project>
+ <modelVersion>4.0.0</modelVersion>
+ <parent>
+ <groupId>org.apache.tuscany.sca</groupId>
+ <artifactId>tuscany-sca</artifactId>
+ <version>2.0-SNAPSHOT</version>
+ <relativePath>../../pom.xml</relativePath>
+ </parent>
+
+ <artifactId>sample-dosgi-dynamic-calculator-operations</artifactId>
+ <name>Apache Tuscany SCA OSGi RemoteService Dynamic Caculator Operations Sample</name>
+
+ <dependencies>
+ <dependency>
+ <groupId>org.apache.tuscany.sca</groupId>
+ <artifactId>tuscany-feature-ejava</artifactId>
+ <version>2.0-SNAPSHOT</version>
+ <type>pom</type>
+ </dependency>
+
+ <dependency>
+ <groupId>org.apache.tuscany.sca</groupId>
+ <artifactId>tuscany-node-launcher-equinox</artifactId>
+ <version>2.0-SNAPSHOT</version>
+ <scope>test</scope>
+ </dependency>
+
+ <dependency>
+ <groupId>org.apache.tuscany.sca</groupId>
+ <artifactId>tuscany-node-impl-osgi</artifactId>
+ <version>2.0-SNAPSHOT</version>
+ <scope>runtime</scope>
+ </dependency>
+
+ <dependency>
+ <groupId>org.eclipse.osgi</groupId>
+ <artifactId>services</artifactId>
+ <version>3.2.0-v20090520-1800</version>
+ <scope>test</scope>
+ </dependency>
+
+ <!-- Equinox Declarative Services -->
+ <dependency>
+ <groupId>org.eclipse.equinox</groupId>
+ <artifactId>ds</artifactId>
+ <version>1.1.0-v20090601</version>
+ <scope>test</scope>
+ </dependency>
+
+ <dependency>
+ <groupId>org.eclipse.equinox</groupId>
+ <artifactId>util</artifactId>
+ <version>1.0.100-v20090520-1800</version>
+ <scope>test</scope>
+ </dependency>
+
+ <dependency>
+ <groupId>junit</groupId>
+ <artifactId>junit</artifactId>
+ <version>4.5</version>
+ <scope>test</scope>
+ </dependency>
+
+ </dependencies>
+
+ <build>
+ <finalName>${artifactId}</finalName>
+ <plugins>
+ <plugin>
+ <artifactId>maven-eclipse-plugin</artifactId>
+ <version>2.5.1</version>
+ <configuration>
+ <buildcommands>
+ <buildcommand>org.eclipse.pde.ManifestBuilder</buildcommand>
+ <buildcommand>org.eclipse.jdt.core.javabuilder</buildcommand>
+ </buildcommands>
+ <projectnatures>
+ <projectnature>org.eclipse.jdt.core.javanature</projectnature>
+ <projectnature>org.eclipse.pde.PluginNature</projectnature>
+ </projectnatures>
+ <classpathContainers>
+ <classpathContainer>org.eclipse.jdt.launching.JRE_CONTAINER
+ </classpathContainer>
+ </classpathContainers>
+ </configuration>
+ </plugin>
+
+ <plugin>
+ <artifactId>maven-jar-plugin</artifactId>
+ <configuration>
+ <archive>
+ <manifestFile>${basedir}/META-INF/MANIFEST.MF</manifestFile>
+ </archive>
+ </configuration>
+ </plugin>
+
+ <plugin>
+ <groupId>org.apache.tuscany.maven.plugins</groupId>
+ <artifactId>maven-osgi-junit-plugin</artifactId>
+ <version>1.0-SNAPSHOT</version>
+ <executions>
+ <execution>
+ <id>osgi-test</id>
+ <phase>test</phase>
+ <goals>
+ <goal>test</goal>
+ </goals>
+ <configuration></configuration>
+ </execution>
+ </executions>
+ </plugin>
+ </plugins>
+ </build>
+
+</project>
diff --git a/java/sca/samples/dosgi-dynamic-calculator-operations/src/main/java/calculator/dosgi/operations/AddService.java b/java/sca/samples/dosgi-dynamic-calculator-operations/src/main/java/calculator/dosgi/operations/AddService.java
new file mode 100644
index 0000000000..971500782f
--- /dev/null
+++ b/java/sca/samples/dosgi-dynamic-calculator-operations/src/main/java/calculator/dosgi/operations/AddService.java
@@ -0,0 +1,31 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package calculator.dosgi.operations;
+
+import org.oasisopen.sca.annotation.Remotable;
+
+/**
+ * The interface for the add service
+ */
+@Remotable
+public interface AddService {
+
+ double add(double n1, double n2);
+
+}
diff --git a/java/sca/samples/dosgi-dynamic-calculator-operations/src/main/java/calculator/dosgi/operations/DivideService.java b/java/sca/samples/dosgi-dynamic-calculator-operations/src/main/java/calculator/dosgi/operations/DivideService.java
new file mode 100644
index 0000000000..49b8a1c0bf
--- /dev/null
+++ b/java/sca/samples/dosgi-dynamic-calculator-operations/src/main/java/calculator/dosgi/operations/DivideService.java
@@ -0,0 +1,31 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package calculator.dosgi.operations;
+
+import org.oasisopen.sca.annotation.Remotable;
+
+/**
+ * The interface for the divide service
+ */
+@Remotable
+public interface DivideService {
+
+ double divide(double n1, double n2);
+
+}
diff --git a/java/sca/samples/dosgi-dynamic-calculator-operations/src/main/java/calculator/dosgi/operations/MultiplyService.java b/java/sca/samples/dosgi-dynamic-calculator-operations/src/main/java/calculator/dosgi/operations/MultiplyService.java
new file mode 100644
index 0000000000..f4e59d12ea
--- /dev/null
+++ b/java/sca/samples/dosgi-dynamic-calculator-operations/src/main/java/calculator/dosgi/operations/MultiplyService.java
@@ -0,0 +1,31 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package calculator.dosgi.operations;
+
+import org.oasisopen.sca.annotation.Remotable;
+
+/**
+ * The interface for the multiply service
+ */
+@Remotable
+public interface MultiplyService {
+
+ double multiply(double n1, double n2);
+
+}
diff --git a/java/sca/samples/dosgi-dynamic-calculator-operations/src/main/java/calculator/dosgi/operations/SubtractService.java b/java/sca/samples/dosgi-dynamic-calculator-operations/src/main/java/calculator/dosgi/operations/SubtractService.java
new file mode 100644
index 0000000000..bfb9b820f7
--- /dev/null
+++ b/java/sca/samples/dosgi-dynamic-calculator-operations/src/main/java/calculator/dosgi/operations/SubtractService.java
@@ -0,0 +1,31 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package calculator.dosgi.operations;
+
+import org.oasisopen.sca.annotation.Remotable;
+
+/**
+ * The interface for the subtract service
+ */
+@Remotable
+public interface SubtractService {
+
+ double subtract(double n1, double n2);
+
+}
diff --git a/java/sca/samples/dosgi-dynamic-calculator-operations/src/main/java/calculator/dosgi/operations/impl/AddServiceImpl.java b/java/sca/samples/dosgi-dynamic-calculator-operations/src/main/java/calculator/dosgi/operations/impl/AddServiceImpl.java
new file mode 100644
index 0000000000..66b2977241
--- /dev/null
+++ b/java/sca/samples/dosgi-dynamic-calculator-operations/src/main/java/calculator/dosgi/operations/impl/AddServiceImpl.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 calculator.dosgi.operations.impl;
+
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+import calculator.dosgi.operations.AddService;
+
+/**
+ * An implementation of the Add service
+ */
+public class AddServiceImpl implements AddService {
+
+ public double add(double n1, double n2) {
+ Logger logger = Logger.getLogger("calculator");
+ logger.log(Level.INFO, "Adding " + n1 + " and " + n2);
+ return n1 + n2;
+ }
+
+}
diff --git a/java/sca/samples/dosgi-dynamic-calculator-operations/src/main/java/calculator/dosgi/operations/impl/DivideServiceImpl.java b/java/sca/samples/dosgi-dynamic-calculator-operations/src/main/java/calculator/dosgi/operations/impl/DivideServiceImpl.java
new file mode 100644
index 0000000000..a3c21b2b96
--- /dev/null
+++ b/java/sca/samples/dosgi-dynamic-calculator-operations/src/main/java/calculator/dosgi/operations/impl/DivideServiceImpl.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 calculator.dosgi.operations.impl;
+
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+import calculator.dosgi.operations.DivideService;
+
+/**
+ * An implementation of the Divide service.
+ */
+public class DivideServiceImpl implements DivideService {
+
+ public double divide(double n1, double n2) {
+ Logger logger = Logger.getLogger("calculator");
+ logger.log(Level.INFO, "Dividing " + n1 + " with " + n2);
+ return n1 / n2;
+ }
+
+}
diff --git a/java/sca/samples/dosgi-dynamic-calculator-operations/src/main/java/calculator/dosgi/operations/impl/MultiplyServiceImpl.java b/java/sca/samples/dosgi-dynamic-calculator-operations/src/main/java/calculator/dosgi/operations/impl/MultiplyServiceImpl.java
new file mode 100644
index 0000000000..7922d2d392
--- /dev/null
+++ b/java/sca/samples/dosgi-dynamic-calculator-operations/src/main/java/calculator/dosgi/operations/impl/MultiplyServiceImpl.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 calculator.dosgi.operations.impl;
+
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+import calculator.dosgi.operations.MultiplyService;
+
+/**
+ * An implementation of the Multiply service.
+ */
+public class MultiplyServiceImpl implements MultiplyService {
+
+ public double multiply(double n1, double n2) {
+ Logger logger = Logger.getLogger("calculator");
+ logger.log(Level.INFO, "Multiplying " + n1 + " with " + n2);
+ return n1 * n2;
+ }
+
+}
diff --git a/java/sca/samples/dosgi-dynamic-calculator-operations/src/main/java/calculator/dosgi/operations/impl/OperationsActivator.java b/java/sca/samples/dosgi-dynamic-calculator-operations/src/main/java/calculator/dosgi/operations/impl/OperationsActivator.java
new file mode 100644
index 0000000000..a9d727b7e9
--- /dev/null
+++ b/java/sca/samples/dosgi-dynamic-calculator-operations/src/main/java/calculator/dosgi/operations/impl/OperationsActivator.java
@@ -0,0 +1,94 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package calculator.dosgi.operations.impl;
+
+import java.util.Dictionary;
+import java.util.Hashtable;
+import java.util.logging.Logger;
+
+import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleActivator;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.ServiceReference;
+import org.osgi.service.packageadmin.PackageAdmin;
+
+import calculator.dosgi.operations.AddService;
+import calculator.dosgi.operations.DivideService;
+import calculator.dosgi.operations.MultiplyService;
+import calculator.dosgi.operations.SubtractService;
+
+/**
+ *
+ */
+public class OperationsActivator implements BundleActivator {
+ private Logger logger = Logger.getLogger(OperationsActivator.class.getName());
+
+ public void start(BundleContext context) throws Exception {
+ logger.info("Starting " + context.getBundle());
+
+ Dictionary<String, Object> props = new Hashtable<String, Object>();
+ props.put("service.exported.configs", new String[] {"sca"});
+ props.put("service.exported.interfaces", new String[] {"*"});
+
+ logger.info("Registering " + AddService.class.getName());
+ props.put("sca.service", "AddComponent#service-name(Add)");
+ props.put("sca.bindings", new String[] {"OSGI-INF/sca/add-service.bindings"});
+ context.registerService(AddService.class.getName(), new AddServiceImpl(), props);
+
+ logger.info("Registering " + SubtractService.class.getName());
+ props.put("sca.service", "SubtractComponent#service-name(Subtract)");
+ props.put("sca.bindings", new String[] {"OSGI-INF/sca/subtract-service.bindings"});
+ context.registerService(SubtractService.class.getName(), new SubtractServiceImpl(), props);
+
+ logger.info("Registering " + MultiplyService.class.getName());
+ props.put("sca.service", "MultiplyComponent#service-name(Multiply)");
+ props.put("sca.bindings", new String[] {"OSGI-INF/sca/multiply-service.bindings"});
+ context.registerService(MultiplyService.class.getName(), new MultiplyServiceImpl(), props);
+
+ logger.info("Registering " + DivideService.class.getName());
+ props.put("sca.service", "DivideComponent#service-name(Divide)");
+ props.put("sca.bindings", new String[] {"OSGI-INF/sca/divide-service.bindings"});
+ context.registerService(DivideService.class.getName(), new DivideServiceImpl(), props);
+
+ getBundle(context, AddService.class);
+ }
+
+ public void stop(BundleContext context) throws Exception {
+ logger.info("Stopping " + context.getBundle());
+ // Registered services will be automatically unregistered
+ }
+
+ private Bundle getBundle(BundleContext bundleContext, Class<?> cls) {
+ PackageAdmin packageAdmin = null;
+ // PackageAdmin is used to resolve bundles
+ ServiceReference ref = bundleContext.getServiceReference("org.osgi.service.packageadmin.PackageAdmin");
+ if (ref != null) {
+ packageAdmin = (PackageAdmin)bundleContext.getService(ref);
+ Bundle bundle = packageAdmin.getBundle(cls);
+ if (bundle != null) {
+ logger.info(cls.getName() + " is loaded by bundle: " + bundle.getSymbolicName());
+ }
+ bundleContext.ungetService(ref);
+ return bundle;
+ }
+ return null;
+ }
+
+}
diff --git a/java/sca/samples/dosgi-dynamic-calculator-operations/src/main/java/calculator/dosgi/operations/impl/SubtractServiceImpl.java b/java/sca/samples/dosgi-dynamic-calculator-operations/src/main/java/calculator/dosgi/operations/impl/SubtractServiceImpl.java
new file mode 100644
index 0000000000..4bbe83b14f
--- /dev/null
+++ b/java/sca/samples/dosgi-dynamic-calculator-operations/src/main/java/calculator/dosgi/operations/impl/SubtractServiceImpl.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 calculator.dosgi.operations.impl;
+
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+import calculator.dosgi.operations.SubtractService;
+
+/**
+ * An implementation of the subtract service.
+ */
+public class SubtractServiceImpl implements SubtractService {
+
+ public double subtract(double n1, double n2) {
+ Logger logger = Logger.getLogger("calculator");
+ logger.log(Level.INFO, "Subtracting " + n1 + " from " + n2);
+ return n1 - n2;
+ }
+
+}
diff --git a/java/sca/samples/dosgi-dynamic-calculator-operations/src/test/java/calculator/dosgi/operations/test/OSGiTestUtils.java b/java/sca/samples/dosgi-dynamic-calculator-operations/src/test/java/calculator/dosgi/operations/test/OSGiTestUtils.java
new file mode 100644
index 0000000000..cd92989da1
--- /dev/null
+++ b/java/sca/samples/dosgi-dynamic-calculator-operations/src/test/java/calculator/dosgi/operations/test/OSGiTestUtils.java
@@ -0,0 +1,105 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package calculator.dosgi.operations.test;
+
+import java.lang.reflect.InvocationHandler;
+import java.lang.reflect.Method;
+import java.lang.reflect.Proxy;
+
+import org.osgi.framework.Bundle;
+
+/**
+ *
+ * Utility class to create OSGi bundles
+ *
+ * @version $Rev$ $Date$
+ */
+public class OSGiTestUtils {
+ private static class InvocationHandlerImpl implements InvocationHandler {
+ private Object instance;
+
+ public InvocationHandlerImpl(Object instance) {
+ super();
+ this.instance = instance;
+ }
+
+ public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
+ Method m = instance.getClass().getMethod(method.getName(), method.getParameterTypes());
+ return m.invoke(instance, args);
+ }
+
+ }
+
+ /**
+ * Returns a string representation of the given bundle.
+ *
+ * @param b
+ * @param verbose
+ * @return
+ */
+ public static String bundleStatus(Bundle bundle, boolean verbose) {
+ StringBuffer sb = new StringBuffer();
+ sb.append(bundle.getBundleId()).append(" ").append(bundle.getSymbolicName());
+ int s = bundle.getState();
+ if ((s & Bundle.UNINSTALLED) != 0) {
+ sb.append(" UNINSTALLED");
+ }
+ if ((s & Bundle.INSTALLED) != 0) {
+ sb.append(" INSTALLED");
+ }
+ if ((s & Bundle.RESOLVED) != 0) {
+ sb.append(" RESOLVED");
+ }
+ if ((s & Bundle.STARTING) != 0) {
+ sb.append(" STARTING");
+ }
+ if ((s & Bundle.STOPPING) != 0) {
+ sb.append(" STOPPING");
+ }
+ if ((s & Bundle.ACTIVE) != 0) {
+ sb.append(" ACTIVE");
+ }
+
+ if (verbose) {
+ sb.append(" ").append(bundle.getLocation());
+ sb.append(" ").append(bundle.getHeaders());
+ }
+ return sb.toString();
+ }
+
+ /**
+ * A utility to cast the object to the given interface. If the class for the object
+ * is loaded by a different classloader, a proxy will be created.
+ *
+ * @param <T>
+ * @param obj
+ * @param cls
+ * @return
+ */
+ public static <T> T cast(Object obj, Class<T> cls) {
+ if (cls.isInstance(obj)) {
+ return cls.cast(obj);
+ } else {
+ return cls.cast(Proxy.newProxyInstance(cls.getClassLoader(),
+ new Class<?>[] {cls},
+ new InvocationHandlerImpl(obj)));
+ }
+ }
+}
diff --git a/java/sca/samples/dosgi-dynamic-calculator-operations/src/test/java/calculator/dosgi/operations/test/OperationsNode.java b/java/sca/samples/dosgi-dynamic-calculator-operations/src/test/java/calculator/dosgi/operations/test/OperationsNode.java
new file mode 100644
index 0000000000..02007c385c
--- /dev/null
+++ b/java/sca/samples/dosgi-dynamic-calculator-operations/src/test/java/calculator/dosgi/operations/test/OperationsNode.java
@@ -0,0 +1,43 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package calculator.dosgi.operations.test;
+
+import org.apache.tuscany.sca.node.equinox.launcher.NodeLauncher;
+
+/**
+ *
+ */
+public class OperationsNode {
+
+ /**
+ * @param args
+ */
+ public static void main(String[] args) {
+ if (args.length == 0) {
+ args = new String[] {"-bundles"};
+ }
+ try {
+ NodeLauncher.main(args);
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+
+}
diff --git a/java/sca/samples/dosgi-dynamic-calculator-operations/src/test/java/calculator/dosgi/operations/test/OperationsOSGiNodeTestCase.java b/java/sca/samples/dosgi-dynamic-calculator-operations/src/test/java/calculator/dosgi/operations/test/OperationsOSGiNodeTestCase.java
new file mode 100644
index 0000000000..eee64bf86f
--- /dev/null
+++ b/java/sca/samples/dosgi-dynamic-calculator-operations/src/test/java/calculator/dosgi/operations/test/OperationsOSGiNodeTestCase.java
@@ -0,0 +1,104 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package calculator.dosgi.operations.test;
+
+import static calculator.dosgi.operations.test.OSGiTestUtils.bundleStatus;
+
+import java.rmi.registry.LocateRegistry;
+import java.rmi.registry.Registry;
+
+import org.apache.tuscany.sca.node.equinox.launcher.EquinoxHost;
+import org.junit.AfterClass;
+import org.junit.Assert;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.Constants;
+
+import calculator.dosgi.operations.AddService;
+
+/**
+ *
+ */
+public class OperationsOSGiNodeTestCase {
+ private static EquinoxHost host;
+ private static BundleContext context;
+ private static Bundle operationsBundle;
+
+ /**
+ * @throws java.lang.Exception
+ */
+ @BeforeClass
+ public static void setUpBeforeClass() throws Exception {
+ try {
+ host = new EquinoxHost();
+ context = host.start();
+
+ for (Bundle b : context.getBundles()) {
+ if (b.getSymbolicName().equals("org.eclipse.equinox.ds") || b.getSymbolicName()
+ .startsWith("org.apache.tuscany.sca.")) {
+ try {
+ if (b.getHeaders().get(Constants.FRAGMENT_HOST) == null) {
+ // Start the non-fragment bundle
+ b.start();
+ }
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ System.out.println(bundleStatus(b, false));
+ }
+ if ("calculator.dosgi.dynamic.operations".equals(b.getSymbolicName())) {
+ operationsBundle = b;
+ }
+ }
+
+ if (operationsBundle != null) {
+ operationsBundle.start();
+ System.out.println(bundleStatus(operationsBundle, false));
+ }
+
+ } catch (Exception e) {
+ e.printStackTrace();
+ throw e;
+ }
+ }
+
+ @Test
+ public void testOSGi() throws Exception {
+ Registry registry = LocateRegistry.getRegistry(8085);
+ Object add = registry.lookup("AddService");
+ AddService addService = OSGiTestUtils.cast(add, AddService.class);
+ double sum = addService.add(1.0, 2.0);
+ Assert.assertEquals(3.0, sum, 0.0);
+ }
+
+ /**
+ * @throws java.lang.Exception
+ */
+ @AfterClass
+ public static void tearDownAfterClass() throws Exception {
+ if (host != null) {
+ host.stop();
+ context = null;
+ }
+ }
+
+}
diff --git a/java/sca/samples/dosgi-dynamic-calculator/LICENSE b/java/sca/samples/dosgi-dynamic-calculator/LICENSE
new file mode 100644
index 0000000000..6e529a25c4
--- /dev/null
+++ b/java/sca/samples/dosgi-dynamic-calculator/LICENSE
@@ -0,0 +1,205 @@
+
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+ 1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+ 2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+ 3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+ 4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+ 6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+ 7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+ 8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+ 9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+ END OF TERMS AND CONDITIONS
+
+ APPENDIX: How to apply the Apache License to your work.
+
+ To apply the Apache License to your work, attach the following
+ boilerplate notice, with the fields enclosed by brackets "[]"
+ replaced with your own identifying information. (Don't include
+ the brackets!) The text should be enclosed in the appropriate
+ comment syntax for the file format. We also recommend that a
+ file or class name and description of purpose be included on the
+ same "printed page" as the copyright notice for easier
+ identification within third-party archives.
+
+ Copyright [yyyy] [name of copyright owner]
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+
+
diff --git a/java/sca/samples/dosgi-dynamic-calculator/META-INF/MANIFEST.MF b/java/sca/samples/dosgi-dynamic-calculator/META-INF/MANIFEST.MF
new file mode 100644
index 0000000000..f943dae97a
--- /dev/null
+++ b/java/sca/samples/dosgi-dynamic-calculator/META-INF/MANIFEST.MF
@@ -0,0 +1,20 @@
+Manifest-Version: 1.0
+Export-Package: calculator.dosgi;version="1.0.1",
+ calculator.dosgi.operations;version="1.0.1"
+Bundle-Version: 1.0.0
+Bundle-Name: calculator.dosgi.dynamic
+Bundle-Activator: calculator.dosgi.impl.CalculatorActivator
+Bundle-ManifestVersion: 2
+Import-Package: org.oasisopen.sca.annotation;version="2.0.0",
+ org.osgi.framework,
+ org.osgi.service.component;resolution:=optional,
+ org.osgi.service.packageadmin,
+ org.osgi.util.tracker
+Bundle-SymbolicName: calculator.dosgi.dynamic
+Bundle-Vendor: The Apache Software Foundation
+Bundle-ActivationPolicy: lazy
+Eclipse-LazyStart: true
+Bundle-License: http://www.apache.org/licenses/LICENSE-2.0.txt
+Bundle-DocURL: http://www.apache.org/
+Service-Component: OSGI-INF/calculator-component.xml
+Bundle-RequiredExecutionEnvironment: J2SE-1.5,JavaSE-1.6
diff --git a/java/sca/samples/dosgi-dynamic-calculator/NOTICE b/java/sca/samples/dosgi-dynamic-calculator/NOTICE
new file mode 100644
index 0000000000..51042eab05
--- /dev/null
+++ b/java/sca/samples/dosgi-dynamic-calculator/NOTICE
@@ -0,0 +1,6 @@
+${pom.name}
+Copyright (c) 2005 - 2009 The Apache Software Foundation
+
+This product includes software developed by
+The Apache Software Foundation (http://www.apache.org/).
+
diff --git a/java/sca/samples/dosgi-dynamic-calculator/OSGI-INF/blueprint/calculator-module.xml b/java/sca/samples/dosgi-dynamic-calculator/OSGI-INF/blueprint/calculator-module.xml
new file mode 100644
index 0000000000..fd834e12ef
--- /dev/null
+++ b/java/sca/samples/dosgi-dynamic-calculator/OSGI-INF/blueprint/calculator-module.xml
@@ -0,0 +1,43 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+-->
+<!-- A sample module-context.xml for OSGI RFC 124 (BluePrint Service) -->
+<components xmlns="http://www.osgi.org/xmlns/blueprint/v1.0.0">
+ <component id="CalculatorComponent" class="calculator.dosgi.impl.CalculatorServiceImpl">
+ <property name="addService" ref="AddService" />
+ <property name="subtractService" ref="SubtractService" />
+ <property name="multiplyService" ref="MultiplyService" />
+ <property name="divideService" ref="DivideService" />
+ </component>
+
+ <!-- We can derive the SCA services for the implementation.osgi -->
+ <service id="CalculatorService" ref="CalculatorComponent" interface="calculator.dosgi.CalculatorService">
+ </service>
+
+ <!-- We can derive the SCA references for the implementation.osgi -->
+ <reference id="AddService" interface="calculator.dosgi.operations.AddService">
+ </reference>
+ <reference id="SubtractService" interface="calculator.dosgi.operations.SubtractService">
+ </reference>
+ <reference id="MultiplyService" interface="calculator.dosgi.operations.MultiplyService">
+ </reference>
+ <reference id="DivideService" interface="calculator.dosgi.operations.DivideService">
+ </reference>
+
+</components> \ No newline at end of file
diff --git a/java/sca/samples/dosgi-dynamic-calculator/OSGI-INF/calculator-component.xml b/java/sca/samples/dosgi-dynamic-calculator/OSGI-INF/calculator-component.xml
new file mode 100644
index 0000000000..5daaa59aae
--- /dev/null
+++ b/java/sca/samples/dosgi-dynamic-calculator/OSGI-INF/calculator-component.xml
@@ -0,0 +1,36 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+-->
+<scr:component name="CalculatorComponent"
+ xmlns:scr="http://www.osgi.org/xmlns/scr/v1.0.0">
+ <implementation class="calculator.dosgi.impl.CalculatorServiceDSImpl" />
+ <service>
+ <provide interface="calculator.dosgi.CalculatorService" />
+ </service>
+
+ <reference name="addService" interface="calculator.dosgi.operations.AddService" bind="setAddService" unbind="unsetAddService"
+ policy="dynamic" />
+ <reference name="subtractService" interface="calculator.dosgi.operations.SubtractService" bind="setSubtractService"
+ unbind="unsetSubtractService" policy="dynamic" />
+ <reference name="multiplyService" interface="calculator.dosgi.operations.MultiplyService" bind="setMultiplyService"
+ unbind="unsetMultiplyService" policy="dynamic" />
+ <reference name="divideService" interface="calculator.dosgi.operations.DivideService" bind="setDivideService"
+ unbind="unsetDivideService" policy="dynamic" />
+
+</scr:component>
diff --git a/java/sca/samples/dosgi-calculator/OSGI-INF/remote-service/calculator-service-descriptions.xml b/java/sca/samples/dosgi-dynamic-calculator/OSGI-INF/remote-service/calculator-service-descriptions.xml
index da76d00024..53e83bf72c 100644
--- a/java/sca/samples/dosgi-calculator/OSGI-INF/remote-service/calculator-service-descriptions.xml
+++ b/java/sca/samples/dosgi-dynamic-calculator/OSGI-INF/remote-service/calculator-service-descriptions.xml
@@ -18,50 +18,64 @@
* under the License.
-->
<!-- A consumer-side service description file for RFC 119 -->
-<service-descriptions xmlns="http://www.osgi.org/xmlns/sd/v1.0.0" xmlns:sca="http://docs.oasis-open.org/ns/opencsa/sca/200903">
+<service-descriptions xmlns="http://www.osgi.org/xmlns/sd/v1.0.0"
+ xmlns:sca="http://docs.oasis-open.org/ns/opencsa/sca/200903"
+ xmlns:tuscany="http://tuscany.apache.org/xmlns/sca/1.1">
<!-- Describe a remote OSGi service -->
<service-description>
<provide interface="calculator.dosgi.operations.AddService" />
- <property name="service.intents">sca:SOAP sca:HTTP</property>
- <property name="osgi.remote.configuration.type">sca</property>
- <property name="osgi.remote.configuration.sca.componentType">
+ <property name="service.exported.intents">sca:SOAP sca:HTTP</property>
+ <property name="service.exported.configs">sca</property>
+ <property name="sca.componentType">
OSGI-INF/sca/bundle.componentType
</property>
- <property name="osgi.remote.configuration.sca.reference">
+ <property name="sca.reference">
addService
</property>
+ <bindings>
+ <tuscany:binding.rmi uri="rmi://localhost:8085/AddService" />
+ </bindings>
</service-description>
<service-description>
<provide interface="calculator.dosgi.operations.SubtractService" />
- <property name="service.intents">sca:SOAP sca:HTTP</property>
- <property name="osgi.remote.configuration.type">sca</property>
- <property name="osgi.remote.configuration.sca.componentType">
+ <property name="service.exported.intents">sca:SOAP sca:HTTP</property>
+ <property name="service.exported.configs">sca</property>
+ <property name="sca.componentType">
OSGI-INF/sca/bundle.componentType
</property>
- <property name="osgi.remote.configuration.sca.reference">
+ <property name="sca.reference">
subtractService
</property>
+ <bindings>
+ <tuscany:binding.rmi uri="rmi://localhost:8085/SubtractService" />
+ </bindings>
</service-description>
<service-description>
<provide interface="calculator.dosgi.operations.MultiplyService" />
- <property name="service.intents">sca:SOAP sca:HTTP</property>
- <property name="osgi.remote.configuration.type">sca</property>
- <property name="osgi.remote.configuration.sca.componentType">
+ <property name="service.exported.intents">sca:SOAP sca:HTTP</property>
+ <property name="service.exported.configs">sca</property>
+ <property name="sca.componentType">
OSGI-INF/sca/bundle.componentType
</property>
- <property name="osgi.remote.configuration.sca.reference">
+ <property name="sca.reference">
multiplyService
</property>
+ <bindings>
+ <tuscany:binding.rmi uri="rmi://localhost:8085/MultiplyService" />
+ </bindings>
</service-description>
<service-description>
<provide interface="calculator.dosgi.operations.DivideService" />
- <property name="service.intents">sca:SOAP sca:HTTP</property>
- <property name="osgi.remote.configuration.type">sca</property>
- <property name="osgi.remote.configuration.sca.componentType">
+ <property name="service.exported.intents">sca:SOAP sca:HTTP</property>
+ <property name="service.exported.configs">sca</property>
+ <property name="sca.componentType">
OSGI-INF/sca/bundle.componentType
</property>
- <property name="osgi.remote.configuration.sca.reference">
+ <property name="sca.reference">
divideService
</property>
+ <bindings>
+ <tuscany:binding.rmi uri="rmi://localhost:8085/DivideService" />
+ </bindings>
</service-description>
</service-descriptions> \ No newline at end of file
diff --git a/java/sca/samples/dosgi-dynamic-calculator/OSGI-INF/sca/calculator-service.bindings b/java/sca/samples/dosgi-dynamic-calculator/OSGI-INF/sca/calculator-service.bindings
new file mode 100644
index 0000000000..90e55f7377
--- /dev/null
+++ b/java/sca/samples/dosgi-dynamic-calculator/OSGI-INF/sca/calculator-service.bindings
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License. You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied. See the License for the
+* specific language governing permissions and limitations
+* under the License.
+-->
+<!-- SCA bindings for calculator service -->
+<bindings xmlns="http://www.osgi.org/xmlns/sd/v1.0.0"
+ xmlns:sca="http://docs.oasis-open.org/ns/opencsa/sca/200903">
+ <sca:binding.ws uri="http://localhost:8086/CalculatorService"/>
+</bindings> \ No newline at end of file
diff --git a/java/sca/samples/dosgi-dynamic-calculator/README b/java/sca/samples/dosgi-dynamic-calculator/README
new file mode 100644
index 0000000000..374c0f0a8b
--- /dev/null
+++ b/java/sca/samples/dosgi-dynamic-calculator/README
@@ -0,0 +1,155 @@
+Distributed OSGi Calculator Sample
+==================================
+This sample implements a distributed calculator using Distributed OSGi (RFC 119) over SCA.
+
+The README in the samples directory (the directory above this) provides
+general instructions about building and running samples. Take a look there
+first.
+
+On Windows, run
+java -jar ..\..\modules\osgi-3.4.0-v20080605-1900.jar -configuration ..\..\features\configuration -clean -console
+
+On *Unix, run
+java -jar ../../modules/osgi-3.4.0-v20080605-1900.jar -configuration ../../features/configuration -clean -console
+
+You should see the osgi console:
+
+osgi>
+
+osgi> Jun 22, 2009 1:32:27 PM org.apache.tuscany.sca.extensibility.equinox.EquinoxServiceDiscoveryActivator start
+INFO: Equinox-based service discoverer is now configured.
+
+You can run "ss" command under the osgi> to see the status of the bundles.
+osgi> ss
+
+Then you can install and start the calculator.dosgi bundle:
+
+osgi> install file:./target/sample-dosgi-calculator.jar
+Bundle id is 181
+
+osgi> start 181
+Jun 22, 2009 1:37:21 PM calculator.dosgi.impl.CalculatorActivator start
+INFO: Starting file:./target/sample-dosgi-calculator.jar [181]
+Jun 22, 2009 1:37:21 PM calculator.dosgi.impl.CalculatorActivator start
+INFO: Registering calculator.dosgi.CalculatorService
+Jun 22, 2009 1:37:21 PM calculator.dosgi.impl.CalculatorActivator getBundle
+INFO: calculator.dosgi.operations.AddService is loaded by bundle: calculator.dos
+gi
+Jun 22, 2009 1:37:21 PM org.apache.tuscany.sca.node.impl.NodeImpl start
+INFO: Starting node: calculator.dosgi
+Jun 22, 2009 1:37:21 PM org.apache.tuscany.sca.node.impl.NodeFactoryImpl configu
+reNode
+INFO: Loading contribution: bundleentry://181/
+Jun 22, 2009 1:37:21 PM org.apache.tuscany.sca.endpoint.tribes.ReplicatedEndpoin
+tRegistry addEndpoint
+INFO: EndpointRegistry: Add endpoint - Endpoint: URI = CalculatorComponent#serv
+ice-binding(CalculatorService/CalculatorService)
+2009-06-22 13:37:21.953::INFO: jetty-6.1.x
+2009-06-22 13:37:21.953::INFO: Started SelectChannelConnector@0.0.0.0:8086
+Jun 22, 2009 1:37:21 PM org.apache.tuscany.sca.http.jetty.JettyServer addServlet
+Mapping
+INFO: Added Servlet mapping: http://rfengt61p:8086/CalculatorService
+Jun 22, 2009 1:37:21 PM org.apache.tuscany.sca.endpoint.tribes.ReplicatedEndpoin
+tRegistry addEndpointReference
+INFO: EndpointRegistry: Add endpoint reference - Endpoint Reference: URI = Calc
+ulatorComponent#reference-binding(addService/addService) Target = Endpoint:
+Jun 22, 2009 1:37:21 PM org.apache.tuscany.sca.endpoint.tribes.ReplicatedEndpoin
+tRegistry addEndpointReference
+INFO: EndpointRegistry: Add endpoint reference - Endpoint Reference: URI = Calc
+ulatorComponent#reference-binding(subtractService/subtractService) Target = Endp
+oint:
+Jun 22, 2009 1:37:21 PM org.apache.tuscany.sca.endpoint.tribes.ReplicatedEndpoin
+tRegistry addEndpointReference
+INFO: EndpointRegistry: Add endpoint reference - Endpoint Reference: URI = Calc
+ulatorComponent#reference-binding(multiplyService/multiplyService) Target = Endp
+oint:
+Jun 22, 2009 1:37:21 PM org.apache.tuscany.sca.endpoint.tribes.ReplicatedEndpoin
+tRegistry addEndpointReference
+INFO: EndpointRegistry: Add endpoint reference - Endpoint Reference: URI = Calc
+ulatorComponent#reference-binding(divideService/divideService) Target = Endpoint
+:
+
+osgi>
+
+You can point your browser to http://localhost:8086/CalculatorService?wsdl to see
+the WSDL.
+
+You can also use the WebService Explorer from Eclipse WTP to test the Web Service.
+
+To stop the bundle:
+
+osgi> stop 181
+Jun 22, 2009 1:39:09 PM org.apache.tuscany.sca.node.impl.NodeImpl stop
+INFO: Stopping node: calculator.dosgi
+Jun 22, 2009 1:39:09 PM org.apache.tuscany.sca.endpoint.tribes.ReplicatedEndpoin
+tRegistry removeEndpoint
+INFO: EndpointRegistry: Remove endpoint - Endpoint: URI = CalculatorComponent#s
+ervice-binding(CalculatorService/CalculatorService)
+Jun 22, 2009 1:39:09 PM org.apache.tuscany.sca.http.jetty.JettyServer removeServ
+letMapping
+INFO: Removed Servlet mapping: /CalculatorService
+Jun 22, 2009 1:39:09 PM calculator.dosgi.impl.CalculatorActivator stop
+INFO: Stopping file:./target/sample-dosgi-calculator.jar [181]
+
+To exit the console, run:
+osgi> exit
+
+Sample Overview
+---------------
+The application consists of two OSGi bundles:
+ * The calculator bundle: It provides the calculator service. The service is implemented by a java class that
+ consumes other services to perform the “add”, “subtract”, “multiply” and “divide” operations.
+ * The operations bundle: It provides the add/subtract/multiply/divide services.
+ (See ../samples/dosgi-calculator-operations)
+
+
+dosgi-calculator/
+ src/
+ main/
+ java/
+ calculator/
+ dosgi/
+ CalculatorService.java - The interface for Calculator service
+ impl/
+ CalculatorActivator.java - OSGi bundle activator for Calculator bundle
+ CalculatorServiceDSImpl.java - OSGi declarative service based implementation
+ CalculatorServiceImpl.java - Basic OSGi implementation
+ operations/
+ AddService.java - Interface for Add
+ SubtractService.java - Interface for Subtract
+ MultiplyService.java - Interface for Multiply
+ DivideService.java - Interface for Divide
+ rmi/
+ OperationsRemote.java - RMI remote interface for operations
+ OperationsRMIServer_Stub.java - RMI stub
+ OperationsRMIServer.java - RMI server implementation of the operations
+ resources/
+ META-INF/
+ sca-contribution.xml
+ OSGI-INF/
+ sca/
+ bundle.componentType - The component type for implementation.osgi of this bundle
+ bundle.composite - The composite file
+ test/
+ java/
+ src/
+ calculator/
+ dosgi/
+ test/
+ CalculatorOSGiNodeTestCase.java - The JUNIT test case that tests this bundle against a RMI service
+
+ META-INF/
+ MANIFEST.MF - The OSGi manifest for this bundle
+ dosig-calculator.png - a pictorial representation of the sample
+ pom.xml - the Maven build file
+
+
+
+Building And Running The Test Case Using Maven
+-------------------------------------------
+With either the binary or source distributions the sample can be built and run
+using Maven as follows.
+
+cd dosgi-calculator
+mvn
+
diff --git a/java/sca/samples/dosgi-dynamic-calculator/dosgi-calculator.png b/java/sca/samples/dosgi-dynamic-calculator/dosgi-calculator.png
new file mode 100644
index 0000000000..805baa54d2
--- /dev/null
+++ b/java/sca/samples/dosgi-dynamic-calculator/dosgi-calculator.png
Binary files differ
diff --git a/java/sca/samples/dosgi-dynamic-calculator/pom.xml b/java/sca/samples/dosgi-dynamic-calculator/pom.xml
new file mode 100644
index 0000000000..3151c7fef6
--- /dev/null
+++ b/java/sca/samples/dosgi-dynamic-calculator/pom.xml
@@ -0,0 +1,139 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+-->
+<project>
+ <modelVersion>4.0.0</modelVersion>
+ <parent>
+ <groupId>org.apache.tuscany.sca</groupId>
+ <artifactId>tuscany-sca</artifactId>
+ <version>2.0-SNAPSHOT</version>
+ <relativePath>../../pom.xml</relativePath>
+ </parent>
+
+ <artifactId>sample-dosgi-dynamic-calculator</artifactId>
+ <name>Apache Tuscany SCA OSGi RemoteService Dynamic Caculator Sample</name>
+
+ <dependencies>
+ <dependency>
+ <groupId>org.apache.tuscany.sca</groupId>
+ <artifactId>tuscany-feature-ejava</artifactId>
+ <version>2.0-SNAPSHOT</version>
+ <type>pom</type>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.tuscany.sca</groupId>
+ <artifactId>tuscany-feature-webservice</artifactId>
+ <version>2.0-SNAPSHOT</version>
+ <type>pom</type>
+ <scope>runtime</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.tuscany.sca</groupId>
+ <artifactId>tuscany-node-launcher-equinox</artifactId>
+ <version>2.0-SNAPSHOT</version>
+ <scope>test</scope>
+ </dependency>
+
+ <dependency>
+ <groupId>org.apache.tuscany.sca</groupId>
+ <artifactId>tuscany-node-impl-osgi</artifactId>
+ <version>2.0-SNAPSHOT</version>
+ <scope>runtime</scope>
+ </dependency>
+
+ <dependency>
+ <groupId>org.eclipse.osgi</groupId>
+ <artifactId>services</artifactId>
+ <version>3.2.0-v20090520-1800</version>
+ </dependency>
+
+ <dependency>
+ <groupId>junit</groupId>
+ <artifactId>junit</artifactId>
+ <version>4.5</version>
+ <scope>test</scope>
+ </dependency>
+
+ <!-- Equinox Declarative Services -->
+ <dependency>
+ <groupId>org.eclipse.equinox</groupId>
+ <artifactId>ds</artifactId>
+ <version>1.1.0-v20090601</version>
+ <scope>test</scope>
+ </dependency>
+
+ <dependency>
+ <groupId>org.eclipse.equinox</groupId>
+ <artifactId>util</artifactId>
+ <version>1.0.100-v20090520-1800</version>
+ <scope>test</scope>
+ </dependency>
+
+ </dependencies>
+
+ <build>
+ <finalName>${artifactId}</finalName>
+ <plugins>
+ <plugin>
+ <artifactId>maven-eclipse-plugin</artifactId>
+ <version>2.5.1</version>
+ <configuration>
+ <buildcommands>
+ <buildcommand>org.eclipse.pde.ManifestBuilder</buildcommand>
+ <buildcommand>org.eclipse.jdt.core.javabuilder</buildcommand>
+ </buildcommands>
+ <projectnatures>
+ <projectnature>org.eclipse.jdt.core.javanature</projectnature>
+ <projectnature>org.eclipse.pde.PluginNature</projectnature>
+ </projectnatures>
+ <classpathContainers>
+ <classpathContainer>org.eclipse.jdt.launching.JRE_CONTAINER
+ </classpathContainer>
+ </classpathContainers>
+ </configuration>
+ </plugin>
+
+ <plugin>
+ <artifactId>maven-jar-plugin</artifactId>
+ <configuration>
+ <archive>
+ <manifestFile>${basedir}/META-INF/MANIFEST.MF</manifestFile>
+ </archive>
+ </configuration>
+ </plugin>
+
+ <plugin>
+ <groupId>org.apache.tuscany.maven.plugins</groupId>
+ <artifactId>maven-osgi-junit-plugin</artifactId>
+ <version>1.0-SNAPSHOT</version>
+ <executions>
+ <execution>
+ <id>osgi-test</id>
+ <phase>test</phase>
+ <goals>
+ <goal>test</goal>
+ </goals>
+ <configuration></configuration>
+ </execution>
+ </executions>
+ </plugin>
+ </plugins>
+ </build>
+
+</project>
diff --git a/java/sca/samples/dosgi-dynamic-calculator/src/main/java/calculator/dosgi/CalculatorService.java b/java/sca/samples/dosgi-dynamic-calculator/src/main/java/calculator/dosgi/CalculatorService.java
new file mode 100644
index 0000000000..cc562b7c2f
--- /dev/null
+++ b/java/sca/samples/dosgi-dynamic-calculator/src/main/java/calculator/dosgi/CalculatorService.java
@@ -0,0 +1,36 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package calculator.dosgi;
+
+import org.oasisopen.sca.annotation.Remotable;
+
+/**
+ * The Calculator service interface.
+ */
+@Remotable
+public interface CalculatorService {
+
+ double add(double n1, double n2);
+
+ double subtract(double n1, double n2);
+
+ double multiply(double n1, double n2);
+
+ double divide(double n1, double n2);
+}
diff --git a/java/sca/samples/dosgi-dynamic-calculator/src/main/java/calculator/dosgi/impl/CalculatorActivator.java b/java/sca/samples/dosgi-dynamic-calculator/src/main/java/calculator/dosgi/impl/CalculatorActivator.java
new file mode 100644
index 0000000000..40388144ee
--- /dev/null
+++ b/java/sca/samples/dosgi-dynamic-calculator/src/main/java/calculator/dosgi/impl/CalculatorActivator.java
@@ -0,0 +1,78 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT 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 calculator.dosgi.impl;
+
+import java.util.Dictionary;
+import java.util.Hashtable;
+import java.util.logging.Logger;
+
+import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleActivator;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.ServiceReference;
+import org.osgi.service.packageadmin.PackageAdmin;
+
+import calculator.dosgi.CalculatorService;
+import calculator.dosgi.operations.AddService;
+
+/**
+ *
+ */
+public class CalculatorActivator implements BundleActivator {
+ private Logger logger = Logger.getLogger(CalculatorActivator.class.getName());
+
+ private Bundle getBundle(BundleContext bundleContext, Class<?> cls) {
+ PackageAdmin packageAdmin = null;
+ // PackageAdmin is used to resolve bundles
+ ServiceReference ref = bundleContext.getServiceReference("org.osgi.service.packageadmin.PackageAdmin");
+ if (ref != null) {
+ packageAdmin = (PackageAdmin)bundleContext.getService(ref);
+ Bundle bundle = packageAdmin.getBundle(cls);
+ if (bundle != null) {
+ logger.info(cls.getName() + " is loaded by bundle: " + bundle.getSymbolicName());
+ }
+ bundleContext.ungetService(ref);
+ return bundle;
+ }
+ return null;
+ }
+
+ public void start(BundleContext context) throws Exception {
+ logger.info("Starting " + context.getBundle());
+ Dictionary<String, Object> props = new Hashtable<String, Object>();
+ props.put("sca.service", "CalculatorComponent#service-name(Calculator)");
+ props.put("calculator", "Calculator");
+ props.put("service.exported.configs", new String[] {"sca"});
+ props.put("sca.bindings", new String[] {"OSGI-INF/sca/calculator-service.bindings"});
+ props.put("service.exported.interfaces", new String[] {"*"});
+ logger.info("Registering " + CalculatorService.class.getName());
+ CalculatorService calculator = new CalculatorServiceImpl(context);
+ context.registerService(CalculatorService.class.getName(), calculator, props);
+
+ getBundle(context, AddService.class);
+
+ }
+
+ public void stop(BundleContext context) throws Exception {
+ logger.info("Stopping " + context.getBundle());
+ // Registered services will be automatically unregistered
+ }
+
+}
diff --git a/java/sca/samples/dosgi-dynamic-calculator/src/main/java/calculator/dosgi/impl/CalculatorServiceDSImpl.java b/java/sca/samples/dosgi-dynamic-calculator/src/main/java/calculator/dosgi/impl/CalculatorServiceDSImpl.java
new file mode 100644
index 0000000000..5f9db16ca9
--- /dev/null
+++ b/java/sca/samples/dosgi-dynamic-calculator/src/main/java/calculator/dosgi/impl/CalculatorServiceDSImpl.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 calculator.dosgi.impl;
+
+import org.osgi.service.component.ComponentContext;
+
+import calculator.dosgi.CalculatorService;
+import calculator.dosgi.operations.AddService;
+import calculator.dosgi.operations.DivideService;
+import calculator.dosgi.operations.MultiplyService;
+import calculator.dosgi.operations.SubtractService;
+
+/**
+ * An implementation of the Calculator service.
+ */
+public class CalculatorServiceDSImpl implements CalculatorService {
+ private AddService addService;
+ private SubtractService subtractService;
+ private MultiplyService multiplyService;
+ private DivideService divideService;
+
+ public CalculatorServiceDSImpl() {
+ super();
+ System.out.println("CalculatorServiceDSImpl()");
+ }
+
+ protected void activate(ComponentContext context) {
+ System.out.println("Activating " + context);
+ }
+
+ protected void deactivate(ComponentContext context) {
+ System.out.println("Deactivating " + context);
+ }
+
+ /*
+ * The following setters can be used for DS injection
+ */
+ public void setAddService(AddService addService) {
+ System.out.println("setAddService()");
+ this.addService = addService;
+ }
+
+ public void setSubtractService(SubtractService subtractService) {
+ this.subtractService = subtractService;
+ }
+
+ public void setDivideService(DivideService divideService) {
+ this.divideService = divideService;
+ }
+
+ public void setMultiplyService(MultiplyService multiplyService) {
+ this.multiplyService = multiplyService;
+ }
+
+ /*
+ * The following setters can be used for DS injection
+ */
+ public void unsetAddService(AddService addService) {
+ System.out.println("unsetAddService()");
+ this.addService = null;
+ }
+
+ public void unsetSubtractService(SubtractService subtractService) {
+ this.subtractService = null;
+ }
+
+ public void unsetDivideService(DivideService divideService) {
+ this.divideService = null;
+ }
+
+ public void unsetMultiplyService(MultiplyService multiplyService) {
+ this.multiplyService = null;
+ }
+ private <T> T getService(Class<T> cls) {
+ for (Object s : new Object[] {addService, subtractService, multiplyService, divideService}) {
+ if (cls.isInstance(s)) {
+ return cls.cast(s);
+ }
+ }
+ throw new IllegalStateException(cls.getSimpleName() + " is not available");
+ }
+
+ public double add(double n1, double n2) {
+ return getService(AddService.class).add(n1, n2);
+ }
+
+ public double subtract(double n1, double n2) {
+ return getService(SubtractService.class).subtract(n1, n2);
+ }
+
+ public double multiply(double n1, double n2) {
+ return getService(MultiplyService.class).multiply(n1, n2);
+ }
+
+ public double divide(double n1, double n2) {
+ return getService(DivideService.class).divide(n1, n2);
+ }
+}
diff --git a/java/sca/samples/dosgi-dynamic-calculator/src/main/java/calculator/dosgi/impl/CalculatorServiceImpl.java b/java/sca/samples/dosgi-dynamic-calculator/src/main/java/calculator/dosgi/impl/CalculatorServiceImpl.java
new file mode 100644
index 0000000000..a9ea37585a
--- /dev/null
+++ b/java/sca/samples/dosgi-dynamic-calculator/src/main/java/calculator/dosgi/impl/CalculatorServiceImpl.java
@@ -0,0 +1,105 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package calculator.dosgi.impl;
+
+import static org.osgi.framework.Constants.OBJECTCLASS;
+
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.Filter;
+import org.osgi.framework.InvalidSyntaxException;
+import org.osgi.util.tracker.ServiceTracker;
+
+import calculator.dosgi.CalculatorService;
+import calculator.dosgi.operations.AddService;
+import calculator.dosgi.operations.DivideService;
+import calculator.dosgi.operations.MultiplyService;
+import calculator.dosgi.operations.SubtractService;
+
+/**
+ * An implementation of the Calculator service.
+ */
+public class CalculatorServiceImpl implements CalculatorService {
+ private ServiceTracker remoteServices;
+ private ServiceTracker localServices;
+
+ public CalculatorServiceImpl() {
+ super();
+ }
+
+ public CalculatorServiceImpl(BundleContext context) {
+ super();
+ Filter remoteFilter = null, localFilter = null;
+ try {
+ remoteFilter =
+ context.createFilter("(&(" + OBJECTCLASS + "=calculator.dosgi.operations.*) (service.imported=*))");
+ localFilter =
+ context.createFilter("(&(" + OBJECTCLASS + "=calculator.dosgi.operations.*) (!(service.imported=*)))");
+ } catch (InvalidSyntaxException e) {
+ e.printStackTrace();
+ }
+ this.remoteServices = new ServiceTracker(context, remoteFilter, null);
+ remoteServices.open();
+ this.localServices = new ServiceTracker(context, localFilter, null);
+ localServices.open();
+ }
+
+ private <T> T getService(Class<T> cls) {
+ try {
+ // Wait for 10 seconds until the remote services are imported
+ remoteServices.waitForService(10000);
+ } catch (InterruptedException e) {
+ throw new IllegalStateException(cls.getSimpleName() + " is not available");
+ }
+ Object[] remoteObjects = remoteServices.getServices();
+ if (remoteObjects != null) {
+ for (Object s : remoteObjects) {
+ if (cls.isInstance(s)) {
+ System.out.println("Remote service: " + s);
+ return cls.cast(s);
+ }
+ }
+ }
+ Object[] localObjects = localServices.getServices();
+ if (localObjects != null) {
+ for (Object s : localObjects) {
+ if (cls.isInstance(s)) {
+ System.out.println("Local service: " + s);
+ return cls.cast(s);
+ }
+ }
+ }
+ throw new IllegalStateException(cls.getSimpleName() + " is not available");
+ }
+
+ public double add(double n1, double n2) {
+ return getService(AddService.class).add(n1, n2);
+ }
+
+ public double subtract(double n1, double n2) {
+ return getService(SubtractService.class).subtract(n1, n2);
+ }
+
+ public double multiply(double n1, double n2) {
+ return getService(MultiplyService.class).multiply(n1, n2);
+ }
+
+ public double divide(double n1, double n2) {
+ return getService(DivideService.class).divide(n1, n2);
+ }
+}
diff --git a/java/sca/samples/dosgi-dynamic-calculator/src/main/java/calculator/dosgi/operations/AddService.java b/java/sca/samples/dosgi-dynamic-calculator/src/main/java/calculator/dosgi/operations/AddService.java
new file mode 100644
index 0000000000..971500782f
--- /dev/null
+++ b/java/sca/samples/dosgi-dynamic-calculator/src/main/java/calculator/dosgi/operations/AddService.java
@@ -0,0 +1,31 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package calculator.dosgi.operations;
+
+import org.oasisopen.sca.annotation.Remotable;
+
+/**
+ * The interface for the add service
+ */
+@Remotable
+public interface AddService {
+
+ double add(double n1, double n2);
+
+}
diff --git a/java/sca/samples/dosgi-dynamic-calculator/src/main/java/calculator/dosgi/operations/DivideService.java b/java/sca/samples/dosgi-dynamic-calculator/src/main/java/calculator/dosgi/operations/DivideService.java
new file mode 100644
index 0000000000..49b8a1c0bf
--- /dev/null
+++ b/java/sca/samples/dosgi-dynamic-calculator/src/main/java/calculator/dosgi/operations/DivideService.java
@@ -0,0 +1,31 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package calculator.dosgi.operations;
+
+import org.oasisopen.sca.annotation.Remotable;
+
+/**
+ * The interface for the divide service
+ */
+@Remotable
+public interface DivideService {
+
+ double divide(double n1, double n2);
+
+}
diff --git a/java/sca/samples/dosgi-dynamic-calculator/src/main/java/calculator/dosgi/operations/MultiplyService.java b/java/sca/samples/dosgi-dynamic-calculator/src/main/java/calculator/dosgi/operations/MultiplyService.java
new file mode 100644
index 0000000000..f4e59d12ea
--- /dev/null
+++ b/java/sca/samples/dosgi-dynamic-calculator/src/main/java/calculator/dosgi/operations/MultiplyService.java
@@ -0,0 +1,31 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package calculator.dosgi.operations;
+
+import org.oasisopen.sca.annotation.Remotable;
+
+/**
+ * The interface for the multiply service
+ */
+@Remotable
+public interface MultiplyService {
+
+ double multiply(double n1, double n2);
+
+}
diff --git a/java/sca/samples/dosgi-dynamic-calculator/src/main/java/calculator/dosgi/operations/SubtractService.java b/java/sca/samples/dosgi-dynamic-calculator/src/main/java/calculator/dosgi/operations/SubtractService.java
new file mode 100644
index 0000000000..bfb9b820f7
--- /dev/null
+++ b/java/sca/samples/dosgi-dynamic-calculator/src/main/java/calculator/dosgi/operations/SubtractService.java
@@ -0,0 +1,31 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package calculator.dosgi.operations;
+
+import org.oasisopen.sca.annotation.Remotable;
+
+/**
+ * The interface for the subtract service
+ */
+@Remotable
+public interface SubtractService {
+
+ double subtract(double n1, double n2);
+
+}
diff --git a/java/sca/samples/dosgi-dynamic-calculator/src/main/java/calculator/rmi/OperationsRMIServer.java b/java/sca/samples/dosgi-dynamic-calculator/src/main/java/calculator/rmi/OperationsRMIServer.java
new file mode 100644
index 0000000000..a4fc52694e
--- /dev/null
+++ b/java/sca/samples/dosgi-dynamic-calculator/src/main/java/calculator/rmi/OperationsRMIServer.java
@@ -0,0 +1,93 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package calculator.rmi;
+
+import java.io.Serializable;
+import java.rmi.Remote;
+import java.rmi.RemoteException;
+import java.rmi.registry.LocateRegistry;
+import java.rmi.registry.Registry;
+import java.rmi.server.UnicastRemoteObject;
+
+/**
+ *
+ */
+public class OperationsRMIServer implements OperationsRemote, Serializable {
+
+ private static final long serialVersionUID = 6081008315263103012L;
+ private transient Registry registry;
+
+ public OperationsRMIServer() throws RemoteException {
+ super();
+ }
+
+ public double add(double n1, double n2) {
+ return n1 + n2;
+ }
+
+ public double subtract(double n1, double n2) {
+ return n1 - n2;
+ }
+
+ public double divide(double n1, double n2) {
+ return n1 / n2;
+ }
+
+ public double multiply(double n1, double n2) {
+ return n1 * n2;
+ }
+
+ public void start() throws RemoteException {
+ Thread thread = new Thread() {
+ public void run() {
+ try {
+ System.out.println("Starting the RMI server for calculator operations...");
+ Remote stub = UnicastRemoteObject.exportObject(OperationsRMIServer.this);
+ registry = LocateRegistry.createRegistry(8085);
+ registry.bind("AddService", stub);
+ registry.bind("SubtractService", stub);
+ registry.bind("MultiplyService", stub);
+ registry.bind("DivideService", stub);
+ System.out.println("RMI server for calculator operations is now started.");
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+ };
+ thread.start();
+ }
+
+ public void stop() {
+ if (registry != null) {
+ try {
+ registry.unbind("AddService");
+ registry.unbind("SubtractService");
+ registry.unbind("MultiplyService");
+ registry.unbind("DivideService");
+ UnicastRemoteObject.unexportObject(this, false);
+ UnicastRemoteObject.unexportObject(registry, false);
+ registry = null;
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+ }
+
+}
diff --git a/java/sca/samples/dosgi-dynamic-calculator/src/main/java/calculator/rmi/OperationsRMIServer_Stub.java b/java/sca/samples/dosgi-dynamic-calculator/src/main/java/calculator/rmi/OperationsRMIServer_Stub.java
new file mode 100644
index 0000000000..a813dfb6f3
--- /dev/null
+++ b/java/sca/samples/dosgi-dynamic-calculator/src/main/java/calculator/rmi/OperationsRMIServer_Stub.java
@@ -0,0 +1,132 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+// Stub class generated by rmic, do not edit.
+// Contents subject to change without notice.
+package calculator.rmi;
+
+public final class OperationsRMIServer_Stub extends java.rmi.server.RemoteStub implements calculator.rmi.OperationsRemote {
+ private static final long serialVersionUID = 2;
+
+ private static java.lang.reflect.Method $method_add_0;
+ private static java.lang.reflect.Method $method_divide_1;
+ private static java.lang.reflect.Method $method_multiply_2;
+ private static java.lang.reflect.Method $method_subtract_3;
+
+ static {
+ try {
+ $method_add_0 =
+ calculator.rmi.OperationsRemote.class.getMethod("add", new java.lang.Class[] {double.class, double.class});
+ $method_divide_1 =
+ calculator.rmi.OperationsRemote.class.getMethod("divide",
+ new java.lang.Class[] {double.class, double.class});
+ $method_multiply_2 =
+ calculator.rmi.OperationsRemote.class.getMethod("multiply", new java.lang.Class[] {double.class,
+ double.class});
+ $method_subtract_3 =
+ calculator.rmi.OperationsRemote.class.getMethod("subtract", new java.lang.Class[] {double.class,
+ double.class});
+ } catch (java.lang.NoSuchMethodException e) {
+ throw new java.lang.NoSuchMethodError("stub class initialization failed");
+ }
+ }
+
+ // constructors
+ public OperationsRMIServer_Stub(java.rmi.server.RemoteRef ref) {
+ super(ref);
+ }
+
+ // methods from remote interfaces
+
+ // implementation of add(double, double)
+ public double add(double $param_double_1, double $param_double_2) throws java.rmi.RemoteException {
+ try {
+ Object $result =
+ ref.invoke(this,
+ $method_add_0,
+ new java.lang.Object[] {new java.lang.Double($param_double_1),
+ new java.lang.Double($param_double_2)},
+ 864055858262779977L);
+ return ((java.lang.Double)$result).doubleValue();
+ } catch (java.lang.RuntimeException e) {
+ throw e;
+ } catch (java.rmi.RemoteException e) {
+ throw e;
+ } catch (java.lang.Exception e) {
+ throw new java.rmi.UnexpectedException("undeclared checked exception", e);
+ }
+ }
+
+ // implementation of divide(double, double)
+ public double divide(double $param_double_1, double $param_double_2) throws java.rmi.RemoteException {
+ try {
+ Object $result =
+ ref.invoke(this,
+ $method_divide_1,
+ new java.lang.Object[] {new java.lang.Double($param_double_1),
+ new java.lang.Double($param_double_2)},
+ 8097593626497421928L);
+ return ((java.lang.Double)$result).doubleValue();
+ } catch (java.lang.RuntimeException e) {
+ throw e;
+ } catch (java.rmi.RemoteException e) {
+ throw e;
+ } catch (java.lang.Exception e) {
+ throw new java.rmi.UnexpectedException("undeclared checked exception", e);
+ }
+ }
+
+ // implementation of multiply(double, double)
+ public double multiply(double $param_double_1, double $param_double_2) throws java.rmi.RemoteException {
+ try {
+ Object $result =
+ ref.invoke(this,
+ $method_multiply_2,
+ new java.lang.Object[] {new java.lang.Double($param_double_1),
+ new java.lang.Double($param_double_2)},
+ -346155016949350695L);
+ return ((java.lang.Double)$result).doubleValue();
+ } catch (java.lang.RuntimeException e) {
+ throw e;
+ } catch (java.rmi.RemoteException e) {
+ throw e;
+ } catch (java.lang.Exception e) {
+ throw new java.rmi.UnexpectedException("undeclared checked exception", e);
+ }
+ }
+
+ // implementation of subtract(double, double)
+ public double subtract(double $param_double_1, double $param_double_2) throws java.rmi.RemoteException {
+ try {
+ Object $result =
+ ref.invoke(this,
+ $method_subtract_3,
+ new java.lang.Object[] {new java.lang.Double($param_double_1),
+ new java.lang.Double($param_double_2)},
+ -610707357620578750L);
+ return ((java.lang.Double)$result).doubleValue();
+ } catch (java.lang.RuntimeException e) {
+ throw e;
+ } catch (java.rmi.RemoteException e) {
+ throw e;
+ } catch (java.lang.Exception e) {
+ throw new java.rmi.UnexpectedException("undeclared checked exception", e);
+ }
+ }
+}
diff --git a/java/sca/samples/dosgi-dynamic-calculator/src/main/java/calculator/rmi/OperationsRemote.java b/java/sca/samples/dosgi-dynamic-calculator/src/main/java/calculator/rmi/OperationsRemote.java
new file mode 100644
index 0000000000..955e386ad8
--- /dev/null
+++ b/java/sca/samples/dosgi-dynamic-calculator/src/main/java/calculator/rmi/OperationsRemote.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 calculator.rmi;
+
+import java.rmi.Remote;
+import java.rmi.RemoteException;
+
+/**
+ * RMI Remote interface
+ */
+public interface OperationsRemote extends Remote {
+ double add(double n1, double n2) throws RemoteException;
+
+ double subtract(double n1, double n2) throws RemoteException;
+
+ double multiply(double n1, double n2) throws RemoteException;
+
+ double divide(double n1, double n2) throws RemoteException;
+
+}
diff --git a/java/sca/samples/dosgi-dynamic-calculator/src/test/java/calculator/dosgi/test/CalculatorNode.java b/java/sca/samples/dosgi-dynamic-calculator/src/test/java/calculator/dosgi/test/CalculatorNode.java
new file mode 100644
index 0000000000..565a314d85
--- /dev/null
+++ b/java/sca/samples/dosgi-dynamic-calculator/src/test/java/calculator/dosgi/test/CalculatorNode.java
@@ -0,0 +1,43 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package calculator.dosgi.test;
+
+import org.apache.tuscany.sca.node.equinox.launcher.NodeLauncher;
+
+/**
+ *
+ */
+public class CalculatorNode {
+
+ /**
+ * @param args
+ */
+ public static void main(String[] args) {
+ if (args.length == 0) {
+ args = new String[] {"-bundles"};
+ }
+ try {
+ NodeLauncher.main(args);
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+
+}
diff --git a/java/sca/samples/dosgi-dynamic-calculator/src/test/java/calculator/dosgi/test/CalculatorOSGiNodeTestCase.java b/java/sca/samples/dosgi-dynamic-calculator/src/test/java/calculator/dosgi/test/CalculatorOSGiNodeTestCase.java
new file mode 100644
index 0000000000..4015c7bbc2
--- /dev/null
+++ b/java/sca/samples/dosgi-dynamic-calculator/src/test/java/calculator/dosgi/test/CalculatorOSGiNodeTestCase.java
@@ -0,0 +1,144 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package calculator.dosgi.test;
+
+import static calculator.dosgi.test.OSGiTestUtils.bundleStatus;
+
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.Reader;
+import java.net.URL;
+
+import org.apache.tuscany.sca.node.equinox.launcher.EquinoxHost;
+import org.junit.AfterClass;
+import org.junit.Assert;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.Constants;
+import org.osgi.framework.ServiceReference;
+
+import calculator.dosgi.CalculatorService;
+import calculator.rmi.OperationsRMIServer;
+
+/**
+ *
+ */
+public class CalculatorOSGiNodeTestCase {
+ private static EquinoxHost host;
+ private static BundleContext context;
+ private static Bundle calculatorBundle;
+ private static OperationsRMIServer rmiServer;
+
+ /**
+ * @throws java.lang.Exception
+ */
+ @BeforeClass
+ public static void setUpBeforeClass() throws Exception {
+ try {
+ rmiServer = new OperationsRMIServer();
+ rmiServer.start();
+
+ host = new EquinoxHost();
+ context = host.start();
+
+ for (Bundle b : context.getBundles()) {
+ System.out.println(b);
+ if (b.getSymbolicName().equals("org.eclipse.equinox.ds") || b.getSymbolicName()
+ .startsWith("org.apache.tuscany.sca.")) {
+ try {
+ if (b.getHeaders().get(Constants.FRAGMENT_HOST) == null) {
+ // Start the non-fragment bundle
+ b.start();
+ }
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ System.out.println(bundleStatus(b, false));
+ }
+ if ("calculator.dosgi.dynamic".equals(b.getSymbolicName())) {
+ calculatorBundle = b;
+ }
+ }
+
+ if (calculatorBundle != null) {
+ calculatorBundle.start();
+ System.out.println(bundleStatus(calculatorBundle, false));
+ }
+
+ } catch (Exception e) {
+ e.printStackTrace();
+ throw e;
+ }
+ }
+
+ @Test
+ public void testOSGi() {
+ ServiceReference ref =
+ calculatorBundle.getBundleContext().getServiceReference(CalculatorService.class.getName());
+ Assert.assertNotNull(ref);
+ Object service = context.getService(ref);
+ Assert.assertNotNull(service);
+ CalculatorService calculator = OSGiTestUtils.cast(service, CalculatorService.class);
+ System.out.println("2.0 + 1.0 = " + calculator.add(2.0, 1.0));
+ System.out.println("2.0 - 1.0 = " + calculator.subtract(2.0, 1.0));
+ System.out.println("2.0 * 1.0 = " + calculator.multiply(2.0, 1.0));
+ System.out.println("2.0 / 1.0 = " + calculator.divide(2.0, 1.0));
+ }
+
+ @Test
+ /**
+ * Test the Web service exposed by the Calculator
+ */
+ public void testWS() throws Exception {
+ URL url = new URL("http://localhost:8086/CalculatorService?wsdl");
+ InputStream is = url.openStream();
+ Reader reader = new InputStreamReader(is);
+ char[] content = new char[10240]; // 10k
+ int len = 0;
+ while (true) {
+ int size = reader.read(content, len, content.length - len);
+ if (size < 0) {
+ break;
+ }
+ len += size;
+ }
+ Assert.assertTrue(len > 0);
+ String str = new String(content, 0, len);
+ System.out.println(str);
+ Assert.assertTrue(str.indexOf("<wsdl:definitions") != -1);
+ }
+
+ /**
+ * @throws java.lang.Exception
+ */
+ @AfterClass
+ public static void tearDownAfterClass() throws Exception {
+ if (host != null) {
+ host.stop();
+ rmiServer.stop();
+ host = null;
+ rmiServer = null;
+ context = null;
+ }
+ }
+
+}
diff --git a/java/sca/samples/dosgi-dynamic-calculator/src/test/java/calculator/dosgi/test/OSGiTestUtils.java b/java/sca/samples/dosgi-dynamic-calculator/src/test/java/calculator/dosgi/test/OSGiTestUtils.java
new file mode 100644
index 0000000000..99e0da9f97
--- /dev/null
+++ b/java/sca/samples/dosgi-dynamic-calculator/src/test/java/calculator/dosgi/test/OSGiTestUtils.java
@@ -0,0 +1,105 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package calculator.dosgi.test;
+
+import java.lang.reflect.InvocationHandler;
+import java.lang.reflect.Method;
+import java.lang.reflect.Proxy;
+
+import org.osgi.framework.Bundle;
+
+/**
+ *
+ * Utility class to create OSGi bundles
+ *
+ * @version $Rev$ $Date$
+ */
+public class OSGiTestUtils {
+ private static class InvocationHandlerImpl implements InvocationHandler {
+ private Object instance;
+
+ public InvocationHandlerImpl(Object instance) {
+ super();
+ this.instance = instance;
+ }
+
+ public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
+ Method m = instance.getClass().getMethod(method.getName(), method.getParameterTypes());
+ return m.invoke(instance, args);
+ }
+
+ }
+
+ /**
+ * Returns a string representation of the given bundle.
+ *
+ * @param b
+ * @param verbose
+ * @return
+ */
+ public static String bundleStatus(Bundle bundle, boolean verbose) {
+ StringBuffer sb = new StringBuffer();
+ sb.append(bundle.getBundleId()).append(" ").append(bundle.getSymbolicName());
+ int s = bundle.getState();
+ if ((s & Bundle.UNINSTALLED) != 0) {
+ sb.append(" UNINSTALLED");
+ }
+ if ((s & Bundle.INSTALLED) != 0) {
+ sb.append(" INSTALLED");
+ }
+ if ((s & Bundle.RESOLVED) != 0) {
+ sb.append(" RESOLVED");
+ }
+ if ((s & Bundle.STARTING) != 0) {
+ sb.append(" STARTING");
+ }
+ if ((s & Bundle.STOPPING) != 0) {
+ sb.append(" STOPPING");
+ }
+ if ((s & Bundle.ACTIVE) != 0) {
+ sb.append(" ACTIVE");
+ }
+
+ if (verbose) {
+ sb.append(" ").append(bundle.getLocation());
+ sb.append(" ").append(bundle.getHeaders());
+ }
+ return sb.toString();
+ }
+
+ /**
+ * A utility to cast the object to the given interface. If the class for the object
+ * is loaded by a different classloader, a proxy will be created.
+ *
+ * @param <T>
+ * @param obj
+ * @param cls
+ * @return
+ */
+ public static <T> T cast(Object obj, Class<T> cls) {
+ if (cls.isInstance(obj)) {
+ return cls.cast(obj);
+ } else {
+ return cls.cast(Proxy.newProxyInstance(cls.getClassLoader(),
+ new Class<?>[] {cls},
+ new InvocationHandlerImpl(obj)));
+ }
+ }
+}
diff --git a/java/sca/samples/pom.xml b/java/sca/samples/pom.xml
index 55582f903a..88fa77c2be 100644
--- a/java/sca/samples/pom.xml
+++ b/java/sca/samples/pom.xml
@@ -51,6 +51,9 @@
<module>dosgi-calculator</module>
<module>dosgi-calculator-operations</module>
+
+ <module>dosgi-dynamic-calculator</module>
+ <module>dosgi-dynamic-calculator-operations</module>
<module>helloworld-bpel</module>