summaryrefslogtreecommitdiffstats
path: root/sca-java-1.x/tags/1.6.1-TUSCANY-3909/implementation-osgi/src/main/java/org/apache/tuscany/sca
diff options
context:
space:
mode:
Diffstat (limited to 'sca-java-1.x/tags/1.6.1-TUSCANY-3909/implementation-osgi/src/main/java/org/apache/tuscany/sca')
-rw-r--r--sca-java-1.x/tags/1.6.1-TUSCANY-3909/implementation-osgi/src/main/java/org/apache/tuscany/sca/implementation/osgi/OSGiImplementation.java45
-rw-r--r--sca-java-1.x/tags/1.6.1-TUSCANY-3909/implementation-osgi/src/main/java/org/apache/tuscany/sca/implementation/osgi/context/OSGiAnnotations.java325
-rw-r--r--sca-java-1.x/tags/1.6.1-TUSCANY-3909/implementation-osgi/src/main/java/org/apache/tuscany/sca/implementation/osgi/context/OSGiPropertyInjector.java293
-rw-r--r--sca-java-1.x/tags/1.6.1-TUSCANY-3909/implementation-osgi/src/main/java/org/apache/tuscany/sca/implementation/osgi/context/OSGiPropertyValueObjectFactory.java226
-rw-r--r--sca-java-1.x/tags/1.6.1-TUSCANY-3909/implementation-osgi/src/main/java/org/apache/tuscany/sca/implementation/osgi/impl/OSGiImplementationImpl.java168
-rw-r--r--sca-java-1.x/tags/1.6.1-TUSCANY-3909/implementation-osgi/src/main/java/org/apache/tuscany/sca/implementation/osgi/runtime/OSGiImplementationProvider.java1254
-rw-r--r--sca-java-1.x/tags/1.6.1-TUSCANY-3909/implementation-osgi/src/main/java/org/apache/tuscany/sca/implementation/osgi/runtime/OSGiImplementationProviderFactory.java109
-rw-r--r--sca-java-1.x/tags/1.6.1-TUSCANY-3909/implementation-osgi/src/main/java/org/apache/tuscany/sca/implementation/osgi/runtime/OSGiInstanceWrapper.java299
-rw-r--r--sca-java-1.x/tags/1.6.1-TUSCANY-3909/implementation-osgi/src/main/java/org/apache/tuscany/sca/implementation/osgi/runtime/OSGiRemotableInvoker.java139
-rw-r--r--sca-java-1.x/tags/1.6.1-TUSCANY-3909/implementation-osgi/src/main/java/org/apache/tuscany/sca/implementation/osgi/runtime/OSGiTargetInvoker.java199
-rw-r--r--sca-java-1.x/tags/1.6.1-TUSCANY-3909/implementation-osgi/src/main/java/org/apache/tuscany/sca/implementation/osgi/xml/OSGiImplementationProcessor.java550
11 files changed, 3607 insertions, 0 deletions
diff --git a/sca-java-1.x/tags/1.6.1-TUSCANY-3909/implementation-osgi/src/main/java/org/apache/tuscany/sca/implementation/osgi/OSGiImplementation.java b/sca-java-1.x/tags/1.6.1-TUSCANY-3909/implementation-osgi/src/main/java/org/apache/tuscany/sca/implementation/osgi/OSGiImplementation.java
new file mode 100644
index 0000000000..7bcb0a1da5
--- /dev/null
+++ b/sca-java-1.x/tags/1.6.1-TUSCANY-3909/implementation-osgi/src/main/java/org/apache/tuscany/sca/implementation/osgi/OSGiImplementation.java
@@ -0,0 +1,45 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.tuscany.sca.implementation.osgi;
+
+import java.util.List;
+
+import org.apache.tuscany.sca.assembly.ComponentProperty;
+import org.apache.tuscany.sca.assembly.Extensible;
+import org.apache.tuscany.sca.assembly.Implementation;
+
+/**
+ *
+ * The model representing an OSGi implementation in an SCA assembly model.
+ *
+ * @version $Rev$ $Date$
+ */
+public interface OSGiImplementation extends Implementation, Extensible {
+
+ String getBundleSymbolicName();
+
+ String getBundleVersion();
+
+ String[] getImports();
+
+ List<ComponentProperty> getReferenceProperties(String referenceName);
+
+ List<ComponentProperty> getServiceProperties(String serviceName);
+
+}
diff --git a/sca-java-1.x/tags/1.6.1-TUSCANY-3909/implementation-osgi/src/main/java/org/apache/tuscany/sca/implementation/osgi/context/OSGiAnnotations.java b/sca-java-1.x/tags/1.6.1-TUSCANY-3909/implementation-osgi/src/main/java/org/apache/tuscany/sca/implementation/osgi/context/OSGiAnnotations.java
new file mode 100644
index 0000000000..33c790585c
--- /dev/null
+++ b/sca-java-1.x/tags/1.6.1-TUSCANY-3909/implementation-osgi/src/main/java/org/apache/tuscany/sca/implementation/osgi/context/OSGiAnnotations.java
@@ -0,0 +1,325 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES 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.context;
+
+
+import java.lang.reflect.Method;
+import java.security.AccessController;
+import java.security.PrivilegedAction;
+import java.util.ArrayList;
+import java.util.Hashtable;
+
+import org.apache.tuscany.sca.assembly.AssemblyFactory;
+import org.apache.tuscany.sca.context.RequestContextFactory;
+import org.apache.tuscany.sca.contribution.ModelFactoryExtensionPoint;
+import org.apache.tuscany.sca.core.invocation.ProxyFactory;
+import org.apache.tuscany.sca.core.scope.Scope;
+import org.apache.tuscany.sca.implementation.java.DefaultJavaImplementationFactory;
+import org.apache.tuscany.sca.implementation.java.IntrospectionException;
+import org.apache.tuscany.sca.implementation.java.JavaImplementation;
+import org.apache.tuscany.sca.implementation.java.JavaImplementationFactory;
+import org.apache.tuscany.sca.implementation.java.impl.JavaScopeImpl;
+import org.apache.tuscany.sca.implementation.java.injection.JavaPropertyValueObjectFactory;
+import org.apache.tuscany.sca.implementation.java.introspect.JavaClassVisitor;
+import org.apache.tuscany.sca.implementation.java.introspect.impl.AllowsPassByReferenceProcessor;
+import org.apache.tuscany.sca.implementation.java.introspect.impl.BaseJavaClassVisitor;
+import org.apache.tuscany.sca.implementation.java.introspect.impl.ComponentNameProcessor;
+import org.apache.tuscany.sca.implementation.java.introspect.impl.ConstructorProcessor;
+import org.apache.tuscany.sca.implementation.java.introspect.impl.ContextProcessor;
+import org.apache.tuscany.sca.implementation.java.introspect.impl.ConversationProcessor;
+import org.apache.tuscany.sca.implementation.java.introspect.impl.DestroyProcessor;
+import org.apache.tuscany.sca.implementation.java.introspect.impl.EagerInitProcessor;
+import org.apache.tuscany.sca.implementation.java.introspect.impl.HeuristicPojoProcessor;
+import org.apache.tuscany.sca.implementation.java.introspect.impl.InitProcessor;
+import org.apache.tuscany.sca.implementation.java.introspect.impl.PolicyProcessor;
+import org.apache.tuscany.sca.implementation.java.introspect.impl.PropertyProcessor;
+import org.apache.tuscany.sca.implementation.java.introspect.impl.ReferenceProcessor;
+import org.apache.tuscany.sca.implementation.java.introspect.impl.ResourceProcessor;
+import org.apache.tuscany.sca.implementation.java.introspect.impl.ServiceProcessor;
+import org.apache.tuscany.sca.interfacedef.java.JavaInterfaceFactory;
+import org.apache.tuscany.sca.policy.PolicyFactory;
+import org.apache.tuscany.sca.runtime.RuntimeComponent;
+import org.osgi.framework.Bundle;
+
+
+/**
+ * OSGi annotation processing
+ * OSGi bundles are not introspected by OSGiImplementation when a component is created.
+ * Instead if the list of implementation classes is specified in <implementation.osgi/>,
+ * the classes are introspected when the bundle is resolved. The classes are loaded using
+ * the bundle ClassLoader, and hence the delay in annotation processing is inevitable.
+ * There is one other difference compared to implementation.java. While instances (and
+ * the instance class) are associated with a component in Java, all Java annotations from
+ * the component implementation class apply to all the component instances. In OSGi,
+ * instances are associated with services, and a bundle can register multiple services.
+ * Hence annotations from classes need to be stored separately so that the right ones
+ * can be associated with the service instance.
+ *
+ * @version $Rev$ $Date$
+ */
+public class OSGiAnnotations {
+
+ private Scope scope = Scope.COMPOSITE;
+ private boolean isEagerInit;
+
+ private String[] classList;
+
+ private Bundle[] bundles;
+
+ private RuntimeComponent runtimeComponent;
+ private JavaPropertyValueObjectFactory propertyValueFactory;
+ private ProxyFactory proxyFactory;
+
+ private JavaImplementationFactory javaImplementationFactory;
+ private JavaInterfaceFactory javaInterfaceFactory;
+ private PolicyFactory policyFactory;
+ private RequestContextFactory requestContextFactory;
+
+ private Hashtable<Class<?>, JavaImplementation> javaAnnotationInfo =
+ new Hashtable<Class<?>, JavaImplementation>();
+ private Hashtable<JavaImplementation, OSGiPropertyInjector> propertyInjectors =
+ new Hashtable<JavaImplementation, OSGiPropertyInjector>();
+
+ private long maxAge = -1;
+ private long maxIdleTime = -1;
+
+ private boolean annotationsProcessed;
+
+
+
+ public OSGiAnnotations(ModelFactoryExtensionPoint modelFactories,
+ String[] classList,
+ RuntimeComponent runtimeComponent,
+ JavaPropertyValueObjectFactory propertyValueFactory,
+ ProxyFactory proxyFactory,
+ RequestContextFactory requestContextFactory,
+ Bundle mainBundle,
+ ArrayList<Bundle> dependentBundles) {
+
+
+ this.classList = classList;
+ this.runtimeComponent = runtimeComponent;
+ this.propertyValueFactory = propertyValueFactory;
+ this.proxyFactory = proxyFactory;
+
+ AssemblyFactory assemblyFactory = modelFactories.getFactory(AssemblyFactory.class);
+ this.javaInterfaceFactory = modelFactories.getFactory(JavaInterfaceFactory.class);
+ this.javaImplementationFactory = createJavaImplementationFactory(assemblyFactory);
+ this.policyFactory = modelFactories.getFactory(PolicyFactory.class);
+
+ bundles = new Bundle[dependentBundles.size() + 1];
+ bundles[0] = mainBundle;
+ for (int i = 0; i < dependentBundles.size(); i++)
+ bundles[i + 1] = dependentBundles.get(i);
+
+ }
+
+
+ public void processAnnotations() throws IntrospectionException {
+
+ if (annotationsProcessed)
+ return;
+ annotationsProcessed = true;
+ for (String className : classList) {
+ for (Bundle bundle : bundles) {
+ try {
+ Class<?> clazz = bundle.loadClass(className);
+
+ processAnnotations(clazz);
+
+ break;
+
+ } catch (ClassNotFoundException e) {
+ }
+ }
+ }
+ }
+
+
+ public void injectProperties(Object instance) {
+ JavaImplementation javaImpl = getAnnotationInfo(instance);
+ if (javaImpl != null) {
+ OSGiPropertyInjector injector = propertyInjectors.get(javaImpl);
+ if (injector != null)
+ injector.injectProperties(instance);
+ }
+ }
+
+
+ public Scope getScope() {
+ return scope;
+ }
+
+
+
+ public boolean isAllowsPassByReference(Object instance, Method method) {
+
+ JavaImplementation javaImpl = getAnnotationInfo(instance);
+ if (javaImpl == null) {
+ return false;
+ }
+ if (javaImpl.isAllowsPassByReference()) {
+ return true;
+ }
+ return javaImpl.isAllowsPassByReference(method);
+ }
+
+
+ public boolean isEagerInit() {
+ return isEagerInit;
+ }
+
+ public long getMaxAge() {
+ return maxAge;
+ }
+
+ public long getMaxIdleTime() {
+ return maxIdleTime;
+ }
+
+ public Method getInitMethod(Object instance) {
+ JavaImplementation javaImpl = getAnnotationInfo(instance);
+ return javaImpl == null? null : javaImpl.getInitMethod();
+ }
+
+
+ public Method getDestroyMethod(Object instance) {
+ JavaImplementation javaImpl = getAnnotationInfo(instance);
+ return javaImpl == null? null : javaImpl.getDestroyMethod();
+ }
+
+
+ /*
+ * Get the annotation corresponding to an instance
+ *
+ */
+ private JavaImplementation getAnnotationInfo(final Object instance) {
+
+ // The simplest case where the implementation class was listed under the
+ // classes attribute of <implementation.osgi/>, or this is the second call
+ // to this method for the implementation class.
+ // Allow privileged access to get classloader. Requires getClassLoader in security policy.
+ JavaImplementation javaImpl = AccessController.doPrivileged(new PrivilegedAction<JavaImplementation>() {
+ public JavaImplementation run() {
+ return javaAnnotationInfo.get(instance.getClass());
+ }
+ });
+ if (javaImpl != null)
+ return javaImpl;
+
+ // Process annotations from the instance class.
+ try {
+ return processAnnotations(instance.getClass());
+ } catch (IntrospectionException e) {
+ // e.printStackTrace();
+ }
+
+ return null;
+ }
+
+
+ private JavaImplementation processAnnotations(Class<?> clazz)
+ throws IntrospectionException {
+
+ JavaImplementation javaImpl = javaImplementationFactory.createJavaImplementation(clazz);
+
+ javaAnnotationInfo.put(clazz, javaImpl);
+
+ OSGiPropertyInjector propertyInjector = new OSGiPropertyInjector(
+ javaImpl, runtimeComponent, propertyValueFactory, proxyFactory, requestContextFactory);
+
+ propertyInjectors.put(javaImpl, propertyInjector);
+
+ if (javaImpl.isEagerInit())
+ isEagerInit = true;
+ if (javaImpl.getMaxAge() != -1)
+ maxAge = javaImpl.getMaxAge();
+ if (javaImpl.getMaxIdleTime() != -1)
+ maxIdleTime = javaImpl.getMaxIdleTime();
+ if (javaImpl.getJavaScope() != JavaScopeImpl.COMPOSITE)
+ scope = new Scope(javaImpl.getJavaScope().getScope());
+
+ return javaImpl;
+ }
+
+
+
+
+ private JavaImplementationFactory createJavaImplementationFactory(AssemblyFactory assemblyFactory) {
+ JavaImplementationFactory javaImplementationFactory = new DefaultJavaImplementationFactory();
+
+ // Create the list of class visitors
+ BaseJavaClassVisitor[] extensions =
+ new BaseJavaClassVisitor[] {
+ new ConstructorProcessor(assemblyFactory),
+ new AllowsPassByReferenceProcessor(assemblyFactory),
+ new ComponentNameProcessor(assemblyFactory),
+ new ContextProcessor(assemblyFactory),
+ new ConversationProcessor(assemblyFactory),
+ new DestroyProcessor(assemblyFactory),
+ new EagerInitProcessor(assemblyFactory),
+ new InitProcessor(assemblyFactory),
+ new PropertyProcessor(assemblyFactory),
+ new ReferenceProcessor(assemblyFactory, javaInterfaceFactory),
+ new ResourceProcessor(assemblyFactory),
+ new OSGiScopeProcessor(assemblyFactory),
+ new ServiceProcessor(assemblyFactory, javaInterfaceFactory),
+ new HeuristicPojoProcessor(assemblyFactory, javaInterfaceFactory),
+ new PolicyProcessor(assemblyFactory, policyFactory)};
+ for (JavaClassVisitor extension : extensions) {
+ javaImplementationFactory.addClassVisitor(extension);
+ }
+
+ return javaImplementationFactory;
+ }
+
+ private class OSGiScopeProcessor extends BaseJavaClassVisitor {
+
+ public OSGiScopeProcessor(AssemblyFactory factory) {
+ super(factory);
+ }
+
+ @Override
+ public <T> void visitClass(Class<T> clazz,
+ JavaImplementation type)
+ throws IntrospectionException {
+ org.osoa.sca.annotations.Scope annotation = clazz.getAnnotation(org.osoa.sca.annotations.Scope.class);
+ if (annotation == null) {
+ type.setJavaScope(JavaScopeImpl.COMPOSITE);
+ return;
+ }
+ String name = annotation.value();
+ JavaScopeImpl scope;
+ if ("COMPOSITE".equals(name)) {
+ scope = JavaScopeImpl.COMPOSITE;
+ } else if ("SESSION".equals(name)) {
+ scope = JavaScopeImpl.SESSION;
+ } else if ("CONVERSATION".equals(name)) {
+ scope = JavaScopeImpl.CONVERSATION;
+ } else if ("REQUEST".equals(name)) {
+ scope = JavaScopeImpl.REQUEST;
+ } else {
+ scope = new JavaScopeImpl(name);
+ }
+ type.setJavaScope(scope);
+ }
+ }
+
+
+}
diff --git a/sca-java-1.x/tags/1.6.1-TUSCANY-3909/implementation-osgi/src/main/java/org/apache/tuscany/sca/implementation/osgi/context/OSGiPropertyInjector.java b/sca-java-1.x/tags/1.6.1-TUSCANY-3909/implementation-osgi/src/main/java/org/apache/tuscany/sca/implementation/osgi/context/OSGiPropertyInjector.java
new file mode 100644
index 0000000000..0264f0b102
--- /dev/null
+++ b/sca-java-1.x/tags/1.6.1-TUSCANY-3909/implementation-osgi/src/main/java/org/apache/tuscany/sca/implementation/osgi/context/OSGiPropertyInjector.java
@@ -0,0 +1,293 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES 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.context;
+
+
+import java.lang.annotation.ElementType;
+import java.lang.reflect.Constructor;
+import java.lang.reflect.Field;
+import java.lang.reflect.Member;
+import java.lang.reflect.Method;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Hashtable;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.tuscany.sca.assembly.ComponentProperty;
+import org.apache.tuscany.sca.assembly.ComponentService;
+import org.apache.tuscany.sca.context.RequestContextFactory;
+import org.apache.tuscany.sca.core.context.RequestContextImpl;
+import org.apache.tuscany.sca.core.factory.ObjectCreationException;
+import org.apache.tuscany.sca.core.factory.ObjectFactory;
+import org.apache.tuscany.sca.core.invocation.CallbackWireObjectFactory;
+import org.apache.tuscany.sca.core.invocation.ProxyFactory;
+import org.apache.tuscany.sca.implementation.java.IntrospectionException;
+import org.apache.tuscany.sca.implementation.java.JavaImplementation;
+import org.apache.tuscany.sca.implementation.java.impl.JavaElementImpl;
+import org.apache.tuscany.sca.implementation.java.impl.JavaResourceImpl;
+import org.apache.tuscany.sca.implementation.java.injection.ArrayMultiplicityObjectFactory;
+import org.apache.tuscany.sca.implementation.java.injection.ConversationIDObjectFactory;
+import org.apache.tuscany.sca.implementation.java.injection.FieldInjector;
+import org.apache.tuscany.sca.implementation.java.injection.Injector;
+import org.apache.tuscany.sca.implementation.java.injection.InvalidAccessorException;
+import org.apache.tuscany.sca.implementation.java.injection.JavaPropertyValueObjectFactory;
+import org.apache.tuscany.sca.implementation.java.injection.ListMultiplicityObjectFactory;
+import org.apache.tuscany.sca.implementation.java.injection.MethodInjector;
+import org.apache.tuscany.sca.implementation.java.injection.ResourceObjectFactory;
+import org.apache.tuscany.sca.implementation.java.introspect.impl.JavaIntrospectionHelper;
+import org.apache.tuscany.sca.runtime.RuntimeComponent;
+import org.apache.tuscany.sca.runtime.RuntimeComponentReference;
+import org.apache.tuscany.sca.runtime.RuntimeWire;
+import org.osoa.sca.ComponentContext;
+import org.osoa.sca.RequestContext;
+import org.osoa.sca.annotations.ConversationID;
+
+
+/**
+ * OSGi property injection support
+ *
+ * @version $Rev$ $Date$
+ */
+public class OSGiPropertyInjector {
+
+
+ private ArrayList<JavaElementImpl> injectionSites = new ArrayList<JavaElementImpl>();
+ private Hashtable<JavaElementImpl, ObjectFactory> factories =
+ new Hashtable<JavaElementImpl, ObjectFactory>();
+
+ private Injector[] injectors;
+
+ public OSGiPropertyInjector(
+ JavaImplementation javaImpl,
+ RuntimeComponent component,
+ JavaPropertyValueObjectFactory propertyValueFactory,
+ ProxyFactory proxyFactory,
+ RequestContextFactory requestContextFactory) throws IntrospectionException {
+
+ createInjectionSites(javaImpl, component, propertyValueFactory, proxyFactory, requestContextFactory);
+
+ injectors = createInjectors();
+
+ }
+
+
+ @SuppressWarnings("unchecked")
+ public void injectProperties(Object instance) {
+
+ for (Injector injector : injectors) {
+ injector.inject(instance);
+ }
+
+ }
+
+
+ @SuppressWarnings("unchecked")
+ private void createInjectionSites(
+ JavaImplementation javaImpl,
+ RuntimeComponent component,
+ JavaPropertyValueObjectFactory propertyValueFactory,
+ ProxyFactory proxyFactory,
+ RequestContextFactory requestContextFactory)
+ {
+
+ List<ComponentProperty> componentProperties = component.getProperties();
+ Map<String, JavaElementImpl> propertyMembers = javaImpl.getPropertyMembers();
+
+ for (ComponentProperty prop : componentProperties) {
+ JavaElementImpl element = propertyMembers.get(prop.getName());
+
+ if (element != null && !(element.getAnchor() instanceof Constructor) && prop.getValue() != null) {
+ Class propertyJavaType = JavaIntrospectionHelper.getBaseType(element.getType(), element.getGenericType());
+ ObjectFactory objFactory = propertyValueFactory.createValueFactory(prop, prop.getValue(), propertyJavaType);
+
+ factories.put(element, objFactory);
+ injectionSites.add(element);
+ }
+ }
+
+ for (Member member : javaImpl.getConversationIDMembers()) {
+ ObjectFactory<String> factory = new ConversationIDObjectFactory();
+ if (member instanceof Field) {
+ JavaElementImpl element = new JavaElementImpl((Field) member);
+ element.setClassifer(ConversationID.class);
+ injectionSites.add(element);
+ factories.put(element, factory);
+ } else if (member instanceof Method) {
+ JavaElementImpl element = new JavaElementImpl((Method) member, 0);
+ element.setName(JavaIntrospectionHelper.toPropertyName(member.getName()));
+ element.setClassifer(ConversationID.class);
+ injectionSites.add(element);
+ factories.put(element, factory);
+ } else {
+ throw new InvalidAccessorException(
+ "Member must be a field or method: " + member.getName());
+ }
+
+ }
+
+ if (!javaImpl.getCallbackMembers().isEmpty()) {
+ Map<String, List<RuntimeWire>> callbackWires = new HashMap<String, List<RuntimeWire>>();
+ for (ComponentService service : component.getServices()) {
+
+ RuntimeComponentReference callbackReference = (RuntimeComponentReference)service.getCallbackReference();
+ if (callbackReference != null) {
+ List<RuntimeWire> wires = callbackReference.getRuntimeWires();
+ if (!wires.isEmpty()) {
+ callbackWires.put(wires.get(0).getSource().getInterfaceContract().getInterface().toString(), wires);
+ }
+ }
+ }
+
+ for (Map.Entry<String, Collection<JavaElementImpl>> entry : javaImpl.getCallbackMembers()
+ .entrySet()) {
+ List<RuntimeWire> wires = callbackWires.get(entry.getKey());
+ if (wires == null) {
+ // this can happen when there are no client wires to a
+ // component that has a callback
+ continue;
+ }
+ for(JavaElementImpl element : entry.getValue()) {
+ ObjectFactory<?> factory = new CallbackWireObjectFactory(element.getType(), proxyFactory, wires);
+ if (!(element.getAnchor() instanceof Constructor)) {
+ injectionSites.add(element);
+ }
+ factories.put(element, factory);
+ }
+ }
+ }
+
+ for (JavaResourceImpl resource : javaImpl.getResources().values()) {
+
+ ObjectFactory<?> objectFactory;
+ Class<?> type = resource.getElement().getType();
+ if (ComponentContext.class.equals(type)) {
+ objectFactory = new ComponentContextFactory(component);
+
+ } else if (RequestContext.class.equals(type)) {
+ objectFactory = new RequestContextObjectFactory(requestContextFactory, proxyFactory);
+
+ } else {
+ boolean optional = resource.isOptional();
+ String mappedName = resource.getMappedName();
+ objectFactory = new ResourceObjectFactory(type, mappedName, optional, null);
+ }
+ factories.put(resource.getElement(), objectFactory);
+ if (!(resource.getElement().getAnchor() instanceof Constructor)) {
+ injectionSites.add(resource.getElement());
+ }
+ }
+
+
+ }
+
+
+ @SuppressWarnings("unchecked")
+ private Injector[] createInjectors() {
+
+ Injector[] injectors = (Injector[])new Injector[injectionSites.size()];
+
+ int i = 0;
+ for (JavaElementImpl element : injectionSites) {
+ Object obj = factories.get(element);
+ if (obj != null) {
+ if (obj instanceof ObjectFactory) {
+ ObjectFactory<?> factory = (ObjectFactory<?>)obj;
+ Member member = (Member)element.getAnchor();
+ if (element.getElementType() == ElementType.FIELD) {
+ injectors[i++] = new FieldInjector((Field)member, factory);
+ } else if (element.getElementType() == ElementType.PARAMETER && member instanceof Method) {
+ injectors[i++] = new MethodInjector((Method)member, factory);
+ } else if (member instanceof Constructor) {
+ // Ignore
+ } else {
+ throw new AssertionError(String.valueOf(element));
+ }
+ } else {
+ injectors[i++] = createMultiplicityInjector(element, (List<ObjectFactory<?>>)obj);
+ }
+ }
+ }
+ return injectors;
+ }
+
+ @SuppressWarnings("unchecked")
+ protected Injector createMultiplicityInjector(JavaElementImpl element, List<ObjectFactory<?>> factories) {
+ Class<?> interfaceType = JavaIntrospectionHelper.getBaseType(element.getType(), element.getGenericType());
+
+ if (element.getAnchor() instanceof Field) {
+ Field field = (Field)element.getAnchor();
+ if (field.getType().isArray()) {
+ return new FieldInjector(field, new ArrayMultiplicityObjectFactory(interfaceType, factories));
+ } else {
+ return new FieldInjector(field, new ListMultiplicityObjectFactory(factories));
+ }
+ } else if (element.getAnchor() instanceof Method) {
+ Method method = (Method)element.getAnchor();
+ if (method.getParameterTypes()[0].isArray()) {
+ return new MethodInjector(method, new ArrayMultiplicityObjectFactory(interfaceType, factories));
+ } else {
+ return new MethodInjector(method, new ListMultiplicityObjectFactory(factories));
+ }
+ } else {
+ throw new InvalidAccessorException("Member must be a field or method: " + element.getName());
+ }
+ }
+
+ private static class ComponentContextFactory implements ObjectFactory {
+
+ RuntimeComponent component;
+
+ private ComponentContextFactory(RuntimeComponent component) {
+ this.component = component;
+ }
+
+ public Object getInstance() throws ObjectCreationException {
+ return component.getComponentContext();
+ }
+
+ }
+
+
+ private static class RequestContextObjectFactory implements ObjectFactory {
+
+ private RequestContextFactory factory;
+ private ProxyFactory proxyFactory;
+
+ public RequestContextObjectFactory(RequestContextFactory factory) {
+ this(factory, null);
+ }
+
+ public RequestContextObjectFactory(RequestContextFactory factory, ProxyFactory proxyFactory) {
+ this.factory = factory;
+ this.proxyFactory = proxyFactory;
+ }
+
+ public RequestContext getInstance() throws ObjectCreationException {
+ if (factory != null) {
+ return factory.createRequestContext();
+ } else {
+ return new RequestContextImpl(proxyFactory);
+ }
+ }
+
+ }
+
+}
diff --git a/sca-java-1.x/tags/1.6.1-TUSCANY-3909/implementation-osgi/src/main/java/org/apache/tuscany/sca/implementation/osgi/context/OSGiPropertyValueObjectFactory.java b/sca-java-1.x/tags/1.6.1-TUSCANY-3909/implementation-osgi/src/main/java/org/apache/tuscany/sca/implementation/osgi/context/OSGiPropertyValueObjectFactory.java
new file mode 100644
index 0000000000..38befa611b
--- /dev/null
+++ b/sca-java-1.x/tags/1.6.1-TUSCANY-3909/implementation-osgi/src/main/java/org/apache/tuscany/sca/implementation/osgi/context/OSGiPropertyValueObjectFactory.java
@@ -0,0 +1,226 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES 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.context;
+
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.StringTokenizer;
+
+import org.apache.tuscany.sca.assembly.Property;
+import org.apache.tuscany.sca.core.factory.ObjectCreationException;
+import org.apache.tuscany.sca.core.factory.ObjectFactory;
+import org.apache.tuscany.sca.databinding.Mediator;
+import org.apache.tuscany.sca.databinding.SimpleTypeMapper;
+import org.apache.tuscany.sca.databinding.impl.SimpleTypeMapperImpl;
+import org.apache.tuscany.sca.databinding.xml.DOMDataBinding;
+import org.apache.tuscany.sca.interfacedef.DataType;
+import org.apache.tuscany.sca.interfacedef.impl.DataTypeImpl;
+import org.apache.tuscany.sca.interfacedef.util.TypeInfo;
+import org.apache.tuscany.sca.interfacedef.util.XMLType;
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+import org.w3c.dom.Node;
+
+/**
+ *
+ * Process properties and create property values.
+ *
+ * This code has been copied from the Java implementation to avoid dependencies on the Java implementation.
+ *
+ * @version $Rev$ $Date$
+ */
+public class OSGiPropertyValueObjectFactory {
+ protected SimpleTypeMapper simpleTypeMapper = new SimpleTypeMapperImpl();
+ boolean isSimpleType;
+
+
+ public OSGiPropertyValueObjectFactory() {
+ }
+
+ public OSGiPropertyValueObjectFactory(Mediator mediator) {
+ }
+
+ public ObjectFactory createValueFactory(Property property, Object propertyValue) {
+
+ Class javaType = SimpleTypeMapperImpl.getJavaType(property.getXSDType());
+ isSimpleType = isSimpleType(property);
+ Document doc = (Document)propertyValue;
+ Element rootElement = doc.getDocumentElement();
+ if (property.isMany()) {
+ if (isSimpleType) {
+ String value = "";
+ if (rootElement.getChildNodes().getLength() > 0) {
+ value = rootElement.getChildNodes().item(0).getTextContent();
+ }
+ List<String> values =
+ getSimplePropertyValues(value, javaType);
+ return new ListObjectFactoryImpl(property,
+ values,
+ isSimpleType,
+ javaType);
+ } else {
+ return new ListObjectFactoryImpl(property,
+ getComplexPropertyValues(doc),
+ isSimpleType,
+ javaType);
+ }
+ } else {
+ if (isSimpleType) {
+ String value = "";
+ if (rootElement.getChildNodes().getLength() > 0) {
+ value = rootElement.getChildNodes().item(0).getTextContent();
+ }
+ return new ObjectFactoryImpl(property,
+ value,
+ isSimpleType,
+ javaType);
+ } else {
+ Object value = getComplexPropertyValues(doc).get(0);
+ return new ObjectFactoryImpl(property,
+ value,
+ isSimpleType,
+ javaType);
+ }
+
+ }
+ }
+
+ private boolean isSimpleType(Property property) {
+ if (property.getXSDType() != null) {
+ return SimpleTypeMapperImpl.isSimpleXSDType(property.getXSDType());
+ } else {
+ if (property instanceof Document) {
+ Document doc = (Document)property;
+ Element element = doc.getDocumentElement();
+ if (element.getChildNodes().getLength() == 1 &&
+ element.getChildNodes().item(0).getNodeType() == Node.TEXT_NODE) {
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+
+ private List<String> getSimplePropertyValues(String concatenatedValue, Class javaType) {
+ List<String> propValues = new ArrayList<String>();
+ StringTokenizer st = null;
+ if ( javaType.getName().equals("java.lang.String")) {
+ st = new StringTokenizer(concatenatedValue, "\"");
+ } else {
+ st = new StringTokenizer(concatenatedValue);
+ }
+ String aToken = null;
+ while (st.hasMoreTokens()) {
+ aToken = st.nextToken();
+ if (aToken.trim().length() > 0) {
+ propValues.add(aToken);
+ }
+ }
+ return propValues;
+ }
+
+ private List<Node> getComplexPropertyValues(Document document) {
+ Element rootElement = document.getDocumentElement();
+ List<Node> propValues = new ArrayList<Node>();
+ for (int count = 0 ; count < rootElement.getChildNodes().getLength() ; ++count) {
+ if (rootElement.getChildNodes().item(count).getNodeType() == Node.ELEMENT_NODE) {
+ propValues.add(rootElement.getChildNodes().item(count));
+ }
+ }
+ return propValues;
+ }
+
+ public abstract class ObjectFactoryImplBase implements ObjectFactory {
+ protected SimpleTypeMapper simpleTypeMapper = new SimpleTypeMapperImpl();
+ protected Property property;
+ protected Object propertyValue;
+ protected Class javaType;
+ protected DataType<XMLType> sourceDataType;
+ protected DataType<?> targetDataType;
+ boolean isSimpleType;
+
+ public ObjectFactoryImplBase(Property property, Object propertyValue, boolean isSimpleType, Class javaType) {
+ this.isSimpleType = isSimpleType;
+ this.property = property;
+ this.propertyValue = propertyValue;
+ this.javaType = javaType;
+ sourceDataType =
+ new DataTypeImpl<XMLType>(DOMDataBinding.NAME, Node.class,
+ new XMLType(null, this.property.getXSDType()));
+ TypeInfo typeInfo = null;
+ if (this.property.getXSDType() != null) {
+ if (SimpleTypeMapperImpl.isSimpleXSDType(this.property.getXSDType())) {
+ typeInfo = new TypeInfo(property.getXSDType(), true, null);
+ } else {
+ typeInfo = new TypeInfo(property.getXSDType(), false, null);
+ }
+ } else {
+ typeInfo = new TypeInfo(property.getXSDType(), false, null);
+ }
+
+ XMLType xmlType = new XMLType(typeInfo);
+ String dataBinding = null; //(String)property.getExtensions().get(DataBinding.class.getName());
+ if (dataBinding != null) {
+ targetDataType = new DataTypeImpl<XMLType>(dataBinding, javaType, xmlType);
+ } else {
+ targetDataType = new DataTypeImpl<XMLType>(dataBinding, javaType, xmlType);
+ }
+ }
+ }
+
+ public class ObjectFactoryImpl extends ObjectFactoryImplBase {
+ public ObjectFactoryImpl(Property property, Object propertyValue, boolean isSimpleType, Class javaType) {
+ super(property, propertyValue, isSimpleType, javaType);
+ }
+
+ @SuppressWarnings("unchecked")
+ public Object getInstance() throws ObjectCreationException {
+ if (isSimpleType) {
+ return simpleTypeMapper.toJavaObject(property.getXSDType(), (String)propertyValue, null);
+ } else {
+ return null;
+ }
+ }
+ }
+
+ public class ListObjectFactoryImpl extends ObjectFactoryImplBase {
+ public ListObjectFactoryImpl(Property property, List<?>propertyValues, boolean isSimpleType, Class javaType) {
+ super(property, propertyValues, isSimpleType, javaType);
+ }
+
+ @SuppressWarnings("unchecked")
+ public List<?> getInstance() throws ObjectCreationException {
+ if (isSimpleType) {
+ List<Object> values = new ArrayList<Object>();
+ for (String aValue : (List<String>)propertyValue) {
+ values.add(simpleTypeMapper.toJavaObject(property.getXSDType(), aValue, null));
+ }
+ return values;
+ } else {
+ List instances = new ArrayList();
+ for (Node aValue : (List<Node>)propertyValue) {
+ instances.add(aValue);
+ }
+ return instances;
+ }
+ }
+ }
+}
+
diff --git a/sca-java-1.x/tags/1.6.1-TUSCANY-3909/implementation-osgi/src/main/java/org/apache/tuscany/sca/implementation/osgi/impl/OSGiImplementationImpl.java b/sca-java-1.x/tags/1.6.1-TUSCANY-3909/implementation-osgi/src/main/java/org/apache/tuscany/sca/implementation/osgi/impl/OSGiImplementationImpl.java
new file mode 100644
index 0000000000..fe3efd22cd
--- /dev/null
+++ b/sca-java-1.x/tags/1.6.1-TUSCANY-3909/implementation-osgi/src/main/java/org/apache/tuscany/sca/implementation/osgi/impl/OSGiImplementationImpl.java
@@ -0,0 +1,168 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES 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.impl;
+
+
+import java.util.Hashtable;
+import java.util.List;
+
+import org.apache.tuscany.sca.assembly.ComponentProperty;
+import org.apache.tuscany.sca.assembly.impl.ImplementationImpl;
+import org.apache.tuscany.sca.contribution.ModelFactoryExtensionPoint;
+import org.apache.tuscany.sca.implementation.osgi.OSGiImplementation;
+
+
+/**
+ * OSGi implementation
+ * All attributes from <implementation.osgi> have getters in this class
+ * This class implements OSGiImplementationInterface which is associated with OSGiImplementationProvider.
+ *
+ * @version $Rev$ $Date$
+ */
+public class OSGiImplementationImpl extends ImplementationImpl implements OSGiImplementation {
+
+ private String bundleSymbolicName;
+ private String bundleVersion;
+
+ private String[] imports;
+ private Hashtable<String, List<ComponentProperty>> referenceProperties;
+ private Hashtable<String, List<ComponentProperty>> serviceProperties;
+
+ private Hashtable<String, List<ComponentProperty>> referenceCallbackProperties;
+ private Hashtable<String, List<ComponentProperty>> serviceCallbackProperties;
+
+ private String[] classList;
+
+ private ModelFactoryExtensionPoint modelFactories;
+
+ private Object osgiBundle;
+
+ public OSGiImplementationImpl(
+ ModelFactoryExtensionPoint modelFactories,
+ String bundleSymbolicName,
+ String bundleVersion,
+ String[] imports,
+ String[] classList,
+ Hashtable<String, List<ComponentProperty>> refProperties,
+ Hashtable<String, List<ComponentProperty>> serviceProperties) {
+
+ super();
+ this.bundleSymbolicName = bundleSymbolicName;
+ this.bundleVersion = bundleVersion;
+ this.imports = imports;
+ this.referenceProperties = refProperties;
+ this.serviceProperties = serviceProperties;
+ this.classList = classList;
+ this.modelFactories = modelFactories;
+ }
+
+ public void setCallbackProperties(Hashtable<String, List<ComponentProperty>> refCallbackProperties,
+ Hashtable<String, List<ComponentProperty>> serviceCallbackProperties) {
+
+ this.referenceCallbackProperties = refCallbackProperties;
+ this.serviceCallbackProperties = serviceCallbackProperties;
+
+ }
+
+
+ public String getBundleSymbolicName() {
+ return bundleSymbolicName;
+ }
+
+ public String getBundleVersion() {
+ return bundleVersion;
+ }
+
+ public String[] getImports() {
+ return imports;
+ }
+
+ public String[] getClassList() {
+ return classList;
+ }
+
+ public ModelFactoryExtensionPoint getModelFactories() {
+ return modelFactories;
+ }
+
+ public List<ComponentProperty> getReferenceProperties(String referenceName) {
+ return referenceProperties.get(referenceName);
+ }
+
+ public List<ComponentProperty> getServiceProperties(String serviceName) {
+ return serviceProperties.get(serviceName);
+ }
+
+ public List<ComponentProperty> getReferenceCallbackProperties(String referenceName) {
+ return referenceCallbackProperties.get(referenceName);
+ }
+
+ public List<ComponentProperty> getServiceCallbackProperties(String serviceName) {
+ return serviceCallbackProperties.get(serviceName);
+ }
+
+ /**
+ * Since OSGi implementation annotations may not be processed until much later, leave it to
+ * the OSGi invoker to decide whether pass-by-reference is allowed.
+ * @return
+ */
+ public boolean isAllowsPassByReference() {
+ return true;
+ }
+
+ public Object getOSGiBundle() {
+ return osgiBundle;
+ }
+
+ public void setOSGiBundle(Object osgiBundle) {
+ this.osgiBundle = osgiBundle;
+ }
+
+ private boolean areEqual(Object obj1, Object obj2) {
+ if (obj1 == obj2)
+ return true;
+ if (obj1 == null || obj2 == null)
+ return false;
+ return obj1.equals(obj2);
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+
+ if (!(obj instanceof OSGiImplementationImpl))
+ return super.equals(obj);
+ OSGiImplementationImpl impl = (OSGiImplementationImpl)obj;
+ if (!areEqual(bundleSymbolicName, impl.bundleSymbolicName))
+ return false;
+ if (!areEqual(bundleVersion, impl.bundleVersion))
+ return false;
+ if (!areEqual(serviceProperties, impl.serviceProperties))
+ return false;
+ if (!areEqual(serviceCallbackProperties, impl.serviceCallbackProperties))
+ return false;
+ if (!areEqual(referenceProperties, impl.referenceProperties))
+ return false;
+ if (!areEqual(referenceCallbackProperties, impl.referenceCallbackProperties))
+ return false;
+ return super.equals(obj);
+ }
+
+
+
+}
diff --git a/sca-java-1.x/tags/1.6.1-TUSCANY-3909/implementation-osgi/src/main/java/org/apache/tuscany/sca/implementation/osgi/runtime/OSGiImplementationProvider.java b/sca-java-1.x/tags/1.6.1-TUSCANY-3909/implementation-osgi/src/main/java/org/apache/tuscany/sca/implementation/osgi/runtime/OSGiImplementationProvider.java
new file mode 100644
index 0000000000..b49f94c1e0
--- /dev/null
+++ b/sca-java-1.x/tags/1.6.1-TUSCANY-3909/implementation-osgi/src/main/java/org/apache/tuscany/sca/implementation/osgi/runtime/OSGiImplementationProvider.java
@@ -0,0 +1,1254 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES 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.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.InputStream;
+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.StringTokenizer;
+import java.util.concurrent.atomic.AtomicInteger;
+import java.util.jar.JarOutputStream;
+import java.util.jar.Manifest;
+import java.util.zip.ZipEntry;
+
+import org.apache.tuscany.sca.assembly.ComponentProperty;
+import org.apache.tuscany.sca.assembly.ComponentReference;
+import org.apache.tuscany.sca.assembly.ComponentService;
+import org.apache.tuscany.sca.assembly.Multiplicity;
+import org.apache.tuscany.sca.assembly.Property;
+import org.apache.tuscany.sca.assembly.Reference;
+import org.apache.tuscany.sca.assembly.Service;
+import org.apache.tuscany.sca.context.RequestContextFactory;
+import org.apache.tuscany.sca.core.context.InstanceWrapper;
+import org.apache.tuscany.sca.core.factory.ObjectCreationException;
+import org.apache.tuscany.sca.core.factory.ObjectFactory;
+import org.apache.tuscany.sca.core.invocation.JDKProxyFactory;
+import org.apache.tuscany.sca.core.invocation.ProxyFactory;
+import org.apache.tuscany.sca.core.scope.Scope;
+import org.apache.tuscany.sca.core.scope.ScopeContainer;
+import org.apache.tuscany.sca.core.scope.ScopeRegistry;
+import org.apache.tuscany.sca.core.scope.ScopedImplementationProvider;
+import org.apache.tuscany.sca.core.scope.ScopedRuntimeComponent;
+import org.apache.tuscany.sca.databinding.DataBindingExtensionPoint;
+import org.apache.tuscany.sca.databinding.impl.SimpleTypeMapperImpl;
+import org.apache.tuscany.sca.implementation.java.IntrospectionException;
+import org.apache.tuscany.sca.implementation.java.injection.JavaPropertyValueObjectFactory;
+import org.apache.tuscany.sca.implementation.osgi.OSGiImplementation;
+import org.apache.tuscany.sca.implementation.osgi.context.OSGiAnnotations;
+import org.apache.tuscany.sca.implementation.osgi.impl.OSGiImplementationImpl;
+import org.apache.tuscany.sca.interfacedef.Interface;
+import org.apache.tuscany.sca.interfacedef.InterfaceContractMapper;
+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.invocation.MessageFactory;
+import org.apache.tuscany.sca.osgi.runtime.OSGiRuntime;
+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.service.packageadmin.ExportedPackage;
+import org.osgi.service.packageadmin.PackageAdmin;
+
+/**
+ * The runtime instantiation of OSGi component implementations
+ *
+ * @version $Rev$ $Date$
+ */
+public class OSGiImplementationProvider implements ScopedImplementationProvider,
+ 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 OSGiImplementationImpl implementation;
+ private OSGiAnnotations osgiAnnotations;
+ private BundleContext bundleContext;
+
+ 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 AtomicInteger processAnnotationsEntryCount = new AtomicInteger();
+
+ private JavaPropertyValueObjectFactory propertyValueFactory;
+
+
+ private Hashtable<String, Object> componentProperties = new Hashtable<String, Object>();
+ private RuntimeComponent runtimeComponent;
+
+ private Bundle osgiBundle;
+ private ArrayList<Bundle> dependentBundles = new ArrayList<Bundle>();
+ private OSGiServiceListener osgiServiceListener;
+ private PackageAdmin packageAdmin;
+
+ private OSGiRuntime osgiRuntime;
+
+ private ScopeRegistry scopeRegistry;
+ private DataBindingExtensionPoint dataBindingRegistry;
+
+ private boolean packagesRefreshed;
+
+ private MessageFactory messageFactory;
+ private InterfaceContractMapper mapper;
+
+
+ public OSGiImplementationProvider(RuntimeComponent definition,
+ OSGiImplementation impl,
+ DataBindingExtensionPoint dataBindingRegistry,
+ JavaPropertyValueObjectFactory propertyValueFactory,
+ ProxyFactory proxyFactory,
+ ScopeRegistry scopeRegistry,
+ RequestContextFactory requestContextFactory,
+ MessageFactory messageFactory,
+ InterfaceContractMapper mapper) throws BundleException {
+
+
+ this.implementation = (OSGiImplementationImpl)impl;
+ this.runtimeComponent = definition;
+ this.dataBindingRegistry = dataBindingRegistry;
+ this.propertyValueFactory = propertyValueFactory;
+ this.scopeRegistry = scopeRegistry;
+ this.messageFactory = messageFactory;
+ this.mapper = mapper;
+
+ bundleContext = getBundleContext();
+ osgiBundle = (Bundle)implementation.getOSGiBundle();
+ bundleContext.addBundleListener(this);
+ osgiServiceListener = new OSGiServiceListener(osgiBundle);
+ bundleContext.addServiceListener(osgiServiceListener);
+
+ // Install and start all dependent bundles
+ String[] imports = implementation.getImports();
+ for (int i = 0; i < imports.length; i++) {
+ String location = imports[i].trim();
+ if (location.length() > 0) {
+ Bundle bundle = bundleContext.installBundle(location);
+ dependentBundles.add(bundle);
+ }
+ }
+
+
+ this.osgiAnnotations = new OSGiAnnotations(
+ implementation.getModelFactories(),
+ implementation.getClassList(),
+ runtimeComponent,
+ propertyValueFactory,
+ proxyFactory,
+ requestContextFactory,
+ osgiBundle,
+ dependentBundles);
+
+
+ // 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 OSGiImplementationImpl getImplementation() {
+ return implementation;
+ }
+
+ // Create a property table from the list of properties
+ // The source properties are properties read from <property/> elements
+ // Create property values in the table of the appropriate class based
+ // on the property type specified.
+ private void processProperties(List<?> props, Hashtable<String, Object> propsTable) {
+
+ if (props != null) {
+ for (Object p : props) {
+
+ Property prop = (Property)p;
+ Class javaType = SimpleTypeMapperImpl.getJavaType(prop.getXSDType());
+ ObjectFactory<?> objFactory = propertyValueFactory.createValueFactory(prop, prop.getValue(), javaType);
+ Object value = objFactory.getInstance();
+
+ propsTable.put(prop.getName(), value);
+ }
+ }
+ }
+
+
+ private BundleContext getBundleContext() throws BundleException {
+
+ try {
+ if (bundleContext == null) {
+ osgiRuntime = OSGiRuntime.getRuntime();
+ bundleContext = osgiRuntime .getBundleContext();
+ }
+ } catch (BundleException e) {
+ throw e;
+ } catch (Exception e) {
+ throw new BundleException("Could not start OSGi runtime", e);
+ }
+
+
+ return bundleContext;
+ }
+
+
+ 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 org.osgi.framework.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 =
+ bundleContext.getServiceReferences(osgiServiceName, filter);
+
+
+ org.osgi.framework.ServiceReference reference = null;
+ if (references != null) {
+ for (org.osgi.framework.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 + ")";
+
+ org.osgi.framework.ServiceReference[] references =
+ bundleContext.getServiceReferences(osgiServiceName, filter);
+
+ if (references != null) {
+ for (org.osgi.framework.ServiceReference ref : references) {
+ if (ref.getBundle() == osgiBundle) {
+ return ref;
+ }
+ }
+ }
+
+ references = bundleContext.getServiceReferences(osgiServiceName, null);
+
+ org.osgi.framework.ServiceReference reference = null;
+
+ if (references != null) {
+ for (org.osgi.framework.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();
+
+ processAnnotations(true);
+
+
+ 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.
+ protected org.osgi.framework.ServiceReference getOSGiServiceReference(ComponentService service)
+ throws ObjectCreationException {
+
+ Hashtable<String, Object> props = new Hashtable<String, Object>();
+ if (!service.isCallback())
+ processProperties(implementation.getServiceProperties(service.getName()), props);
+ else
+ processProperties(implementation.getServiceCallbackProperties(service.getName()), props);
+
+ String filter = getOSGiFilter(props);
+ Interface serviceInterface = service.getInterfaceContract().getInterface();
+ String scaServiceName = service.getName();
+
+ return getOSGiServiceReference(serviceInterface, filter, scaServiceName);
+
+ }
+
+ protected org.osgi.framework.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) {
+ Hashtable<String, Object> props = new Hashtable<String, Object>();
+ ComponentReference scaRef = componentReferenceWires.get(refWire);
+ processProperties(implementation.getReferenceCallbackProperties(scaRef.getName()), props);
+ filter = getOSGiFilter(props);
+ }
+
+ return getOSGiServiceReference(callbackInterface, filter, null);
+ }
+
+ private org.osgi.framework.ServiceReference getOSGiServiceReference(Interface serviceInterface,
+ String filter, String scaServiceName)
+ throws ObjectCreationException {
+
+ try {
+
+ String serviceInterfaceName = null;
+
+ org.osgi.framework.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);
+ }
+ }
+
+
+ // Felix does not support bundle fragments. This is a temporary workaround.
+ protected Bundle installDummyBundleWithoutFragments(Class<?> interfaceClass)
+ throws Exception {
+
+ ByteArrayOutputStream out = new ByteArrayOutputStream();
+
+ String EOL = System.getProperty("line.separator");
+
+ String interfaceName = interfaceClass.getName();
+ String packageName = getPackageName(interfaceClass);
+ String bundleName = "dummy.sca." + packageName;
+
+ String manifestStr = "Manifest-Version: 1.0" + EOL
+ + "Bundle-ManifestVersion: 2" + EOL + "Bundle-Name: "
+ + bundleName + EOL + "Bundle-SymbolicName: " + bundleName + EOL
+ + "Bundle-Version: " + "1.0.0" + EOL
+ + "Bundle-Localization: plugin" + EOL;
+
+ ArrayList<String> dummyClasses = new ArrayList<String>();
+
+ StringBuilder manifestBuf = new StringBuilder();
+ manifestBuf.append(manifestStr);
+ manifestBuf.append("Export-Package: " + packageName + EOL);
+ String exportedInterfaces = interfaceName;
+ Bundle existingBundle = getDummyHostBundle(packageName);
+ String existingClasses;
+ dummyClasses.add(interfaceClass.getName());
+ for (Class<?> clazz : interfaceClass.getClasses()) {
+ dummyClasses.add(clazz.getName());
+ }
+ if (existingBundle != null &&
+ (existingClasses = (String)existingBundle.getHeaders().get("SCA-Dummy-Classes")) != null) {
+ exportedInterfaces = exportedInterfaces + " " + existingClasses;
+
+ StringTokenizer tokenizer = new StringTokenizer(existingClasses);
+ while (tokenizer.hasMoreTokens()) {
+ String className = tokenizer.nextToken();
+ if (!dummyClasses.contains(className))
+ dummyClasses.add(className);
+ }
+ }
+
+ manifestBuf.append("SCA-Dummy-Classes: " + exportedInterfaces + EOL);
+
+ ByteArrayInputStream manifestStream = new ByteArrayInputStream(
+ manifestBuf.toString().getBytes());
+ Manifest manifest = new Manifest();
+ manifest.read(manifestStream);
+
+ JarOutputStream jarOut = new JarOutputStream(out, manifest);
+
+ for (int i = 0; i < dummyClasses.size(); i++) {
+
+ String className = dummyClasses.get(i);
+
+ Class clazz = interfaceClass.getClassLoader().loadClass(className);
+ className = clazz.getName().replaceAll("\\.", "/") + ".class";
+ ZipEntry ze = new ZipEntry(className);
+ jarOut.putNextEntry(ze);
+ InputStream stream = clazz.getResourceAsStream(clazz.getSimpleName() + ".class");
+
+ byte[] bytes = new byte[stream.available()];
+ stream.read(bytes);
+ jarOut.write(bytes);
+ stream.close();
+ }
+
+
+ jarOut.close();
+ out.close();
+
+ if (existingBundle != null) {
+ existingBundle.stop();
+ existingBundle.uninstall();
+ }
+
+ ByteArrayInputStream in = new ByteArrayInputStream(out.toByteArray());
+
+ Bundle bundle = bundleContext.installBundle("file://" + bundleName
+ + ".jar", in);
+
+ bundle.start();
+
+ if (existingBundle != null && packageAdmin != null) {
+ refreshPackages();
+
+ }
+
+ return bundle;
+
+ }
+
+ private Bundle getDummyHostBundle(String packageName) {
+
+ if (packageAdmin == null)
+ return null;
+
+ ExportedPackage exp = packageAdmin.getExportedPackage(packageName);
+ if (exp == null)
+ return null;
+ else
+ return exp.getExportingBundle();
+ }
+
+ private static String getPackageName(Class<?> cls) {
+ String name = cls.getName();
+ int index = name.lastIndexOf('.');
+ return index == -1 ? "" : name.substring(0, index);
+ }
+
+ private Bundle installDummyBundle(Class<?> interfaceClass)
+ throws Exception {
+
+
+ if (!osgiRuntime.supportsBundleFragments()) {
+ return installDummyBundleWithoutFragments(interfaceClass);
+ }
+
+ ByteArrayOutputStream out = new ByteArrayOutputStream();
+
+ String EOL = System.getProperty("line.separator");
+ ArrayList<Class<?>> dummyClasses = new ArrayList<Class<?>>();
+
+ String interfaceName = interfaceClass.getName();
+ String packageName = getPackageName(interfaceClass);
+ String bundleName = "dummy.sca." + interfaceName;
+
+
+ String manifestStr = "Manifest-Version: 1.0" + EOL +
+ "Bundle-ManifestVersion: 2" + EOL +
+ "Bundle-Name: " + bundleName + EOL +
+ "Bundle-SymbolicName: " + bundleName + EOL +
+ "Bundle-Version: " + "1.0.0" + EOL +
+ "Bundle-Localization: plugin" + EOL;
+
+
+ StringBuilder manifestBuf = new StringBuilder();
+ manifestBuf.append(manifestStr);
+ manifestBuf.append("Export-Package: " + packageName + EOL);
+ Bundle dummyHost = getDummyHostBundle(packageName);
+ if (dummyHost != null)
+ manifestBuf.append("Fragment-Host: " + dummyHost.getSymbolicName() + EOL);
+
+ ByteArrayInputStream manifestStream = new ByteArrayInputStream(manifestBuf.toString().getBytes());
+ Manifest manifest = new Manifest();
+ manifest.read(manifestStream);
+
+ dummyClasses.add(interfaceClass);
+ for (Class<?> clazz : interfaceClass.getClasses()) {
+ dummyClasses.add(clazz);
+ }
+
+ JarOutputStream jarOut = new JarOutputStream(out, manifest);
+
+ for (int i = 0; i < dummyClasses.size(); i++) {
+
+ Class<?> clazz = dummyClasses.get(i);
+ String className = clazz.getName();
+ className = clazz.getName().replaceAll("\\.", "/") + ".class";
+ ZipEntry ze = new ZipEntry(className);
+ jarOut.putNextEntry(ze);
+ InputStream stream = clazz.getResourceAsStream(clazz.getSimpleName() + ".class");
+
+ byte[] bytes = new byte[stream.available()];
+ stream.read(bytes);
+ jarOut.write(bytes);
+ stream.close();
+ }
+
+ jarOut.close();
+ out.close();
+
+
+ ByteArrayInputStream in = new ByteArrayInputStream(out.toByteArray());
+
+
+ Bundle bundle = bundleContext.installBundle(
+ "file://" + bundleName + ".jar",
+ in);
+
+ if (dummyHost == null)
+ bundle.start();
+
+ return bundle;
+
+ }
+
+
+
+ public InstanceWrapper<?> createInstanceWrapper() throws ObjectCreationException {
+
+ return new OSGiInstanceWrapper<Object>(this, osgiAnnotations, bundleContext);
+ }
+
+
+
+ private void resolveWireCreateDummyBundles(final Class interfaceClass) throws Exception {
+
+
+ try {
+
+ osgiBundle.loadClass(interfaceClass.getName());
+
+ } catch (ClassNotFoundException e) {
+
+ // The interface used by the proxy is not in the source bundle
+ // A dummy bundle needs to be installed to create the proxy
+ // Allow privileged access to file system. Requires FileSystem permission in security
+ // policy.
+ Bundle dummyBundle = AccessController.doPrivileged(new PrivilegedExceptionAction<Bundle>() {
+ public Bundle run() throws Exception {
+ return installDummyBundle(interfaceClass);
+ }
+ });
+
+ if (packageAdmin != null) {
+
+ packageAdmin.resolveBundles(new Bundle[]{dummyBundle, osgiBundle});
+
+ }
+
+ }
+ }
+
+ /**
+ * 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 = new Hashtable<String, Object>();
+ processProperties(implementation.getReferenceProperties(scaRef.getName()), targetProperties);
+
+
+ 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 = new Hashtable<String, Object>();
+ processProperties(implementation.getReferenceProperties(scaRef.getName()), targetProperties);
+ 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);
+ }
+
+
+ JDKProxyFactory proxyService = new JDKProxyFactory(messageFactory, mapper);
+
+ // 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 {
+ bundleContext.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;
+
+ org.osgi.framework.ServiceReference configAdminReference =
+ bundleContext.getServiceReference("org.osgi.service.cm.ConfigurationAdmin");
+ if (configAdminReference != null) {
+
+ Object cm = bundleContext.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) {
+
+ List<ComponentProperty> serviceProps = implementation.getServiceProperties(service.getName());
+ String pid = null;
+
+ if (serviceProps != null) {
+ for (ComponentProperty prop : serviceProps) {
+ if (prop.getName().equals("service.pid")) {
+ ObjectFactory objFactory = propertyValueFactory.createValueFactory(prop,
+ prop.getValue(), String.class);
+ pid = (String)objFactory.getInstance();
+ }
+ }
+ }
+ 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 osgiAnnotations.getScope();
+ }
+
+ public boolean isEagerInit() {
+ return osgiAnnotations.isEagerInit();
+ }
+
+ public long getMaxAge() {
+ return osgiAnnotations.getMaxAge();
+ }
+
+ public long getMaxIdleTime() {
+ return osgiAnnotations.getMaxIdleTime();
+ }
+
+ protected ScopeContainer<?> getScopeContainer() {
+ startBundle(true);
+ return ((ScopedRuntimeComponent)runtimeComponent).getScopeContainer();
+ }
+
+ public Invoker createTargetInvoker(RuntimeComponentService service, Operation operation) {
+
+
+ Interface serviceInterface = operation.getInterface();
+ boolean isRemotable = serviceInterface.isRemotable();
+
+
+ Invoker invoker = new OSGiTargetInvoker(operation, this, service);
+ if (isRemotable) {
+ return new OSGiRemotableInvoker(osgiAnnotations, dataBindingRegistry, operation, this, service);
+ } else {
+ 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);
+ }
+
+ }
+
+ }
+
+ processProperties(runtimeComponent.getProperties(), componentProperties);
+
+ return true;
+
+ }
+
+ public void start() {
+ setReferencesAndProperties();
+ }
+
+ public void processAnnotations(boolean doWait) throws IntrospectionException {
+
+ if (!enterMethod(doWait, processAnnotationsEntryCount))
+ return;
+
+ try {
+ osgiAnnotations.processAnnotations();
+
+ Scope scope = osgiAnnotations.getScope();
+ if (scope.equals(Scope.SYSTEM) || scope.equals(Scope.COMPOSITE)) {
+ // Nothing
+ } else {
+
+ if (runtimeComponent instanceof ScopedRuntimeComponent) {
+
+ ScopedRuntimeComponent component = (ScopedRuntimeComponent) runtimeComponent;
+
+ ScopeContainer oldScopeContainer = component.getScopeContainer();
+ component.setScopeContainer(null);
+ ScopeContainer scopeContainer = scopeRegistry.getScopeContainer(runtimeComponent);
+
+ if (oldScopeContainer != null && oldScopeContainer.getLifecycleState() == ScopeContainer.RUNNING) {
+ scopeContainer.start();
+ }
+
+ component.setScopeContainer(scopeContainer);
+ }
+
+ }
+ } finally {
+ exitMethod(processAnnotationsEntryCount);
+ }
+ }
+
+ public void stop() {
+
+ if (osgiServiceListener != null)
+ bundleContext.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) {
+ try {
+ processAnnotations(false);
+ } catch (Throwable e) {
+ e.printStackTrace();
+ }
+ }
+ }
+
+ private class OSGiServiceListener implements ServiceListener {
+
+ private Bundle bundle;
+
+ OSGiServiceListener(Bundle bundle) {
+ this.bundle = bundle;
+ }
+
+ public void serviceChanged(org.osgi.framework.ServiceEvent event) {
+
+
+ org.osgi.framework.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/sca-java-1.x/tags/1.6.1-TUSCANY-3909/implementation-osgi/src/main/java/org/apache/tuscany/sca/implementation/osgi/runtime/OSGiImplementationProviderFactory.java b/sca-java-1.x/tags/1.6.1-TUSCANY-3909/implementation-osgi/src/main/java/org/apache/tuscany/sca/implementation/osgi/runtime/OSGiImplementationProviderFactory.java
new file mode 100644
index 0000000000..1a13ef99f7
--- /dev/null
+++ b/sca-java-1.x/tags/1.6.1-TUSCANY-3909/implementation-osgi/src/main/java/org/apache/tuscany/sca/implementation/osgi/runtime/OSGiImplementationProviderFactory.java
@@ -0,0 +1,109 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES 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.context.ContextFactoryExtensionPoint;
+import org.apache.tuscany.sca.context.RequestContextFactory;
+import org.apache.tuscany.sca.contribution.ModelFactoryExtensionPoint;
+import org.apache.tuscany.sca.core.ExtensionPointRegistry;
+import org.apache.tuscany.sca.core.UtilityExtensionPoint;
+import org.apache.tuscany.sca.core.invocation.ExtensibleProxyFactory;
+import org.apache.tuscany.sca.core.invocation.ProxyFactory;
+import org.apache.tuscany.sca.core.invocation.ProxyFactoryExtensionPoint;
+import org.apache.tuscany.sca.core.scope.ScopeRegistry;
+import org.apache.tuscany.sca.databinding.DataBindingExtensionPoint;
+import org.apache.tuscany.sca.databinding.Mediator;
+import org.apache.tuscany.sca.implementation.java.injection.JavaPropertyValueObjectFactory;
+import org.apache.tuscany.sca.implementation.osgi.OSGiImplementation;
+import org.apache.tuscany.sca.interfacedef.InterfaceContractMapper;
+import org.apache.tuscany.sca.invocation.MessageFactory;
+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 DataBindingExtensionPoint dataBindings;
+ private JavaPropertyValueObjectFactory propertyFactory;
+ private ProxyFactory proxyFactory;
+ private ScopeRegistry scopeRegistry;
+ private MessageFactory messageFactory;
+ private InterfaceContractMapper mapper;
+
+ private RequestContextFactory requestContextFactory;
+
+ public OSGiImplementationProviderFactory(ExtensionPointRegistry extensionPoints ) {
+
+ dataBindings = extensionPoints.getExtensionPoint(DataBindingExtensionPoint.class);
+ ProxyFactoryExtensionPoint proxyFactories = extensionPoints.getExtensionPoint(ProxyFactoryExtensionPoint.class);
+ proxyFactory = new ExtensibleProxyFactory(proxyFactories);
+ ContextFactoryExtensionPoint contextFactories = extensionPoints.getExtensionPoint(ContextFactoryExtensionPoint.class);
+ requestContextFactory = contextFactories.getFactory(RequestContextFactory.class);
+
+
+ // FIXME: Scope registry is not an extension point, and this usage is specific
+ // to implementation.osgi since it needs to change scope after the component is
+ // created. Do we need to find a better way?
+ scopeRegistry = extensionPoints.getExtensionPoint(ScopeRegistry.class);
+
+ Mediator mediator = extensionPoints.getExtensionPoint(UtilityExtensionPoint.class).getUtility(Mediator.class);
+ propertyFactory = new JavaPropertyValueObjectFactory(mediator);
+
+ ModelFactoryExtensionPoint modelFactories = extensionPoints.getExtensionPoint(ModelFactoryExtensionPoint.class);
+ messageFactory = modelFactories.getFactory(MessageFactory.class);
+
+ UtilityExtensionPoint utilities = extensionPoints.getExtensionPoint(UtilityExtensionPoint.class);
+ mapper = utilities.getUtility(InterfaceContractMapper.class);
+ }
+
+ public ImplementationProvider createImplementationProvider(RuntimeComponent component,
+ OSGiImplementation implementation) {
+
+ try {
+
+ return new OSGiImplementationProvider(component,
+ implementation,
+ dataBindings,
+ propertyFactory,
+ proxyFactory,
+ scopeRegistry,
+ requestContextFactory,
+ messageFactory,
+ mapper
+ );
+
+ } catch (BundleException e) {
+ throw new RuntimeException(e);
+ }
+
+ }
+
+ public Class<OSGiImplementation> getModelType() {
+ return OSGiImplementation.class;
+ }
+
+}
diff --git a/sca-java-1.x/tags/1.6.1-TUSCANY-3909/implementation-osgi/src/main/java/org/apache/tuscany/sca/implementation/osgi/runtime/OSGiInstanceWrapper.java b/sca-java-1.x/tags/1.6.1-TUSCANY-3909/implementation-osgi/src/main/java/org/apache/tuscany/sca/implementation/osgi/runtime/OSGiInstanceWrapper.java
new file mode 100644
index 0000000000..e775041592
--- /dev/null
+++ b/sca-java-1.x/tags/1.6.1-TUSCANY-3909/implementation-osgi/src/main/java/org/apache/tuscany/sca/implementation/osgi/runtime/OSGiInstanceWrapper.java
@@ -0,0 +1,299 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.tuscany.sca.implementation.osgi.runtime;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.lang.annotation.Annotation;
+import java.lang.reflect.Method;
+import java.util.Hashtable;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Random;
+import java.util.jar.JarOutputStream;
+import java.util.jar.Manifest;
+
+import org.apache.tuscany.sca.assembly.ComponentService;
+import org.apache.tuscany.sca.core.context.InstanceWrapper;
+import org.apache.tuscany.sca.core.scope.Scope;
+import org.apache.tuscany.sca.core.scope.TargetDestructionException;
+import org.apache.tuscany.sca.core.scope.TargetInitializationException;
+import org.apache.tuscany.sca.implementation.osgi.context.OSGiAnnotations;
+import org.apache.tuscany.sca.interfacedef.Interface;
+import org.apache.tuscany.sca.interfacedef.java.JavaInterface;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.BundleException;
+import org.osgi.framework.ServiceReference;
+import org.osoa.sca.annotations.Destroy;
+import org.osoa.sca.annotations.Init;
+
+
+/**
+ * InstanceWrapper for creating instances for OSGi components.
+ * This class needs to implement InstanceWrapper since the wrapper is stored in
+ * the scope container. But getInstance() is called on this wrapper only through the
+ * OSGi target invoker. OSGiTargetInvoker always invokes getInstance for a specific
+ * service since one OSGi SCA component can associate different objects with
+ * different services (this is different from Java SCA components which always associate
+ * a single component instance with multiple services).
+ *
+ * @version $Rev$ $Date$
+ */
+public class OSGiInstanceWrapper<T> implements InstanceWrapper<T> {
+ private static final Random RANDOM_NUMBER_GENERATOR = new Random();
+
+ private OSGiAnnotations annotationProcessor;
+ private OSGiImplementationProvider provider;
+ private BundleContext bundleContext;
+ private Hashtable<Object,InstanceInfo<T>> instanceInfoList =
+ new Hashtable<Object,InstanceInfo<T>>();
+
+ // Dummy bundles are used to create a new service object for scopes other than COMPOSITE
+ private Bundle dummyReferenceBundle;
+
+
+ public OSGiInstanceWrapper(OSGiImplementationProvider provider,
+ OSGiAnnotations annotationProcessor,
+ BundleContext bundleContext) {
+
+ this.provider = provider;
+ this.annotationProcessor = annotationProcessor;
+ this.bundleContext = bundleContext;
+ }
+
+ public synchronized T getInstance(ComponentService service) throws TargetInitializationException {
+
+ // If an instance corresponding to this service has already been created, return the instance.
+ if (instanceInfoList.get(service) != null)
+ return instanceInfoList.get(service).osgiInstance;
+
+ // There is no strict relation between service and callback instances. The instance semantics
+ // actually applies to the component instance in SCA. But for OSGi services, the callback
+ // is just another OSGi service, and could correspond to any of the service instances in
+ // the component. To implement the SCA scope semantics for callbacks, OSGi callbacks
+ // should also be made on the service object which implements the callback. The following code
+ // finds the first possible callback instance based on the interfaces implemented by the service
+ // objects in this component. Note that the interfaces are checked by name rather than using
+ // instanceof since the class seen by Tuscany could be from a different classloader from that
+ // used by the bundle.
+ if (service.isCallback()) {
+ Iterator<InstanceInfo<T>> instances = instanceInfoList.values().iterator();
+ while (instances.hasNext()) {
+ InstanceInfo<T> instanceInfo = instances.next();
+ Interface interfaze = service.getInterfaceContract().getInterface();
+ if (interfaze instanceof JavaInterface && ((JavaInterface)interfaze).getJavaClass() != null) {
+ String interfaceName = ((JavaInterface)interfaze).getJavaClass().getName();
+ Class[] interfaces = instanceInfo.osgiInstance.getClass().getInterfaces();
+ for (Class clazz : interfaces) {
+ if (clazz.getName().equals(interfaceName)) {
+ return instanceInfo.osgiInstance;
+ }
+ }
+
+ }
+
+ }
+ }
+
+ Bundle refBundle = provider.startBundle(true);
+
+ // For scopes other than composite, the service object is obtained using a dummy reference
+ // bundle to guarantee that a new instance is created each time. This combined with the Tuscany
+ // scope container code guarantee SCA scope semantics for OSGi components as long as service
+ // factories are used.
+ if (!annotationProcessor.getScope().equals(Scope.COMPOSITE)) {
+ refBundle = getDummyReferenceBundle();
+ }
+
+ InstanceInfo<T> instanceInfo = new InstanceInfo<T>();
+
+ instanceInfo.refBundleContext = refBundle.getBundleContext();
+
+ instanceInfo.osgiInstance = getInstanceObject(instanceInfo, service);
+
+ try {
+
+ if (!isInitialized(instanceInfo.osgiInstance)) {
+
+ annotationProcessor.injectProperties(instanceInfo.osgiInstance);
+ callLifecycleMethod(instanceInfo.osgiInstance, Init.class);
+
+ instanceInfo.isFirstInstance = true;
+ }
+
+ instanceInfoList.put(service, instanceInfo);
+
+ } catch (Exception e) {
+ throw new TargetInitializationException(e);
+ }
+
+ return instanceInfo.osgiInstance;
+ }
+
+
+
+ // This method is provided purely to implement InstanceWrapper interface, and is never called.
+ public T getInstance() {
+
+ return null;
+ }
+
+ public void start() throws TargetInitializationException {
+
+ if (provider.isEagerInit()) {
+ List<ComponentService> services = provider.getRuntimeComponent().getServices();
+ for (ComponentService service : services) {
+ getInstance(service);
+ }
+ }
+ }
+
+ public synchronized void stop() throws TargetDestructionException {
+
+ for (InstanceInfo<T> instanceInfo : instanceInfoList.values()) {
+ if (instanceInfo.osgiInstance != null && instanceInfo.osgiServiceReference != null) {
+
+ try {
+
+ if (instanceInfo.isFirstInstance)
+ callLifecycleMethod(instanceInfo.osgiInstance, Destroy.class);
+
+ instanceInfo.refBundleContext.ungetService(instanceInfo.osgiServiceReference);
+
+ instanceInfo.osgiInstance = null;
+ instanceInfo.osgiServiceReference = null;
+
+ } catch (Exception e) {
+ throw new TargetDestructionException(e);
+ }
+ }
+ }
+ instanceInfoList.clear();
+ if (dummyReferenceBundle != null) {
+ try {
+ dummyReferenceBundle.uninstall();
+ } catch (BundleException e) {
+ throw new TargetDestructionException(e);
+ }
+ dummyReferenceBundle = null;
+ }
+ }
+
+ @SuppressWarnings("unchecked")
+ private T getInstanceObject(InstanceInfo<T> instanceInfo, ComponentService service) {
+
+ /**
+ * Since implementation.osgi is not well integrated with the OSGi lifecycle
+ * it is possible that the service is deactivated before the service instance
+ * is obtained when using declarative services. Retry in this case.
+ */
+ int maxRetries = 10;
+ for (int i = 0; i < maxRetries; i++) {
+ instanceInfo.osgiServiceReference = provider.getOSGiServiceReference(service);
+ if (instanceInfo.osgiServiceReference == null)
+ return null;
+ T obj = (T)instanceInfo.refBundleContext.getService(instanceInfo.osgiServiceReference);
+ if (obj != null)
+ return obj;
+ }
+ return null;
+ }
+
+ private Bundle getDummyReferenceBundle() throws TargetInitializationException {
+
+ if (dummyReferenceBundle != null)
+ return dummyReferenceBundle;
+
+ ByteArrayOutputStream out = new ByteArrayOutputStream();
+
+ String EOL = System.getProperty("line.separator");
+ String bundleName = "dummy.sca." + RANDOM_NUMBER_GENERATOR.nextInt();
+
+
+ String manifestStr = "Manifest-Version: 1.0" + EOL +
+ "Bundle-ManifestVersion: 2" + EOL +
+ "Bundle-Name: " + bundleName + EOL +
+ "Bundle-SymbolicName: " + bundleName + EOL +
+ "Bundle-Version: " + "1.0.0" + EOL +
+ "Bundle-Localization: plugin" + EOL;
+
+
+ StringBuilder manifestBuf = new StringBuilder();
+ manifestBuf.append(manifestStr);
+
+ try {
+ ByteArrayInputStream manifestStream = new ByteArrayInputStream(manifestBuf.toString().getBytes());
+ Manifest manifest = new Manifest();
+ manifest.read(manifestStream);
+
+
+ JarOutputStream jarOut = new JarOutputStream(out, manifest);
+
+ jarOut.close();
+ out.close();
+
+
+ ByteArrayInputStream in = new ByteArrayInputStream(out.toByteArray());
+
+ dummyReferenceBundle = bundleContext.installBundle("file://" + bundleName + ".jar", in);
+
+ dummyReferenceBundle.start();
+
+ } catch (Exception e) {
+ throw new TargetInitializationException(e);
+ }
+
+ return dummyReferenceBundle;
+
+ }
+
+ private void callLifecycleMethod(Object instance,
+ Class<? extends Annotation> annotationClass) throws Exception {
+
+ Method method = null;
+ if (annotationClass == Init.class) {
+ method = annotationProcessor.getInitMethod(instance);
+ } else if (annotationClass == Destroy.class) {
+ method = annotationProcessor.getDestroyMethod(instance);
+ }
+
+ if (method != null) {
+ method.setAccessible(true);
+ method.invoke(instance);
+ }
+ }
+
+ private boolean isInitialized(Object instance) {
+ for (InstanceInfo<?> info : instanceInfoList.values()) {
+ if (info.osgiInstance == instance)
+ return true;
+ }
+ return false;
+ }
+
+ private static class InstanceInfo<T> {
+ private T osgiInstance;
+ private ServiceReference osgiServiceReference;
+ private BundleContext refBundleContext;
+ private boolean isFirstInstance;
+
+ }
+
+}
diff --git a/sca-java-1.x/tags/1.6.1-TUSCANY-3909/implementation-osgi/src/main/java/org/apache/tuscany/sca/implementation/osgi/runtime/OSGiRemotableInvoker.java b/sca-java-1.x/tags/1.6.1-TUSCANY-3909/implementation-osgi/src/main/java/org/apache/tuscany/sca/implementation/osgi/runtime/OSGiRemotableInvoker.java
new file mode 100644
index 0000000000..deb44d26fb
--- /dev/null
+++ b/sca-java-1.x/tags/1.6.1-TUSCANY-3909/implementation-osgi/src/main/java/org/apache/tuscany/sca/implementation/osgi/runtime/OSGiRemotableInvoker.java
@@ -0,0 +1,139 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.tuscany.sca.implementation.osgi.runtime;
+
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.util.IdentityHashMap;
+import java.util.Map;
+
+import org.apache.tuscany.sca.databinding.DataBinding;
+import org.apache.tuscany.sca.databinding.DataBindingExtensionPoint;
+import org.apache.tuscany.sca.implementation.osgi.context.OSGiAnnotations;
+import org.apache.tuscany.sca.interfacedef.DataType;
+import org.apache.tuscany.sca.interfacedef.Operation;
+import org.apache.tuscany.sca.invocation.DataExchangeSemantics;
+import org.apache.tuscany.sca.invocation.Message;
+import org.apache.tuscany.sca.runtime.RuntimeComponentService;
+
+/**
+ * An interceptor to enforce pass-by-value semantics for remotable interfaces
+ *
+ * @version $Rev$ $Date$
+ */
+public class OSGiRemotableInvoker extends OSGiTargetInvoker implements DataExchangeSemantics {
+
+ private DataBindingExtensionPoint registry;
+ private Operation operation;
+ private OSGiAnnotations osgiAnnotations;
+
+ /**
+ * @param registry
+ * @param operation
+ * @param method
+ * @param component
+ */
+ public OSGiRemotableInvoker(OSGiAnnotations osgiAnnotations,
+ DataBindingExtensionPoint registry,
+ Operation operation,
+ OSGiImplementationProvider provider,
+ RuntimeComponentService service) {
+ super(operation, provider, service);
+ this.osgiAnnotations = osgiAnnotations;
+ this.registry = registry;
+ this.operation = operation;
+ }
+
+ @Override
+ public Object invokeMethod(Object targetObject, Method m, Message msg) throws InvocationTargetException {
+
+ Object result;
+ if (osgiAnnotations.isAllowsPassByReference(targetObject, m)) {
+ result = super.invokeMethod(targetObject, m, msg);
+ } else {
+ Object obj = msg.getBody();
+ msg.setBody(copy((Object[])obj));
+
+ result = super.invokeMethod(targetObject, m, msg);
+
+ if (operation.getOutputType() != null) {
+ String dataBindingId = operation.getOutputType().getDataBinding();
+ DataBinding dataBinding = registry.getDataBinding(dataBindingId);
+ result = copy(result, operation.getOutputType(), dataBinding);
+ }
+ }
+ return result;
+ }
+
+ public Object[] copy(Object[] args) {
+ if (args == null) {
+ return null;
+ }
+ Object[] copiedArgs = new Object[args.length];
+ Map<Object, Object> map = new IdentityHashMap<Object, Object>();
+ for (int i = 0; i < args.length; i++) {
+ if (args[i] == null) {
+ copiedArgs[i] = null;
+ } else {
+ Object copiedArg = map.get(args[i]);
+ if (copiedArg != null) {
+ copiedArgs[i] = copiedArg;
+ } else {
+ DataType dt = operation.getInputType().getLogical().get(i);
+ String dataBindingId = dt.getDataBinding();
+ DataBinding dataBinding = registry.getDataBinding(dataBindingId);
+ copiedArg = copy(args[i], dt, dataBinding);
+ map.put(args[i], copiedArg);
+ copiedArgs[i] = copiedArg;
+ }
+ }
+ }
+ return copiedArgs;
+ }
+
+ public Object copy(Object arg, DataType dataType, DataBinding argDataBinding) {
+ if (arg == null) {
+ return null;
+ }
+ Object copiedArg;
+ if (argDataBinding != null) {
+ copiedArg = argDataBinding.copy(arg, dataType, operation);
+ } else {
+ copiedArg = arg;
+ dataType = registry.introspectType(arg, operation);
+ if (dataType != null) {
+ DataBinding binding = registry.getDataBinding(dataType.getDataBinding());
+ if (binding != null) {
+ copiedArg = binding.copy(arg, dataType, operation);
+ }
+ }
+ // FIXME: What to do if it's not recognized?
+ }
+ return copiedArg;
+ }
+
+ /**
+ * @see org.apache.tuscany.sca.invocation.PassByValueAware#allowsPassByReference()
+ */
+ public boolean allowsPassByReference() {
+ return true;
+ }
+
+}
diff --git a/sca-java-1.x/tags/1.6.1-TUSCANY-3909/implementation-osgi/src/main/java/org/apache/tuscany/sca/implementation/osgi/runtime/OSGiTargetInvoker.java b/sca-java-1.x/tags/1.6.1-TUSCANY-3909/implementation-osgi/src/main/java/org/apache/tuscany/sca/implementation/osgi/runtime/OSGiTargetInvoker.java
new file mode 100644
index 0000000000..deb39a47cd
--- /dev/null
+++ b/sca-java-1.x/tags/1.6.1-TUSCANY-3909/implementation-osgi/src/main/java/org/apache/tuscany/sca/implementation/osgi/runtime/OSGiTargetInvoker.java
@@ -0,0 +1,199 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES 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.context.InstanceWrapper;
+import org.apache.tuscany.sca.core.invocation.TargetInvocationException;
+import org.apache.tuscany.sca.core.scope.Scope;
+import org.apache.tuscany.sca.core.scope.ScopeContainer;
+import org.apache.tuscany.sca.core.scope.TargetResolutionException;
+import org.apache.tuscany.sca.interfacedef.ConversationSequence;
+import org.apache.tuscany.sca.interfacedef.Operation;
+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.EndpointReference;
+import org.apache.tuscany.sca.runtime.ReferenceParameters;
+import org.apache.tuscany.sca.runtime.RuntimeComponentService;
+
+/**
+ * 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 RuntimeComponentService service;
+
+ // Scope container is reset by the OSGi implementation provider if @Scope
+ // annotation is used to modify the scope (default is composite)
+ // Hence this field is initialized on the first invoke.
+ private ScopeContainer scopeContainer;
+
+ public OSGiTargetInvoker(
+ Operation operation,
+ OSGiImplementationProvider provider,
+ RuntimeComponentService service) {
+
+
+ this.operation = operation;
+ this.service = service;
+ this.provider = provider;
+
+ }
+
+ /**
+ * Resolves the target service instance or returns a cached one
+ */
+ @SuppressWarnings("unchecked")
+ protected InstanceWrapper getInstance(Object contextId)
+ throws TargetResolutionException, TargetInvocationException {
+
+ if (scopeContainer == null)
+ scopeContainer = provider.getScopeContainer();
+
+
+ return scopeContainer.getWrapper(contextId);
+
+ }
+
+ @SuppressWarnings("unchecked")
+ private Object invokeTarget(Message msg) throws InvocationTargetException {
+
+ if (scopeContainer == null)
+ scopeContainer = provider.getScopeContainer();
+
+
+ Operation op = msg.getOperation();
+ if (op == null) {
+ op = this.operation;
+ }
+ ConversationSequence sequence = op.getConversationSequence();
+
+ Object contextId = null;
+
+ EndpointReference from = msg.getFrom();
+ ReferenceParameters parameters = null;
+
+ if (from != null) {
+ parameters = from.getReferenceParameters();
+ }
+ // check what sort of context is required
+ if (scopeContainer != null) {
+ Scope scope = scopeContainer.getScope();
+ if (scope == Scope.REQUEST) {
+ contextId = Thread.currentThread();
+ } else if (scope == Scope.CONVERSATION && parameters != null) {
+ contextId = parameters.getConversationID();
+ }
+ }
+
+ try {
+
+ OSGiInstanceWrapper wrapper = (OSGiInstanceWrapper)getInstance(contextId);
+ Object instance;
+
+
+ // detects whether the scope container has created a conversation Id. This will
+ // happen in the case that the component has conversational scope but only the
+ // callback interface is conversational. Or in the callback case if the service interface
+ // is conversational and the callback interface isn't. If we are in this situation we need
+ // to get the contextId of this component and remove it after we have invoked the method on
+ // it. It is possible that the component instance will not go away when it is removed below
+ // because a callback conversation will still be holding a reference to it
+ boolean removeTemporaryConversationalComponentAfterCall = false;
+ if (parameters != null && (contextId == null) && (parameters.getConversationID() != null)) {
+ contextId = parameters.getConversationID();
+ removeTemporaryConversationalComponentAfterCall = true;
+ }
+
+ instance = wrapper.getInstance(service);
+
+ Method m = JavaInterfaceUtil.findMethod(instance.getClass(), operation);
+
+ Object ret = invokeMethod(instance, m, msg);
+
+ scopeContainer.returnWrapper(wrapper, contextId);
+
+ if ((sequence == ConversationSequence.CONVERSATION_END) || (removeTemporaryConversationalComponentAfterCall)) {
+ // if end conversation, or we have the special case where a conversational
+ // object was created to service the stateless half of a stateful component
+ scopeContainer.remove(contextId);
+ parameters.setConversationID(null);
+ }
+
+ 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 messageId = msg.getMessageID();
+ // Message workContext = ThreadMessageContext.getMessageContext();
+ // if (messageId != null) {
+ // workContext.setCorrelationID(messageId);
+ // }
+ Object resp = invokeTarget(msg);
+ msg.setBody(resp);
+ } catch (InvocationTargetException e) {
+ msg.setFaultBody(e.getCause());
+ }
+ return msg;
+ }
+
+
+}
diff --git a/sca-java-1.x/tags/1.6.1-TUSCANY-3909/implementation-osgi/src/main/java/org/apache/tuscany/sca/implementation/osgi/xml/OSGiImplementationProcessor.java b/sca-java-1.x/tags/1.6.1-TUSCANY-3909/implementation-osgi/src/main/java/org/apache/tuscany/sca/implementation/osgi/xml/OSGiImplementationProcessor.java
new file mode 100644
index 0000000000..20e999bca8
--- /dev/null
+++ b/sca-java-1.x/tags/1.6.1-TUSCANY-3909/implementation-osgi/src/main/java/org/apache/tuscany/sca/implementation/osgi/xml/OSGiImplementationProcessor.java
@@ -0,0 +1,550 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES 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.xml;
+
+import static javax.xml.XMLConstants.W3C_XML_SCHEMA_INSTANCE_NS_URI;
+import static javax.xml.XMLConstants.XMLNS_ATTRIBUTE_NS_URI;
+import static javax.xml.stream.XMLStreamConstants.END_ELEMENT;
+import static javax.xml.stream.XMLStreamConstants.START_ELEMENT;
+
+import java.util.ArrayList;
+import java.util.Hashtable;
+import java.util.List;
+import java.util.StringTokenizer;
+
+import javax.xml.namespace.QName;
+import javax.xml.parsers.DocumentBuilderFactory;
+import javax.xml.parsers.ParserConfigurationException;
+import javax.xml.stream.XMLStreamConstants;
+import javax.xml.stream.XMLStreamException;
+import javax.xml.stream.XMLStreamReader;
+import javax.xml.stream.XMLStreamWriter;
+
+import org.apache.tuscany.sca.assembly.AssemblyFactory;
+import org.apache.tuscany.sca.assembly.ComponentProperty;
+import org.apache.tuscany.sca.assembly.ComponentType;
+import org.apache.tuscany.sca.assembly.Property;
+import org.apache.tuscany.sca.assembly.Reference;
+import org.apache.tuscany.sca.assembly.Service;
+import org.apache.tuscany.sca.assembly.xml.Constants;
+import org.apache.tuscany.sca.contribution.ModelFactoryExtensionPoint;
+import org.apache.tuscany.sca.contribution.osgi.BundleReference;
+import org.apache.tuscany.sca.contribution.processor.StAXArtifactProcessor;
+import org.apache.tuscany.sca.contribution.resolver.ClassReference;
+import org.apache.tuscany.sca.contribution.resolver.ModelResolver;
+import org.apache.tuscany.sca.contribution.service.ContributionReadException;
+import org.apache.tuscany.sca.contribution.service.ContributionResolveException;
+import org.apache.tuscany.sca.contribution.service.ContributionWriteException;
+import org.apache.tuscany.sca.databinding.impl.SimpleTypeMapperImpl;
+import org.apache.tuscany.sca.implementation.osgi.impl.OSGiImplementationImpl;
+import org.apache.tuscany.sca.interfacedef.Interface;
+import org.apache.tuscany.sca.interfacedef.InvalidInterfaceException;
+import org.apache.tuscany.sca.interfacedef.java.JavaInterface;
+import org.apache.tuscany.sca.interfacedef.java.JavaInterfaceContract;
+import org.apache.tuscany.sca.interfacedef.java.JavaInterfaceFactory;
+import org.apache.tuscany.sca.monitor.Monitor;
+import org.apache.tuscany.sca.monitor.Problem;
+import org.apache.tuscany.sca.monitor.Problem.Severity;
+import org.apache.tuscany.sca.monitor.impl.ProblemImpl;
+import org.osgi.framework.Bundle;
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+import org.w3c.dom.NamedNodeMap;
+import org.w3c.dom.Node;
+
+/**
+ *
+ * Process an <implementation.osgi/> element in a component definition. An instance of
+ * OSGiImplementation is created.
+ * Also associates the component type file with the implementation.
+ *
+ * @version $Rev$ $Date$
+ */
+public class OSGiImplementationProcessor implements StAXArtifactProcessor<OSGiImplementationImpl> {
+
+ public static final QName IMPLEMENTATION_OSGI = new QName(Constants.SCA10_TUSCANY_NS, "implementation.osgi");
+
+ private static final String BUNDLE_SYMBOLICNAME= "bundleSymbolicName";
+ private static final String BUNDLE_VERSION = "bundleVersion";
+ private static final String CLASSES = "classes";
+ private static final String IMPORTS = "imports";
+
+ private static final QName PROPERTIES_QNAME = new QName(Constants.SCA10_TUSCANY_NS, "properties");
+ private static final QName PROPERTY_QNAME = new QName(Constants.SCA10_TUSCANY_NS, "property");
+
+ private JavaInterfaceFactory javaInterfaceFactory;
+ private AssemblyFactory assemblyFactory;
+ private ModelFactoryExtensionPoint modelFactories;
+ private Monitor monitor;
+
+ private static final DocumentBuilderFactory domFactory = DocumentBuilderFactory.newInstance();
+ static {
+ domFactory.setNamespaceAware(true);
+ }
+
+ public OSGiImplementationProcessor(ModelFactoryExtensionPoint modelFactories, Monitor monitor) {
+ this.monitor = monitor;
+ this.modelFactories = modelFactories;
+ this.assemblyFactory = modelFactories.getFactory(AssemblyFactory.class);
+ this.javaInterfaceFactory = modelFactories.getFactory(JavaInterfaceFactory.class);
+ }
+
+ /**
+ * Report a exception.
+ *
+ * @param problems
+ * @param message
+ * @param model
+ */
+ private void error(String message, Object model, Exception ex) {
+ if (monitor != null) {
+ Problem problem = new ProblemImpl(this.getClass().getName(), "impl-osgi-validation-messages", Severity.ERROR, model, message, ex);
+ monitor.problem(problem);
+ }
+ }
+
+ /**
+ * Report a error.
+ *
+ * @param problems
+ * @param message
+ * @param model
+ */
+ private void error(String message, Object model, Object... messageParameters) {
+ if (monitor != null) {
+ Problem problem = new ProblemImpl(this.getClass().getName(), "impl-osgi-validation-messages", Severity.ERROR, model, message, (Object[])messageParameters);
+ monitor.problem(problem);
+ }
+ }
+
+ public QName getArtifactType() {
+ return IMPLEMENTATION_OSGI;
+ }
+
+ public Class<OSGiImplementationImpl> getModelType() {
+ return OSGiImplementationImpl.class;
+ }
+
+ private String[] tokenize(String str) {
+ StringTokenizer tokenizer = new StringTokenizer(str);
+ String[] tokens = new String[tokenizer.countTokens()];
+ for (int i= 0; i < tokens.length; i++) {
+ tokens[i] = tokenizer.nextToken();
+ }
+
+ return tokens;
+ }
+
+ public OSGiImplementationImpl read(XMLStreamReader reader) throws ContributionReadException, XMLStreamException {
+ assert IMPLEMENTATION_OSGI.equals(reader.getName());
+
+ String bundleSymbolicName = reader.getAttributeValue(null, BUNDLE_SYMBOLICNAME);
+ String bundleVersion = reader.getAttributeValue(null, BUNDLE_VERSION);
+ String imports = reader.getAttributeValue(null, IMPORTS);
+ String[] importList;
+ if (imports != null)
+ importList = tokenize(imports);
+ else
+ importList = new String[0];
+ String classes = reader.getAttributeValue(null, CLASSES);
+ String[] classList;
+ if (classes != null)
+ classList = tokenize(classes);
+ else
+ classList = new String[0];
+
+ Hashtable<String, List<ComponentProperty>> refProperties =
+ new Hashtable<String, List<ComponentProperty>>();
+ Hashtable<String, List<ComponentProperty>> serviceProperties =
+ new Hashtable<String, List<ComponentProperty>>();
+ Hashtable<String, List<ComponentProperty>> refCallbackProperties =
+ new Hashtable<String, List<ComponentProperty>>();
+ Hashtable<String, List<ComponentProperty>> serviceCallbackProperties =
+ new Hashtable<String, List<ComponentProperty>>();
+
+ while (reader.hasNext()) {
+
+ int next = reader.next();
+ if (next == END_ELEMENT && IMPLEMENTATION_OSGI.equals(reader.getName())) {
+ break;
+ }
+ else if (next == START_ELEMENT && PROPERTIES_QNAME.equals(reader.getName())) {
+
+ // FIXME: This is temporary code which allows reference and service properties used
+ // for filtering OSGi services to be specified in <implementation.osgi/>
+ // This should really be provided in the component type file since these
+ // properties are associated with an implementation rather than a configured
+ // instance of an implementation.
+ String refName = reader.getAttributeValue(null, "reference");
+ String serviceName = reader.getAttributeValue(null, "service");
+ String refCallbackName = reader.getAttributeValue(null, "referenceCallback");
+ String serviceCallbackName = reader.getAttributeValue(null, "serviceCallback");
+ List<ComponentProperty> props = readProperties(reader);
+ if (refName != null)
+ refProperties.put(refName, props);
+ else if (serviceName != null)
+ serviceProperties.put(serviceName, props);
+ else if (refCallbackName != null)
+ refCallbackProperties.put(refCallbackName, props);
+ else if (serviceCallbackName != null)
+ serviceCallbackProperties.put(serviceCallbackName, props);
+ else {
+ error("PropertyShouldSpecifySR", reader);
+ //throw new ContributionReadException("Properties in implementation.osgi should specify service or reference");
+ }
+ }
+
+ }
+
+ OSGiImplementationImpl implementation = new OSGiImplementationImpl(
+ modelFactories,
+ bundleSymbolicName,
+ bundleVersion,
+ importList,
+ classList,
+ refProperties,
+ serviceProperties);
+ implementation.setCallbackProperties(refCallbackProperties, serviceCallbackProperties);
+
+ implementation.setUnresolved(true);
+
+ return implementation;
+
+ }
+
+
+ public void resolve(OSGiImplementationImpl impl, ModelResolver resolver) throws ContributionResolveException {
+
+ try {
+
+ if (impl == null || !impl.isUnresolved())
+ return;
+
+ impl.setUnresolved(false);
+
+ BundleReference bundleReference = new BundleReference(impl.getBundleSymbolicName(), impl.getBundleVersion());
+ BundleReference resolvedBundle = resolver.resolveModel(BundleReference.class, bundleReference);
+ Bundle bundle = (Bundle)resolvedBundle.getBundle();
+ if (bundle != null) {
+ impl.setOSGiBundle(bundle);
+ } else {
+ error("CouldNotLocateOSGiBundle", impl, impl.getBundleSymbolicName());
+ //throw new ContributionResolveException("Could not locate OSGi bundle " +
+ //impl.getBundleSymbolicName());
+ return;
+ }
+
+ String bundleName = resolvedBundle.getBundleRelativePath();
+ String ctURI = bundleName.endsWith(".jar") || bundleName.endsWith(".JAR")?
+ bundleName.substring(0, bundleName.lastIndexOf(".")) : bundleName;
+ ctURI = ctURI.replaceAll("\\.", "/");
+ ctURI = ctURI + ".componentType";
+
+ ComponentType componentType = assemblyFactory.createComponentType();
+ componentType.setURI(ctURI);
+ componentType.setUnresolved(true);
+ componentType = resolver.resolveModel(ComponentType.class, componentType);
+ if (componentType.isUnresolved()) {
+ error("MissingComponentTypeFile", impl, ctURI);
+ //throw new ContributionResolveException("missing .componentType side file " + ctURI);
+ return;
+ }
+
+ List<Service> services = componentType.getServices();
+ for (Service service : services) {
+ Interface interfaze = service.getInterfaceContract().getInterface();
+ if (interfaze instanceof JavaInterface) {
+ JavaInterface javaInterface = (JavaInterface)interfaze;
+ if (javaInterface.getJavaClass() == null) {
+
+ javaInterface.setJavaClass(getJavaClass(resolver, javaInterface.getName()));
+ }
+ Class<?> callback = null;
+ if (service.getInterfaceContract().getCallbackInterface() instanceof JavaInterface) {
+ JavaInterface callbackInterface = (JavaInterface)service.getInterfaceContract().getCallbackInterface();
+ if (callbackInterface.getJavaClass() == null) {
+ callbackInterface.setJavaClass(getJavaClass(resolver, callbackInterface.getName()));
+ }
+ callback = callbackInterface.getJavaClass();
+ }
+
+ Service serv = createService(service, javaInterface.getJavaClass(), callback);
+ impl.getServices().add(serv);
+ }
+ }
+
+ List<Reference> references = componentType.getReferences();
+ for (Reference reference : references) {
+ Interface interfaze = reference.getInterfaceContract().getInterface();
+ if (interfaze instanceof JavaInterface) {
+ JavaInterface javaInterface = (JavaInterface)interfaze;
+ if (javaInterface.getJavaClass() == null) {
+ javaInterface.setJavaClass(getJavaClass(resolver, javaInterface.getName()));
+ }
+ Reference ref = createReference(reference, javaInterface.getJavaClass());
+ impl.getReferences().add(ref);
+ }
+ else
+ impl.getReferences().add(reference);
+ }
+
+ List<Property> properties = componentType.getProperties();
+ for (Property property : properties) {
+ impl.getProperties().add(property);
+ }
+ impl.setConstrainingType(componentType.getConstrainingType());
+
+ } catch (InvalidInterfaceException e) {
+ ContributionResolveException ce = new ContributionResolveException(e);
+ error("ContributionResolveException", resolver, ce);
+ //throw ce;
+ }
+
+ }
+
+
+ private Class getJavaClass(ModelResolver resolver, String className) {
+ ClassReference ref = new ClassReference(className);
+ ref = resolver.resolveModel(ClassReference.class, ref);
+ return ref.getJavaClass();
+ }
+
+ private Service createService(Service serv, Class<?> interfaze, Class<?> callbackInterfaze) throws InvalidInterfaceException {
+ Service service = assemblyFactory.createService();
+ JavaInterfaceContract interfaceContract = javaInterfaceFactory.createJavaInterfaceContract();
+ service.setInterfaceContract(interfaceContract);
+
+
+ // create a relative URI
+ service.setName(serv.getName());
+
+ JavaInterface callInterface = javaInterfaceFactory.createJavaInterface(interfaze);
+ service.getInterfaceContract().setInterface(callInterface);
+
+ if (callbackInterfaze != null) {
+ JavaInterface callbackInterface = javaInterfaceFactory.createJavaInterface(callbackInterfaze);
+ service.getInterfaceContract().setCallbackInterface(callbackInterface);
+ }
+ else if (callInterface.getCallbackClass() != null) {
+ JavaInterface callbackInterface = javaInterfaceFactory.createJavaInterface(callInterface.getCallbackClass());
+ service.getInterfaceContract().setCallbackInterface(callbackInterface);
+ }
+ return service;
+ }
+
+ private Reference createReference(Reference ref, Class<?> clazz) throws InvalidInterfaceException {
+ org.apache.tuscany.sca.assembly.Reference reference = assemblyFactory.createReference();
+ JavaInterfaceContract interfaceContract = javaInterfaceFactory.createJavaInterfaceContract();
+ reference.setInterfaceContract(interfaceContract);
+
+ reference.setName(ref.getName());
+ reference.setMultiplicity(ref.getMultiplicity());
+
+ JavaInterface callInterface = javaInterfaceFactory.createJavaInterface(clazz);
+ reference.getInterfaceContract().setInterface(callInterface);
+ if (callInterface.getCallbackClass() != null) {
+ JavaInterface callbackInterface = javaInterfaceFactory.createJavaInterface(callInterface.getCallbackClass());
+ reference.getInterfaceContract().setCallbackInterface(callbackInterface);
+ }
+
+ return reference;
+ }
+
+ public void write(OSGiImplementationImpl model, XMLStreamWriter outputSource) throws ContributionWriteException, XMLStreamException {
+
+ //FIXME Implement this method
+ }
+
+
+ private QName getQNameValue(XMLStreamReader reader, String value) {
+ if (value != null) {
+ int index = value.indexOf(':');
+ String prefix = index == -1 ? "" : value.substring(0, index);
+ String localName = index == -1 ? value : value.substring(index + 1);
+ String ns = reader.getNamespaceContext().getNamespaceURI(prefix);
+ if (ns == null) {
+ ns = "";
+ }
+ return new QName(ns, localName, prefix);
+ } else {
+ return null;
+ }
+ }
+
+ private void declareNamespace(Element element, String prefix, String ns) {
+ String qname = null;
+ if ("".equals(prefix)) {
+ qname = "xmlns";
+ } else {
+ qname = "xmlns:" + prefix;
+ }
+ Node node = element;
+ boolean declared = false;
+ while (node != null && node.getNodeType() == Node.ELEMENT_NODE) {
+ NamedNodeMap attrs = node.getAttributes();
+ if (attrs == null) {
+ break;
+ }
+ Node attr = attrs.getNamedItem(qname);
+ if (attr != null) {
+ declared = ns.equals(attr.getNodeValue());
+ break;
+ }
+ node = node.getParentNode();
+ }
+ if (!declared) {
+ org.w3c.dom.Attr attr = element.getOwnerDocument().createAttributeNS(XMLNS_ATTRIBUTE_NS_URI, qname);
+ attr.setValue(ns);
+ element.setAttributeNodeNS(attr);
+ }
+ }
+
+ private Element createElement(Document document, QName name) {
+ String prefix = name.getPrefix();
+ String qname = (prefix != null && prefix.length() > 0) ? prefix + ":" + name.getLocalPart() : name
+ .getLocalPart();
+ return document.createElementNS(name.getNamespaceURI(), qname);
+ }
+
+ private void loadElement(XMLStreamReader reader, Element root) throws XMLStreamException {
+ Document document = root.getOwnerDocument();
+ Node current = root;
+ while (true) {
+ switch (reader.next()) {
+ case XMLStreamConstants.START_ELEMENT:
+ QName name = reader.getName();
+ Element child = createElement(document, name);
+
+ // push the new element and make it the current one
+ current.appendChild(child);
+ current = child;
+
+ declareNamespace(child, name.getPrefix(), name.getNamespaceURI());
+
+ int count = reader.getNamespaceCount();
+ for (int i = 0; i < count; i++) {
+ String prefix = reader.getNamespacePrefix(i);
+ String ns = reader.getNamespaceURI(i);
+ declareNamespace(child, prefix, ns);
+ }
+
+ // add the attributes for this element
+ count = reader.getAttributeCount();
+ for (int i = 0; i < count; i++) {
+ String ns = reader.getAttributeNamespace(i);
+ String prefix = reader.getAttributePrefix(i);
+ String localPart = reader.getAttributeLocalName(i);
+ String value = reader.getAttributeValue(i);
+ child.setAttributeNS(ns, localPart, value);
+ declareNamespace(child, prefix, ns);
+ }
+
+ break;
+ case XMLStreamConstants.CDATA:
+ current.appendChild(document.createCDATASection(reader.getText()));
+ break;
+ case XMLStreamConstants.CHARACTERS:
+ current.appendChild(document.createTextNode(reader.getText()));
+ break;
+ case XMLStreamConstants.END_ELEMENT:
+ // if we are back at the root then we are done
+ if (current == root) {
+ return;
+ }
+
+ // pop the element off the stack
+ current = current.getParentNode();
+ }
+ }
+ }
+
+ private Document readPropertyValue(XMLStreamReader reader, QName type)
+ throws XMLStreamException, ParserConfigurationException {
+
+ Document doc = domFactory.newDocumentBuilder().newDocument();
+
+ // root element has no namespace and local name "value"
+ Element root = doc.createElementNS(null, "value");
+ if (type != null) {
+ org.w3c.dom.Attr xsi = doc.createAttributeNS(XMLNS_ATTRIBUTE_NS_URI, "xmlns:xsi");
+ xsi.setValue(W3C_XML_SCHEMA_INSTANCE_NS_URI);
+ root.setAttributeNodeNS(xsi);
+
+ String prefix = type.getPrefix();
+ if (prefix == null || prefix.length() == 0) {
+ prefix = "ns";
+ }
+
+ declareNamespace(root, prefix, type.getNamespaceURI());
+
+ org.w3c.dom.Attr xsiType = doc.createAttributeNS(W3C_XML_SCHEMA_INSTANCE_NS_URI, "xsi:type");
+ xsiType.setValue(prefix + ":" + type.getLocalPart());
+ root.setAttributeNodeNS(xsiType);
+ }
+ doc.appendChild(root);
+
+ loadElement(reader, root);
+ return doc;
+ }
+
+ private void readProperty(ComponentProperty prop, XMLStreamReader reader)
+ throws XMLStreamException, ContributionReadException {
+
+
+ prop.setName(reader.getAttributeValue(null, "name"));
+ String xsdType = reader.getAttributeValue(null, "type");
+ if (xsdType != null)
+ prop.setXSDType(getQNameValue(reader, xsdType));
+ else
+ prop.setXSDType(SimpleTypeMapperImpl.XSD_STRING);
+
+ try {
+ Document value = readPropertyValue(reader, prop.getXSDType());
+ prop.setValue(value);
+ } catch (ParserConfigurationException e) {
+ ContributionReadException ce = new ContributionReadException(e);
+ error("ContributionReadException", reader, ce);
+ throw ce;
+ }
+ }
+
+ private List<ComponentProperty> readProperties(XMLStreamReader reader)
+ throws XMLStreamException, ContributionReadException {
+
+ List<ComponentProperty> properties = new ArrayList<ComponentProperty>();
+
+ while (reader.hasNext()) {
+
+ int next = reader.next();
+ if (next == END_ELEMENT && PROPERTIES_QNAME.equals(reader.getName())) {
+ break;
+ }
+ else if (next == START_ELEMENT && PROPERTY_QNAME.equals(reader.getName())) {
+
+ ComponentProperty componentProperty = assemblyFactory.createComponentProperty();
+ readProperty(componentProperty, reader);
+ properties.add(componentProperty);
+ }
+ }
+
+ return properties;
+
+ }
+
+}