summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--java/sca/modules/implementation-osgi-runtime/LICENSE203
-rw-r--r--java/sca/modules/implementation-osgi-runtime/NOTICE6
-rw-r--r--java/sca/modules/implementation-osgi-runtime/pom.xml162
-rw-r--r--java/sca/modules/implementation-osgi-runtime/src/main/java/org/apache/tuscany/sca/implementation/osgi/runtime/OSGiImplementationManager.java112
-rw-r--r--java/sca/modules/implementation-osgi-runtime/src/main/java/org/apache/tuscany/sca/implementation/osgi/runtime/OSGiImplementationProvider.java850
-rw-r--r--java/sca/modules/implementation-osgi-runtime/src/main/java/org/apache/tuscany/sca/implementation/osgi/runtime/OSGiImplementationProviderFactory.java59
-rw-r--r--java/sca/modules/implementation-osgi-runtime/src/main/java/org/apache/tuscany/sca/implementation/osgi/runtime/OSGiImplementationRuntimeActivator.java83
-rw-r--r--java/sca/modules/implementation-osgi-runtime/src/main/java/org/apache/tuscany/sca/implementation/osgi/runtime/OSGiServiceTracker.java40
-rw-r--r--java/sca/modules/implementation-osgi-runtime/src/main/java/org/apache/tuscany/sca/implementation/osgi/runtime/OSGiTargetInvoker.java121
-rw-r--r--java/sca/modules/implementation-osgi-runtime/src/main/resources/META-INF/definitions.xml37
-rw-r--r--java/sca/modules/implementation-osgi-runtime/src/main/resources/META-INF/services/org.apache.tuscany.sca.provider.ImplementationProviderFactory19
-rw-r--r--java/sca/modules/implementation-osgi-runtime/src/main/resources/impl-osgi-validation-messages.properties25
-rw-r--r--java/sca/modules/implementation-osgi-runtime/src/test/java/calculator/CalculatorActivator.java74
-rw-r--r--java/sca/modules/implementation-osgi-runtime/src/test/java/calculator/CalculatorService.java39
-rw-r--r--java/sca/modules/implementation-osgi-runtime/src/test/java/calculator/CalculatorServiceDSImpl.java113
-rw-r--r--java/sca/modules/implementation-osgi-runtime/src/test/java/calculator/CalculatorServiceImpl.java104
-rw-r--r--java/sca/modules/implementation-osgi-runtime/src/test/java/calculator/operations/AddService.java31
-rw-r--r--java/sca/modules/implementation-osgi-runtime/src/test/java/calculator/operations/AddServiceImpl.java35
-rw-r--r--java/sca/modules/implementation-osgi-runtime/src/test/java/calculator/operations/DivideService.java31
-rw-r--r--java/sca/modules/implementation-osgi-runtime/src/test/java/calculator/operations/DivideServiceImpl.java35
-rw-r--r--java/sca/modules/implementation-osgi-runtime/src/test/java/calculator/operations/MultiplyService.java31
-rw-r--r--java/sca/modules/implementation-osgi-runtime/src/test/java/calculator/operations/MultiplyServiceImpl.java35
-rw-r--r--java/sca/modules/implementation-osgi-runtime/src/test/java/calculator/operations/OperationsActivator.java63
-rw-r--r--java/sca/modules/implementation-osgi-runtime/src/test/java/calculator/operations/SubtractService.java31
-rw-r--r--java/sca/modules/implementation-osgi-runtime/src/test/java/calculator/operations/SubtractServiceImpl.java35
-rw-r--r--java/sca/modules/implementation-osgi-runtime/src/test/java/calculator/test/CalculatorOSGiTestCase.java200
-rw-r--r--java/sca/modules/implementation-osgi-runtime/src/test/java/org/apache/tuscany/sca/implementation/osgi/runtime/OSGiTestCase.java84
-rw-r--r--java/sca/modules/implementation-osgi-runtime/src/test/java/org/apache/tuscany/sca/implementation/osgi/test/OSGiTestBundles.java180
-rw-r--r--java/sca/modules/implementation-osgi-runtime/src/test/java/org/apache/tuscany/sca/implementation/osgi/test/OSGiTestImpl.java50
-rw-r--r--java/sca/modules/implementation-osgi-runtime/src/test/java/org/apache/tuscany/sca/implementation/osgi/test/OSGiTestInterface.java32
-rw-r--r--java/sca/modules/implementation-osgi-runtime/src/test/resources/OSGI-INF/add-component.xml25
-rw-r--r--java/sca/modules/implementation-osgi-runtime/src/test/resources/OSGI-INF/calculator-component.xml36
-rw-r--r--java/sca/modules/implementation-osgi-runtime/src/test/resources/OSGI-INF/divide-component.xml25
-rw-r--r--java/sca/modules/implementation-osgi-runtime/src/test/resources/OSGI-INF/multiply-component.xml25
-rw-r--r--java/sca/modules/implementation-osgi-runtime/src/test/resources/OSGI-INF/sca/bundle.componentType54
-rw-r--r--java/sca/modules/implementation-osgi-runtime/src/test/resources/OSGI-INF/subtract-component.xml25
-rw-r--r--java/sca/modules/implementation-osgi-runtime/src/test/resources/calculator/META-INF/MANIFEST.MF18
-rw-r--r--java/sca/modules/implementation-osgi-runtime/src/test/resources/calculator/calculator.composite38
-rw-r--r--java/sca/modules/implementation-osgi-runtime/src/test/resources/calculator/operations/META-INF/MANIFEST.MF19
-rw-r--r--java/sca/modules/implementation-osgi-runtime/src/test/resources/calculator/operations/operations.composite38
40 files changed, 3223 insertions, 0 deletions
diff --git a/java/sca/modules/implementation-osgi-runtime/LICENSE b/java/sca/modules/implementation-osgi-runtime/LICENSE
new file mode 100644
index 0000000000..6b0b1270ff
--- /dev/null
+++ b/java/sca/modules/implementation-osgi-runtime/LICENSE
@@ -0,0 +1,203 @@
+
+ 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/modules/implementation-osgi-runtime/NOTICE b/java/sca/modules/implementation-osgi-runtime/NOTICE
new file mode 100644
index 0000000000..25bb89c9b2
--- /dev/null
+++ b/java/sca/modules/implementation-osgi-runtime/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/modules/implementation-osgi-runtime/pom.xml b/java/sca/modules/implementation-osgi-runtime/pom.xml
new file mode 100644
index 0000000000..13ef5c983f
--- /dev/null
+++ b/java/sca/modules/implementation-osgi-runtime/pom.xml
@@ -0,0 +1,162 @@
+<?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-modules</artifactId>
+ <version>2.0-SNAPSHOT</version>
+ <relativePath>../pom.xml</relativePath>
+ </parent>
+
+ <artifactId>tuscany-implementation-osgi-runtime</artifactId>
+ <name>Apache Tuscany SCA OSGi Implementation Extension Runtime</name>
+
+ <packaging>jar</packaging>
+
+ <dependencies>
+
+ <dependency>
+ <groupId>org.apache.tuscany.sca</groupId>
+ <artifactId>tuscany-implementation-osgi</artifactId>
+ <version>2.0-SNAPSHOT</version>
+ </dependency>
+
+ <dependency>
+ <groupId>org.apache.tuscany.sca</groupId>
+ <artifactId>tuscany-contribution-osgi</artifactId>
+ <version>2.0-SNAPSHOT</version>
+ <scope>runtime</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.eclipse</groupId>
+ <artifactId>osgi</artifactId>
+ <version>3.3.0-v20070530</version>
+ <scope>compile</scope>
+ </dependency>
+
+ <dependency>
+ <groupId>org.eclipse.osgi</groupId>
+ <artifactId>services</artifactId>
+ <version>3.1.200-v20070605</version>
+ <scope>test</scope>
+ </dependency>
+
+ <dependency>
+ <groupId>org.apache.tuscany.sca</groupId>
+ <artifactId>tuscany-node-api</artifactId>
+ <version>2.0-SNAPSHOT</version>
+ </dependency>
+
+ <dependency>
+ <groupId>org.apache.tuscany.sca</groupId>
+ <artifactId>tuscany-sca-api</artifactId>
+ <version>2.0-SNAPSHOT</version>
+ </dependency>
+
+ <dependency>
+ <groupId>org.apache.tuscany.sca</groupId>
+ <artifactId>tuscany-core</artifactId>
+ <version>2.0-SNAPSHOT</version>
+ </dependency>
+
+ <dependency>
+ <groupId>org.apache.tuscany.sca</groupId>
+ <artifactId>tuscany-interface</artifactId>
+ <version>2.0-SNAPSHOT</version>
+ </dependency>
+
+ <dependency>
+ <groupId>org.apache.tuscany.sca</groupId>
+ <artifactId>tuscany-interface-java</artifactId>
+ <version>2.0-SNAPSHOT</version>
+ </dependency>
+
+ <dependency>
+ <groupId>org.apache.tuscany.sca</groupId>
+ <artifactId>tuscany-interface-java-xml</artifactId>
+ <version>2.0-SNAPSHOT</version>
+ <scope>runtime</scope>
+ </dependency>
+
+ <dependency>
+ <groupId>org.apache.tuscany.sca</groupId>
+ <artifactId>tuscany-implementation-java</artifactId>
+ <version>2.0-SNAPSHOT</version>
+ </dependency>
+
+ <dependency>
+ <groupId>org.apache.tuscany.sca</groupId>
+ <artifactId>tuscany-implementation-java-runtime</artifactId>
+ <version>2.0-SNAPSHOT</version>
+ </dependency>
+
+ <dependency>
+ <groupId>org.apache.tuscany.sca</groupId>
+ <artifactId>tuscany-implementation-java-xml</artifactId>
+ <version>2.0-SNAPSHOT</version>
+ </dependency>
+
+ <dependency>
+ <groupId>org.apache.tuscany.sca</groupId>
+ <artifactId>tuscany-assembly-xml</artifactId>
+ <version>2.0-SNAPSHOT</version>
+ <scope>runtime</scope>
+ </dependency>
+
+ <dependency>
+ <groupId>org.apache.tuscany.sca</groupId>
+ <artifactId>tuscany-databinding</artifactId>
+ <version>2.0-SNAPSHOT</version>
+ </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>test</scope>
+ </dependency>
+
+ <dependency>
+ <groupId>junit</groupId>
+ <artifactId>junit</artifactId>
+ <version>4.5</version>
+ <scope>test</scope>
+ </dependency>
+
+
+ <dependency>
+ <groupId>org.apache.tuscany.sca</groupId>
+ <artifactId>tuscany-binding-sca</artifactId>
+ <version>2.0-SNAPSHOT</version>
+ <scope>test</scope>
+ </dependency>
+
+ </dependencies>
+
+</project>
diff --git a/java/sca/modules/implementation-osgi-runtime/src/main/java/org/apache/tuscany/sca/implementation/osgi/runtime/OSGiImplementationManager.java b/java/sca/modules/implementation-osgi-runtime/src/main/java/org/apache/tuscany/sca/implementation/osgi/runtime/OSGiImplementationManager.java
new file mode 100644
index 0000000000..fdc2e1ee2d
--- /dev/null
+++ b/java/sca/modules/implementation-osgi-runtime/src/main/java/org/apache/tuscany/sca/implementation/osgi/runtime/OSGiImplementationManager.java
@@ -0,0 +1,112 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.tuscany.sca.implementation.osgi.runtime;
+
+import java.net.URL;
+import java.util.Dictionary;
+import java.util.Enumeration;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+
+import org.apache.tuscany.sca.implementation.osgi.OSGiImplementation;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.BundleEvent;
+import org.osgi.framework.ServiceEvent;
+import org.osgi.framework.ServiceListener;
+import org.osgi.framework.SynchronousBundleListener;
+
+/**
+ * Managing the mapping between OSGi bundles and SCA implementation.osgi
+ */
+public class OSGiImplementationManager implements SynchronousBundleListener, ServiceListener {
+ private BundleContext bundleContext;
+ private Map<Bundle, OSGiImplementation> implementations = new ConcurrentHashMap<Bundle, OSGiImplementation>();
+
+ public OSGiImplementationManager(BundleContext bundleContext) {
+ super();
+ this.bundleContext = bundleContext;
+ }
+
+ public void start() {
+ for (Bundle b : bundleContext.getBundles()) {
+ if ((b.getState() & Bundle.ACTIVE) != 0) {
+ // Process the active bundles
+ bundleStarted(b);
+ }
+ }
+ }
+
+ public static boolean isSCABundle(Bundle bundle) {
+ Dictionary<?, ?> headers = bundle.getHeaders();
+ // OSGi RFC 119 SCA
+ if (headers.get("SCA-Composite") != null) {
+ return true;
+ }
+ Enumeration<?> entries = bundle.findEntries("OSGI-INF/sca", "*", false);
+ if (entries != null && entries.hasMoreElements()) {
+ return true;
+ }
+
+ // OSGi Declarative Services
+ if (headers.get("Service-Component") != null) {
+ return true;
+ }
+
+ // OSGI RFC 124: BluePrint Service
+ if (headers.get("Bundle-Blueprint") != null) {
+ return true;
+ }
+
+ entries = bundle.findEntries("OSGI-INF/blueprint", "*.xml", false);
+ if (entries != null && entries.hasMoreElements()) {
+ return true;
+ }
+ return false;
+ }
+
+ private void bundleStarted(Bundle bundle) {
+ if (!isSCABundle(bundle)) {
+ return;
+ }
+ URL compositeFile = bundle.getEntry("OSGI-INF/sca/bundle.composite");
+ URL componentTypeFile = bundle.getEntry("OSGI-INF/sca/bundle.componentType");
+ }
+
+ private void bundleStopping(Bundle bundle) {
+ OSGiImplementation impl = implementations.remove(bundle);
+ if (impl == null) {
+ return;
+ }
+ }
+
+ public void serviceChanged(ServiceEvent event) {
+ }
+
+ public void bundleChanged(BundleEvent event) {
+ int type = event.getType();
+ if (type == BundleEvent.STOPPING) {
+ bundleStopping(event.getBundle());
+ } else if (type == BundleEvent.STARTED) {
+ bundleStarted(event.getBundle());
+ }
+ }
+
+}
diff --git a/java/sca/modules/implementation-osgi-runtime/src/main/java/org/apache/tuscany/sca/implementation/osgi/runtime/OSGiImplementationProvider.java b/java/sca/modules/implementation-osgi-runtime/src/main/java/org/apache/tuscany/sca/implementation/osgi/runtime/OSGiImplementationProvider.java
new file mode 100644
index 0000000000..b00aabde39
--- /dev/null
+++ b/java/sca/modules/implementation-osgi-runtime/src/main/java/org/apache/tuscany/sca/implementation/osgi/runtime/OSGiImplementationProvider.java
@@ -0,0 +1,850 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS 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.implementation.osgi.runtime;
+
+import java.lang.reflect.Method;
+import java.security.AccessController;
+import java.security.PrivilegedActionException;
+import java.security.PrivilegedExceptionAction;
+import java.util.ArrayList;
+import java.util.Dictionary;
+import java.util.HashSet;
+import java.util.Hashtable;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.atomic.AtomicInteger;
+
+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.Extensible;
+import org.apache.tuscany.sca.assembly.Multiplicity;
+import org.apache.tuscany.sca.assembly.Reference;
+import org.apache.tuscany.sca.assembly.Service;
+import org.apache.tuscany.sca.core.factory.ObjectCreationException;
+import org.apache.tuscany.sca.core.invocation.ProxyFactory;
+import org.apache.tuscany.sca.core.invocation.ProxyFactoryExtensionPoint;
+import org.apache.tuscany.sca.core.scope.Scope;
+import org.apache.tuscany.sca.implementation.osgi.OSGiImplementation;
+import org.apache.tuscany.sca.implementation.osgi.OSGiProperty;
+import org.apache.tuscany.sca.interfacedef.Interface;
+import org.apache.tuscany.sca.interfacedef.Operation;
+import org.apache.tuscany.sca.interfacedef.java.JavaInterface;
+import org.apache.tuscany.sca.invocation.Invoker;
+import org.apache.tuscany.sca.provider.ImplementationProvider;
+import org.apache.tuscany.sca.runtime.EndpointReference;
+import org.apache.tuscany.sca.runtime.RuntimeComponent;
+import org.apache.tuscany.sca.runtime.RuntimeComponentReference;
+import org.apache.tuscany.sca.runtime.RuntimeComponentService;
+import org.apache.tuscany.sca.runtime.RuntimeWire;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.BundleEvent;
+import org.osgi.framework.BundleException;
+import org.osgi.framework.BundleListener;
+import org.osgi.framework.Constants;
+import org.osgi.framework.FrameworkEvent;
+import org.osgi.framework.FrameworkListener;
+import org.osgi.framework.InvalidSyntaxException;
+import org.osgi.framework.ServiceEvent;
+import org.osgi.framework.ServiceListener;
+import org.osgi.framework.ServiceReference;
+import org.osgi.service.packageadmin.PackageAdmin;
+
+/**
+ * The runtime instantiation of OSGi component implementations
+ *
+ * @version $Rev$ $Date$
+ */
+public class OSGiImplementationProvider implements ImplementationProvider, FrameworkListener, BundleListener {
+
+ private static final String COMPONENT_SERVICE_NAME = "component.service.name";
+
+ // Maximum milliseconds to wait for a method to complete
+ private static final long METHOD_TIMEOUT_MILLIS = 60000;
+ // Maximum milliseconds to wait for services to be registered into OSGi service registry
+ private static final long SERVICE_TIMEOUT_MILLIS = 300000;
+
+ private OSGiImplementation implementation;
+ private Hashtable<RuntimeWire, Reference> referenceWires = new Hashtable<RuntimeWire, Reference>();
+ private Hashtable<RuntimeWire, ComponentReference> componentReferenceWires =
+ new Hashtable<RuntimeWire, ComponentReference>();
+ private HashSet<RuntimeWire> resolvedWires = new HashSet<RuntimeWire>();
+ private boolean wiresResolved;
+
+ private AtomicInteger startBundleEntryCount = new AtomicInteger();
+
+ private Hashtable<String, Object> componentProperties = new Hashtable<String, Object>();
+ private RuntimeComponent runtimeComponent;
+
+ Bundle osgiBundle;
+ private ArrayList<Bundle> dependentBundles = new ArrayList<Bundle>();
+ private OSGiServiceListener osgiServiceListener;
+ private PackageAdmin packageAdmin;
+
+ private ProxyFactoryExtensionPoint proxyFactoryExtensionPoint;
+
+ private boolean packagesRefreshed;
+
+ public OSGiImplementationProvider(RuntimeComponent component,
+ OSGiImplementation impl,
+ ProxyFactoryExtensionPoint proxyFactoryExtensionPoint) throws BundleException {
+
+ this.implementation = impl;
+ this.runtimeComponent = component;
+ this.proxyFactoryExtensionPoint = proxyFactoryExtensionPoint;
+
+ BundleContext bundleContext = OSGiImplementationRuntimeActivator.getBundleContext();
+ osgiBundle = (Bundle)implementation.getBundle();
+ bundleContext.addBundleListener(this);
+ osgiServiceListener = new OSGiServiceListener(osgiBundle);
+ bundleContext.addServiceListener(osgiServiceListener);
+
+ // PackageAdmin is used to resolve bundles
+ org.osgi.framework.ServiceReference packageAdminReference =
+ bundleContext.getServiceReference("org.osgi.service.packageadmin.PackageAdmin");
+ if (packageAdminReference != null) {
+ packageAdmin = (PackageAdmin)bundleContext.getService(packageAdminReference);
+ bundleContext.addFrameworkListener(this);
+ }
+
+ }
+
+ protected RuntimeComponent getRuntimeComponent() {
+ return runtimeComponent;
+ }
+
+ protected OSGiImplementation getImplementation() {
+ return implementation;
+ }
+
+ private String getOSGiFilter(Hashtable<String, Object> props) {
+
+ String filter = "";
+
+ if (props != null && props.size() > 0) {
+ int propCount = 0;
+ for (String propName : props.keySet()) {
+ if (propName.equals("service.pid"))
+ continue;
+ filter = filter + "(" + propName + "=" + props.get(propName) + ")";
+ propCount++;
+ }
+
+ if (propCount > 1)
+ filter = "(&" + filter + ")";
+ } else
+ filter = null;
+ return filter;
+ }
+
+ /*
+ * Return a matching service registered by the specified bundle.
+ * If <implementation.osgi /> has the attribute filter defined, return a service
+ * reference that matches the filter. Otherwise, return a service which has a component
+ * name equal to this component's name. If not found, return a service which no
+ * component name set.
+ *
+ * Even though services registered by this bundle can be filtered using the
+ * service listener, we use this method to filter all service references so that
+ * the service matching functionality of OSGi can be directly used.
+ */
+ private ServiceReference getOSGiServiceReference(String scaServiceName,
+ String osgiServiceName,
+ String filter) throws InvalidSyntaxException {
+
+ String compServiceName = runtimeComponent.getName() + "/" + scaServiceName;
+ if (filter != null && filter.length() > 0) {
+ org.osgi.framework.ServiceReference[] references =
+ osgiBundle.getBundleContext().getServiceReferences(osgiServiceName, filter);
+
+ ServiceReference reference = null;
+ if (references != null) {
+ for (ServiceReference ref : references) {
+ if (ref.getBundle() != osgiBundle)
+ continue;
+ Object compName = ref.getProperty(COMPONENT_SERVICE_NAME);
+ if (compName == null && reference == null)
+ reference = ref;
+ if (scaServiceName == null || compServiceName.equals(compName)) {
+ reference = ref;
+ break;
+ }
+ }
+ }
+
+ return reference;
+
+ }
+
+ filter = scaServiceName == null ? null : "(" + COMPONENT_SERVICE_NAME + "=" + compServiceName + ")";
+
+ ServiceReference[] references =
+ osgiBundle.getBundleContext().getServiceReferences(osgiServiceName, filter);
+
+ if (references != null) {
+ for (ServiceReference ref : references) {
+ if (ref.getBundle() == osgiBundle) {
+ return ref;
+ }
+ }
+ }
+
+ references = osgiBundle.getBundleContext().getServiceReferences(osgiServiceName, null);
+
+ ServiceReference reference = null;
+
+ if (references != null) {
+ for (ServiceReference ref : references) {
+
+ if (ref.getBundle() != osgiBundle)
+ continue;
+ Object compName = ref.getProperty(COMPONENT_SERVICE_NAME);
+ if (compName == null && reference == null)
+ reference = ref;
+ if (compServiceName.equals(compName)) {
+ reference = ref;
+ break;
+ }
+ }
+ }
+
+ return reference;
+ }
+
+ /**
+ * This method is used to avoid full synchronization of methods which should
+ * be executed only once.
+ *
+ * entryCount=0: The count is incremented, and this thread executes the method. Returns true.
+ *
+ * entryCount=1: Another thread is already executing this method.
+ * Wait for the thread to complete if doWait is true. Returns false.
+ *
+ * entryCount=2: The method has already been executed. Returns false.
+ *
+ * @param doWait If true, and another method is executing this method
+ * wait for method execution to complete
+ * @param entryCount Atomic integer used to ensure that the method is
+ * executed only once
+ * @return true if this thread has exclusive access to execute this method
+ */
+ private boolean enterMethod(boolean doWait, AtomicInteger entryCount) {
+
+ if (entryCount.compareAndSet(0, 1)) {
+ return true;
+ } else {
+ if (doWait) {
+ synchronized (entryCount) {
+ if (entryCount.get() != 2) {
+ try {
+ entryCount.wait(METHOD_TIMEOUT_MILLIS);
+ } catch (InterruptedException e) {
+ }
+ }
+ }
+ }
+ return false;
+ }
+ }
+
+ /**
+ * Called on method exit of methods which were entered after
+ * enterMethod returned true. Increments entryCount, and wakes
+ * up threads waiting for the method to complete.
+ *
+ * @param entryCount Atomic integer used for synchronization
+ */
+ private void exitMethod(AtomicInteger entryCount) {
+ entryCount.compareAndSet(1, 2);
+ synchronized (entryCount) {
+ entryCount.notifyAll();
+ }
+ }
+
+ protected Bundle startBundle(boolean doWait) throws ObjectCreationException {
+
+ try {
+
+ if (enterMethod(doWait, startBundleEntryCount)) {
+
+ configurePropertiesUsingConfigAdmin();
+
+ resolveBundle();
+
+ for (Bundle bundle : dependentBundles) {
+ try {
+ if (bundle.getState() != Bundle.ACTIVE && bundle.getState() != Bundle.STARTING) {
+ bundle.start();
+ }
+ } catch (BundleException e) {
+ if (bundle.getHeaders().get("Fragment-Host") == null)
+ throw e;
+ }
+ }
+
+ }
+
+ if (osgiBundle.getState() != Bundle.ACTIVE && osgiBundle.getState() != Bundle.STARTING) {
+
+ int retry = 0;
+
+ while (retry++ < 10) {
+ try {
+ AccessController.doPrivileged(new PrivilegedExceptionAction<Object>() {
+ public Object run() throws BundleException {
+ osgiBundle.start();
+ return null;
+ }
+ });
+ break;
+ // } catch ( BundleException e) {
+ } catch (PrivilegedActionException e) {
+ // It is possible that the thread "Refresh Packages" is in the process of
+ // changing the state of this bundle.
+ Thread.yield();
+
+ if (retry == 10)
+ throw e;
+ }
+ }
+ }
+
+ } catch (Exception e) {
+ throw new ObjectCreationException(e);
+ } finally {
+ exitMethod(startBundleEntryCount);
+ }
+ return osgiBundle;
+ }
+
+ // This method is called by OSGiInstanceWrapper.getInstance to obtain the OSGi service reference
+ // corresponding to the specified service. The properties used to filter the service should
+ // be chosen based on whether this is a normal service or a callback.
+ /**
+ * @param component
+ * @param service
+ * @return
+ */
+ protected ServiceReference getOSGiServiceReference(Component component, ComponentService service)
+ throws ObjectCreationException {
+
+ Hashtable<String, Object> props = getOSGiProperties(service);
+
+ String filter = getOSGiFilter(props);
+ Interface serviceInterface = service.getInterfaceContract().getInterface();
+ String scaServiceName = service.getName();
+
+ return getOSGiServiceReference(serviceInterface, filter, scaServiceName);
+
+ }
+
+ /**
+ * Get all the OSGi properties from the extension list
+ * @param extensible
+ * @return
+ */
+ private Hashtable<String, Object> getOSGiProperties(Extensible extensible) {
+ Hashtable<String, Object> props = new Hashtable<String, Object>();
+ for (Object ext : extensible.getExtensions()) {
+ if (ext instanceof OSGiProperty) {
+ OSGiProperty p = (OSGiProperty)ext;
+ props.put(p.getName(), p.getValue());
+ }
+ }
+ return props;
+ }
+
+ protected ServiceReference getOSGiServiceReference(EndpointReference from, Interface callbackInterface)
+ throws ObjectCreationException {
+
+ RuntimeWire refWire = null;
+ String filter = null;
+ for (RuntimeWire wire : referenceWires.keySet()) {
+ if (wire.getSource() == from) {
+ refWire = wire;
+ break;
+ }
+ }
+ if (refWire != null) {
+ ComponentReference scaRef = componentReferenceWires.get(refWire);
+ Hashtable<String, Object> props = getOSGiProperties(scaRef);
+ filter = getOSGiFilter(props);
+ }
+
+ return getOSGiServiceReference(callbackInterface, filter, null);
+ }
+
+ private ServiceReference getOSGiServiceReference(Interface serviceInterface, String filter, String scaServiceName)
+ throws ObjectCreationException {
+
+ try {
+
+ String serviceInterfaceName = null;
+
+ ServiceReference osgiServiceReference = null;
+
+ if (serviceInterface instanceof JavaInterface) {
+ serviceInterfaceName = ((JavaInterface)serviceInterface).getJavaClass().getName();
+
+ if ((osgiServiceReference = getOSGiServiceReference(scaServiceName, serviceInterfaceName, filter)) == null) {
+
+ // The service listener for our bundle will notify us when the service is registered.
+ synchronized (implementation) {
+
+ // When declarative services are used, the component is started asynchronously
+ // So this thread has to wait for the service to be registered by the component
+ // activate method
+ // For regular bundle activators, bundle.start activates the bundle synchronously
+ // and hence the service would probably have been started by the bundle activator
+ long startTime = System.currentTimeMillis();
+ while ((osgiServiceReference =
+ getOSGiServiceReference(scaServiceName, serviceInterfaceName, filter)) == null) {
+
+ // Wait for the bundle to register the service
+ implementation.wait(100);
+ if (System.currentTimeMillis() - startTime > SERVICE_TIMEOUT_MILLIS)
+ break;
+ }
+ }
+
+ }
+ }
+
+ return osgiServiceReference;
+
+ } catch (Exception e) {
+ throw new ObjectCreationException(e);
+ }
+ }
+
+ /**
+ * For OSGi->Java wires, create a proxy corresponding to the Java interfaces
+ * and register the proxy with the OSGi registry, so that the source OSGi bundle can
+ * locate the target Java instance from the registry like a regular OSGi service.
+ *
+ * For OSGi->OSGi wires, start the target OSGi bundle, so that references of the
+ * target are resolved before the source OSGi bundle is started. If the reference
+ * has properties specified, create a Proxy and register a service with highest
+ * possible ranking. The Proxy should wire to the correct OSGi instance specified
+ * in the SCA composite.
+ *
+ * The first phase determines whether a proxy should be installed. It also registers
+ * a dummy bundle if necessary to resolve the bundle. When phase1 is completed on all
+ * wires of the component, the bundle should be resolved. Phase2 registers the proxy service.
+ */
+ private boolean resolveWireResolveReferences(Bundle bundle,
+ Class<?> interfaceClass,
+ RuntimeWire wire,
+ boolean isOSGiToOSGiWire) throws Exception {
+
+ // FIXME: At the moment injection of values into instances require an instance to be obtained
+ // through the instance wrapper, and hence requires a proxy. When we do this processing here,
+ // we don't yet know whether the target requires any property or callback injection. So it is
+ // safer to create a proxy all the time.
+ boolean createProxy = true;
+
+ ComponentReference scaRef = componentReferenceWires.get(wire);
+ Hashtable<String, Object> targetProperties = getOSGiProperties(scaRef);
+
+ if (isOSGiToOSGiWire) {
+
+ OSGiImplementationProvider implProvider =
+ (OSGiImplementationProvider)wire.getTarget().getComponent().getImplementationProvider();
+
+ // This is an OSGi->OSGi wire
+ isOSGiToOSGiWire = true;
+
+ // If the target component is stateless, use a proxy to create a new service each time
+ if (!implProvider.getScope().equals(Scope.COMPOSITE))
+ createProxy = true;
+
+ Interface interfaze = wire.getTarget().getInterfaceContract().getInterface();
+
+ // If the target interface is remotable, create a proxy to support pass-by-value semantics
+ // AllowsPassByReference is not detected until the target instance is obtained.
+ if (interfaze.isRemotable())
+ createProxy = true;
+
+ // If any of the operations in the target interface is non-blocking, create a proxy
+ List<Operation> ops = interfaze.getOperations();
+ for (Operation op : ops) {
+ if (op.isNonBlocking())
+ createProxy = true;
+ }
+
+ // If properties are specified for the reference, create a proxy since rewiring may be required
+ if (targetProperties.size() > 0) {
+ createProxy = true;
+ }
+
+ // If properties are specified for the component, create a proxy for configuring
+ // the component services.
+ if (componentProperties.size() > 0) {
+ createProxy = true;
+ }
+
+ // Since this is an OSGi->OSGi wire, start the target bundle before starting the
+ // source bundle if there is no proxy. For direct wiring without a proxy, this ordering
+ // is irrelevant in terms of class resolution, but the target needs to be started at some
+ // point. But there is no opportunity later on to start the target OSGi bundle without a proxy.
+ // When a Proxy is used, the target bundle needs to be resolved for the source bundle
+ // to be resolved so that the interface is visible to the source. In this case the bundle
+ // will be started when an instance is needed.
+ if (!createProxy) {
+ implProvider.startBundle(false);
+ } else {
+ implProvider.resolveBundle();
+ }
+ } else {
+ createProxy = true;
+ }
+
+ return createProxy;
+ }
+
+ // Register proxy service
+ private void resolveWireRegisterProxyService(final Bundle bundle, final Class interfaceClass, RuntimeWire wire)
+ throws Exception {
+
+ ComponentReference scaRef = componentReferenceWires.get(wire);
+ Hashtable<String, Object> targetProperties = getOSGiProperties(scaRef);
+ targetProperties.put(Constants.SERVICE_RANKING, Integer.MAX_VALUE);
+
+ if (targetProperties.get(COMPONENT_SERVICE_NAME) == null && wire.getTarget().getComponent() != null) {
+ String compServiceName =
+ wire.getTarget().getComponent().getName() + "/" + wire.getTarget().getContract().getName();
+ targetProperties.put(COMPONENT_SERVICE_NAME, compServiceName);
+ }
+
+ ProxyFactory proxyService = proxyFactoryExtensionPoint.getInterfaceProxyFactory();
+ if (!interfaceClass.isInterface()) {
+ proxyService = proxyFactoryExtensionPoint.getClassProxyFactory();
+ }
+
+ // Allow privileged access to load classes. Requires getClassLoader permission in security
+ // policy.
+ final Class<?> proxyInterface = AccessController.doPrivileged(new PrivilegedExceptionAction<Class<?>>() {
+ public Class<?> run() throws Exception {
+ return bundle.loadClass(interfaceClass.getName());
+ }
+ });
+
+ final Object proxy = proxyService.createProxy(proxyInterface, wire);
+ final Hashtable<String, Object> finalTargetProperties = targetProperties;
+ AccessController.doPrivileged(new PrivilegedExceptionAction<Object>() {
+ public Object run() throws Exception {
+ osgiBundle.getBundleContext().registerService(proxyInterface.getName(), proxy, finalTargetProperties);
+ return null;
+ }
+ });
+
+ }
+
+ private void refreshPackages() {
+
+ if (packageAdmin != null) {
+ synchronized (this) {
+ packagesRefreshed = false;
+ packageAdmin.refreshPackages(null);
+
+ if (!packagesRefreshed) {
+ try {
+ this.wait(2000);
+ } catch (InterruptedException e) {
+ // ignore
+ }
+ }
+ packagesRefreshed = false;
+ }
+ }
+ }
+
+ private void resolveBundle() throws ObjectCreationException {
+
+ try {
+
+ if (!wiresResolved) {
+ wiresResolved = true;
+
+ if (!setReferencesAndProperties()) {
+ wiresResolved = false;
+ return;
+ }
+
+ int refPlusServices = referenceWires.size() + runtimeComponent.getServices().size();
+ boolean[] createProxyService = new boolean[refPlusServices];
+ Class<?>[] interfaceClasses = new Class<?>[refPlusServices];
+ boolean[] isOSGiToOSGiWire = new boolean[refPlusServices];
+ boolean[] wireResolved = new boolean[refPlusServices];
+ int index = 0;
+ for (RuntimeWire wire : referenceWires.keySet()) {
+
+ Reference reference = referenceWires.get(wire);
+
+ isOSGiToOSGiWire[index] =
+ wire.getTarget().getComponent() != null && wire.getTarget().getComponent()
+ .getImplementationProvider() instanceof OSGiImplementationProvider;
+
+ Interface refInterface = reference.getInterfaceContract().getInterface();
+ if (refInterface instanceof JavaInterface) {
+ interfaceClasses[index] = ((JavaInterface)refInterface).getJavaClass();
+
+ // if (!isOSGiToOSGiWire[index])
+ // resolveWireCreateDummyBundles(interfaceClasses[index]);
+
+ }
+
+ if (!resolvedWires.contains(wire)) {
+ resolvedWires.add(wire);
+ } else
+ wireResolved[index] = true;
+
+ index++;
+ }
+ for (ComponentService service : runtimeComponent.getServices()) {
+ Interface callbackInterface = service.getInterfaceContract().getCallbackInterface();
+ if (callbackInterface instanceof JavaInterface) {
+ interfaceClasses[index] = ((JavaInterface)callbackInterface).getJavaClass();
+
+// resolveWireCreateDummyBundles(interfaceClasses[index]);
+ }
+
+ index++;
+ }
+
+ index = 0;
+ for (RuntimeWire wire : referenceWires.keySet()) {
+
+ if (!wireResolved[index]) {
+ createProxyService[index] =
+ resolveWireResolveReferences(osgiBundle,
+ interfaceClasses[index],
+ wire,
+ isOSGiToOSGiWire[index]);
+ }
+ index++;
+ }
+
+ refreshPackages();
+
+ index = 0;
+ for (RuntimeWire wire : referenceWires.keySet()) {
+
+ if (createProxyService[index] && !wireResolved[index])
+ resolveWireRegisterProxyService(osgiBundle, interfaceClasses[index], wire);
+ index++;
+ }
+ } else if (osgiBundle.getState() == Bundle.INSTALLED && packageAdmin != null) {
+ packageAdmin.resolveBundles(new Bundle[] {osgiBundle});
+ }
+
+ } catch (Exception e) {
+ e.printStackTrace();
+ throw new ObjectCreationException(e);
+ }
+ }
+
+ @SuppressWarnings("unchecked")
+ private void configurePropertiesUsingConfigAdmin() {
+
+ try {
+
+ if (componentProperties.size() == 0)
+ return;
+
+ ServiceReference configAdminReference =
+ osgiBundle.getBundleContext().getServiceReference("org.osgi.service.cm.ConfigurationAdmin");
+ if (configAdminReference != null) {
+
+ Object cm = osgiBundle.getBundleContext().getService(configAdminReference);
+ Class cmClass = cm.getClass().getClassLoader().loadClass("org.osgi.service.cm.ConfigurationAdmin");
+ Method getConfigMethod = cmClass.getMethod("getConfiguration", String.class, String.class);
+
+ Class configClass = cm.getClass().getClassLoader().loadClass("org.osgi.service.cm.Configuration");
+
+ Method getMethod = configClass.getMethod("getProperties");
+ Method updateMethod = configClass.getMethod("update", Dictionary.class);
+
+ List<Service> services = implementation.getServices();
+ HashSet<String> pidsProcessed = new HashSet<String>();
+
+ for (Service service : services) {
+
+ Hashtable<String, Object> properties = getOSGiProperties(service);
+ String pid = null;
+
+ if (properties != null) {
+ for (Map.Entry<String, Object> prop : properties.entrySet()) {
+ pid = (String)prop.getValue();
+ }
+ }
+ if (pid == null || pidsProcessed.contains(pid))
+ continue;
+
+ Object config = getConfigMethod.invoke(cm, pid, null);
+ Dictionary props = (Dictionary)getMethod.invoke(config);
+ if (props == null) {
+ props = new Hashtable<String, Object>();
+ }
+ for (String propertyName : componentProperties.keySet()) {
+
+ props.put(propertyName, componentProperties.get(propertyName));
+ }
+
+ updateMethod.invoke(config, props);
+
+ }
+
+ }
+
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+
+ }
+
+ public boolean isOptimizable() {
+ return false;
+ }
+
+ public Scope getScope() {
+ return Scope.COMPOSITE;
+ }
+
+ public boolean isEagerInit() {
+ return false;
+ }
+
+ public long getMaxAge() {
+ return 0l;
+ }
+
+ public long getMaxIdleTime() {
+ return 0l;
+ }
+
+ public Invoker createTargetInvoker(RuntimeComponentService service, Operation operation) {
+ Interface serviceInterface = operation.getInterface();
+ Invoker invoker = new OSGiTargetInvoker(operation, this, service);
+ return invoker;
+ }
+
+ public Invoker createInvoker(RuntimeComponentService service, Operation operation) {
+ return createTargetInvoker(service, operation);
+ }
+
+ public boolean supportsOneWayInvocation() {
+ return false;
+ }
+
+ private boolean setReferencesAndProperties() {
+
+ for (Reference ref : implementation.getReferences()) {
+ List<RuntimeWire> wireList = null;
+ ComponentReference compRef = null;
+ for (ComponentReference cRef : runtimeComponent.getReferences()) {
+ if (cRef.getName().equals(ref.getName())) {
+
+ wireList = ((RuntimeComponentReference)cRef).getRuntimeWires();
+
+ compRef = cRef;
+ break;
+ }
+ }
+
+ if (ref.getMultiplicity() == Multiplicity.ONE_N || ref.getMultiplicity() == Multiplicity.ZERO_N) {
+ for (RuntimeWire wire : wireList) {
+ referenceWires.put(wire, ref);
+ componentReferenceWires.put(wire, compRef);
+ }
+
+ } else {
+ if (wireList == null && ref.getMultiplicity() == Multiplicity.ONE_ONE) {
+ throw new IllegalStateException("Required reference is missing: " + ref.getName());
+ }
+ if (wireList != null && !wireList.isEmpty()) {
+ RuntimeWire wire = wireList.get(0);
+ referenceWires.put(wire, ref);
+ componentReferenceWires.put(wire, compRef);
+ }
+
+ }
+
+ }
+
+ componentProperties = getOSGiProperties(runtimeComponent);
+
+ return true;
+
+ }
+
+ public void start() {
+ setReferencesAndProperties();
+ }
+
+ public void stop() {
+
+ if (osgiServiceListener != null) {
+ OSGiImplementationRuntimeActivator.getBundleContext().removeServiceListener(osgiServiceListener);
+ }
+ }
+
+ public void frameworkEvent(FrameworkEvent event) {
+ if (event.getType() == FrameworkEvent.PACKAGES_REFRESHED) {
+ synchronized (this) {
+ packagesRefreshed = true;
+ this.notifyAll();
+ }
+ }
+
+ }
+
+ public void bundleChanged(BundleEvent event) {
+ if (event.getType() == BundleEvent.RESOLVED && event.getBundle() == osgiBundle) {
+ // TODO
+ }
+ }
+
+ private class OSGiServiceListener implements ServiceListener {
+
+ private Bundle bundle;
+
+ OSGiServiceListener(Bundle bundle) {
+ this.bundle = bundle;
+ }
+
+ public void serviceChanged(org.osgi.framework.ServiceEvent event) {
+
+ ServiceReference reference = event.getServiceReference();
+
+ if (event.getType() == ServiceEvent.REGISTERED && reference.getBundle() == bundle) {
+
+ synchronized (implementation) {
+
+ implementation.notifyAll();
+ }
+ }
+
+ if (event.getType() == ServiceEvent.UNREGISTERING && reference.getBundle() == bundle) {
+ // TODO: Process deregistering of OSGi services.
+ }
+ }
+ }
+}
diff --git a/java/sca/modules/implementation-osgi-runtime/src/main/java/org/apache/tuscany/sca/implementation/osgi/runtime/OSGiImplementationProviderFactory.java b/java/sca/modules/implementation-osgi-runtime/src/main/java/org/apache/tuscany/sca/implementation/osgi/runtime/OSGiImplementationProviderFactory.java
new file mode 100644
index 0000000000..0e4a3ef995
--- /dev/null
+++ b/java/sca/modules/implementation-osgi-runtime/src/main/java/org/apache/tuscany/sca/implementation/osgi/runtime/OSGiImplementationProviderFactory.java
@@ -0,0 +1,59 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.tuscany.sca.implementation.osgi.runtime;
+
+import org.apache.tuscany.sca.core.ExtensionPointRegistry;
+import org.apache.tuscany.sca.core.invocation.ProxyFactoryExtensionPoint;
+import org.apache.tuscany.sca.implementation.osgi.OSGiImplementation;
+import org.apache.tuscany.sca.provider.ImplementationProvider;
+import org.apache.tuscany.sca.provider.ImplementationProviderFactory;
+import org.apache.tuscany.sca.runtime.RuntimeComponent;
+import org.osgi.framework.BundleException;
+
+/**
+ * Builds a OSGi-based implementation provider from a component definition
+ *
+ * @version $Rev$ $Date$
+ */
+public class OSGiImplementationProviderFactory implements ImplementationProviderFactory<OSGiImplementation> {
+
+ private ProxyFactoryExtensionPoint proxyFactoryExtensionPoint;
+
+ public OSGiImplementationProviderFactory(ExtensionPointRegistry extensionPoints) {
+ proxyFactoryExtensionPoint = extensionPoints.getExtensionPoint(ProxyFactoryExtensionPoint.class);
+ }
+
+ public ImplementationProvider createImplementationProvider(RuntimeComponent component,
+ OSGiImplementation implementation) {
+
+ try {
+
+ return new OSGiImplementationProvider(component, implementation, proxyFactoryExtensionPoint);
+
+ } catch (BundleException e) {
+ throw new RuntimeException(e);
+ }
+
+ }
+
+ public Class<OSGiImplementation> getModelType() {
+ return OSGiImplementation.class;
+ }
+
+}
diff --git a/java/sca/modules/implementation-osgi-runtime/src/main/java/org/apache/tuscany/sca/implementation/osgi/runtime/OSGiImplementationRuntimeActivator.java b/java/sca/modules/implementation-osgi-runtime/src/main/java/org/apache/tuscany/sca/implementation/osgi/runtime/OSGiImplementationRuntimeActivator.java
new file mode 100644
index 0000000000..4567f8a708
--- /dev/null
+++ b/java/sca/modules/implementation-osgi-runtime/src/main/java/org/apache/tuscany/sca/implementation/osgi/runtime/OSGiImplementationRuntimeActivator.java
@@ -0,0 +1,83 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS 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.implementation.osgi.runtime;
+
+import static org.apache.tuscany.sca.implementation.osgi.runtime.OSGiImplementationManager.isSCABundle;
+
+import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleActivator;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.BundleEvent;
+import org.osgi.framework.SynchronousBundleListener;
+
+/**
+ * Bundle activator to receive the BundleContext
+ */
+public class OSGiImplementationRuntimeActivator implements BundleActivator, SynchronousBundleListener {
+ private static BundleContext bundleContext;
+ private boolean inited;
+
+ private void init() {
+ synchronized (this) {
+ if (inited) {
+ return;
+ }
+ inited = true;
+ }
+ }
+
+ public void start(BundleContext context) throws Exception {
+ bundleContext = context;
+ boolean found = false;
+ for (Bundle b : context.getBundles()) {
+ if (isSCABundle(b)) {
+ found = true;
+ break;
+ }
+ }
+
+ if (found) {
+ init();
+ } else {
+ context.addBundleListener(this);
+ }
+ }
+
+ public void stop(BundleContext context) throws Exception {
+ context.removeBundleListener(this);
+ bundleContext = null;
+ }
+
+ public static BundleContext getBundleContext() {
+ return bundleContext;
+ }
+
+ public void bundleChanged(BundleEvent event) {
+ if (event.getType() == BundleEvent.STARTING) {
+ if (isSCABundle(event.getBundle())) {
+ // The bundle is an SCA implementation, init implementation.osgi
+ bundleContext.removeBundleListener(this);
+ init();
+ }
+ }
+
+ }
+
+}
diff --git a/java/sca/modules/implementation-osgi-runtime/src/main/java/org/apache/tuscany/sca/implementation/osgi/runtime/OSGiServiceTracker.java b/java/sca/modules/implementation-osgi-runtime/src/main/java/org/apache/tuscany/sca/implementation/osgi/runtime/OSGiServiceTracker.java
new file mode 100644
index 0000000000..c7fd3058dc
--- /dev/null
+++ b/java/sca/modules/implementation-osgi-runtime/src/main/java/org/apache/tuscany/sca/implementation/osgi/runtime/OSGiServiceTracker.java
@@ -0,0 +1,40 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.tuscany.sca.implementation.osgi.runtime;
+
+import org.osgi.framework.ServiceReference;
+import org.osgi.util.tracker.ServiceTrackerCustomizer;
+
+/**
+ * A ServiceTracker
+ */
+public class OSGiServiceTracker implements ServiceTrackerCustomizer {
+
+ public Object addingService(ServiceReference serviceReference) {
+ return null;
+ }
+
+ public void modifiedService(ServiceReference serviceReference, Object service) {
+ }
+
+ public void removedService(ServiceReference serviceReference, Object service) {
+ }
+
+}
diff --git a/java/sca/modules/implementation-osgi-runtime/src/main/java/org/apache/tuscany/sca/implementation/osgi/runtime/OSGiTargetInvoker.java b/java/sca/modules/implementation-osgi-runtime/src/main/java/org/apache/tuscany/sca/implementation/osgi/runtime/OSGiTargetInvoker.java
new file mode 100644
index 0000000000..f6e2eb09ed
--- /dev/null
+++ b/java/sca/modules/implementation-osgi-runtime/src/main/java/org/apache/tuscany/sca/implementation/osgi/runtime/OSGiTargetInvoker.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.implementation.osgi.runtime;
+
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+
+import org.apache.tuscany.sca.core.factory.InstanceWrapper;
+import org.apache.tuscany.sca.interfacedef.Operation;
+import org.apache.tuscany.sca.interfacedef.java.JavaInterface;
+import org.apache.tuscany.sca.interfacedef.java.impl.JavaInterfaceUtil;
+import org.apache.tuscany.sca.invocation.Invoker;
+import org.apache.tuscany.sca.invocation.Message;
+import org.apache.tuscany.sca.runtime.RuntimeComponent;
+import org.apache.tuscany.sca.runtime.RuntimeComponentService;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.ServiceReference;
+
+/**
+ * Java->OSGi references use OSGiTargetInvoker to call methods from OSGi bundles
+ * OSGi->Java references use JDKProxyService and invocation handler and do not use this class
+ * OSGi->OSGi references go through OSGi reference mechanisms when a proxy is not used
+ * When a proxy is used, this invoker is used to call methods from OSGi bundles
+ * A proxy is used for OSGi->OSGi if
+ * 1) target reference properties are specified OR
+ * 2) there are one or more non-blocking methods in the target interface OR
+ * 3) scope is not COMPOSITE
+ *
+ * @version $Rev$ $Date$
+ */
+public class OSGiTargetInvoker<T> implements Invoker {
+
+ private Operation operation;
+ protected InstanceWrapper<T> target;
+
+ private final OSGiImplementationProvider provider;
+ private final RuntimeComponent component;
+ private final RuntimeComponentService service;
+
+ public OSGiTargetInvoker(Operation operation, OSGiImplementationProvider provider, RuntimeComponentService service) {
+
+ this.operation = operation;
+ this.service = service;
+ this.provider = provider;
+ this.component = provider.getRuntimeComponent();
+
+ }
+
+ private Object invokeTarget(Message msg) throws InvocationTargetException {
+
+ Operation op = msg.getOperation();
+ if (op == null) {
+ op = this.operation;
+ }
+
+ try {
+ BundleContext bundleContext = provider.getImplementation().getBundle().getBundleContext();
+ JavaInterface javaInterface = (JavaInterface)op.getInterface();
+ // FIXME: What is the filter?
+ String filter = "(sca.service=" + component.getURI() + "#service-name\\(" + service.getName() + "\\))";
+ ServiceReference[] refs = bundleContext.getServiceReferences(javaInterface.getName(), filter);
+ Object instance = bundleContext.getService(refs[0]);
+ Method m = JavaInterfaceUtil.findMethod(instance.getClass(), operation);
+
+ Object ret = invokeMethod(instance, m, msg);
+
+ return ret;
+ } catch (InvocationTargetException e) {
+ throw e;
+ } catch (Exception e) {
+ throw new InvocationTargetException(e);
+ }
+ }
+
+ protected Object invokeMethod(Object instance, Method m, Message msg) throws InvocationTargetException {
+
+ try {
+
+ Object payload = msg.getBody();
+
+ if (payload != null && !payload.getClass().isArray()) {
+ return m.invoke(instance, payload);
+ } else {
+ return m.invoke(instance, (Object[])payload);
+ }
+
+ } catch (InvocationTargetException e) {
+ throw e;
+ } catch (Exception e) {
+ throw new InvocationTargetException(e);
+ }
+ }
+
+ public Message invoke(Message msg) {
+ try {
+ Object resp = invokeTarget(msg);
+ msg.setBody(resp);
+ } catch (InvocationTargetException e) {
+ msg.setFaultBody(e.getCause());
+ }
+ return msg;
+ }
+
+}
diff --git a/java/sca/modules/implementation-osgi-runtime/src/main/resources/META-INF/definitions.xml b/java/sca/modules/implementation-osgi-runtime/src/main/resources/META-INF/definitions.xml
new file mode 100644
index 0000000000..f531c2c4ed
--- /dev/null
+++ b/java/sca/modules/implementation-osgi-runtime/src/main/resources/META-INF/definitions.xml
@@ -0,0 +1,37 @@
+<?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:definitions xmlns:sca="http://docs.oasis-open.org/ns/opencsa/sca/200903"
+ targetNamespace="http://www.osgi.org/xmlns/sca/intents/v1.0.0">
+
+ <intent name="passByReference" constrains="sca:implementation"
+ intentType="implementation">
+ <description>
+ An OSGi intent to pass data by reference
+ </description>
+ </intent>
+
+ <intent name="passByValue" constrains="sca:implementation"
+ intentType="implementation">
+ <description>
+ An OSGi intent to pass data by value
+ </description>
+ </intent>
+
+</sca:definitions> \ No newline at end of file
diff --git a/java/sca/modules/implementation-osgi-runtime/src/main/resources/META-INF/services/org.apache.tuscany.sca.provider.ImplementationProviderFactory b/java/sca/modules/implementation-osgi-runtime/src/main/resources/META-INF/services/org.apache.tuscany.sca.provider.ImplementationProviderFactory
new file mode 100644
index 0000000000..c2cd957351
--- /dev/null
+++ b/java/sca/modules/implementation-osgi-runtime/src/main/resources/META-INF/services/org.apache.tuscany.sca.provider.ImplementationProviderFactory
@@ -0,0 +1,19 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+
+# Implementation class for the implementation extension
+org.apache.tuscany.sca.implementation.osgi.runtime.OSGiImplementationProviderFactory;model=org.apache.tuscany.sca.implementation.osgi.OSGiImplementation
diff --git a/java/sca/modules/implementation-osgi-runtime/src/main/resources/impl-osgi-validation-messages.properties b/java/sca/modules/implementation-osgi-runtime/src/main/resources/impl-osgi-validation-messages.properties
new file mode 100644
index 0000000000..2503be0b13
--- /dev/null
+++ b/java/sca/modules/implementation-osgi-runtime/src/main/resources/impl-osgi-validation-messages.properties
@@ -0,0 +1,25 @@
+#
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+#
+ContributionReadException = ContributionReadException occured due to:
+ContributionResolveException = ContributionResolveException occured due to:
+PropertyShouldSpecifySR = Properties in implementation.osgi should specify service or reference
+CouldNotLocateOSGiBundle = Could not locate OSGi bundle: {0}
+MissingComponentTypeFile = Missing .componentType side file: {0} \ No newline at end of file
diff --git a/java/sca/modules/implementation-osgi-runtime/src/test/java/calculator/CalculatorActivator.java b/java/sca/modules/implementation-osgi-runtime/src/test/java/calculator/CalculatorActivator.java
new file mode 100644
index 0000000000..1489ae2b07
--- /dev/null
+++ b/java/sca/modules/implementation-osgi-runtime/src/test/java/calculator/CalculatorActivator.java
@@ -0,0 +1,74 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES 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;
+
+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.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");
+ 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/modules/implementation-osgi-runtime/src/test/java/calculator/CalculatorService.java b/java/sca/modules/implementation-osgi-runtime/src/test/java/calculator/CalculatorService.java
new file mode 100644
index 0000000000..0f7dec116f
--- /dev/null
+++ b/java/sca/modules/implementation-osgi-runtime/src/test/java/calculator/CalculatorService.java
@@ -0,0 +1,39 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package calculator;
+
+import java.rmi.Remote;
+import java.rmi.RemoteException;
+
+import org.oasisopen.sca.annotation.Remotable;
+
+/**
+ * The Calculator service interface.
+ */
+@Remotable
+public interface CalculatorService 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/modules/implementation-osgi-runtime/src/test/java/calculator/CalculatorServiceDSImpl.java b/java/sca/modules/implementation-osgi-runtime/src/test/java/calculator/CalculatorServiceDSImpl.java
new file mode 100644
index 0000000000..7f9fa6803c
--- /dev/null
+++ b/java/sca/modules/implementation-osgi-runtime/src/test/java/calculator/CalculatorServiceDSImpl.java
@@ -0,0 +1,113 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package calculator;
+
+import org.osgi.service.component.ComponentContext;
+
+import calculator.operations.AddService;
+import calculator.operations.DivideService;
+import calculator.operations.MultiplyService;
+import calculator.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/modules/implementation-osgi-runtime/src/test/java/calculator/CalculatorServiceImpl.java b/java/sca/modules/implementation-osgi-runtime/src/test/java/calculator/CalculatorServiceImpl.java
new file mode 100644
index 0000000000..2d36ba76ad
--- /dev/null
+++ b/java/sca/modules/implementation-osgi-runtime/src/test/java/calculator/CalculatorServiceImpl.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;
+
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.Constants;
+import org.osgi.framework.Filter;
+import org.osgi.framework.InvalidSyntaxException;
+import org.osgi.util.tracker.ServiceTracker;
+
+import calculator.operations.AddService;
+import calculator.operations.DivideService;
+import calculator.operations.MultiplyService;
+import calculator.operations.SubtractService;
+
+/**
+ * An implementation of the Calculator service.
+ */
+public class CalculatorServiceImpl implements CalculatorService {
+// private AddService addService;
+// private SubtractService subtractService;
+// private MultiplyService multiplyService;
+// private DivideService divideService;
+
+ private ServiceTracker tracker;
+
+ public CalculatorServiceImpl() {
+ super();
+ }
+
+ public CalculatorServiceImpl(BundleContext context) {
+ super();
+ Filter filter = null;
+ try {
+ filter = context.createFilter("(" + Constants.OBJECTCLASS + "=calculator.operations.*)");
+ } catch (InvalidSyntaxException e) {
+ e.printStackTrace();
+ }
+ this.tracker = new ServiceTracker(context, filter, null);
+ tracker.open();
+ }
+
+ /*
+ * The following setters can be used for DS injection
+ */
+ /*
+ public void setAddService(AddService addService) {
+ 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;
+ }
+ */
+
+ private <T> T getService(Class<T> cls) {
+ for (Object s : tracker.getServices()) {
+ 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/modules/implementation-osgi-runtime/src/test/java/calculator/operations/AddService.java b/java/sca/modules/implementation-osgi-runtime/src/test/java/calculator/operations/AddService.java
new file mode 100644
index 0000000000..2fe405a322
--- /dev/null
+++ b/java/sca/modules/implementation-osgi-runtime/src/test/java/calculator/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.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/modules/implementation-osgi-runtime/src/test/java/calculator/operations/AddServiceImpl.java b/java/sca/modules/implementation-osgi-runtime/src/test/java/calculator/operations/AddServiceImpl.java
new file mode 100644
index 0000000000..685d641b1c
--- /dev/null
+++ b/java/sca/modules/implementation-osgi-runtime/src/test/java/calculator/operations/AddServiceImpl.java
@@ -0,0 +1,35 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package calculator.operations;
+
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+/**
+ * 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/modules/implementation-osgi-runtime/src/test/java/calculator/operations/DivideService.java b/java/sca/modules/implementation-osgi-runtime/src/test/java/calculator/operations/DivideService.java
new file mode 100644
index 0000000000..dfc5df6784
--- /dev/null
+++ b/java/sca/modules/implementation-osgi-runtime/src/test/java/calculator/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.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/modules/implementation-osgi-runtime/src/test/java/calculator/operations/DivideServiceImpl.java b/java/sca/modules/implementation-osgi-runtime/src/test/java/calculator/operations/DivideServiceImpl.java
new file mode 100644
index 0000000000..945b0315b0
--- /dev/null
+++ b/java/sca/modules/implementation-osgi-runtime/src/test/java/calculator/operations/DivideServiceImpl.java
@@ -0,0 +1,35 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package calculator.operations;
+
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+/**
+ * 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/modules/implementation-osgi-runtime/src/test/java/calculator/operations/MultiplyService.java b/java/sca/modules/implementation-osgi-runtime/src/test/java/calculator/operations/MultiplyService.java
new file mode 100644
index 0000000000..b70c233f1a
--- /dev/null
+++ b/java/sca/modules/implementation-osgi-runtime/src/test/java/calculator/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.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/modules/implementation-osgi-runtime/src/test/java/calculator/operations/MultiplyServiceImpl.java b/java/sca/modules/implementation-osgi-runtime/src/test/java/calculator/operations/MultiplyServiceImpl.java
new file mode 100644
index 0000000000..175322c14d
--- /dev/null
+++ b/java/sca/modules/implementation-osgi-runtime/src/test/java/calculator/operations/MultiplyServiceImpl.java
@@ -0,0 +1,35 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package calculator.operations;
+
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+/**
+ * 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/modules/implementation-osgi-runtime/src/test/java/calculator/operations/OperationsActivator.java b/java/sca/modules/implementation-osgi-runtime/src/test/java/calculator/operations/OperationsActivator.java
new file mode 100644
index 0000000000..5da79ee803
--- /dev/null
+++ b/java/sca/modules/implementation-osgi-runtime/src/test/java/calculator/operations/OperationsActivator.java
@@ -0,0 +1,63 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package calculator.operations;
+
+import java.util.Dictionary;
+import java.util.Hashtable;
+import java.util.logging.Logger;
+
+import org.osgi.framework.BundleActivator;
+import org.osgi.framework.BundleContext;
+
+/**
+ *
+ */
+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>();
+
+ logger.info("Registering " + AddService.class.getName());
+ props.put("sca.service", "AddComponent#service-name(Add)");
+ context.registerService(AddService.class.getName(), new AddServiceImpl(), props);
+
+ logger.info("Registering " + SubtractService.class.getName());
+ props.put("sca.service", "SubtractComponent#service-name(Subtract)");
+ context.registerService(SubtractService.class.getName(), new SubtractServiceImpl(), props);
+
+ logger.info("Registering " + MultiplyService.class.getName());
+ props.put("sca.service", "MultiplyComponent#service-name(Multiply)");
+ context.registerService(MultiplyService.class.getName(), new MultiplyServiceImpl(), props);
+
+ logger.info("Registering " + DivideService.class.getName());
+ props.put("sca.service", "DivideComponent#service-name(Divide)");
+ context.registerService(DivideService.class.getName(), new DivideServiceImpl(), props);
+
+ }
+
+ public void stop(BundleContext context) throws Exception {
+ logger.info("Stopping " + context.getBundle());
+ // Registered services will be automatically unregistered
+ }
+
+}
diff --git a/java/sca/modules/implementation-osgi-runtime/src/test/java/calculator/operations/SubtractService.java b/java/sca/modules/implementation-osgi-runtime/src/test/java/calculator/operations/SubtractService.java
new file mode 100644
index 0000000000..1d83a23229
--- /dev/null
+++ b/java/sca/modules/implementation-osgi-runtime/src/test/java/calculator/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.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/modules/implementation-osgi-runtime/src/test/java/calculator/operations/SubtractServiceImpl.java b/java/sca/modules/implementation-osgi-runtime/src/test/java/calculator/operations/SubtractServiceImpl.java
new file mode 100644
index 0000000000..cf1744bc61
--- /dev/null
+++ b/java/sca/modules/implementation-osgi-runtime/src/test/java/calculator/operations/SubtractServiceImpl.java
@@ -0,0 +1,35 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package calculator.operations;
+
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+/**
+ * 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/modules/implementation-osgi-runtime/src/test/java/calculator/test/CalculatorOSGiTestCase.java b/java/sca/modules/implementation-osgi-runtime/src/test/java/calculator/test/CalculatorOSGiTestCase.java
new file mode 100644
index 0000000000..3477732c5f
--- /dev/null
+++ b/java/sca/modules/implementation-osgi-runtime/src/test/java/calculator/test/CalculatorOSGiTestCase.java
@@ -0,0 +1,200 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package calculator.test;
+
+import java.io.File;
+import java.lang.reflect.InvocationHandler;
+import java.lang.reflect.Method;
+import java.lang.reflect.Proxy;
+import java.net.URL;
+import java.util.HashSet;
+import java.util.Set;
+
+import org.apache.tuscany.sca.implementation.osgi.test.OSGiTestBundles;
+import org.apache.tuscany.sca.node.equinox.launcher.EquinoxHost;
+import org.junit.AfterClass;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.ServiceReference;
+
+import calculator.CalculatorActivator;
+import calculator.CalculatorService;
+import calculator.CalculatorServiceDSImpl;
+import calculator.CalculatorServiceImpl;
+import calculator.operations.AddService;
+import calculator.operations.AddServiceImpl;
+import calculator.operations.DivideService;
+import calculator.operations.DivideServiceImpl;
+import calculator.operations.MultiplyService;
+import calculator.operations.MultiplyServiceImpl;
+import calculator.operations.OperationsActivator;
+import calculator.operations.SubtractService;
+import calculator.operations.SubtractServiceImpl;
+
+/**
+ *
+ */
+public class CalculatorOSGiTestCase {
+ private static EquinoxHost host;
+
+ /**
+ * @throws java.lang.Exception
+ */
+ @BeforeClass
+ public static void setUpBeforeClass() throws Exception {
+ Set<URL> bundles = new HashSet<URL>();
+
+ File plugins = new File("target/test-classes/plugins");
+ for (File f : plugins.listFiles()) {
+ if (f.isFile()) {
+ bundles.add(f.toURI().toURL());
+ }
+ }
+
+ bundles.add(OSGiTestBundles.createBundle("target/test-classes/calculator-bundle.jar",
+ "calculator/META-INF/MANIFEST.MF",
+ new String[] {"OSGI-INF/calculator-component.xml"},
+ CalculatorService.class,
+ CalculatorServiceImpl.class,
+ CalculatorServiceDSImpl.class,
+ CalculatorActivator.class));
+
+ bundles.add(OSGiTestBundles.createBundle("target/test-classes/operations-bundle.jar",
+ "calculator/operations/META-INF/MANIFEST.MF",
+ new String[] {"OSGI-INF/add-component.xml",
+ "OSGI-INF/subtract-component.xml",
+ "OSGI-INF/multiply-component.xml",
+ "OSGI-INF/divide-component.xml"},
+ OperationsActivator.class,
+ AddService.class,
+ AddServiceImpl.class,
+ SubtractService.class,
+ SubtractServiceImpl.class,
+ MultiplyService.class,
+ MultiplyServiceImpl.class,
+ DivideService.class,
+ DivideServiceImpl.class));
+ try {
+ host = new EquinoxHost(bundles);
+ BundleContext context = host.start();
+ for (Bundle b : context.getBundles()) {
+ if (b.getSymbolicName().equals("org.eclipse.equinox.ds")) {
+ b.start();
+ System.out.println(string(b, false));
+ }
+ }
+ for (Bundle b : context.getBundles()) {
+ if (b.getSymbolicName().startsWith("calculator")) {
+ b.start();
+ System.out.println(string(b, false));
+ }
+ }
+ ServiceReference ref = context.getServiceReference(CalculatorService.class.getName());
+ CalculatorService calculator = cast(context.getService(ref), 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));
+ } catch (Exception e) {
+ e.printStackTrace();
+ throw e;
+ }
+ }
+
+ private 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)));
+ }
+ }
+
+ 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);
+ }
+
+ }
+
+ @Test
+ public void testOSGi() {
+
+ }
+
+ /**
+ * Returns a string representation of the given bundle.
+ *
+ * @param b
+ * @param verbose
+ * @return
+ */
+ static String string(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();
+ }
+
+ /**
+ * @throws java.lang.Exception
+ */
+ @AfterClass
+ public static void tearDownAfterClass() throws Exception {
+ if (host != null) {
+ host.stop();
+ }
+ }
+
+}
diff --git a/java/sca/modules/implementation-osgi-runtime/src/test/java/org/apache/tuscany/sca/implementation/osgi/runtime/OSGiTestCase.java b/java/sca/modules/implementation-osgi-runtime/src/test/java/org/apache/tuscany/sca/implementation/osgi/runtime/OSGiTestCase.java
new file mode 100644
index 0000000000..e95629c611
--- /dev/null
+++ b/java/sca/modules/implementation-osgi-runtime/src/test/java/org/apache/tuscany/sca/implementation/osgi/runtime/OSGiTestCase.java
@@ -0,0 +1,84 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS 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.implementation.osgi.runtime;
+
+import java.io.File;
+import java.lang.reflect.Proxy;
+import java.net.URL;
+
+import org.apache.tuscany.sca.implementation.osgi.test.OSGiTestBundles;
+import org.apache.tuscany.sca.implementation.osgi.test.OSGiTestImpl;
+import org.apache.tuscany.sca.implementation.osgi.test.OSGiTestInterface;
+import org.apache.tuscany.sca.node.Node;
+import org.apache.tuscany.sca.node.equinox.launcher.Contribution;
+import org.apache.tuscany.sca.node.equinox.launcher.NodeLauncher;
+import org.junit.AfterClass;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+/**
+ *
+ * Test the execution of an OSGi implementation type
+ *
+ * @version $Rev$ $Date$
+ */
+public class OSGiTestCase {
+ private static NodeLauncher host;
+ private static Node node;
+
+ @BeforeClass
+ public static void setUp() throws Exception {
+ host = NodeLauncher.newInstance();
+ String compositeName = "osgitest.composite";
+ URL bundle =
+ OSGiTestBundles.createBundle("target/test-classes/OSGiTestService.jar",
+ "osgi.test",
+ null,
+ null,
+ (String[])null,
+ OSGiTestImpl.class,
+ OSGiTestInterface.class);
+
+ node =
+ host.createNode(compositeName, new Contribution("c1", new File("target/test-classes").toURI().toString()));
+ node.start();
+ }
+
+ @AfterClass
+ public static void tearDown() throws Exception {
+ if (host != null) {
+ node.stop();
+ host.destroy();
+ }
+ }
+
+ @Test
+ public void testOSGiComponent() throws Exception {
+
+ OSGiTestInterface testService = node.getService(OSGiTestInterface.class, "OSGiTestServiceComponent");
+ assert (testService != null);
+
+ assert (testService instanceof Proxy);
+
+ String str = testService.testService();
+ System.out.println(str);
+ }
+
+}
diff --git a/java/sca/modules/implementation-osgi-runtime/src/test/java/org/apache/tuscany/sca/implementation/osgi/test/OSGiTestBundles.java b/java/sca/modules/implementation-osgi-runtime/src/test/java/org/apache/tuscany/sca/implementation/osgi/test/OSGiTestBundles.java
new file mode 100644
index 0000000000..6d55f6b7ec
--- /dev/null
+++ b/java/sca/modules/implementation-osgi-runtime/src/test/java/org/apache/tuscany/sca/implementation/osgi/test/OSGiTestBundles.java
@@ -0,0 +1,180 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS 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.implementation.osgi.test;
+
+import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.URL;
+import java.util.HashSet;
+import java.util.Set;
+import java.util.jar.JarOutputStream;
+import java.util.jar.Manifest;
+import java.util.zip.ZipEntry;
+
+import org.osgi.framework.BundleActivator;
+import org.osgi.framework.Constants;
+
+/**
+ *
+ * Utility class to create OSGi bundles
+ *
+ * @version $Rev$ $Date$
+ */
+public class OSGiTestBundles {
+ private static String getPackageName(Class<?> cls) {
+ String name = cls.getName();
+ int index = name.lastIndexOf('.');
+ return index == -1 ? "" : name.substring(0, index);
+ }
+
+ public static URL createBundle(String jarName, String mfFile, String[] resources, Class<?>... classes)
+ throws IOException {
+ InputStream is = OSGiTestBundles.class.getClassLoader().getResourceAsStream(mfFile);
+ Manifest manifest = new Manifest(is);
+ is.close();
+
+ ByteArrayOutputStream out = new ByteArrayOutputStream();
+ JarOutputStream jarOut = new JarOutputStream(out, manifest);
+
+ for (Class<?> cls : classes) {
+ addClass(jarOut, cls);
+ }
+
+ if (resources != null) {
+ for (String resource : resources) {
+ addResource(jarOut, OSGiTestBundles.class.getClassLoader(), resource);
+ }
+ }
+
+ jarOut.close();
+ out.close();
+
+ File jar = new File(jarName);
+ FileOutputStream fileOut = new FileOutputStream(jar);
+ fileOut.write(out.toByteArray());
+ fileOut.close();
+
+ return jar.toURI().toURL();
+ }
+
+ public static URL createBundle(String jarName,
+ String bundleName,
+ String exports,
+ String imports,
+ String[] resources,
+ Class<?>... classes) throws IOException {
+
+ Class<?> activator = null;
+ Set<String> packages = new HashSet<String>();
+ StringBuffer exportPackages = new StringBuffer();
+ if (exports != null) {
+ exportPackages.append(exports);
+ }
+ for (Class<?> cls : classes) {
+ if (BundleActivator.class.isAssignableFrom(cls)) {
+ activator = cls;
+ }
+ if (exports == null && cls.isInterface()) {
+ String pkg = getPackageName(cls);
+ if (packages.add(pkg)) {
+ exportPackages.append(pkg).append(",");
+ }
+ }
+ }
+ int len = exportPackages.length();
+ if (len > 0 && exportPackages.charAt(len - 1) == ',') {
+ exportPackages.deleteCharAt(len - 1);
+ }
+
+ Manifest manifest = new Manifest();
+ // This attribute Manifest-Version is required so that the MF will be added to the jar
+ manifest.getMainAttributes().putValue("Manifest-Version", "1.0");
+ manifest.getMainAttributes().putValue(Constants.BUNDLE_MANIFESTVERSION, "2");
+ manifest.getMainAttributes().putValue(Constants.BUNDLE_SYMBOLICNAME, bundleName);
+ manifest.getMainAttributes().putValue(Constants.BUNDLE_VERSION, "1.0.0");
+ manifest.getMainAttributes().putValue(Constants.BUNDLE_NAME, bundleName);
+ manifest.getMainAttributes().putValue(Constants.EXPORT_PACKAGE, exportPackages.toString());
+ StringBuffer importPackages = new StringBuffer();
+ if (imports != null) {
+ importPackages.append(imports).append(",org.osgi.framework");
+ } else {
+ importPackages.append("org.osgi.framework");
+ }
+ manifest.getMainAttributes().putValue(Constants.IMPORT_PACKAGE, importPackages.toString());
+
+ if (activator != null) {
+ manifest.getMainAttributes().putValue(Constants.BUNDLE_ACTIVATOR, activator.getName());
+ }
+
+ ByteArrayOutputStream out = new ByteArrayOutputStream();
+ JarOutputStream jarOut = new JarOutputStream(out, manifest);
+
+ for (Class<?> cls : classes) {
+ addClass(jarOut, cls);
+ }
+
+ if (resources != null) {
+ for (String resource : resources) {
+ addResource(jarOut, OSGiTestBundles.class.getClassLoader(), resource);
+ }
+ }
+
+ jarOut.close();
+ out.close();
+
+ File jar = new File(jarName);
+ FileOutputStream fileOut = new FileOutputStream(jar);
+ fileOut.write(out.toByteArray());
+ fileOut.close();
+
+ return jar.toURI().toURL();
+ }
+
+ private static void addClass(JarOutputStream jarOut, Class<?> javaClass) throws IOException, FileNotFoundException {
+ String classFile = javaClass.getName().replace('.', '/') + ".class";
+ URL url = javaClass.getResource(javaClass.getSimpleName() + ".class");
+ addEntry(jarOut, url, classFile);
+ }
+
+ private static void addResource(JarOutputStream jarOut, ClassLoader cl, String resourceName) throws IOException,
+ FileNotFoundException {
+ URL url = cl.getResource(resourceName);
+ addEntry(jarOut, url, resourceName);
+ }
+
+ private static void addEntry(JarOutputStream jarOut, URL url, String resourceName) throws IOException,
+ FileNotFoundException {
+ String path = url.getPath();
+
+ ZipEntry ze = new ZipEntry(resourceName);
+
+ jarOut.putNextEntry(ze);
+ FileInputStream file = new FileInputStream(path);
+ byte[] fileContents = new byte[file.available()];
+ file.read(fileContents);
+ jarOut.write(fileContents);
+ jarOut.closeEntry();
+ }
+}
diff --git a/java/sca/modules/implementation-osgi-runtime/src/test/java/org/apache/tuscany/sca/implementation/osgi/test/OSGiTestImpl.java b/java/sca/modules/implementation-osgi-runtime/src/test/java/org/apache/tuscany/sca/implementation/osgi/test/OSGiTestImpl.java
new file mode 100644
index 0000000000..f6db6edc12
--- /dev/null
+++ b/java/sca/modules/implementation-osgi-runtime/src/test/java/org/apache/tuscany/sca/implementation/osgi/test/OSGiTestImpl.java
@@ -0,0 +1,50 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.tuscany.sca.implementation.osgi.test;
+
+import java.util.Hashtable;
+
+import org.osgi.framework.BundleActivator;
+import org.osgi.framework.BundleContext;
+
+/**
+ *
+ * Test class - Implementation of an OSGi service
+ *
+ * @version $Rev$ $Date$
+ */
+public class OSGiTestImpl implements OSGiTestInterface, BundleActivator {
+
+ public String testService() {
+
+ return OSGiTestImpl.class.getName();
+
+ }
+
+ public void start(BundleContext bc) throws Exception {
+
+ bc.registerService(OSGiTestInterface.class.getName(), this, new Hashtable<String, Object>());
+
+ }
+
+ public void stop(BundleContext bc) throws Exception {
+ }
+
+}
diff --git a/java/sca/modules/implementation-osgi-runtime/src/test/java/org/apache/tuscany/sca/implementation/osgi/test/OSGiTestInterface.java b/java/sca/modules/implementation-osgi-runtime/src/test/java/org/apache/tuscany/sca/implementation/osgi/test/OSGiTestInterface.java
new file mode 100644
index 0000000000..499ec8082e
--- /dev/null
+++ b/java/sca/modules/implementation-osgi-runtime/src/test/java/org/apache/tuscany/sca/implementation/osgi/test/OSGiTestInterface.java
@@ -0,0 +1,32 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS 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.implementation.osgi.test;
+
+/**
+ *
+ * Test class - Interface for an OSGi service
+ *
+ * @version $Rev$ $Date$
+ */
+public interface OSGiTestInterface {
+
+ String testService() throws Exception;
+
+}
diff --git a/java/sca/modules/implementation-osgi-runtime/src/test/resources/OSGI-INF/add-component.xml b/java/sca/modules/implementation-osgi-runtime/src/test/resources/OSGI-INF/add-component.xml
new file mode 100644
index 0000000000..f1ed05111a
--- /dev/null
+++ b/java/sca/modules/implementation-osgi-runtime/src/test/resources/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.operations.AddServiceImpl" />
+ <service>
+ <provide interface="calculator.operations.AddService" />
+ </service>
+</scr:component>
diff --git a/java/sca/modules/implementation-osgi-runtime/src/test/resources/OSGI-INF/calculator-component.xml b/java/sca/modules/implementation-osgi-runtime/src/test/resources/OSGI-INF/calculator-component.xml
new file mode 100644
index 0000000000..442ab858e9
--- /dev/null
+++ b/java/sca/modules/implementation-osgi-runtime/src/test/resources/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.CalculatorServiceDSImpl" />
+ <service>
+ <provide interface="calculator.CalculatorService" />
+ </service>
+
+ <reference name="addService" interface="calculator.operations.AddService" bind="setAddService" unbind="unsetAddService"
+ policy="dynamic" />
+ <reference name="subtractService" interface="calculator.operations.SubtractService" bind="setSubtractService"
+ unbind="unsetSubtractService" policy="dynamic" />
+ <reference name="multiplyService" interface="calculator.operations.MultiplyService" bind="setMultiplyService"
+ unbind="unsetMultiplyService" policy="dynamic" />
+ <reference name="divideService" interface="calculator.operations.DivideService" bind="setDivideService"
+ unbind="unsetDivideService" policy="dynamic" />
+
+</scr:component>
diff --git a/java/sca/modules/implementation-osgi-runtime/src/test/resources/OSGI-INF/divide-component.xml b/java/sca/modules/implementation-osgi-runtime/src/test/resources/OSGI-INF/divide-component.xml
new file mode 100644
index 0000000000..60a6cef4e1
--- /dev/null
+++ b/java/sca/modules/implementation-osgi-runtime/src/test/resources/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.operations.DivideServiceImpl" />
+ <service>
+ <provide interface="calculator.operations.DivideService" />
+ </service>
+</scr:component>
diff --git a/java/sca/modules/implementation-osgi-runtime/src/test/resources/OSGI-INF/multiply-component.xml b/java/sca/modules/implementation-osgi-runtime/src/test/resources/OSGI-INF/multiply-component.xml
new file mode 100644
index 0000000000..2fd843b272
--- /dev/null
+++ b/java/sca/modules/implementation-osgi-runtime/src/test/resources/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.operations.MultiplyServiceImpl" />
+ <service>
+ <provide interface="calculator.operations.MultiplyService" />
+ </service>
+</scr:component>
diff --git a/java/sca/modules/implementation-osgi-runtime/src/test/resources/OSGI-INF/sca/bundle.componentType b/java/sca/modules/implementation-osgi-runtime/src/test/resources/OSGI-INF/sca/bundle.componentType
new file mode 100644
index 0000000000..73c7ca7c13
--- /dev/null
+++ b/java/sca/modules/implementation-osgi-runtime/src/test/resources/OSGI-INF/sca/bundle.componentType
@@ -0,0 +1,54 @@
+<?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.
+-->
+<componentType xmlns="http://docs.oasis-open.org/ns/opencsa/sca/200903"
+ xmlns:xsd="http://www.w3.org/2001/XMLSchema"
+ xmlns:t="http://tuscany.apache.org/xmlns/sca/1.1">
+ <!-- The service elment defines an SCA view of the OSGi service -->
+ <service name="Calculator">
+ <!-- The interface will be mapped into the OSGi service class -->
+ <interface.java interface="calculator.CalculatorService"/>
+ <!-- The list of OSGi properties -->
+ <t:osgi.property name="prop1">1</t:osgi.property>
+ <t:osgi.property name="prop2">ABC</t:osgi.property>
+ </service>
+
+ <!-- The reference elment defines an SCA proxy to a remote OSGi service -->
+ <reference name="addService">
+ <interface.java interface="calculator.operations.AddService"/>
+ <t:osgi.property name="prop1">1</t:osgi.property>
+ <t:osgi.property name="prop2">ABC</t:osgi.property>
+ </reference>
+ <reference name="subtractService">
+ <interface.java interface="calculator.operations.SubtractService"/>
+ <t:osgi.property name="prop1">1</t:osgi.property>
+ <t:osgi.property name="prop2">ABC</t:osgi.property>
+ </reference>
+ <reference name="multiplyService">
+ <interface.java interface="calculator.operations.MultiplyService"/>
+ <t:osgi.property name="prop1">1</t:osgi.property>
+ <t:osgi.property name="prop2">ABC</t:osgi.property>
+ </reference>
+ <reference name="divideService">
+ <interface.java interface="calculator.operations.DivideService"/>
+ <t:osgi.property name="prop1">1</t:osgi.property>
+ <t:osgi.property name="prop2">ABC</t:osgi.property>
+ </reference>
+
+</componentType>
diff --git a/java/sca/modules/implementation-osgi-runtime/src/test/resources/OSGI-INF/subtract-component.xml b/java/sca/modules/implementation-osgi-runtime/src/test/resources/OSGI-INF/subtract-component.xml
new file mode 100644
index 0000000000..ceb0a5d821
--- /dev/null
+++ b/java/sca/modules/implementation-osgi-runtime/src/test/resources/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.operations.SubtractServiceImpl" />
+ <service>
+ <provide interface="calculator.operations.SubtractService" />
+ </service>
+</scr:component>
diff --git a/java/sca/modules/implementation-osgi-runtime/src/test/resources/calculator/META-INF/MANIFEST.MF b/java/sca/modules/implementation-osgi-runtime/src/test/resources/calculator/META-INF/MANIFEST.MF
new file mode 100644
index 0000000000..808cc60c79
--- /dev/null
+++ b/java/sca/modules/implementation-osgi-runtime/src/test/resources/calculator/META-INF/MANIFEST.MF
@@ -0,0 +1,18 @@
+Manifest-Version: 1.0
+Export-Package: calculator;version="1.0.0"
+Bundle-Version: 1.0.0
+Bundle-Name: calculator
+Bundle-Activator: calculator.CalculatorActivator
+Bundle-ManifestVersion: 2
+Import-Package: calculator.operations;version="1.0.0",
+ org.osgi.framework,
+ org.osgi.service.packageadmin,
+ org.osgi.util.tracker,
+ org.osgi.service.component;resolution:=optional
+Bundle-SymbolicName: calculator
+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
diff --git a/java/sca/modules/implementation-osgi-runtime/src/test/resources/calculator/calculator.composite b/java/sca/modules/implementation-osgi-runtime/src/test/resources/calculator/calculator.composite
new file mode 100644
index 0000000000..9674e6d68f
--- /dev/null
+++ b/java/sca/modules/implementation-osgi-runtime/src/test/resources/calculator/calculator.composite
@@ -0,0 +1,38 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+-->
+<composite xmlns="http://docs.oasis-open.org/ns/opencsa/sca/200903"
+ xmlns:tuscany="http://tuscany.apache.org/xmlns/sca/1.1"
+ xmlns:xsd="http://www.w3.org/2001/XMLSchema"
+ targetNamespace="http://calculator"
+ name="CalculatorComposite">
+
+ <component name="CalculatorComponent">
+ <tuscany:implementation.osgi bundleSymbolicName="calculator" bundleVersion="1.0.0" />
+ <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/modules/implementation-osgi-runtime/src/test/resources/calculator/operations/META-INF/MANIFEST.MF b/java/sca/modules/implementation-osgi-runtime/src/test/resources/calculator/operations/META-INF/MANIFEST.MF
new file mode 100644
index 0000000000..1414d227b0
--- /dev/null
+++ b/java/sca/modules/implementation-osgi-runtime/src/test/resources/calculator/operations/META-INF/MANIFEST.MF
@@ -0,0 +1,19 @@
+Manifest-Version: 1.0
+Export-Package: calculator.operations;version="1.0.0"
+Bundle-Version: 1.0.0
+Bundle-Name: calculator.operations
+Bundle-Activator: calculator.operations.OperationsActivator
+Bundle-ManifestVersion: 2
+Import-Package: calculator.operations;version="1.0.0",
+ org.osgi.framework,
+ org.osgi.service.component;resolution:=optional
+Bundle-SymbolicName: calculator.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
diff --git a/java/sca/modules/implementation-osgi-runtime/src/test/resources/calculator/operations/operations.composite b/java/sca/modules/implementation-osgi-runtime/src/test/resources/calculator/operations/operations.composite
new file mode 100644
index 0000000000..8afb7dc8a2
--- /dev/null
+++ b/java/sca/modules/implementation-osgi-runtime/src/test/resources/calculator/operations/operations.composite
@@ -0,0 +1,38 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+-->
+<composite xmlns="http://docs.oasis-open.org/ns/opencsa/sca/200903"
+ xmlns:tuscany="http://tuscany.apache.org/xmlns/sca/1.1"
+ xmlns:xsd="http://www.w3.org/2001/XMLSchema"
+ targetNamespace="http://calculator"
+ name="OperationsComposite">
+
+ <component name="OperationsComponent">
+ <tuscany:implementation.osgi bundleSymbolicName="calculator.operations" bundleVersion="1.0.0" />
+ <service name="AddService">
+ </service>
+ <service name="SubtractService">
+ </service>
+ <service name="MultiplyService">
+ </service>
+ <service name="DivideService">
+ </service>
+ </component>
+
+</composite>