From d5f1d093fe6fa491cdec392dca7137639e98d149 Mon Sep 17 00:00:00 2001 From: jsdelfino Date: Mon, 15 Sep 2008 00:26:00 +0000 Subject: Pulled a recent revision of trunk into the sca-android branch, to apply the android patches from JIRA TUSCANY-2440 to it. git-svn-id: http://svn.us.apache.org/repos/asf/tuscany@695318 13f79535-47bb-0310-9956-ffa450edef68 --- .../osgi/runtime/OSGiTargetInvoker.java | 199 +++++++++++++++++++++ 1 file changed, 199 insertions(+) create mode 100644 branches/sca-android/modules/implementation-osgi/src/main/java/org/apache/tuscany/sca/implementation/osgi/runtime/OSGiTargetInvoker.java (limited to 'branches/sca-android/modules/implementation-osgi/src/main/java/org/apache/tuscany/sca/implementation/osgi/runtime/OSGiTargetInvoker.java') diff --git a/branches/sca-android/modules/implementation-osgi/src/main/java/org/apache/tuscany/sca/implementation/osgi/runtime/OSGiTargetInvoker.java b/branches/sca-android/modules/implementation-osgi/src/main/java/org/apache/tuscany/sca/implementation/osgi/runtime/OSGiTargetInvoker.java new file mode 100644 index 0000000000..deb39a47cd --- /dev/null +++ b/branches/sca-android/modules/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 implements Invoker { + + private Operation operation; + protected InstanceWrapper 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; + } + + +} -- cgit v1.2.3