diff options
Diffstat (limited to 'sca-java-1.x/branches/sca-java-1.6.2/modules/core/src/main/java/org/apache/tuscany/sca/core/invocation')
27 files changed, 3565 insertions, 0 deletions
diff --git a/sca-java-1.x/branches/sca-java-1.6.2/modules/core/src/main/java/org/apache/tuscany/sca/core/invocation/CallableReferenceObjectFactory.java b/sca-java-1.x/branches/sca-java-1.6.2/modules/core/src/main/java/org/apache/tuscany/sca/core/invocation/CallableReferenceObjectFactory.java new file mode 100644 index 0000000000..588c43b8b1 --- /dev/null +++ b/sca-java-1.x/branches/sca-java-1.6.2/modules/core/src/main/java/org/apache/tuscany/sca/core/invocation/CallableReferenceObjectFactory.java @@ -0,0 +1,63 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.tuscany.sca.core.invocation; + +import org.apache.tuscany.sca.assembly.Binding; +import org.apache.tuscany.sca.core.factory.ObjectCreationException; +import org.apache.tuscany.sca.core.factory.ObjectFactory; +import org.apache.tuscany.sca.runtime.RuntimeComponent; +import org.apache.tuscany.sca.runtime.RuntimeComponentReference; +import org.osoa.sca.CallableReference; + +/** + * Uses a wire to return a CallableReference + * + * @version $Rev$ $Date$ + */ +public class CallableReferenceObjectFactory implements ObjectFactory<CallableReference<?>> { + private Class<?> businessInterface; + private RuntimeComponent component; + private RuntimeComponentReference reference; + private Binding binding; + + /** + * Constructor. + * + * To support the @Reference protected CallableReference<MyService> ref; + * + * @param businessInterface the interface to inject + * @param component the component defining the reference to be injected + * @param reference the reference to be injected + * @param binding the binding for the reference + */ + public CallableReferenceObjectFactory(Class<?> businessInterface, + RuntimeComponent component, + RuntimeComponentReference reference, + Binding binding) { + this.businessInterface = businessInterface; + this.component = component; + this.reference = reference; + this.binding = binding; + } + + public CallableReference<?> getInstance() throws ObjectCreationException { + return component.getComponentContext().getServiceReference(businessInterface, reference, binding); + } + +} diff --git a/sca-java-1.x/branches/sca-java-1.6.2/modules/core/src/main/java/org/apache/tuscany/sca/core/invocation/CallbackInterfaceInterceptor.java b/sca-java-1.x/branches/sca-java-1.6.2/modules/core/src/main/java/org/apache/tuscany/sca/core/invocation/CallbackInterfaceInterceptor.java new file mode 100644 index 0000000000..d19aa237cd --- /dev/null +++ b/sca-java-1.x/branches/sca-java-1.6.2/modules/core/src/main/java/org/apache/tuscany/sca/core/invocation/CallbackInterfaceInterceptor.java @@ -0,0 +1,57 @@ +/* + * 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.core.invocation; + +import org.apache.tuscany.sca.invocation.Interceptor; +import org.apache.tuscany.sca.invocation.Invoker; +import org.apache.tuscany.sca.invocation.Message; +import org.apache.tuscany.sca.runtime.ReferenceParameters; +import org.osoa.sca.NoRegisteredCallbackException; + +/** + * An interceptor applied to the forward direction of a wire that ensures the callback target implements the required + * service contract. This is required as callback targets may be set dynamically by service implementations. + * + * @version $Rev$ $Date$ + */ +public class CallbackInterfaceInterceptor implements Interceptor { + private Invoker next; + + public CallbackInterfaceInterceptor() { + } + + public Message invoke(Message msg) { + ReferenceParameters parameters = msg.getFrom().getReferenceParameters(); + if (parameters.getCallbackObjectID() != null || parameters.getCallbackReference() != msg.getFrom() + .getCallbackEndpoint()) { + return next.invoke(msg); + } else { + throw new NoRegisteredCallbackException("Callback target does not implement the callback interface"); + } + } + + public void setNext(Invoker next) { + this.next = next; + } + + public Invoker getNext() { + return next; + } + +} diff --git a/sca-java-1.x/branches/sca-java-1.6.2/modules/core/src/main/java/org/apache/tuscany/sca/core/invocation/CallbackReferenceImpl.java b/sca-java-1.x/branches/sca-java-1.6.2/modules/core/src/main/java/org/apache/tuscany/sca/core/invocation/CallbackReferenceImpl.java new file mode 100644 index 0000000000..97c69c33cb --- /dev/null +++ b/sca-java-1.x/branches/sca-java-1.6.2/modules/core/src/main/java/org/apache/tuscany/sca/core/invocation/CallbackReferenceImpl.java @@ -0,0 +1,268 @@ +/*
+ * 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.core.invocation;
+
+import java.io.IOException;
+import java.io.ObjectInput;
+import java.io.ObjectOutput;
+import java.util.List;
+
+import org.apache.tuscany.sca.assembly.Binding;
+import org.apache.tuscany.sca.assembly.Component;
+import org.apache.tuscany.sca.assembly.ComponentService;
+import org.apache.tuscany.sca.assembly.Contract;
+import org.apache.tuscany.sca.assembly.OptimizableBinding;
+import org.apache.tuscany.sca.core.assembly.EndpointReferenceImpl;
+import org.apache.tuscany.sca.core.assembly.RuntimeComponentReferenceImpl;
+import org.apache.tuscany.sca.core.assembly.RuntimeWireImpl;
+import org.apache.tuscany.sca.core.context.CallableReferenceImpl;
+import org.apache.tuscany.sca.core.context.ComponentContextHelper;
+import org.apache.tuscany.sca.interfacedef.InterfaceContract;
+import org.apache.tuscany.sca.interfacedef.java.JavaInterface;
+import org.apache.tuscany.sca.invocation.Message;
+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;
+
+/**
+ * Returns proxy instance for a wire callback
+ *
+ * @version $Rev: 576055 $ $Date: 2007-09-16 08:11:45 +0100 (Sun, 16 Sep 2007) $
+ */
+public class CallbackReferenceImpl<B> extends CallableReferenceImpl<B> {
+ private RuntimeWire wire;
+ private List<RuntimeWire> wires;
+ private EndpointReference resolvedEndpoint;
+ private Object convID;
+
+ public static CallbackReferenceImpl newInstance(Class interfaze,
+ ProxyFactory proxyFactory,
+ List<RuntimeWire> wires) {
+ if (getCallbackEndpoint(ThreadMessageContext.getMessageContext()) != null) {
+ return new CallbackReferenceImpl(interfaze, proxyFactory, wires);
+ } else {
+ return null;
+ }
+ }
+
+ /**
+ * Public constructor for Externalizable serialization/deserialization.
+ */
+ public CallbackReferenceImpl() {
+ super();
+ }
+
+ private CallbackReferenceImpl(Class<B> interfaze, ProxyFactory proxyFactory, List<RuntimeWire> wires) {
+ super(interfaze, null, proxyFactory);
+ this.wires = wires;
+ init();
+ }
+
+ public void init() {
+ Message msgContext = ThreadMessageContext.getMessageContext();
+ wire = selectCallbackWire(msgContext);
+ if (wire == null) {
+ //FIXME: need better exception
+ throw new RuntimeException("No callback binding found for " + msgContext.getTo().getURI());
+ }
+ resolvedEndpoint = getCallbackEndpoint(msgContext);
+ convID = msgContext.getFrom().getReferenceParameters().getConversationID();
+ callbackID = msgContext.getFrom().getReferenceParameters().getCallbackID();
+ }
+
+ @Override
+ protected Object createProxy() throws Exception {
+ return proxyFactory.createCallbackProxy(this);
+ }
+
+ protected RuntimeWire getCallbackWire() {
+ if (resolvedEndpoint == null) {
+ return null;
+ } else {
+ return cloneAndBind(wire);
+ }
+ }
+
+ protected Object getConvID() {
+ return convID;
+ }
+
+ protected EndpointReference getResolvedEndpoint() {
+ return resolvedEndpoint;
+ }
+
+ private RuntimeWire selectCallbackWire(Message msgContext) {
+ // look for callback binding with same name as service binding
+ EndpointReference to = msgContext.getTo();
+ if (to == null) {
+ //FIXME: need better exception
+ throw new RuntimeException("Destination for forward call is not available");
+ }
+ for (RuntimeWire wire : wires) {
+ if (wire.getSource().getBinding().getName().equals(to.getBinding().getName())) {
+ return wire;
+ }
+ }
+
+ // if no match, look for callback binding with same type as service binding
+ for (RuntimeWire wire : wires) {
+ if (wire.getSource().getBinding().getClass() == to.getBinding().getClass()) {
+ return wire;
+ }
+ }
+
+ // no suitable callback wire was found
+ return null;
+ }
+
+ /**
+ * @param msgContext
+ */
+ private static EndpointReference getCallbackEndpoint(Message msgContext) {
+ EndpointReference from = msgContext.getFrom();
+ if (from == null) {
+ return null;
+ }
+ return from.getReferenceParameters().getCallbackReference();
+ }
+
+ private RuntimeWire cloneAndBind(RuntimeWire wire) {
+ RuntimeWire boundWire = null;
+ if (resolvedEndpoint != null) {
+ boundWire = ((RuntimeWireImpl)wire).lookupCache(resolvedEndpoint);
+ if (boundWire != null) {
+ return boundWire;
+ }
+ try {
+ Contract contract = resolvedEndpoint.getContract();
+ RuntimeComponentReference ref = null;
+ if (contract == null) {
+ boundWire = (RuntimeWire)wire.clone();
+
+ } else if (contract instanceof RuntimeComponentReference) {
+ ref = (RuntimeComponentReference)contract;
+ boundWire = ref.getRuntimeWire(resolvedEndpoint.getBinding());
+
+ } else { // contract instanceof RuntimeComponentService
+ ref = bind((RuntimeComponentReference)wire.getSource().getContract(),
+ resolvedEndpoint.getComponent(),
+ (RuntimeComponentService)contract);
+ boundWire = ref.getRuntimeWires().get(0);
+ }
+ configureWire(boundWire);
+ ((RuntimeWireImpl)wire).addToCache(resolvedEndpoint, boundWire);
+ } catch (CloneNotSupportedException e) {
+ // will not happen
+ }
+ }
+ return boundWire;
+ }
+
+ private static RuntimeComponentReference bind(RuntimeComponentReference reference,
+ RuntimeComponent component,
+ RuntimeComponentService service) throws CloneNotSupportedException {
+ RuntimeComponentReference ref = (RuntimeComponentReference)reference.clone();
+ ref.getTargets().add(service);
+ ref.getBindings().clear();
+ for (Binding binding : service.getBindings()) {
+ if (binding instanceof OptimizableBinding) {
+ OptimizableBinding optimizableBinding = (OptimizableBinding)((OptimizableBinding)binding).clone();
+ optimizableBinding.setTargetBinding(binding);
+ optimizableBinding.setTargetComponent(component);
+ optimizableBinding.setTargetComponentService(service);
+ ref.getBindings().add(optimizableBinding);
+ } else {
+ ref.getBindings().add(binding);
+ }
+ }
+ return ref;
+ }
+
+ private void configureWire(RuntimeWire wire) {
+ // need to set the endpoint on the binding also so that when the chains are created next
+ // the sca binding can decide whether to provide local or remote invokers.
+ // TODO - there is a problem here though in that I'm setting a target on a
+ // binding that may possibly be trying to point at two things in the multi threaded
+ // case. Need to confirm the general model here and how the clone and bind part
+ // is intended to work
+ Binding binding = wire.getSource().getBinding();
+ binding.setURI(resolvedEndpoint.getURI());
+
+ // also need to set the target contract as it varies for the sca binding depending on
+ // whether it is local or remote
+ RuntimeComponentReference ref = (RuntimeComponentReference)wire.getSource().getContract();
+ wire.getTarget().setInterfaceContract(ref.getBindingProvider(binding).getBindingInterfaceContract());
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
+ super.readExternal(in);
+ this.callbackID = in.readObject();
+ this.convID = in.readObject();
+
+ this.compositeActivator = ComponentContextHelper.getCurrentCompositeActivator();
+
+ // Get the target Component and Service from the URI
+ final String uri = in.readUTF();
+ final Component targetComponent = super.resolveComponentURI(uri);
+ final ComponentService targetService = super.resolveServiceURI(uri, targetComponent);
+ final InterfaceContract targetServiceIfaceContract = targetService.getInterfaceContract();
+
+ // Re-create the resolved Endpoint
+ this.resolvedEndpoint = new EndpointReferenceImpl(
+ (RuntimeComponent) targetComponent, targetService, null,
+ targetServiceIfaceContract);
+
+ // Copy the Java Interface from the Service
+ final JavaInterface ji = (JavaInterface) targetServiceIfaceContract.getInterface();
+ this.businessInterface = (Class<B>) ji.getJavaClass();
+
+ // We need to re-create the callback wire. We need to do this on a clone of the Service
+ // wire since we need to change some details on it.
+ // FIXME: Is this the best way to do this?
+ final RuntimeWire cbWire = ((RuntimeComponentService) targetService).getRuntimeWires().get(0);
+ try {
+ this.wire = (RuntimeWireImpl) cbWire.clone();
+ } catch (CloneNotSupportedException e) {
+ throw new IOException(e.toString());
+ }
+
+ // Setup the reference on the cloned wire
+ final RuntimeComponentReference ref = new RuntimeComponentReferenceImpl();
+ ref.setComponent((RuntimeComponent) targetComponent);
+ ref.setInterfaceContract(targetServiceIfaceContract);
+ ((EndpointReferenceImpl) this.wire.getSource()).setContract(ref);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void writeExternal(ObjectOutput out) throws IOException {
+ super.writeExternal(out);
+ out.writeObject(this.callbackID);
+ out.writeObject(this.convID);
+ out.writeUTF(this.resolvedEndpoint.getURI());
+ }
+}
diff --git a/sca-java-1.x/branches/sca-java-1.6.2/modules/core/src/main/java/org/apache/tuscany/sca/core/invocation/CallbackReferenceObjectFactory.java b/sca-java-1.x/branches/sca-java-1.6.2/modules/core/src/main/java/org/apache/tuscany/sca/core/invocation/CallbackReferenceObjectFactory.java new file mode 100644 index 0000000000..b5b40811ad --- /dev/null +++ b/sca-java-1.x/branches/sca-java-1.6.2/modules/core/src/main/java/org/apache/tuscany/sca/core/invocation/CallbackReferenceObjectFactory.java @@ -0,0 +1,48 @@ +/*
+ * 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.core.invocation;
+
+import java.util.List;
+
+import org.apache.tuscany.sca.core.factory.ObjectCreationException;
+import org.apache.tuscany.sca.core.factory.ObjectFactory;
+import org.apache.tuscany.sca.runtime.RuntimeWire;
+import org.osoa.sca.CallableReference;
+
+/**
+ * Uses a wire to return a CallableReference
+ *
+ * @version $Rev: 574648 $ $Date: 2007-09-11 18:45:36 +0100 (Tue, 11 Sep 2007) $
+ */
+public class CallbackReferenceObjectFactory implements ObjectFactory<CallableReference<?>> {
+ private Class<?> businessInterface;
+ private ProxyFactory proxyFactory;
+ private List<RuntimeWire> wires;
+
+ public CallbackReferenceObjectFactory(Class<?> interfaze, ProxyFactory proxyFactory, List<RuntimeWire> wires) {
+ this.businessInterface = interfaze;
+ this.proxyFactory = proxyFactory;
+ this.wires = wires;
+ }
+
+ public CallableReference<?> getInstance() throws ObjectCreationException {
+ return CallbackReferenceImpl.newInstance(businessInterface, proxyFactory, wires);
+ }
+
+}
diff --git a/sca-java-1.x/branches/sca-java-1.6.2/modules/core/src/main/java/org/apache/tuscany/sca/core/invocation/CallbackWireObjectFactory.java b/sca-java-1.x/branches/sca-java-1.6.2/modules/core/src/main/java/org/apache/tuscany/sca/core/invocation/CallbackWireObjectFactory.java new file mode 100644 index 0000000000..2b37c30451 --- /dev/null +++ b/sca-java-1.x/branches/sca-java-1.6.2/modules/core/src/main/java/org/apache/tuscany/sca/core/invocation/CallbackWireObjectFactory.java @@ -0,0 +1,47 @@ +/* + * 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.core.invocation; + +import java.util.List; + +import org.apache.tuscany.sca.core.factory.ObjectCreationException; +import org.apache.tuscany.sca.core.factory.ObjectFactory; +import org.apache.tuscany.sca.runtime.RuntimeWire; + +/** + * Returns proxy instance for a wire callback + * + * @version $Rev$ $Date$ + */ +public class CallbackWireObjectFactory<B> implements ObjectFactory<B> { + private Class<B> businessInterface; + private ProxyFactory proxyFactory; + private List<RuntimeWire> wires; + + public CallbackWireObjectFactory(Class<B> interfaze, ProxyFactory proxyFactory, List<RuntimeWire> wires) { + this.businessInterface = interfaze; + this.proxyFactory = proxyFactory; + this.wires = wires; + } + + public B getInstance() throws ObjectCreationException { + return proxyFactory.createCallbackProxy(businessInterface, wires); + } + +} diff --git a/sca-java-1.x/branches/sca-java-1.6.2/modules/core/src/main/java/org/apache/tuscany/sca/core/invocation/CglibProxyFactory.java b/sca-java-1.x/branches/sca-java-1.6.2/modules/core/src/main/java/org/apache/tuscany/sca/core/invocation/CglibProxyFactory.java new file mode 100644 index 0000000000..0b3c043340 --- /dev/null +++ b/sca-java-1.x/branches/sca-java-1.6.2/modules/core/src/main/java/org/apache/tuscany/sca/core/invocation/CglibProxyFactory.java @@ -0,0 +1,172 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.apache.tuscany.sca.core.invocation; + +import java.lang.reflect.Method; +import java.util.List; + +import net.sf.cglib.proxy.Callback; +import net.sf.cglib.proxy.Enhancer; +import net.sf.cglib.proxy.Factory; +import net.sf.cglib.proxy.MethodInterceptor; +import net.sf.cglib.proxy.MethodProxy; + +import org.apache.tuscany.sca.core.context.CallableReferenceImpl; +import org.apache.tuscany.sca.core.context.ServiceReferenceImpl; +import org.apache.tuscany.sca.interfacedef.InterfaceContractMapper; +import org.apache.tuscany.sca.interfacedef.impl.InterfaceContractMapperImpl; +import org.apache.tuscany.sca.invocation.MessageFactory; +import org.apache.tuscany.sca.runtime.RuntimeWire; +import org.osoa.sca.CallableReference; +import org.osoa.sca.ServiceReference; + +/** + * The implementation of a wire service that uses cglib dynamic proxies + * + * @version $Rev$ $Date$ + */ +@SuppressWarnings("unused") +public class CglibProxyFactory implements ProxyFactory { + private MessageFactory messageFactory; + + public CglibProxyFactory(MessageFactory messageFactory, InterfaceContractMapper mapper) { + this.messageFactory = messageFactory; + + } + + public <T> T createProxy(Class<T> interfaze, RuntimeWire wire) throws ProxyCreationException { + ServiceReference<T> serviceReference = new ServiceReferenceImpl(interfaze, wire, this); + return createProxy(serviceReference); + } + + private class CglibClassLoader extends ClassLoader { + private ClassLoader appLoader; + private ClassLoader bundleLoader; + + @Override + public Class<?> loadClass(String className) + throws ClassNotFoundException { + try { + return appLoader.loadClass(className); + } catch (ClassNotFoundException ex ) { + return bundleLoader.loadClass(className); + } + } + + CglibClassLoader(ClassLoader app, ClassLoader bundle) { + this.appLoader = app; + this.bundleLoader = bundle; + } + } + /** + * create the proxy with cglib. use the same JDKInvocationHandler as + * JDKProxyService. + */ + public <T> T createProxy(CallableReference<T> callableReference) throws ProxyCreationException { + Enhancer enhancer = new Enhancer(); + Class<T> interfaze = callableReference.getBusinessInterface(); + ClassLoader cl = new CglibClassLoader(interfaze.getClassLoader(), getClass().getClassLoader()); + enhancer.setClassLoader(cl); + enhancer.setSuperclass(interfaze); + enhancer.setCallback(new CglibMethodInterceptor<T>(callableReference)); + Object proxy = enhancer.create(); + ((CallableReferenceImpl)callableReference).setProxy(proxy); + return interfaze.cast(proxy); + } + + /** + * create the callback proxy with cglib. use the same + * JDKCallbackInvocationHandler as JDKProxyService. + */ + public <T> T createCallbackProxy(Class<T> interfaze, final List<RuntimeWire> wires) throws ProxyCreationException { + CallbackReferenceImpl<T> callbackReference = CallbackReferenceImpl.newInstance(interfaze, this, wires); + return callbackReference != null ? createCallbackProxy(callbackReference) : null; + } + + /** + * create the callback proxy with cglib. use the same + * JDKCallbackInvocationHandler as JDKProxyService. + */ + public <T> T createCallbackProxy(CallbackReferenceImpl<T> callbackReference) throws ProxyCreationException { + Enhancer enhancer = new Enhancer(); + Class<T> interfaze = callbackReference.getBusinessInterface(); + enhancer.setSuperclass(interfaze); + enhancer.setCallback(new CglibMethodInterceptor<T>(callbackReference)); + Object proxy = enhancer.create(); + callbackReference.setProxy(proxy); + return interfaze.cast(proxy); + } + + @SuppressWarnings("unchecked") + public <B, R extends CallableReference<B>> R cast(B target) throws IllegalArgumentException { + if (isProxyClass(target.getClass())) { + Factory factory = (Factory)target; + Callback[] callbacks = factory.getCallbacks(); + if (callbacks.length != 1 || !(callbacks[0] instanceof CglibMethodInterceptor)) { + throw new IllegalArgumentException("The object is not a known proxy."); + } + CglibMethodInterceptor interceptor = (CglibMethodInterceptor)callbacks[0]; + return (R)interceptor.invocationHandler.getCallableReference(); + } else { + throw new IllegalArgumentException("The object is not a known proxy."); + } + } + + /** + * @see org.apache.tuscany.sca.core.invocation.ProxyFactory#isProxyClass(java.lang.Class) + */ + public boolean isProxyClass(Class<?> clazz) { + return Factory.class.isAssignableFrom(clazz); + } + + private class CglibMethodInterceptor<T> implements MethodInterceptor { + private JDKInvocationHandler invocationHandler; + + public CglibMethodInterceptor(CallableReference<T> callableReference) { + invocationHandler = new JDKInvocationHandler(messageFactory, callableReference); + } + + public CglibMethodInterceptor(CallbackReferenceImpl<T> callbackReference) { + invocationHandler = new JDKCallbackInvocationHandler(messageFactory, callbackReference); + } + + /* + public CglibMethodInterceptor(Class<T> interfaze, RuntimeWire wire) { + ServiceReference<T> serviceRef = new ServiceReferenceImpl<T>(interfaze, wire, CglibProxyFactory.this); + invocationHandler = new JDKInvocationHandler(messageFactory, serviceRef); + } + + public CglibMethodInterceptor(Class<T> interfaze, List<RuntimeWire> wires) { + CallbackReferenceImpl ref = new CallbackReferenceImpl(interfaze, CglibProxyFactory.this, wires); + invocationHandler = new JDKCallbackInvocationHandler(messageFactory, ref); + } + */ + + /** + * @see net.sf.cglib.proxy.MethodInterceptor#intercept(java.lang.Object, java.lang.reflect.Method, java.lang.Object[], net.sf.cglib.proxy.MethodProxy) + */ + public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable { + Object result = invocationHandler.invoke(proxy, method, args); + return result; + } + + } + +} diff --git a/sca-java-1.x/branches/sca-java-1.6.2/modules/core/src/main/java/org/apache/tuscany/sca/core/invocation/DefaultProxyFactoryExtensionPoint.java b/sca-java-1.x/branches/sca-java-1.6.2/modules/core/src/main/java/org/apache/tuscany/sca/core/invocation/DefaultProxyFactoryExtensionPoint.java new file mode 100644 index 0000000000..9acb4be6f8 --- /dev/null +++ b/sca-java-1.x/branches/sca-java-1.6.2/modules/core/src/main/java/org/apache/tuscany/sca/core/invocation/DefaultProxyFactoryExtensionPoint.java @@ -0,0 +1,74 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.apache.tuscany.sca.core.invocation; + +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.interfacedef.InterfaceContractMapper; +import org.apache.tuscany.sca.invocation.MessageFactory; + +/** + * Default implementation of a ProxyFactoryExtensionPoint. + * + * @version $Rev$ $Date$ + */ +public class DefaultProxyFactoryExtensionPoint implements ProxyFactoryExtensionPoint { + private InterfaceContractMapper interfaceContractMapper; + private MessageFactory messageFactory; + + private ProxyFactory interfaceFactory; + private ProxyFactory classFactory; + + public DefaultProxyFactoryExtensionPoint(ExtensionPointRegistry extensionPoints) { + UtilityExtensionPoint utilities = extensionPoints.getExtensionPoint(UtilityExtensionPoint.class); + this.interfaceContractMapper = utilities.getUtility(InterfaceContractMapper.class); + + ModelFactoryExtensionPoint modelFactories = extensionPoints.getExtensionPoint(ModelFactoryExtensionPoint.class); + this.messageFactory = modelFactories.getFactory(MessageFactory.class); + + interfaceFactory = new JDKProxyFactory(messageFactory, interfaceContractMapper); + } + + public DefaultProxyFactoryExtensionPoint(MessageFactory messageFactory, InterfaceContractMapper mapper) { + this.interfaceContractMapper = mapper; + this.messageFactory = messageFactory; + interfaceFactory = new JDKProxyFactory(messageFactory, mapper); + } + + public ProxyFactory getClassProxyFactory() { + return classFactory; + } + + public ProxyFactory getInterfaceProxyFactory() { + return interfaceFactory; + } + + public void setClassProxyFactory(ProxyFactory factory) { + this.classFactory = factory; + + } + + public void setInterfaceProxyFactory(ProxyFactory factory) { + this.interfaceFactory = factory; + + } + +} diff --git a/sca-java-1.x/branches/sca-java-1.6.2/modules/core/src/main/java/org/apache/tuscany/sca/core/invocation/ExtensibleProxyFactory.java b/sca-java-1.x/branches/sca-java-1.6.2/modules/core/src/main/java/org/apache/tuscany/sca/core/invocation/ExtensibleProxyFactory.java new file mode 100644 index 0000000000..fcb48259b9 --- /dev/null +++ b/sca-java-1.x/branches/sca-java-1.6.2/modules/core/src/main/java/org/apache/tuscany/sca/core/invocation/ExtensibleProxyFactory.java @@ -0,0 +1,113 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.apache.tuscany.sca.core.invocation; + +import java.util.List; + +import org.apache.tuscany.sca.runtime.RuntimeWire; +import org.osoa.sca.CallableReference; + +/** + * An extensible proxy factory. + * + * @version $Rev: $ $Date: $ + */ +public class ExtensibleProxyFactory implements ProxyFactory { + + private ProxyFactoryExtensionPoint proxyFactories; + + public ExtensibleProxyFactory(ProxyFactoryExtensionPoint proxyFactories) { + this.proxyFactories = proxyFactories; + } + + /** + * @see org.apache.tuscany.sca.core.invocation.ProxyFactory#cast(java.lang.Object) + */ + @SuppressWarnings("unchecked") + public <B, R extends CallableReference<B>> R cast(B target) throws IllegalArgumentException { + ProxyFactory interfaceFactory = proxyFactories.getInterfaceProxyFactory(); + ProxyFactory classFactory = proxyFactories.getClassProxyFactory(); + if (interfaceFactory.isProxyClass(target.getClass())) { + return (R)interfaceFactory.cast(target); + } else if (classFactory != null && classFactory.isProxyClass(target.getClass())) { + return (R)classFactory.cast(target); + } else { + throw new IllegalArgumentException("The target is not a callable proxy"); + } + } + + /** + * @see org.apache.tuscany.sca.core.invocation.ProxyFactory#createCallbackProxy(java.lang.Class, + * java.util.List) + */ + public <T> T createCallbackProxy(Class<T> interfaze, List<RuntimeWire> wires) throws ProxyCreationException { + ProxyFactory interfaceFactory = proxyFactories.getInterfaceProxyFactory(); + ProxyFactory classFactory = proxyFactories.getClassProxyFactory(); + if (interfaze.isInterface()) { + return interfaceFactory.createCallbackProxy(interfaze, wires); + } else { + return classFactory.createCallbackProxy(interfaze, wires); + } + } + + public <T> T createProxy(CallableReference<T> callableReference) throws ProxyCreationException { + ProxyFactory interfaceFactory = proxyFactories.getInterfaceProxyFactory(); + ProxyFactory classFactory = proxyFactories.getClassProxyFactory(); + if (callableReference.getBusinessInterface().isInterface()) { + return interfaceFactory.createProxy(callableReference); + } else { + return classFactory.createProxy(callableReference); + } + } + + public <T> T createCallbackProxy(CallbackReferenceImpl<T> callbackReference) throws ProxyCreationException { + ProxyFactory interfaceFactory = proxyFactories.getInterfaceProxyFactory(); + ProxyFactory classFactory = proxyFactories.getClassProxyFactory(); + if (callbackReference.getBusinessInterface().isInterface()) { + return interfaceFactory.createCallbackProxy(callbackReference); + } else { + return classFactory.createCallbackProxy(callbackReference); + } + } + + /** + * @see org.apache.tuscany.sca.core.invocation.ProxyFactory#createProxy(java.lang.Class, + * org.apache.tuscany.sca.runtime.RuntimeWire) + */ + public <T> T createProxy(Class<T> interfaze, RuntimeWire wire) throws ProxyCreationException { + ProxyFactory interfaceFactory = proxyFactories.getInterfaceProxyFactory(); + ProxyFactory classFactory = proxyFactories.getClassProxyFactory(); + if (interfaze.isInterface()) { + return interfaceFactory.createProxy(interfaze, wire); + } else { + return classFactory.createProxy(interfaze, wire); + } + } + + /** + * @see org.apache.tuscany.sca.core.invocation.ProxyFactory#isProxyClass(java.lang.Class) + */ + public boolean isProxyClass(Class<?> clazz) { + ProxyFactory interfaceFactory = proxyFactories.getInterfaceProxyFactory(); + ProxyFactory classFactory = proxyFactories.getClassProxyFactory(); + return interfaceFactory.isProxyClass(clazz) || (classFactory != null && classFactory.isProxyClass(clazz)); + } + +} diff --git a/sca-java-1.x/branches/sca-java-1.6.2/modules/core/src/main/java/org/apache/tuscany/sca/core/invocation/ExtensibleWireProcessor.java b/sca-java-1.x/branches/sca-java-1.6.2/modules/core/src/main/java/org/apache/tuscany/sca/core/invocation/ExtensibleWireProcessor.java new file mode 100644 index 0000000000..934f2f7aa0 --- /dev/null +++ b/sca-java-1.x/branches/sca-java-1.6.2/modules/core/src/main/java/org/apache/tuscany/sca/core/invocation/ExtensibleWireProcessor.java @@ -0,0 +1,44 @@ +/* + * 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.core.invocation; + +import org.apache.tuscany.sca.runtime.RuntimeWire; +import org.apache.tuscany.sca.runtime.RuntimeWireProcessor; +import org.apache.tuscany.sca.runtime.RuntimeWireProcessorExtensionPoint; + +/** + * The default implementation of an extensible <code>WireProcessor</code> + * + * @version $Rev$ $Date$ + */ +public class ExtensibleWireProcessor implements RuntimeWireProcessor { + + private RuntimeWireProcessorExtensionPoint processors; + + public ExtensibleWireProcessor(RuntimeWireProcessorExtensionPoint processors) { + this.processors = processors; + } + + public void process(RuntimeWire wire) { + for (RuntimeWireProcessor processor : processors.getWireProcessors()) { + processor.process(wire); + } + } + +} diff --git a/sca-java-1.x/branches/sca-java-1.6.2/modules/core/src/main/java/org/apache/tuscany/sca/core/invocation/InvocationChainImpl.java b/sca-java-1.x/branches/sca-java-1.6.2/modules/core/src/main/java/org/apache/tuscany/sca/core/invocation/InvocationChainImpl.java new file mode 100644 index 0000000000..c559a42bdc --- /dev/null +++ b/sca-java-1.x/branches/sca-java-1.6.2/modules/core/src/main/java/org/apache/tuscany/sca/core/invocation/InvocationChainImpl.java @@ -0,0 +1,191 @@ +/* + * 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.core.invocation; + +import java.util.ArrayList; +import java.util.List; +import java.util.ListIterator; + +import org.apache.tuscany.sca.interfacedef.Operation; +import org.apache.tuscany.sca.invocation.DataExchangeSemantics; +import org.apache.tuscany.sca.invocation.Interceptor; +import org.apache.tuscany.sca.invocation.InvocationChain; +import org.apache.tuscany.sca.invocation.Invoker; +import org.apache.tuscany.sca.invocation.Phase; + +/** + * Default implementation of an invocation chain + * + * @version $Rev$ $Date$ + */ +public class InvocationChainImpl implements InvocationChain { + private Operation sourceOperation; + private Operation targetOperation; + private List<Node> nodes = new ArrayList<Node>(); + + // FIXME: Not a good practice to use static reference + private static final PhaseManager phaseManager = new PhaseManager(); + private boolean forReference; + private boolean allowsPassByReference; + + public InvocationChainImpl(Operation sourceOperation, Operation targetOperation, boolean forReference) { + // TODO - binding invocation chain doesn't provide operations + //assert sourceOperation != null; + //assert targetOperation != null; + this.targetOperation = targetOperation; + this.sourceOperation = sourceOperation; + this.forReference = forReference; + } + + public Operation getTargetOperation() { + return targetOperation; + } + + public void setTargetOperation(Operation operation) { + this.targetOperation = operation; + } + + public void addInterceptor(Interceptor interceptor) { + String phase = forReference ? Phase.REFERENCE : Phase.SERVICE; + addInterceptor(phase, interceptor); + } + + public void addInvoker(Invoker invoker) { + String phase = forReference ? Phase.REFERENCE_BINDING : Phase.IMPLEMENTATION; + addInvoker(phase, invoker); + } + + public Invoker getHeadInvoker() { + return nodes.isEmpty() ? null : nodes.get(0).getInvoker(); + } + + public Invoker getTailInvoker() { + return nodes.isEmpty() ? null : nodes.get(nodes.size() - 1).getInvoker(); + } + + /** + * @return the sourceOperation + */ + public Operation getSourceOperation() { + return sourceOperation; + } + + /** + * @param sourceOperation the sourceOperation to set + */ + public void setSourceOperation(Operation sourceOperation) { + this.sourceOperation = sourceOperation; + } + + public void addInterceptor(int index, Interceptor interceptor) { + addInterceptor(interceptor); + } + + public void addInterceptor(String phase, Interceptor interceptor) { + addInvoker(phase, interceptor); + } + + private void addInvoker(String phase, Invoker invoker) { + int index = phaseManager.getAllPhases().indexOf(phase); + if (index == -1) { + throw new IllegalArgumentException("Invalid phase name: " + phase); + } + Node node = new Node(index, invoker); + ListIterator<Node> li = nodes.listIterator(); + Node before = null, after = null; + boolean found = false; + while (li.hasNext()) { + before = after; + after = li.next(); + if (after.getPhaseIndex() > index) { + // Move back + li.previous(); + li.add(node); + found = true; + break; + } + } + if (!found) { + // Add to the end + nodes.add(node); + before = after; + after = null; + } + + // Relink the interceptors + if (before != null) { + if (before.getInvoker() instanceof Interceptor) { + ((Interceptor)before.getInvoker()).setNext(invoker); + } + } + if (after != null) { + if (invoker instanceof Interceptor) { + ((Interceptor)invoker).setNext(after.getInvoker()); + } + } + + } + + public boolean allowsPassByReference() { + if (allowsPassByReference) { + // No need to check the invokers + return true; + } + // Check if any of the invokers allows pass-by-reference + boolean allowsPBR = false; + for (Node i : nodes) { + if (i.getInvoker() instanceof DataExchangeSemantics) { + if (((DataExchangeSemantics)i.getInvoker()).allowsPassByReference()) { + allowsPBR = true; + break; + } + } + } + return allowsPBR; + } + + public void setAllowsPassByReference(boolean allowsPBR) { + this.allowsPassByReference = allowsPBR; + } + + private static class Node { + private int phaseIndex; + private Invoker invoker; + + public Node(int phaseIndex, Invoker invoker) { + super(); + this.phaseIndex = phaseIndex; + this.invoker = invoker; + } + + public int getPhaseIndex() { + return phaseIndex; + } + + public Invoker getInvoker() { + return invoker; + } + + @Override + public String toString() { + return "(" + phaseIndex + ")" + invoker; + } + } + +} diff --git a/sca-java-1.x/branches/sca-java-1.6.2/modules/core/src/main/java/org/apache/tuscany/sca/core/invocation/JDKCallbackInvocationHandler.java b/sca-java-1.x/branches/sca-java-1.6.2/modules/core/src/main/java/org/apache/tuscany/sca/core/invocation/JDKCallbackInvocationHandler.java new file mode 100644 index 0000000000..62e8b4d3ee --- /dev/null +++ b/sca-java-1.x/branches/sca-java-1.6.2/modules/core/src/main/java/org/apache/tuscany/sca/core/invocation/JDKCallbackInvocationHandler.java @@ -0,0 +1,124 @@ +/* + * 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.core.invocation; + +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; + +import org.apache.tuscany.sca.core.assembly.RuntimeWireImpl; +import org.apache.tuscany.sca.core.context.CallableReferenceImpl; +import org.apache.tuscany.sca.core.conversation.ConversationState; +import org.apache.tuscany.sca.core.scope.TargetResolutionException; +import org.apache.tuscany.sca.invocation.InvocationChain; +import org.apache.tuscany.sca.invocation.Message; +import org.apache.tuscany.sca.invocation.MessageFactory; +import org.apache.tuscany.sca.runtime.ReferenceParameters; +import org.apache.tuscany.sca.runtime.RuntimeWire; +import org.osoa.sca.NoRegisteredCallbackException; +import org.osoa.sca.ServiceRuntimeException; + +/** + * Responsible for dispatching to a callback through a wire. <p/> TODO cache + * target invoker + * + * @version $Rev$ $Date$ + */ +public class JDKCallbackInvocationHandler extends JDKInvocationHandler { + private static final long serialVersionUID = -3350283555825935609L; + + public JDKCallbackInvocationHandler(MessageFactory messageFactory, CallbackReferenceImpl ref) { + super(messageFactory, ref); + this.fixedWire = false; + } + + @Override + @SuppressWarnings( {"unchecked"}) + public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { + if (Object.class == method.getDeclaringClass()) { + return invokeObjectMethod(method, args); + } + + // obtain a dedicated wire to be used for this callback invocation + RuntimeWire wire = ((CallbackReferenceImpl)callableReference).getCallbackWire(); + if (wire == null) { + //FIXME: need better exception + throw new ServiceRuntimeException("No callback wire found"); + } + + // set the conversational state based on the interface that + // is specified for the reference that this wire belongs to + initConversational(wire); + + // set the conversation id into the conversation object. This is + // a special case for callbacks as, unless otherwise set manually, + // the callback should use the same conversation id as was received + // on the incoming call to this component + if (conversational) { + + if (conversation == null || conversation.getState() == ConversationState.ENDED) { + conversation = null; + } + Object convID = conversation == null ? null : conversation.getConversationID(); + + // create a conversation id if one doesn't exist + // already, i.e. the conversation is just starting + if (convID == null) { + convID = ((CallbackReferenceImpl)callableReference).getConvID(); + if (convID != null) { + conversation = ((RuntimeWireImpl)wire).getConversationManager().getConversation(convID); + if (callableReference != null) { + ((CallableReferenceImpl)callableReference).attachConversation(conversation); + } + } + } + } + + setEndpoint(((CallbackReferenceImpl)callableReference).getResolvedEndpoint()); + + InvocationChain chain = getInvocationChain(method, wire); + if (chain == null) { + throw new IllegalArgumentException("No matching operation is found: " + method); + } + + try { + return invoke(chain, args, wire, wire.getSource()); + } catch (InvocationTargetException e) { + Throwable t = e.getCause(); + if (t instanceof NoRegisteredCallbackException) { + throw t; + } + throw e; + } finally { + // allow the cloned wire to be reused by subsequent callbacks + ((RuntimeWireImpl)wire).releaseWire(); + } + } + + /** + * + */ + @Override + protected void handleCallback(Message msg, RuntimeWire wire, Object currentConversationID) + throws TargetResolutionException { + ReferenceParameters parameters = msg.getFrom().getReferenceParameters(); + parameters.setCallbackID(getCallbackID()); + } + + +} diff --git a/sca-java-1.x/branches/sca-java-1.6.2/modules/core/src/main/java/org/apache/tuscany/sca/core/invocation/JDKInvocationHandler.java b/sca-java-1.x/branches/sca-java-1.6.2/modules/core/src/main/java/org/apache/tuscany/sca/core/invocation/JDKInvocationHandler.java new file mode 100644 index 0000000000..4c6abc726c --- /dev/null +++ b/sca-java-1.x/branches/sca-java-1.6.2/modules/core/src/main/java/org/apache/tuscany/sca/core/invocation/JDKInvocationHandler.java @@ -0,0 +1,614 @@ +/* + * 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.core.invocation; + +import java.io.Serializable; +import java.lang.reflect.InvocationHandler; +import java.lang.reflect.Method; +import java.lang.reflect.Proxy; +import java.util.IdentityHashMap; +import java.util.List; +import java.util.Map; +import java.util.UUID; + +import javax.xml.ws.Holder; + +import org.apache.tuscany.sca.core.assembly.CompositeActivator; +import org.apache.tuscany.sca.core.assembly.RuntimeWireImpl; +import org.apache.tuscany.sca.core.context.CallableReferenceImpl; +import org.apache.tuscany.sca.core.context.ComponentContextImpl; +import org.apache.tuscany.sca.core.context.InstanceWrapper; +import org.apache.tuscany.sca.core.conversation.ConversationManager; +import org.apache.tuscany.sca.core.conversation.ConversationState; +import org.apache.tuscany.sca.core.conversation.ExtendedConversation; +import org.apache.tuscany.sca.core.scope.Scope; +import org.apache.tuscany.sca.core.scope.ScopeContainer; +import org.apache.tuscany.sca.core.scope.ScopedRuntimeComponent; +import org.apache.tuscany.sca.core.scope.TargetDestructionException; +import org.apache.tuscany.sca.core.scope.TargetResolutionException; +import org.apache.tuscany.sca.interfacedef.ConversationSequence; +import org.apache.tuscany.sca.interfacedef.DataType; +import org.apache.tuscany.sca.interfacedef.Interface; +import org.apache.tuscany.sca.interfacedef.InterfaceContract; +import org.apache.tuscany.sca.interfacedef.InvalidInterfaceException; +import org.apache.tuscany.sca.interfacedef.Operation; +import org.apache.tuscany.sca.interfacedef.ParameterMode; +import org.apache.tuscany.sca.interfacedef.java.JavaInterface; +import org.apache.tuscany.sca.interfacedef.java.JavaOperation; +import org.apache.tuscany.sca.invocation.InvocationChain; +import org.apache.tuscany.sca.invocation.Invoker; +import org.apache.tuscany.sca.invocation.Message; +import org.apache.tuscany.sca.invocation.MessageFactory; +import org.apache.tuscany.sca.runtime.EndpointReference; +import org.apache.tuscany.sca.runtime.ReferenceParameters; +import org.apache.tuscany.sca.runtime.RuntimeComponent; +import org.apache.tuscany.sca.runtime.RuntimeWire; +import org.osoa.sca.CallableReference; +import org.osoa.sca.ConversationEndedException; +import org.osoa.sca.ServiceReference; +import org.osoa.sca.ServiceRuntimeException; + +/** + * @version $Rev$ $Date$ + */ +public class JDKInvocationHandler implements InvocationHandler, Serializable { + private static final long serialVersionUID = -3366410500152201371L; + + protected boolean conversational; + protected ExtendedConversation conversation; + protected MessageFactory messageFactory; + protected EndpointReference source; + protected EndpointReference target; + protected RuntimeWire wire; + protected CallableReference<?> callableReference; + protected Class<?> businessInterface; + + protected boolean fixedWire = true; + + protected transient Map<Method, InvocationChain> chains = new IdentityHashMap<Method, InvocationChain>(); + + public JDKInvocationHandler(MessageFactory messageFactory, Class<?> businessInterface, RuntimeWire wire) { + this.messageFactory = messageFactory; + this.wire = wire; + this.businessInterface = businessInterface; + init(this.wire); + } + + public JDKInvocationHandler(MessageFactory messageFactory, CallableReference<?> callableReference) { + this.messageFactory = messageFactory; + this.callableReference = callableReference; + if (callableReference != null) { + this.businessInterface = callableReference.getBusinessInterface(); + this.conversation = (ExtendedConversation)callableReference.getConversation(); + this.wire = ((CallableReferenceImpl<?>)callableReference).getRuntimeWire(); + + /* ==========================================================================*/ + // TUSCANY-3140 - in some cases we have noticed that the runtime engine for a + // component implementation uses a different classloader compared + // to the classloader used in the first instance to introspect the + // component type and create the component model. If the business + // interface of the callable reference is different from the + // interface of the reference then set the reference interface to the + // business interface + if (wire != null){ + Interface iface = wire.getSource().getInterfaceContract().getInterface(); + if (iface instanceof JavaInterface) { + JavaInterface javaIFace = (JavaInterface)iface; + // only reset the interface if the classes have the same name but the + // class object is different + if ((javaIFace.getJavaClass().getName().equals(this.businessInterface.getName())) && + (javaIFace.getJavaClass() != this.businessInterface)) { + try { + RuntimeComponent wireSourceComponent = wire.getSource().getComponent(); + CompositeActivator compositeActivator = ((ComponentContextImpl)wireSourceComponent.getComponentContext()).getCompositeActivator(); + if (compositeActivator != null && compositeActivator.getJavaInterfaceFactory() != null) { + //reconstruct java interface using interface loaded by implementation class loader + iface.getOperations().clear(); + compositeActivator.getJavaInterfaceFactory().createJavaInterface((JavaInterface) iface, this.businessInterface); + } + } catch (InvalidInterfaceException e) { + e.printStackTrace(); + } + } + } + } + /* ==========================================================================*/ + + if (wire != null) { + init(wire); + } + } + } + + protected void init(RuntimeWire wire) { + if (wire != null) { + try { + // Clone the endpoint reference so that reference parameters can be changed + source = (EndpointReference)wire.getSource().clone(); + } catch (CloneNotSupportedException e) { + throw new ServiceRuntimeException(e); + } + initConversational(wire); + } + } + + protected void initConversational(RuntimeWire wire) { + InterfaceContract contract = wire.getSource().getInterfaceContract(); + this.conversational = contract.getInterface().isConversational(); + } + + protected Object getCallbackID() { + if (callableReference != null) { + return callableReference.getCallbackID(); + } else { + return null; + } + } + + protected Object getConversationID() { + if (callableReference != null && callableReference instanceof ServiceReference) { + return ((ServiceReference)callableReference).getConversationID(); + } else { + return null; + } + } + + protected Object getCallbackObject() { + if (callableReference != null && callableReference instanceof ServiceReference) { + return ((ServiceReference)callableReference).getCallback(); + } else { + return null; + } + } + + public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { + if (Object.class == method.getDeclaringClass()) { + return invokeObjectMethod(method, args); + } + if (wire == null) { + throw new ServiceRuntimeException("No runtime wire is available"); + } + InvocationChain chain = getInvocationChain(method, wire); + if (chain == null) { + throw new IllegalArgumentException("No matching operation is found: " + method); + } + + Object result = invoke(chain, args, wire, source); + + Operation operation = chain.getSourceOperation(); + if (operation != null && operation.getInterface().isRemotable()) { + List<DataType> inputTypes = operation.getInputType().getLogical(); + // Returned Holder data <T> are placed back in Holder<T>. + for (int i = 0, size = inputTypes.size(); i < size; i++) { + if (operation.getParameterModes().get(i) != ParameterMode.IN) { + // Pop results and place in holder (demote). + Holder holder = (Holder)args[i]; + holder.value = result; + } + } + } + + return result; + } + + /** + * Handle the methods on the Object.class + * @param method + * @param args + */ + protected Object invokeObjectMethod(Method method, Object[] args) throws Throwable { + String name = method.getName(); + if ("toString".equals(name)) { + return "[Proxy - " + toString() + "]"; + } else if ("equals".equals(name)) { + Object obj = args[0]; + if (obj == null) { + return false; + } + if (!Proxy.isProxyClass(obj.getClass())) { + return false; + } + return equals(Proxy.getInvocationHandler(obj)); + } else if ("hashCode".equals(name)) { + return hashCode(); + } else { + return method.invoke(this); + } + } + + /** + * Determines if the given operation matches the given method + * + * @return true if the operation matches, false if does not + */ + // FIXME: Should it be in the InterfaceContractMapper? + @SuppressWarnings("unchecked") + private static boolean match(Operation operation, Method method) { + if (operation instanceof JavaOperation) { + JavaOperation javaOp = (JavaOperation)operation; + Method m = javaOp.getJavaMethod(); + if (!method.getName().equals(m.getName())) { + return false; + } + if (method.equals(m)) { + return true; + } + } else { + if (!method.getName().equals(operation.getName())) { + return false; + } + } + + // For remotable interface, operation is not overloaded. + if (operation.getInterface().isRemotable()) { + return true; + } + + Class<?>[] params = method.getParameterTypes(); + + DataType<List<DataType>> inputType = null; + if (operation.isInputWrapperStyle()) { + inputType = operation.getInputWrapper().getUnwrappedInputType(); + } else { + inputType = operation.getInputType(); + } + List<DataType> types = inputType.getLogical(); + boolean matched = true; + if (types.size() == params.length && method.getName().equals(operation.getName())) { + for (int i = 0; i < params.length; i++) { + Class<?> clazz = params[i]; + Class<?> type = types.get(i).getPhysical(); + // Object.class.isAssignableFrom(int.class) returns false + if (type != Object.class && (!type.isAssignableFrom(clazz))) { + matched = false; + } + } + } else { + matched = false; + } + return matched; + + } + + protected synchronized InvocationChain getInvocationChain(Method method, RuntimeWire wire) { + if (fixedWire) { + InvocationChain chain = chains.get(method); + if (chain != null) { + return chain; + } + } + InvocationChain found = null; + for (InvocationChain chain : wire.getInvocationChains()) { + Operation operation = chain.getSourceOperation(); + if (operation.isDynamic()) { + operation.setName(method.getName()); + found = chain; + break; + } else if (match(operation, method)) { + found = chain; + break; + } + } + if (fixedWire) { + chains.put(method, found); + } + return found; + } + + protected void setEndpoint(EndpointReference endpoint) { + this.target = endpoint; + } + + protected Object invoke(InvocationChain chain, Object[] args, RuntimeWire wire, EndpointReference source) + throws Throwable { + Message msg = messageFactory.createMessage(); + msg.setFrom(source); + if (target != null) { + msg.setTo(target); + } else { + msg.setTo(wire.getTarget()); + } + Invoker headInvoker = chain.getHeadInvoker(); + Operation operation = chain.getTargetOperation(); + + msg.setOperation(operation); + + // Holder pattern. Items stored in a Holder<T> are promoted to T. + // After the invoke, the returned data <T> are placed back in Holder<T>. + if (operation != null && operation.getInterface().isRemotable()) { + args = promoteHolderArgs(chain.getSourceOperation(), args); + } + msg.setBody(args); + + Message msgContext = ThreadMessageContext.getMessageContext(); + Object currentConversationID = msgContext.getFrom().getReferenceParameters().getConversationID(); + + conversationPreinvoke(msg, wire); + handleCallback(msg, wire, currentConversationID); + ThreadMessageContext.setMessageContext(msg); + boolean abnormalEndConversation = false; + try { + // dispatch the wire down the chain and get the response + Message resp = headInvoker.invoke(msg); + Object body = resp.getBody(); + if (resp.isFault()) { + // mark the conversation as ended if the exception is not a business exception + if (currentConversationID != null) { + try { + boolean businessException = false; + + for (DataType dataType : operation.getFaultTypes()) { + if (dataType.getPhysical() == ((Throwable)body).getClass()) { + businessException = true; + break; + } + } + + if (businessException == false) { + abnormalEndConversation = true; + } + } catch (Exception ex) { + // TODO - sure what the best course of action is here. We have + // a system exception in the middle of a business exception + } + } + throw (Throwable)body; + } + return body; + } finally { + conversationPostInvoke(msg, wire, abnormalEndConversation); + ThreadMessageContext.setMessageContext(msgContext); + } + } + + /** + * @param msg + * @param wire + * @param interfaze + * @throws TargetResolutionException + */ + protected void handleCallback(Message msg, RuntimeWire wire, Object currentConversationID) + throws TargetResolutionException { + + if (msg.getFrom() == null || msg.getFrom().getCallbackEndpoint() == null) { + return; + } + + ReferenceParameters parameters = msg.getFrom().getReferenceParameters(); + parameters.setCallbackID(getCallbackID()); + parameters.setCallbackReference(msg.getFrom().getCallbackEndpoint()); + + // If we are passing out a callback target + // register the calling component instance against this + // new conversation id so that stateful callbacks will be + // able to find it + Object callbackObject = getCallbackObject(); + if (conversational && callbackObject == null) { + // the component instance is already registered + // so add another registration + ScopeContainer<Object> scopeContainer = getConversationalScopeContainer(wire); + + if (scopeContainer != null && currentConversationID != null) { + scopeContainer.addWrapperReference(currentConversationID, conversation.getConversationID()); + } + } + + Interface interfaze = msg.getFrom().getCallbackEndpoint().getInterfaceContract().getInterface(); + if (callbackObject != null) { + if (callbackObject instanceof ServiceReference) { + EndpointReference callbackRef = ((CallableReferenceImpl)callbackObject).getEndpointReference(); + parameters.setCallbackReference(callbackRef); + } else { + if (interfaze != null) { + if (!interfaze.isConversational()) { + throw new IllegalArgumentException( + "Callback object for stateless callback is not a ServiceReference"); + } else { + if (!(callbackObject instanceof Serializable)) { + throw new IllegalArgumentException( + "Callback object for stateful callback is not Serializable"); + } + ScopeContainer scopeContainer = getConversationalScopeContainer(wire); + if (scopeContainer != null) { + InstanceWrapper wrapper = new CallbackObjectWrapper(callbackObject); + scopeContainer.registerWrapper(wrapper, conversation.getConversationID()); + } + parameters.setCallbackObjectID(callbackObject); + } + } + } + } + } + + /** + * Pre-invoke for the conversation handling + * @param msg + * @throws TargetResolutionException + */ + private void conversationPreinvoke(Message msg, RuntimeWire wire) { + if (!conversational) { + // Not conversational or the conversation has been started + return; + } + + ConversationManager conversationManager = ((RuntimeWireImpl)wire).getConversationManager(); + + if (conversation == null || conversation.getState() == ConversationState.ENDED) { + + conversation = conversationManager.startConversation(getConversationID()); + + // if this is a local wire then set up the conversation timeouts here based on the + // parameters from the component + if (wire.getTarget().getComponent() != null) { + conversation.initializeConversationAttributes(wire.getTarget().getComponent()); + } + + // connect the conversation to the CallableReference so it can be retrieve in the future + if (callableReference != null) { + ((CallableReferenceImpl)callableReference).attachConversation(conversation); + } + } else if (conversation.isExpired()) { + throw new ConversationEndedException("Conversation " + conversation.getConversationID() + " has expired."); + } + + // if this is a local wire then schedule conversation timeouts based on the timeout + // parameters from the service implementation. If this isn't a local wire then + // the RuntimeWireInvoker will take care of this + if (wire.getTarget().getComponent() != null) { + conversation.updateLastReferencedTime(); + } + + msg.getFrom().getReferenceParameters().setConversationID(conversation.getConversationID()); + + } + + /** + * Post-invoke for the conversation handling + * @param wire + * @param operation + * @throws TargetDestructionException + */ + @SuppressWarnings("unchecked") + private void conversationPostInvoke(Message msg, RuntimeWire wire, boolean abnormalEndConversation) + throws TargetDestructionException { + Operation operation = msg.getOperation(); + ConversationSequence sequence = operation.getConversationSequence(); + // We check that conversation has not already ended as there is only one + // conversation manager in the runtime and so, in the case of remote bindings, + // the conversation will already have been stopped when we get back to the client + if ((sequence == ConversationSequence.CONVERSATION_END || abnormalEndConversation) && (conversation.getState() != ConversationState.ENDED)) { + + // remove conversation id from scope container + ScopeContainer scopeContainer = getConversationalScopeContainer(wire); + + if (scopeContainer != null) { + scopeContainer.remove(conversation.getConversationID()); + } + + conversation.end(); + } + } + + private ScopeContainer<Object> getConversationalScopeContainer(RuntimeWire wire) { + ScopeContainer<Object> scopeContainer = null; + + RuntimeComponent runtimeComponent = wire.getSource().getComponent(); + + if (runtimeComponent instanceof ScopedRuntimeComponent) { + ScopedRuntimeComponent scopedRuntimeComponent = (ScopedRuntimeComponent)runtimeComponent; + ScopeContainer<Object> tmpScopeContainer = scopedRuntimeComponent.getScopeContainer(); + + if ((tmpScopeContainer != null) && (tmpScopeContainer.getScope() == Scope.CONVERSATION)) { + scopeContainer = tmpScopeContainer; + } + } + + return scopeContainer; + } + + /** + * Creates a new conversation id + * + * @return the conversation id + */ + private Object createConversationID() { + if (getConversationID() != null) { + return getConversationID(); + } else { + return UUID.randomUUID().toString(); + } + } + + /** + * @return the callableReference + */ + public CallableReference<?> getCallableReference() { + return callableReference; + } + + /** + * @param callableReference the callableReference to set + */ + public void setCallableReference(CallableReference<?> callableReference) { + this.callableReference = callableReference; + } + + /** + * Minimal wrapper for a callback object contained in a ServiceReference + */ + private static class CallbackObjectWrapper<T> implements InstanceWrapper<T> { + + private T instance; + + private CallbackObjectWrapper(T instance) { + this.instance = instance; + } + + public T getInstance() { + return instance; + } + + public void start() { + // do nothing + } + + public void stop() { + // do nothing + } + + } + + /** + * Creates a copy of arguments. Holder<T> values are promoted to T. + * Note. It is essential that arg Holders not be destroyed here. + * PromotedArgs should not destroy holders. They are used on response return. + * @param args containing Holders and other objects. + * @return Object [] + */ + protected static Object[] promoteHolderArgs(Operation operation, Object[] args) { + if (args == null) + return args; + + Object[] promotedArgs = new Object[args.length]; + List<ParameterMode> modes = operation.getParameterModes(); + for (int i = 0; i < args.length; i++) { + Object argument = args[i]; + if (argument != null) { + if (modes.get(i) != ParameterMode.IN) { + promotedArgs[i] = ((Holder)argument).value; + } else { + promotedArgs[i] = args[i]; + } + + } + } + return promotedArgs; + } + + /** + * Given an Object, tells if it is a Holder by comparing to "javax.xml.ws.Holder" + * @param testClass + * @return boolean stating whether Object is a Holder type. + */ + protected static boolean isHolder(Object object) { + return Holder.class.isInstance(object); + } + +} diff --git a/sca-java-1.x/branches/sca-java-1.6.2/modules/core/src/main/java/org/apache/tuscany/sca/core/invocation/JDKProxyFactory.java b/sca-java-1.x/branches/sca-java-1.6.2/modules/core/src/main/java/org/apache/tuscany/sca/core/invocation/JDKProxyFactory.java new file mode 100644 index 0000000000..a2cbd1365b --- /dev/null +++ b/sca-java-1.x/branches/sca-java-1.6.2/modules/core/src/main/java/org/apache/tuscany/sca/core/invocation/JDKProxyFactory.java @@ -0,0 +1,104 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.tuscany.sca.core.invocation; + +import java.lang.reflect.InvocationHandler; +import java.security.AccessController; +import java.security.PrivilegedAction; +import java.util.List; +import java.util.HashMap; + +import org.apache.tuscany.sca.core.invocation.SCAProxy; +import org.apache.tuscany.sca.core.context.CallableReferenceImpl; +import org.apache.tuscany.sca.core.context.ServiceReferenceImpl; +import org.apache.tuscany.sca.interfacedef.InterfaceContractMapper; +import org.apache.tuscany.sca.invocation.MessageFactory; +import org.apache.tuscany.sca.runtime.RuntimeWire; +import org.osoa.sca.CallableReference; +import org.osoa.sca.ServiceReference; + +/** + * the default implementation of a wire service that uses JDK dynamic proxies + * + * @version $Rev$ $Date$ + */ +public class JDKProxyFactory implements ProxyFactory { + protected InterfaceContractMapper contractMapper; + private MessageFactory messageFactory; + + public JDKProxyFactory(MessageFactory messageFactory, InterfaceContractMapper mapper) { + this.contractMapper = mapper; + this.messageFactory = messageFactory; + } + + /** + * The original createProxy method assumes that the proxy doesn't want to + * share conversation state so sets the conversation object to null + */ + public <T> T createProxy(Class<T> interfaze, RuntimeWire wire) throws ProxyCreationException { + ServiceReference<T> serviceReference = new ServiceReferenceImpl(interfaze, wire, this); + return createProxy(serviceReference); + } + + public <T> T createProxy(CallableReference<T> callableReference) throws ProxyCreationException { + assert callableReference != null; + final Class<T> interfaze = callableReference.getBusinessInterface(); + InvocationHandler handler = new JDKInvocationHandler(messageFactory, callableReference); + // Allow privileged access to class loader. Requires RuntimePermission in security policy. + ClassLoader cl = AccessController.doPrivileged(new PrivilegedAction<ClassLoader>() { + public ClassLoader run() { + return interfaze.getClassLoader(); + } + }); + Object proxy = SCAProxy.newProxyInstance(cl, new Class[] {interfaze}, handler); + ((CallableReferenceImpl)callableReference).setProxy(proxy); + return interfaze.cast(proxy); + } + + public <T> T createCallbackProxy(Class<T> interfaze, List<RuntimeWire> wires) throws ProxyCreationException { + CallbackReferenceImpl<T> callbackReference = CallbackReferenceImpl.newInstance(interfaze, this, wires); + return callbackReference != null ? createCallbackProxy(callbackReference) : null; + } + + public <T> T createCallbackProxy(CallbackReferenceImpl<T> callbackReference) throws ProxyCreationException { + assert callbackReference != null; + Class<T> interfaze = callbackReference.getBusinessInterface(); + InvocationHandler handler = new JDKCallbackInvocationHandler(messageFactory, callbackReference); + ClassLoader cl = interfaze.getClassLoader(); + Object proxy = SCAProxy.newProxyInstance(cl, new Class[] {interfaze}, handler); + callbackReference.setProxy(proxy); + return interfaze.cast(proxy); + } + + public <B, R extends CallableReference<B>> R cast(B target) throws IllegalArgumentException { + InvocationHandler handler = SCAProxy.getInvocationHandler(target); + if (handler instanceof JDKInvocationHandler) { + return (R)((JDKInvocationHandler)handler).getCallableReference(); + } else { + throw new IllegalArgumentException("The object is not a known proxy."); + } + } + + /** + * @see org.apache.tuscany.sca.core.invocation.ProxyFactory#isProxyClass(java.lang.Class) + */ + public boolean isProxyClass(Class<?> clazz) { + return SCAProxy.isProxyClass(clazz); + } +} diff --git a/sca-java-1.x/branches/sca-java-1.6.2/modules/core/src/main/java/org/apache/tuscany/sca/core/invocation/MessageFactoryImpl.java b/sca-java-1.x/branches/sca-java-1.6.2/modules/core/src/main/java/org/apache/tuscany/sca/core/invocation/MessageFactoryImpl.java new file mode 100644 index 0000000000..6e182a6a14 --- /dev/null +++ b/sca-java-1.x/branches/sca-java-1.6.2/modules/core/src/main/java/org/apache/tuscany/sca/core/invocation/MessageFactoryImpl.java @@ -0,0 +1,36 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.apache.tuscany.sca.core.invocation; + +import org.apache.tuscany.sca.invocation.Message; +import org.apache.tuscany.sca.invocation.MessageFactory; + +/** + * Implementation of MessageFactory. + * + * @version $Rev$ $Date$ + */ +public class MessageFactoryImpl implements MessageFactory { + + public Message createMessage() { + return new MessageImpl(); + } + +} diff --git a/sca-java-1.x/branches/sca-java-1.6.2/modules/core/src/main/java/org/apache/tuscany/sca/core/invocation/MessageImpl.java b/sca-java-1.x/branches/sca-java-1.6.2/modules/core/src/main/java/org/apache/tuscany/sca/core/invocation/MessageImpl.java new file mode 100644 index 0000000000..ca2bf051c8 --- /dev/null +++ b/sca-java-1.x/branches/sca-java-1.6.2/modules/core/src/main/java/org/apache/tuscany/sca/core/invocation/MessageImpl.java @@ -0,0 +1,113 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.tuscany.sca.core.invocation; + +import java.util.ArrayList; +import java.util.List; + +import org.apache.tuscany.sca.core.assembly.EndpointReferenceImpl; +import org.apache.tuscany.sca.interfacedef.Operation; +import org.apache.tuscany.sca.invocation.Message; +import org.apache.tuscany.sca.runtime.EndpointReference; + +/** + * The default implementation of a message flowed through a wire during an invocation + * + * @version $Rev $Date$ + */ +public class MessageImpl implements Message { + private Object bindingContext; + private List<Object> headers = new ArrayList<Object>(); + private Object body; + private Object messageID; + private boolean isFault; + private Operation operation; + + private EndpointReference from; + private EndpointReference to; + + public MessageImpl() { + this.from = new EndpointReferenceImpl("/"); + this.to = new EndpointReferenceImpl("/"); + } + + @SuppressWarnings("unchecked") + public <T> T getBody() { + return (T)body; + } + + public <T> void setBody(T body) { + this.isFault = false; + this.body = body; + } + + public Object getMessageID() { + return messageID; + } + + public void setMessageID(Object messageId) { + this.messageID = messageId; + } + + public boolean isFault() { + return isFault; + } + + public void setFaultBody(Object fault) { + this.isFault = true; + this.body = fault; + } + + public EndpointReference getFrom() { + return from; + } + + public void setFrom(EndpointReference from) { + this.from = from; + } + + public EndpointReference getTo() { + return to; + } + + public void setTo(EndpointReference to) { + this.to = to; + } + + public Operation getOperation() { + return operation; + } + + public void setOperation(Operation op) { + this.operation = op; + } + + public List<Object> getHeaders() { + return headers; + } + + @SuppressWarnings("unchecked") + public <T> T getBindingContext() { + return (T)bindingContext; + } + + public <T> void setBindingContext(T bindingContext) { + this.bindingContext = bindingContext; + } +} diff --git a/sca-java-1.x/branches/sca-java-1.6.2/modules/core/src/main/java/org/apache/tuscany/sca/core/invocation/NoMethodForOperationException.java b/sca-java-1.x/branches/sca-java-1.6.2/modules/core/src/main/java/org/apache/tuscany/sca/core/invocation/NoMethodForOperationException.java new file mode 100644 index 0000000000..733544d387 --- /dev/null +++ b/sca-java-1.x/branches/sca-java-1.6.2/modules/core/src/main/java/org/apache/tuscany/sca/core/invocation/NoMethodForOperationException.java @@ -0,0 +1,43 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.tuscany.sca.core.invocation; + + +/** + * Thrown when an {@link org.apache.tuscany.sca.core.factory.model.Operation} cannot be mapped to a method on an interface + * @version $Rev$ $Date$ + */ +public class NoMethodForOperationException extends ProxyCreationException { + private static final long serialVersionUID = 5116536602309483679L; + + public NoMethodForOperationException() { + } + + public NoMethodForOperationException(String message) { + super(message); + } + + public NoMethodForOperationException(String message, Throwable cause) { + super(message, cause); + } + + public NoMethodForOperationException(Throwable cause) { + super(cause); + } +} diff --git a/sca-java-1.x/branches/sca-java-1.6.2/modules/core/src/main/java/org/apache/tuscany/sca/core/invocation/NonBlockingInterceptor.java b/sca-java-1.x/branches/sca-java-1.6.2/modules/core/src/main/java/org/apache/tuscany/sca/core/invocation/NonBlockingInterceptor.java new file mode 100644 index 0000000000..d6911281c8 --- /dev/null +++ b/sca-java-1.x/branches/sca-java-1.6.2/modules/core/src/main/java/org/apache/tuscany/sca/core/invocation/NonBlockingInterceptor.java @@ -0,0 +1,202 @@ +/* + * 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.core.invocation; + +import java.util.LinkedList; +import java.util.List; +import java.util.Map; +import java.util.logging.Level; +import java.util.logging.Logger; + +import org.apache.tuscany.sca.interfacedef.Operation; +import org.apache.tuscany.sca.invocation.Interceptor; +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.RuntimeWire; +import org.apache.tuscany.sca.work.WorkScheduler; +import org.osoa.sca.ServiceRuntimeException; + +/** + * Adds non-blocking behavior to an invocation chain + * + * @version $Rev$ $Date$ + */ +public class NonBlockingInterceptor implements Interceptor { + + private static final Message RESPONSE = new ImmutableMessage(); + + /** + * The JDK logger that will be used to log messages. + */ + private static final Logger LOGGER = Logger.getLogger(NonBlockingInterceptor.class.getName()); + + private WorkScheduler workScheduler; + private Invoker next; + + public NonBlockingInterceptor(WorkScheduler workScheduler) { + this.workScheduler = workScheduler; + } + + public NonBlockingInterceptor(WorkScheduler workScheduler, Interceptor next) { + this.workScheduler = workScheduler; + this.next = next; + } + + /** + * Sets desired workScheduler to NonBlockingInterceptor. This is a useful function for the extension framework + * to set desired workmanager on the InvocationChain, other than default workmanager which is set per Tuscany runtime. + * Using this function, extension framework can set desired workmanager on InvocationChain during post wire processing. + * @param workScheduler workScheduler which contains workmanager + */ + public void setWorkScheduler(WorkScheduler workScheduler){ + this.workScheduler = workScheduler; + } + + public Message invoke(final Message msg) { + // Schedule the invocation of the next interceptor in a new Work instance + try { + workScheduler.scheduleWork(new Runnable() { + public void run() { + Message context = ThreadMessageContext.setMessageContext(msg); + try { + Message response = null; + + Throwable ex = null; + try { + response = next.invoke(msg); + } catch (Throwable t) { + ex = t; + } + + // Tuscany-2225 - Did the @OneWay method complete successfully? + // (i.e. no exceptions) + if (response != null && response.isFault()) { + // The @OneWay method threw an Exception. Lets log it and + // then pass it on to the WorkScheduler so it can notify any + // listeners + ex = (Throwable)response.getBody(); + } + if (ex != null) { + LOGGER.log(Level.SEVERE, "Exception from @OneWay invocation", ex); + throw new ServiceRuntimeException("Exception from @OneWay invocation", ex); + } + } finally { + ThreadMessageContext.setMessageContext(context); + } + } + }); + } catch (Exception e) { + throw new ServiceRuntimeException(e); + } + return RESPONSE; + } + + public Invoker getNext() { + return next; + } + + public void setNext(Invoker next) { + this.next = next; + } + + /** + * A dummy message passed back on an invocation + */ + private static class ImmutableMessage implements Message { + + @SuppressWarnings("unchecked") + public Object getBody() { + return null; + } + + public void setBody(Object body) { + if (body != null) { + throw new UnsupportedOperationException(); + } + } + + public void setCallbackWires(LinkedList<RuntimeWire> wires) { + + } + + public Object getMessageID() { + return null; + } + + public void setMessageID(Object messageId) { + throw new UnsupportedOperationException(); + } + + public boolean isFault() { + return false; + } + + public void setFaultBody(Object fault) { + throw new UnsupportedOperationException(); + } + + public EndpointReference getFrom() { + return null; + } + + public EndpointReference getTo() { + return null; + } + + public void setFrom(EndpointReference from) { + throw new UnsupportedOperationException(); + } + + public void setTo(EndpointReference to) { + throw new UnsupportedOperationException(); + } + + public Operation getOperation() { + return null; + } + + public void setOperation(Operation op) { + throw new UnsupportedOperationException(); + } + + /** + * @see org.apache.tuscany.sca.invocation.Message#getReplyTo() + */ + public EndpointReference getReplyTo() { + return null; + } + + public Map<String, Object> getQoSContext() { + return null; + } + + public List<Object> getHeaders() { + return null; + } + + public <T> T getBindingContext() { + return null; + } + + public <T> void setBindingContext(T bindingContext) { + } + } + +} diff --git a/sca-java-1.x/branches/sca-java-1.6.2/modules/core/src/main/java/org/apache/tuscany/sca/core/invocation/PhaseManager.java b/sca-java-1.x/branches/sca-java-1.6.2/modules/core/src/main/java/org/apache/tuscany/sca/core/invocation/PhaseManager.java new file mode 100644 index 0000000000..a3c8429c7b --- /dev/null +++ b/sca-java-1.x/branches/sca-java-1.6.2/modules/core/src/main/java/org/apache/tuscany/sca/core/invocation/PhaseManager.java @@ -0,0 +1,298 @@ +/* + * 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.core.invocation; + +import static org.apache.tuscany.sca.invocation.Phase.IMPLEMENTATION; +import static org.apache.tuscany.sca.invocation.Phase.IMPLEMENTATION_POLICY; +import static org.apache.tuscany.sca.invocation.Phase.REFERENCE; +import static org.apache.tuscany.sca.invocation.Phase.REFERENCE_BINDING; +import static org.apache.tuscany.sca.invocation.Phase.REFERENCE_BINDING_POLICY; +import static org.apache.tuscany.sca.invocation.Phase.REFERENCE_BINDING_TRANSPORT; +import static org.apache.tuscany.sca.invocation.Phase.REFERENCE_BINDING_WIREFORMAT; +import static org.apache.tuscany.sca.invocation.Phase.REFERENCE_INTERFACE; +import static org.apache.tuscany.sca.invocation.Phase.REFERENCE_POLICY; +import static org.apache.tuscany.sca.invocation.Phase.SERVICE; +import static org.apache.tuscany.sca.invocation.Phase.SERVICE_BINDING; +import static org.apache.tuscany.sca.invocation.Phase.SERVICE_BINDING_OPERATION_SELECTOR; +import static org.apache.tuscany.sca.invocation.Phase.SERVICE_BINDING_POLICY; +import static org.apache.tuscany.sca.invocation.Phase.SERVICE_BINDING_TRANSPORT; +import static org.apache.tuscany.sca.invocation.Phase.SERVICE_BINDING_WIREFORMAT; +import static org.apache.tuscany.sca.invocation.Phase.SERVICE_INTERFACE; +import static org.apache.tuscany.sca.invocation.Phase.SERVICE_POLICY; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.StringTokenizer; +import java.util.logging.Level; +import java.util.logging.Logger; + +import org.apache.tuscany.sca.extensibility.ServiceDeclaration; +import org.apache.tuscany.sca.extensibility.ServiceDiscovery; +import org.apache.tuscany.sca.invocation.Phase; +import org.osoa.sca.ServiceRuntimeException; + +/** + * @version $Rev$ $Date$ + */ +public class PhaseManager { + private static final Logger log = Logger.getLogger(PhaseManager.class.getName()); + + public static final String STAGE_REFERENCE = "reference"; + public static final String STAGE_REFERENCE_BINDING = "reference.binding"; + public static final String STAGE_SERVICE_BINDING = "service.binding"; + public static final String STAGE_SERVICE = "service"; + public static final String STAGE_IMPLEMENTATION = "implementation"; + + private static final String[] SYSTEM_REFERENCE_PHASES = + {REFERENCE, REFERENCE_INTERFACE, REFERENCE_POLICY, REFERENCE_BINDING}; + + private static final String[] SYSTEM_REFERENCE_BINDING_PHASES = + {REFERENCE_BINDING_WIREFORMAT, REFERENCE_BINDING_POLICY, REFERENCE_BINDING_TRANSPORT}; + + private static final String[] SYSTEM_SERVICE_BINDING_PHASES = + {SERVICE_BINDING_TRANSPORT, SERVICE_BINDING_OPERATION_SELECTOR, SERVICE_BINDING_WIREFORMAT, SERVICE_BINDING_POLICY}; + + private static final String[] SYSTEM_SERVICE_PHASES = + {SERVICE_BINDING, SERVICE_POLICY, SERVICE_INTERFACE, SERVICE}; + + private static final String[] SYSTEM_IMPLEMENTATION_PHASES = {IMPLEMENTATION_POLICY, IMPLEMENTATION}; + + private String pattern = Phase.class.getName(); + private Map<String, Stage> stages; + private List<String> phases; + + public class Stage { + private String name; + private PhaseSorter<String> sorter = new PhaseSorter<String>(); + private Set<String> firstSet = new HashSet<String>(); + private Set<String> lastSet = new HashSet<String>(); + private List<String> phases = new ArrayList<String>(); + + public Stage(String name) { + super(); + this.name = name; + } + + public String getName() { + return name; + } + + public PhaseSorter<String> getSorter() { + return sorter; + } + + public Set<String> getFirstSet() { + return firstSet; + } + + public Set<String> getLastSet() { + return lastSet; + } + + public List<String> getPhases() { + return phases; + } + + @Override + public String toString() { + return name + phases; + } + } + + // For unit test purpose + PhaseManager(String pattern) { + super(); + this.pattern = pattern; + } + + public PhaseManager() { + } + + private List<String> getPhases(String stage) { + Stage s = getStages().get(stage); + return s == null ? null : s.getPhases(); + } + + public List<String> getReferencePhases() { + return getPhases(STAGE_REFERENCE); + } + + public List<String> getServicePhases() { + return getPhases(STAGE_SERVICE); + } + + public List<String> getReferenceBindingPhases() { + return getPhases(STAGE_REFERENCE_BINDING); + } + + public List<String> getServiceBindingPhases() { + return getPhases(STAGE_SERVICE_BINDING); + } + + public List<String> getImplementationPhases() { + return getPhases(STAGE_IMPLEMENTATION); + } + + public synchronized List<String> getAllPhases() { + if (phases == null) { + phases = new ArrayList<String>(); + phases.addAll(getReferencePhases()); + phases.addAll(getReferenceBindingPhases()); + phases.addAll(getServiceBindingPhases()); + phases.addAll(getServicePhases()); + phases.addAll(getImplementationPhases()); + } + return phases; + } + + public synchronized Map<String, Stage> getStages() { + if (stages != null) { + return stages; + } + init(); + + Set<ServiceDeclaration> services; + try { + services = ServiceDiscovery.getInstance().getServiceDeclarations(pattern); + } catch (IOException e) { + throw new ServiceRuntimeException(e); + } + + for (ServiceDeclaration d : services) { + if (log.isLoggable(Level.FINE)) { + log.fine(d.getLocation() + ": " + d.getAttributes()); + } + String name = d.getAttributes().get("name"); + if (name == null) { + throw new ServiceRuntimeException("Required attribute 'name' is missing."); + } + String stageName = d.getAttributes().get("stage"); + if (stageName == null) { + throw new ServiceRuntimeException("Required attribute 'stage' is missing."); + } + Stage stage = stages.get(stageName); + if (stage == null) { + throw new ServiceRuntimeException("Invalid stage: " + stage); + } + PhaseSorter<String> graph = stage.getSorter(); + Set<String> firstSet = stage.getFirstSet(), lastSet = stage.getLastSet(); + + String before = d.getAttributes().get("before"); + String after = d.getAttributes().get("after"); + if (before != null) { + StringTokenizer tokenizer = new StringTokenizer(before); + while (tokenizer.hasMoreTokens()) { + String p = tokenizer.nextToken(); + if (!"*".equals(p)) { + graph.addEdge(name, p); + } else { + firstSet.add(name); + } + } + } + if (after != null) { + StringTokenizer tokenizer = new StringTokenizer(after); + while (tokenizer.hasMoreTokens()) { + String p = tokenizer.nextToken(); + if (!"*".equals(p)) { + graph.addEdge(p, name); + } else { + lastSet.add(name); + } + } + } + graph.addVertext(name); + if(firstSet.size()>1) { + log.warning("More than one phases are declared to be first: "+firstSet); + } + for (String s : firstSet) { + for (String v : new HashSet<String>(graph.getVertices().keySet())) { + if (!firstSet.contains(v)) { + graph.addEdge(s, v); + } + } + } + if(lastSet.size()>1) { + log.warning("More than one phases are declared to be the last: "+lastSet); + } + for (String s : lastSet) { + for (String v : new HashSet<String>(graph.getVertices().keySet())) { + if (!lastSet.contains(v)) { + graph.addEdge(v, s); + } + } + } + + } + + for (Stage s : stages.values()) { + List<String> phases = s.getSorter().topologicalSort(false); + s.getPhases().clear(); + s.getPhases().addAll(phases); + } + if (log.isLoggable(Level.FINE)) { + log.fine("Stages: " + stages); + } + return stages; + } + + private void init() { + stages = new HashMap<String, Stage>(); + + Stage referenceStage = new Stage(STAGE_REFERENCE); + for (int i = 1; i < SYSTEM_REFERENCE_PHASES.length; i++) { + referenceStage.getSorter().addEdge(SYSTEM_REFERENCE_PHASES[i - 1], SYSTEM_REFERENCE_PHASES[i]); + } + referenceStage.getLastSet().add(REFERENCE_BINDING); + stages.put(referenceStage.getName(), referenceStage); + + Stage referenceBindingStage = new Stage(STAGE_REFERENCE_BINDING); + for (int i = 1; i < SYSTEM_REFERENCE_BINDING_PHASES.length; i++) { + referenceBindingStage.getSorter().addEdge(SYSTEM_REFERENCE_BINDING_PHASES[i - 1], SYSTEM_REFERENCE_BINDING_PHASES[i]); + } + stages.put(referenceBindingStage.getName(), referenceBindingStage); + + Stage serviceBindingStage = new Stage(STAGE_SERVICE_BINDING); + for (int i = 1; i < SYSTEM_SERVICE_BINDING_PHASES.length; i++) { + serviceBindingStage.getSorter().addEdge(SYSTEM_SERVICE_BINDING_PHASES[i - 1], SYSTEM_SERVICE_BINDING_PHASES[i]); + } + stages.put(serviceBindingStage.getName(), serviceBindingStage); + + + Stage serviceStage = new Stage(STAGE_SERVICE); + for (int i = 1; i < SYSTEM_SERVICE_PHASES.length; i++) { + serviceStage.getSorter().addEdge(SYSTEM_SERVICE_PHASES[i - 1], SYSTEM_SERVICE_PHASES[i]); + } + stages.put(serviceStage.getName(), serviceStage); + + Stage implementationStage = new Stage(STAGE_IMPLEMENTATION); + for (int i = 1; i < SYSTEM_IMPLEMENTATION_PHASES.length; i++) { + implementationStage.getSorter().addEdge(SYSTEM_IMPLEMENTATION_PHASES[i - 1], + SYSTEM_IMPLEMENTATION_PHASES[i]); + } + implementationStage.getLastSet().add(IMPLEMENTATION); + stages.put(implementationStage.getName(), implementationStage); + } +} diff --git a/sca-java-1.x/branches/sca-java-1.6.2/modules/core/src/main/java/org/apache/tuscany/sca/core/invocation/PhaseSorter.java b/sca-java-1.x/branches/sca-java-1.6.2/modules/core/src/main/java/org/apache/tuscany/sca/core/invocation/PhaseSorter.java new file mode 100644 index 0000000000..fc4bea3d9f --- /dev/null +++ b/sca-java-1.x/branches/sca-java-1.6.2/modules/core/src/main/java/org/apache/tuscany/sca/core/invocation/PhaseSorter.java @@ -0,0 +1,236 @@ +/* + * 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.core.invocation; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** + * Directed, weighted graph + * + * @param <V> The type of vertex object + * @param <E> The type of edge object + * + * @version $Rev$ $Date$ + */ +public class PhaseSorter<V> implements Cloneable { + private final Map<V, Vertex> vertices = new HashMap<V, Vertex>(); + + /** + * Vertex of a graph + */ + public final class Vertex { + private V value; + + // TODO: Do we want to support multiple edges for a vertex pair? If so, + // we should use a List instead of Map + private Map<Vertex, Edge> outEdges = new HashMap<Vertex, Edge>(); + private Map<Vertex, Edge> inEdges = new HashMap<Vertex, Edge>(); + + private Vertex(V value) { + this.value = value; + } + + @Override + public String toString() { + return "(" + value + ")"; + } + + public V getValue() { + return value; + } + + public Map<Vertex, Edge> getOutEdges() { + return outEdges; + } + + public Map<Vertex, Edge> getInEdges() { + return inEdges; + } + + } + + /** + * An Edge connects two vertices in one direction + */ + public final class Edge { + private Vertex sourceVertex; + + private Vertex targetVertex; + + public Edge(Vertex source, Vertex target) { + this.sourceVertex = source; + this.targetVertex = target; + } + + @Override + public String toString() { + return sourceVertex + "->" + targetVertex; + } + + public Vertex getTargetVertex() { + return targetVertex; + } + + public void setTargetVertex(Vertex vertex) { + this.targetVertex = vertex; + } + + public Vertex getSourceVertex() { + return sourceVertex; + } + + public void setSourceVertex(Vertex sourceVertex) { + this.sourceVertex = sourceVertex; + } + } + + public void addEdge(V source, V target) { + Vertex s = getVertex(source); + if (s == null) { + s = new Vertex(source); + vertices.put(source, s); + } + Vertex t = getVertex(target); + if (t == null) { + t = new Vertex(target); + vertices.put(target, t); + } + Edge edge = new Edge(s, t); + s.outEdges.put(t, edge); + t.inEdges.put(s, edge); + } + + public void addVertext(V source) { + Vertex s = getVertex(source); + if (s == null) { + s = new Vertex(source); + vertices.put(source, s); + } + } + + public Vertex getVertex(V source) { + Vertex s = vertices.get(source); + return s; + } + + public boolean removeEdge(V source, V target) { + Vertex s = getVertex(source); + if (s == null) { + return false; + } + + Vertex t = getVertex(target); + if (t == null) { + return false; + } + + return s.outEdges.remove(t) != null && t.inEdges.remove(s) != null; + + } + + public void removeEdge(Edge edge) { + edge.sourceVertex.outEdges.remove(edge.targetVertex); + edge.targetVertex.inEdges.remove(edge.sourceVertex); + } + + public void removeVertex(Vertex vertex) { + vertices.remove(vertex.getValue()); + for (Edge e : new ArrayList<Edge>(vertex.outEdges.values())) { + removeEdge(e); + } + for (Edge e : new ArrayList<Edge>(vertex.inEdges.values())) { + removeEdge(e); + } + } + + public Edge getEdge(Vertex source, Vertex target) { + return source.outEdges.get(target); + } + + public Edge getEdge(V source, V target) { + Vertex sv = getVertex(source); + if (sv == null) { + return null; + } + Vertex tv = getVertex(target); + if (tv == null) { + return null; + } + return getEdge(getVertex(source), getVertex(target)); + } + + @Override + public String toString() { + StringBuffer sb = new StringBuffer(); + for (Vertex v : vertices.values()) { + sb.append(v.outEdges.values()).append("\n"); + } + return sb.toString(); + } + + public Map<V, Vertex> getVertices() { + return vertices; + } + + public void addGraph(PhaseSorter<V> otherGraph) { + for (Vertex v : otherGraph.vertices.values()) { + for (Edge e : v.outEdges.values()) { + addEdge(e.sourceVertex.value, e.targetVertex.value); + } + } + } + + private Vertex getFirst() { + for (Vertex v : vertices.values()) { + if (v.inEdges.isEmpty()) { + return v; + } + } + if (!vertices.isEmpty()) { + throw new IllegalArgumentException("Circular ordering has been detected: " + toString()); + } else { + return null; + } + } + + public List<V> topologicalSort(boolean readOnly) { + PhaseSorter<V> graph = (!readOnly) ? this : (PhaseSorter<V>)clone(); + List<V> list = new ArrayList<V>(); + while (true) { + Vertex v = graph.getFirst(); + if (v == null) { + break; + } + list.add(v.getValue()); + graph.removeVertex(v); + } + + return list; + } + + @Override + public Object clone() { + PhaseSorter<V> copy = new PhaseSorter<V>(); + copy.addGraph(this); + return copy; + } +} diff --git a/sca-java-1.x/branches/sca-java-1.6.2/modules/core/src/main/java/org/apache/tuscany/sca/core/invocation/ProxyCreationException.java b/sca-java-1.x/branches/sca-java-1.6.2/modules/core/src/main/java/org/apache/tuscany/sca/core/invocation/ProxyCreationException.java new file mode 100644 index 0000000000..0b36b178f3 --- /dev/null +++ b/sca-java-1.x/branches/sca-java-1.6.2/modules/core/src/main/java/org/apache/tuscany/sca/core/invocation/ProxyCreationException.java @@ -0,0 +1,48 @@ +/* + * 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.core.invocation; + +import org.apache.tuscany.sca.core.factory.ObjectCreationException; + + +/** + * Denotes an error creating a proxy + * + * @version $Rev$ $Date$ + */ +public class ProxyCreationException extends ObjectCreationException { + private static final long serialVersionUID = 8002454344828513781L; + + public ProxyCreationException() { + super(); + } + + public ProxyCreationException(String message, Throwable cause) { + super(message, cause); + } + + public ProxyCreationException(String message) { + super(message); + } + + public ProxyCreationException(Throwable cause) { + super(cause); + } + +} diff --git a/sca-java-1.x/branches/sca-java-1.6.2/modules/core/src/main/java/org/apache/tuscany/sca/core/invocation/ProxyFactory.java b/sca-java-1.x/branches/sca-java-1.6.2/modules/core/src/main/java/org/apache/tuscany/sca/core/invocation/ProxyFactory.java new file mode 100644 index 0000000000..cb836e42c1 --- /dev/null +++ b/sca-java-1.x/branches/sca-java-1.6.2/modules/core/src/main/java/org/apache/tuscany/sca/core/invocation/ProxyFactory.java @@ -0,0 +1,87 @@ +/* + * 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.core.invocation; + +import java.util.List; + +import org.apache.tuscany.sca.runtime.RuntimeWire; +import org.osoa.sca.CallableReference; + +/** + * Creates proxies that implement Java interfaces and invocation handlers for fronting wires + * + * @version $Rev$ $Date$ + */ + +public interface ProxyFactory { + + /** + * Creates a Java proxy for the given wire + * + * @param interfaze the interface the proxy implements + * @param wire the wire to proxy + * @return the proxy + * @throws ProxyCreationException + */ + <T> T createProxy(Class<T> interfaze, RuntimeWire wire) throws ProxyCreationException; + + /** + * Creates a Java proxy for the given CallableReference + * + * @param callableReference The CallableReference + * @return the proxy + * @throws ProxyCreationException + */ + <T> T createProxy(CallableReference<T> callableReference) throws ProxyCreationException; + + /** + * Creates a Java proxy for the service contract callback + * + * @param interfaze the interface the proxy should implement + * @return the proxy + * @throws ProxyCreationException + */ + <T> T createCallbackProxy(Class<T> interfaze, List<RuntimeWire> wires) throws ProxyCreationException; + + /** + * Creates a Java proxy for the given callback reference + * + * @param callableReference The CallableReference + * @return the proxy + * @throws ProxyCreationException + */ + <T> T createCallbackProxy(CallbackReferenceImpl<T> callbackReference) throws ProxyCreationException; + + /** + * Cast a proxy to a CallableReference. + * + * @param target a proxy generated by this implementation + * @return a CallableReference (or subclass) equivalent to this proxy + * @throws IllegalArgumentException if the object supplied is not a proxy + */ + <B, R extends CallableReference<B>> R cast(B target) throws IllegalArgumentException; + + /** + * Test if a given class is a generated proxy class by this factory + * @param clazz A java class or interface + * @return true if the class is a generated proxy class by this factory + */ + boolean isProxyClass(Class<?> clazz); + +} diff --git a/sca-java-1.x/branches/sca-java-1.6.2/modules/core/src/main/java/org/apache/tuscany/sca/core/invocation/ProxyFactoryExtensionPoint.java b/sca-java-1.x/branches/sca-java-1.6.2/modules/core/src/main/java/org/apache/tuscany/sca/core/invocation/ProxyFactoryExtensionPoint.java new file mode 100644 index 0000000000..875a252798 --- /dev/null +++ b/sca-java-1.x/branches/sca-java-1.6.2/modules/core/src/main/java/org/apache/tuscany/sca/core/invocation/ProxyFactoryExtensionPoint.java @@ -0,0 +1,53 @@ +/* + * 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.core.invocation; + + +/** + * The extension point to plug in proxy factories + * @version $Rev$ $Date$ + */ +public interface ProxyFactoryExtensionPoint { + + /** + * Get the proxy factory for java interfaces + * @return + */ + ProxyFactory getInterfaceProxyFactory(); + + /** + * Get the proxy factory for java classes + * @return + */ + ProxyFactory getClassProxyFactory(); + + /** + * Set the proxy factory for java interfaces + * @param factory + */ + void setInterfaceProxyFactory(ProxyFactory factory); + + /** + * Set the proxy factory for java classes + * @param factory + */ + void setClassProxyFactory(ProxyFactory factory); + +} diff --git a/sca-java-1.x/branches/sca-java-1.6.2/modules/core/src/main/java/org/apache/tuscany/sca/core/invocation/RuntimeWireInvoker.java b/sca-java-1.x/branches/sca-java-1.6.2/modules/core/src/main/java/org/apache/tuscany/sca/core/invocation/RuntimeWireInvoker.java new file mode 100644 index 0000000000..906628ee32 --- /dev/null +++ b/sca-java-1.x/branches/sca-java-1.6.2/modules/core/src/main/java/org/apache/tuscany/sca/core/invocation/RuntimeWireInvoker.java @@ -0,0 +1,264 @@ +/* + * 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.core.invocation; + +import java.lang.reflect.InvocationTargetException; + +import org.apache.tuscany.sca.core.context.InstanceWrapper; +import org.apache.tuscany.sca.core.conversation.ConversationManager; +import org.apache.tuscany.sca.core.conversation.ConversationState; +import org.apache.tuscany.sca.core.conversation.ExtendedConversation; +import org.apache.tuscany.sca.core.scope.Scope; +import org.apache.tuscany.sca.core.scope.ScopeContainer; +import org.apache.tuscany.sca.core.scope.ScopedRuntimeComponent; +import org.apache.tuscany.sca.core.scope.TargetDestructionException; +import org.apache.tuscany.sca.core.scope.TargetResolutionException; +import org.apache.tuscany.sca.interfacedef.ConversationSequence; +import org.apache.tuscany.sca.interfacedef.InterfaceContract; +import org.apache.tuscany.sca.interfacedef.Operation; +import org.apache.tuscany.sca.invocation.InvocationChain; +import org.apache.tuscany.sca.invocation.Invoker; +import org.apache.tuscany.sca.invocation.Message; +import org.apache.tuscany.sca.invocation.MessageFactory; +import org.apache.tuscany.sca.runtime.EndpointReference; +import org.apache.tuscany.sca.runtime.ReferenceParameters; +import org.apache.tuscany.sca.runtime.RuntimeComponent; +import org.apache.tuscany.sca.runtime.RuntimeWire; +import org.osoa.sca.ConversationEndedException; +import org.osoa.sca.ServiceRuntimeException; + +/** + * @version $Rev$ $Date$ + */ +public class RuntimeWireInvoker implements Invoker{ + protected ConversationManager conversationManager; + protected boolean conversational; + protected ExtendedConversation conversation; + protected MessageFactory messageFactory; + protected Object conversationID; + protected Object callbackID; + protected Object callbackObject; + protected RuntimeWire wire; + + public RuntimeWireInvoker(MessageFactory messageFactory, ConversationManager conversationManager, RuntimeWire wire) { + this.messageFactory = messageFactory; + this.wire = wire; + this.conversationManager = conversationManager; + init(wire); + } + + protected void init(RuntimeWire wire) { + if (wire != null) { + ReferenceParameters parameters = wire.getSource().getReferenceParameters(); + this.callbackID = parameters.getCallbackID(); + this.callbackObject = parameters.getCallbackReference(); + this.conversationID = parameters.getConversationID(); + InterfaceContract contract = wire.getSource().getInterfaceContract(); + this.conversational = contract.getInterface().isConversational(); + } + } + + /* + * TODO - Introduced to allow the RuntimeWireInvoker to sit on the end of the + * service binding chain. Runtime wire invoke needs splitting up into + * separate conversation, callback interceptors etc. + */ + public Message invoke(Message msg) { + + try { + Object response = invoke(msg.getOperation(),msg); + // Hack to put the response back in a message. + // shouldn't take it out of the response message in the first place + msg.setBody(response); + } catch (InvocationTargetException e) { +// throw new ServiceRuntimeException(e); + } + + return msg; + } + + public Object invoke(Operation operation, Message msg) throws InvocationTargetException { + return invoke(wire, operation, msg); + } + + public Object invoke(RuntimeWire wire, Operation operation, Message msg) throws InvocationTargetException { + RuntimeWire runtimeWire = wire == null ? this.wire : wire; + InvocationChain chain = runtimeWire.getInvocationChain(operation); + return invoke(chain, msg, runtimeWire); + } + + protected Object invoke(InvocationChain chain, Message msg, RuntimeWire wire) throws InvocationTargetException { + EndpointReference from = msg.getFrom(); + EndpointReference epFrom = wire.getSource(); + if (from != null) { + from.mergeEndpoint(epFrom); + } else { + msg.setFrom(epFrom); + } + msg.setTo(wire.getTarget()); + + Invoker headInvoker = chain.getHeadInvoker(); + Operation operation = chain.getTargetOperation(); + msg.setOperation(operation); + + Message msgContext = ThreadMessageContext.getMessageContext(); + Object currentConversationID = msgContext.getFrom().getReferenceParameters().getConversationID(); + + ThreadMessageContext.setMessageContext(msg); + try { + conversationPreinvoke(msg); + // handleCallback(msg, currentConversationID); + // dispatch the wire down the chain and get the response + Message resp = headInvoker.invoke(msg); + Object body = resp.getBody(); + if (resp.isFault()) { + throw new InvocationTargetException((Throwable)body); + } + return body; + } catch (InvocationTargetException e) { + throw e; + } catch (Throwable e) { + throw new ServiceRuntimeException(e); + } finally { + try { + conversationPostInvoke(msg); + } catch (TargetDestructionException e) { + throw new ServiceRuntimeException(e); + } finally { + ThreadMessageContext.setMessageContext(msgContext); + } + } + } + + /** + * @param msgContext + */ + protected EndpointReference getCallbackEndpoint(Message msgContext) { + EndpointReference from = msgContext.getFrom(); + return from == null ? null : from.getReferenceParameters().getCallbackReference(); + } + + /** + * Pre-invoke for the conversation handling + * @param msg + * @throws TargetResolutionException + */ + private void conversationPreinvoke(Message msg) { + if (conversational) { + ReferenceParameters parameters = msg.getFrom().getReferenceParameters(); + // in some cases the ConversationID that should be used comes in with the + // message, e.g. when ws binding is in use. + Object convID = parameters.getConversationID(); + if (convID != null) { + conversationID = convID; + } + conversation = conversationManager.getConversation(conversationID); + + if (conversation == null || conversation.getState() == ConversationState.ENDED) { + conversation = conversationManager.startConversation(conversationID); + conversation.initializeConversationAttributes(wire.getTarget().getComponent()); + } else if (conversation.conversationalAttributesInitialized() == false) { + conversation.initializeConversationAttributes(wire.getTarget().getComponent()); + } else if (conversation.isExpired()){ + throw new ConversationEndedException("Conversation has expired."); + } + + conversation.updateLastReferencedTime(); + + parameters.setConversationID(conversation.getConversationID()); + } + } + + /** + * Post-invoke for the conversation handling + * @param wire + * @param operation + * @throws TargetDestructionException + */ + @SuppressWarnings("unchecked") + private void conversationPostInvoke(Message msg) throws TargetDestructionException { + if (conversational) { + Operation operation = msg.getOperation(); + ConversationSequence sequence = operation.getConversationSequence(); + if (sequence == ConversationSequence.CONVERSATION_END) { + // in some cases the ConversationID that should be used comes in with the + // message, e.g. when ws binding is in use. + Object convID = msg.getFrom().getReferenceParameters().getConversationID(); + if (convID != null) { + conversationID = convID; + } + conversation = conversationManager.getConversation(conversationID); + + // remove conversation id from scope container + ScopeContainer scopeContainer = getConversationalScopeContainer(msg); + + if (scopeContainer != null) { + scopeContainer.remove(conversation.getConversationID()); + } + + conversation.end(); + } + } + } + + @SuppressWarnings("unchecked") + private ScopeContainer getConversationalScopeContainer(Message msg) { + ScopeContainer scopeContainer = null; + + RuntimeComponent component = msg.getTo().getComponent(); + + if (component instanceof ScopedRuntimeComponent) { + ScopedRuntimeComponent scopedRuntimeComponent = (ScopedRuntimeComponent)component; + ScopeContainer container = scopedRuntimeComponent.getScopeContainer(); + + if ((container != null) && (container.getScope() == Scope.CONVERSATION)) { + scopeContainer = container; + } + } + + return scopeContainer; + } + + + /** + * Minimal wrapper for a callback object contained in a ServiceReference + */ + private static class CallbackObjectWrapper<T> implements InstanceWrapper<T> { + + private T instance; + + private CallbackObjectWrapper(T instance) { + this.instance = instance; + } + + public T getInstance() { + return instance; + } + + public void start() { + // do nothing + } + + public void stop() { + // do nothing + } + } + +} diff --git a/sca-java-1.x/branches/sca-java-1.6.2/modules/core/src/main/java/org/apache/tuscany/sca/core/invocation/SCAProxy.java b/sca-java-1.x/branches/sca-java-1.6.2/modules/core/src/main/java/org/apache/tuscany/sca/core/invocation/SCAProxy.java new file mode 100644 index 0000000000..f2907638ad --- /dev/null +++ b/sca-java-1.x/branches/sca-java-1.6.2/modules/core/src/main/java/org/apache/tuscany/sca/core/invocation/SCAProxy.java @@ -0,0 +1,78 @@ +/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.tuscany.sca.core.invocation;
+
+import java.lang.ref.WeakReference;
+import java.lang.reflect.InvocationHandler;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Proxy;
+import java.lang.reflect.Constructor;
+import java.util.WeakHashMap;
+
+public class SCAProxy extends Proxy
+{
+ protected SCAProxy (InvocationHandler handler) {
+ super(handler);
+ }
+
+ // This is a cache containing the proxy class constructor for each business interface.
+ // This improves performance compared to calling Proxy.newProxyInstance()
+ // every time that a proxy is needed.
+ private static WeakHashMap cache = new WeakHashMap<Class, WeakReference<Constructor>>();
+
+ public static Object newProxyInstance(ClassLoader classloader, Class aclass[], InvocationHandler invocationhandler)
+ throws IllegalArgumentException
+ {
+ try {
+ if(invocationhandler == null)
+ throw new NullPointerException();
+ // Lookup cached constructor. aclass[0] is the reference's business interface.
+ Constructor proxyCTOR = null;
+ synchronized(cache) {
+ WeakReference<Constructor> ref = (WeakReference<Constructor>) cache.get(aclass[0]);
+ if (ref != null){
+ proxyCTOR = ref.get();
+ }
+ }
+ if(proxyCTOR == null) {
+ Class proxyClass = getProxyClass(classloader, aclass);
+ proxyCTOR = proxyClass.getConstructor(constructorParams);
+ synchronized(cache){
+ cache.put(aclass[0],new WeakReference<Constructor>(proxyCTOR));
+ }
+ }
+ return proxyCTOR.newInstance(new Object[] { invocationhandler });
+ }
+ catch(NoSuchMethodException e) {
+ throw new InternalError(e.toString());
+ }
+ catch(IllegalAccessException e) {
+ throw new InternalError(e.toString());
+ }
+ catch (InstantiationException e) {
+ throw new InternalError(e.toString());
+ }
+ catch (InvocationTargetException e) {
+ throw new InternalError(e.toString());
+ }
+ }
+
+ private static final Class constructorParams[] = { InvocationHandler.class };
+
+}
\ No newline at end of file diff --git a/sca-java-1.x/branches/sca-java-1.6.2/modules/core/src/main/java/org/apache/tuscany/sca/core/invocation/TargetInvocationException.java b/sca-java-1.x/branches/sca-java-1.6.2/modules/core/src/main/java/org/apache/tuscany/sca/core/invocation/TargetInvocationException.java new file mode 100644 index 0000000000..2c4d657882 --- /dev/null +++ b/sca-java-1.x/branches/sca-java-1.6.2/modules/core/src/main/java/org/apache/tuscany/sca/core/invocation/TargetInvocationException.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.core.invocation; + +/** + * Raised when an error is encountered during a target invocation + * + * @version $Rev$ $Date$ + */ +public class TargetInvocationException extends Exception { + + private static final long serialVersionUID = -6553427708442761743L; + + public TargetInvocationException() { + super(); + } + + public TargetInvocationException(String message, Throwable cause) { + super(message, cause); + } + + public TargetInvocationException(String message) { + super(message); + } + + public TargetInvocationException(Throwable cause) { + super(cause); + } +} diff --git a/sca-java-1.x/branches/sca-java-1.6.2/modules/core/src/main/java/org/apache/tuscany/sca/core/invocation/ThreadMessageContext.java b/sca-java-1.x/branches/sca-java-1.6.2/modules/core/src/main/java/org/apache/tuscany/sca/core/invocation/ThreadMessageContext.java new file mode 100644 index 0000000000..becf5f9295 --- /dev/null +++ b/sca-java-1.x/branches/sca-java-1.6.2/modules/core/src/main/java/org/apache/tuscany/sca/core/invocation/ThreadMessageContext.java @@ -0,0 +1,89 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.tuscany.sca.core.invocation; + +import org.apache.tuscany.sca.core.assembly.EndpointReferenceImpl; +import org.apache.tuscany.sca.invocation.Message; + +/** + * Class for tunnelling a WorkContext through the invocation of a user class. + * + * @version $Rev$ $Date$ + */ +public final class ThreadMessageContext { + + // TUSCANY-3770: Used as a marker for detecting when thread context information can be removed + private static final Message msg = new MessageImpl(); + + private static final ThreadLocal<Message> CONTEXT = new ThreadLocal<Message>() { + @Override + protected synchronized Message initialValue() { + return msg; + } + }; + + private ThreadMessageContext() { + } + + /** + * Set the WorkContext for the current thread. + * The current work context is returned and must be restored after the invocation is complete. + * Typical usage would be: + * <pre> + * WorkContext old = PojoWorkContextTunnel.setThreadWorkContext(newContext); + * try { + * ... invoke user code ... + * } finally { + * PojoWorkContextTunnel.setThreadWorkContext(old); + * } + * </pre> + * @param context + * @return the current work context for the thread; this must be restored after the invocation is made + */ + public static Message setMessageContext(Message context) { + Message old = CONTEXT.get(); + CONTEXT.set(context); + + // TUSCANY-3770: Remove thread context information when the request invocation has completed + if (context == msg) { + CONTEXT.remove(); + } + + return old; + } + + /** + * Returns the WorkContext for the current thread. + * + * @return the WorkContext for the current thread + */ + public static Message getMessageContext() { + return CONTEXT.get(); + } + + // TUSCANY-3770: This method is no longer needed, as thread context information is removed implicitly + /* + * Removes and state from the current thread to ensure that + * any associated classloaders can be GCd + * + public static void removeMessageContext() { + CONTEXT.remove(); + } + */ +} diff --git a/sca-java-1.x/branches/sca-java-1.6.2/modules/core/src/main/java/org/apache/tuscany/sca/core/invocation/WireObjectFactory.java b/sca-java-1.x/branches/sca-java-1.6.2/modules/core/src/main/java/org/apache/tuscany/sca/core/invocation/WireObjectFactory.java new file mode 100644 index 0000000000..246f9c45d6 --- /dev/null +++ b/sca-java-1.x/branches/sca-java-1.6.2/modules/core/src/main/java/org/apache/tuscany/sca/core/invocation/WireObjectFactory.java @@ -0,0 +1,54 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.tuscany.sca.core.invocation; + +import org.apache.tuscany.sca.core.context.ServiceReferenceImpl; +import org.apache.tuscany.sca.core.factory.ObjectCreationException; +import org.apache.tuscany.sca.core.factory.ObjectFactory; +import org.apache.tuscany.sca.runtime.RuntimeWire; + +/** + * Uses a wire to return an object instance + * + * @version $Rev$ $Date$ + */ +public class WireObjectFactory<T> implements ObjectFactory<T> { + private Class<T> interfaze; + private RuntimeWire wire; + private ProxyFactory proxyService; + + /** + * Constructor. + * + * @param interfaze the interface to inject on the client + * @param wire the backing wire + * @param proxyService the wire service to create the proxy + * @throws NoMethodForOperationException + */ + public WireObjectFactory(Class<T> interfaze, RuntimeWire wire, ProxyFactory proxyService) { + this.interfaze = interfaze; + this.wire = wire; + this.proxyService = proxyService; + } + + public T getInstance() throws ObjectCreationException { + return new ServiceReferenceImpl<T>(interfaze, wire, proxyService).getProxy(); + } + +} |