/*
* 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.assembly;
import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
import java.util.List;
import org.apache.tuscany.sca.assembly.Binding;
import org.apache.tuscany.sca.assembly.Component;
import org.apache.tuscany.sca.assembly.ComponentReference;
import org.apache.tuscany.sca.assembly.ComponentService;
import org.apache.tuscany.sca.assembly.Contract;
import org.apache.tuscany.sca.core.conversation.ConversationManager;
import org.apache.tuscany.sca.core.invocation.InvocationChainImpl;
import org.apache.tuscany.sca.core.invocation.NonBlockingInterceptor;
import org.apache.tuscany.sca.core.invocation.RuntimeWireInvoker;
import org.apache.tuscany.sca.interfacedef.InterfaceContract;
import org.apache.tuscany.sca.interfacedef.InterfaceContractMapper;
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.provider.ImplementationProvider;
import org.apache.tuscany.sca.provider.ReferenceBindingProvider;
import org.apache.tuscany.sca.runtime.EndpointReference;
import org.apache.tuscany.sca.runtime.RuntimeComponent;
import org.apache.tuscany.sca.runtime.RuntimeComponentReference;
import org.apache.tuscany.sca.runtime.RuntimeComponentService;
import org.apache.tuscany.sca.runtime.RuntimeWire;
import org.apache.tuscany.sca.runtime.RuntimeWireProcessor;
import org.apache.tuscany.sca.work.WorkScheduler;
import org.osoa.sca.ServiceRuntimeException;
/**
* @version $Rev: 608822 $ $Date: 2008-01-04 12:59:56 +0000 (Fri, 04 Jan 2008) $
*/
public class RuntimeWireImpl implements RuntimeWire {
private EndpointReference wireSource;
private EndpointReference wireTarget;
private transient RuntimeWireProcessor wireProcessor;
private transient InterfaceContractMapper interfaceContractMapper;
private transient WorkScheduler workScheduler;
private transient MessageFactory messageFactory;
private transient ConversationManager conversationManager;
private transient RuntimeWireInvoker invoker;
private List<InvocationChain> chains;
/**
* @param source
* @param target
* @param interfaceContractMapper
* @param workScheduler
* @param wireProcessor
* @param messageFactory
* @param conversationManager
*/
public RuntimeWireImpl(EndpointReference source,
EndpointReference target,
InterfaceContractMapper interfaceContractMapper,
WorkScheduler workScheduler,
RuntimeWireProcessor wireProcessor,
MessageFactory messageFactory, ConversationManager conversationManager) {
super();
this.wireSource = source;
this.wireTarget = target;
this.interfaceContractMapper = interfaceContractMapper;
this.workScheduler = workScheduler;
this.wireProcessor = wireProcessor;
this.messageFactory = messageFactory;
this.conversationManager = conversationManager;
this.invoker = new RuntimeWireInvoker(this.messageFactory, this.conversationManager, this);
}
public synchronized List<InvocationChain> getInvocationChains() {
if (chains == null) {
initInvocationChains();
}
return chains;
}
public InvocationChain getInvocationChain(Operation operation) {
for (InvocationChain chain : getInvocationChains()) {
Operation op = null;
if (wireSource.getContract() != null) {
// Reference chain
op = chain.getSourceOperation();
} else {
// Service chain
op = chain.getTargetOperation();
}
if (interfaceContractMapper.isCompatible(operation, op, op.getInterface().isRemotable())) {
return chain;
}
}
return null;
}
public Object invoke(Operation operation, Object[] args) throws InvocationTargetException {
Message msg = messageFactory.createMessage();
msg.setBody(args);
return invoker.invoke(operation, msg);
}
public Object invoke(Operation operation, Message msg) throws InvocationTargetException {
return invoker.invoke(operation, msg);
}
/**
* Initialize the invocation chains
*/
private void initInvocationChains() {
chains = new ArrayList<InvocationChain>();
InterfaceContract sourceContract = wireSource.getInterfaceContract();
InterfaceContract targetContract = wireTarget.getInterfaceContract();
Contract source = wireSource.getContract();
if (source instanceof RuntimeComponentReference) {
// It's the reference wire
RuntimeComponentReference reference = (RuntimeComponentReference)wireSource.getContract();
Binding refBinding = wireSource.getBinding();
for (Operation operation : sourceContract.getInterface().getOperations()) {
Operation targetOperation = interfaceContractMapper.map(targetContract.getInterface(), operation);
if (targetOperation == null) {
throw new ServiceRuntimeException("No matching operation for " + operation.getName()
+ " is found in reference "
+ wireSource.getComponent().getURI()
+ "#"
+ reference.getName());
}
InvocationChain chain = new InvocationChainImpl(operation, targetOperation);
if (operation.isNonBlocking()) {
addNonBlockingInterceptor(reference, refBinding, chain);
}
addBindingInterceptor(reference, refBinding, chain, operation);
chains.add(chain);
}
} else {
// It's the service wire
RuntimeComponentService service = (RuntimeComponentService)wireTarget.getContract();
RuntimeComponent serviceComponent = wireTarget.getComponent();
for (Operation operation : sourceContract.getInterface().getOperations()) {
Operation targetOperation = interfaceContractMapper.map(targetContract.getInterface(), operation);
if (targetOperation == null) {
throw new ServiceRuntimeException("No matching operation for " + operation.getName()
+ " is found in service "
+ serviceComponent.getURI()
+ "#"
+ service.getName());
}
InvocationChain chain = new InvocationChainImpl(operation, targetOperation);
addImplementationInterceptor(serviceComponent, service, chain, targetOperation);
chains.add(chain);
}
}
wireProcessor.process(this);
}
public EndpointReference getSource() {
return wireSource;
}
public EndpointReference getTarget() {
return wireTarget;
}
public void setTarget(EndpointReference target) {
if (this.wireTarget != target) {
rebuild();
}
this.wireTarget = target;
}
public void rebuild() {
this.chains = null;
}
/**
* Add the interceptor for a binding
*
* @param reference
* @param binding
* @param chain
* @param operation
*/
private void addBindingInterceptor(ComponentReference reference,
Binding binding,
InvocationChain chain,
Operation operation) {
try {
ReferenceBindingProvider provider = ((RuntimeComponentReference)reference).getBindingProvider(binding);
if (provider != null) {
Invoker invoker = provider.createInvoker(operation);
if (invoker != null) {
chain.addInvoker(invoker);
}
}
} catch (RuntimeException e) {
throw e;
}
}
/**
* Add a non-blocking interceptor if the reference binding needs it
*
* @param reference
* @param binding
* @param chain
*/
private void addNonBlockingInterceptor(ComponentReference reference, Binding binding, InvocationChain chain) {
ReferenceBindingProvider provider = ((RuntimeComponentReference)reference).getBindingProvider(binding);
if (provider != null) {
boolean supportsOneWayInvocation = provider.supportsOneWayInvocation();
if (!supportsOneWayInvocation) {
chain.addInterceptor(new NonBlockingInterceptor(workScheduler));
}
}
}
/**
* Add the interceptor for a component implementation
*
* @param component
* @param service
* @param chain
* @param operation
*/
private void addImplementationInterceptor(Component component,
ComponentService service,
InvocationChain chain,
Operation operation) {
ImplementationProvider provider = ((RuntimeComponent)component).getImplementationProvider();
if (provider != null) {
Invoker invoker = null;
invoker = provider.createInvoker((RuntimeComponentService)service, operation);
chain.addInvoker(invoker);
}
}
/**
* @see java.lang.Object#clone()
*/
@Override
public Object clone() throws CloneNotSupportedException {
RuntimeWireImpl copy = (RuntimeWireImpl)super.clone();
copy.wireSource = (EndpointReference)wireSource.clone();
copy.wireTarget = (EndpointReference)wireTarget.clone();
copy.invoker = new RuntimeWireInvoker(copy.messageFactory, copy.conversationManager, copy);
return copy;
}
/**
* @return the conversationManager
*/
public ConversationManager getConversationManager() {
return conversationManager;
}
}