diff options
Diffstat (limited to 'sca-java-1.x/tags/java-M1-final/java/sca/core/src/main/java/org/apache/tuscany/core/wire/jdk/JDKInvocationHandler.java')
-rw-r--r-- | sca-java-1.x/tags/java-M1-final/java/sca/core/src/main/java/org/apache/tuscany/core/wire/jdk/JDKInvocationHandler.java | 137 |
1 files changed, 137 insertions, 0 deletions
diff --git a/sca-java-1.x/tags/java-M1-final/java/sca/core/src/main/java/org/apache/tuscany/core/wire/jdk/JDKInvocationHandler.java b/sca-java-1.x/tags/java-M1-final/java/sca/core/src/main/java/org/apache/tuscany/core/wire/jdk/JDKInvocationHandler.java new file mode 100644 index 0000000000..2cef096a5e --- /dev/null +++ b/sca-java-1.x/tags/java-M1-final/java/sca/core/src/main/java/org/apache/tuscany/core/wire/jdk/JDKInvocationHandler.java @@ -0,0 +1,137 @@ +/** + * + * Copyright 2005 The Apache Software Foundation or its licensors, as applicable. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.tuscany.core.wire.jdk; + +import org.apache.tuscany.core.context.TargetException; +import org.apache.tuscany.core.wire.Interceptor; +import org.apache.tuscany.core.wire.InvocationConfiguration; +import org.apache.tuscany.core.wire.TargetInvoker; +import org.apache.tuscany.core.message.Message; +import org.apache.tuscany.core.message.MessageFactory; + +import java.lang.reflect.InvocationHandler; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.util.HashMap; +import java.util.Map; + +/** + * Receives a request from a JDK proxy and dispatches it to a target invoker or source interceptor stack + * + * @version $Rev$ $Date$ + */ +public class JDKInvocationHandler implements InvocationHandler { + + private MessageFactory messageFactory; + + /* + * an association of an operation to configuration holder. The holder contains the master wire configuration + * and a locale clone of the master TargetInvoker. TargetInvokers will be cloned by the handler and placed in the + * holder if they are cacheable. This allows optimizations such as avoiding target resolution when a source refers + * to a target of greater scope since the target reference can be maintained by the invoker. When a target invoker + * is not cacheable, the master associated with the wire configuration will be used. + */ + private Map<Method, ConfigHolder> configuration; + + public JDKInvocationHandler(MessageFactory messageFactory, Map<Method, ? extends InvocationConfiguration> configuration) { + assert (messageFactory != null) : "Message factory was null"; + assert (configuration != null) : "Configuration not specified"; + this.configuration = new HashMap<Method, ConfigHolder>(configuration.size()); + for (Map.Entry<Method, ? extends InvocationConfiguration> entry : configuration.entrySet()) { + this.configuration.put(entry.getKey(), new ConfigHolder(entry.getValue())); + } + this.messageFactory = messageFactory; + } + + /** + * Dispatches a client request made on a proxy + */ + public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { + Interceptor headInterceptor = null; + ConfigHolder holder = configuration.get(method); + if (holder == null) { + TargetException e = new TargetException("Operation not configured"); + e.setIdentifier(method.getName()); + throw e; + } + InvocationConfiguration config = holder.config; + if (config != null) { + headInterceptor = config.getHeadInterceptor(); + } + + TargetInvoker invoker; + + if (holder.cachedInvoker == null) { + assert config != null; + if(config.getTargetInvoker() == null){ + TargetException e= new TargetException("No target invoker configured for operation"); + e.setIdentifier(config.getMethod().getName()); + throw e; + } + if (config.getTargetInvoker().isCacheable()) { + // clone and store the invoker locally + holder.cachedInvoker = (TargetInvoker) config.getTargetInvoker().clone(); + invoker = holder.cachedInvoker; + } else { + invoker = config.getTargetInvoker(); + } + } else { + assert config != null; + invoker = config.getTargetInvoker(); + } + if (headInterceptor == null) { + try { + // short-circuit the dispatch and invoke the target directly + if (config.getTargetInvoker() == null) { + throw new AssertionError("No target invoker [" + method.getName() + "]"); + } + return config.getTargetInvoker().invokeTarget(args); + } catch (InvocationTargetException e) { + // the cause was thrown by the target so throw it + throw e.getCause(); + } + } else { + Message msg = messageFactory.createMessage(); + msg.setTargetInvoker(invoker); + msg.setBody(args); + // dispatch the wire down the chain and get the response + Message resp = headInterceptor.invoke(msg); + + Object body = resp.getBody(); + if (body instanceof Throwable) { + throw (Throwable) body; + } + return body; + } + } + + /** + * A holder used to associate an wire configuration with a local copy of a target invoker that was previously + * cloned from the configuration master + */ + private class ConfigHolder { + + public ConfigHolder(InvocationConfiguration config) { + this.config = config; + } + + InvocationConfiguration config; + + TargetInvoker cachedInvoker; + } + +}
\ No newline at end of file |