* @param optimizable true if the wire connection can be optimized
*/
void connect(OutboundWire sourceWire, InboundWire targetWire, boolean optimizable) {
SCAObject source = sourceWire.getContainer();
SCAObject target = targetWire.getContainer();
ServiceContract contract = sourceWire.getServiceContract();
Map<Operation<?>, InboundInvocationChain> targetChains = targetWire.getInvocationChains();
// perform optimization, if possible
// REVIEW: (kentaminator@gmail.com) shouldn't this check whether the interceptors in the
// source & target chains are marked as optimizable? (and if so, optimize them away?)
if (optimizable && sourceWire.getInvocationChains().isEmpty() && targetChains.isEmpty()) {
sourceWire.setTargetWire(targetWire);
if (postProcessorRegistry != null) {
// run wire post-processors
postProcessorRegistry.process(sourceWire, targetWire);
}
return;
}
// match outbound to inbound chains
for (OutboundInvocationChain outboundChain : sourceWire.getInvocationChains().values()) {
Operation<?> operation = outboundChain.getOperation();
InboundInvocationChain inboundChain = targetChains.get(operation);
if (inboundChain == null) {
BuilderConfigException e =
new BuilderConfigException("Incompatible source and target interfaces for reference");
e.setIdentifier(sourceWire.getReferenceName());
throw e;
}
Operation<?> inboundOperation = inboundChain.getOperation();
boolean isOneWayOperation = operation.isNonBlocking();
boolean operationHasCallback = contract.getCallbackName() != null;
if (isOneWayOperation && operationHasCallback) {
throw new ComponentRuntimeException("Operation cannot be marked one-way and have a callback");
}
TargetInvoker invoker = null;
if (target instanceof Component) {
Component component = (Component) target;
if (isOneWayOperation || operationHasCallback) {
invoker = component.createAsyncTargetInvoker(targetWire, inboundOperation);
} else {
String portName = sourceWire.getTargetName().getPortName();
invoker = component.createTargetInvoker(portName, inboundOperation);
}
} else if (target instanceof Reference) {
Reference reference = (Reference) target;
if (!(reference instanceof CompositeReference) && operationHasCallback) {
// Notice that for bound references we only use async target invokers for callback operations
invoker = reference.createAsyncTargetInvoker(sourceWire, inboundOperation);
} else {
ServiceContract targetContract = targetWire.getServiceContract();
invoker = reference.createTargetInvoker(targetContract, inboundOperation);
}
} else if (target instanceof CompositeService) {
CompositeService compServ = (CompositeService) target;
invoker = compServ.createTargetInvoker(targetWire.getServiceContract(), inboundChain.getOperation());
}
if (source instanceof Service && !(source instanceof CompositeService)) {
// services are a special case: invoker must go on the inbound chain
if (target instanceof Component && (isOneWayOperation || operationHasCallback)) {
// if the target is a component and the operation is non-blocking
connect(outboundChain, inboundChain, null, true);
} else {
connect(outboundChain, inboundChain, null, false);
}
Service service = (Service) source;
InboundInvocationChain chain = service.getInboundWire().getInvocationChains().get(operation);
chain.setTargetInvoker(invoker);
} else {
if (target instanceof Component && (isOneWayOperation || operationHasCallback)) {
// if the target is a component and the operation is non-blocking
connect(outboundChain, inboundChain, invoker, true);
} else {
connect(outboundChain, inboundChain, invoker, false);
}
}
}
// create source callback chains and connect them if target callback chains exist
Map<Operation<?>, OutboundInvocationChain> sourceCallbackChains =
targetWire.getSourceCallbackInvocationChains(source.getName());
for (InboundInvocationChain inboundChain : sourceWire.getTargetCallbackInvocationChains().values()) {
Operation<?> operation = inboundChain.getOperation();
if (sourceCallbackChains != null && sourceCallbackChains.get(operation) != null) {
String name = operation.getName();
BuilderConfigException e =
new BuilderConfigException("Source callback chain should not exist for operation [" + name + "]");
e.setIdentifier(sourceWire.getReferenceName());
throw e;
}
Operation targetOp =
(Operation)targetWire.getServiceContract().getCallbackOperations().get(operation.getName());
OutboundInvocationChain outboundChain = wireService.createOutboundChain(targetOp);
targetWire.addSourceCallbackInvocationChain(source.getName(), targetOp, outboundChain);
if (source instanceof Component) {
Component component = (Component) source;
TargetInvoker invoker = component.createTargetInvoker(null, operation);
connect(outboundChain, inboundChain, invoker, false);
} else if (source instanceof CompositeReference) {
CompositeReference compRef = (CompositeReference) source;
ServiceContract sourceContract = sourceWire.getServiceContract();
TargetInvoker invoker = compRef.createCallbackTargetInvoker(sourceContract, operation);
connect(outboundChain, inboundChain, invoker, false);
} else if (source instanceof Service) {
Service service = (Service) source;
ServiceContract sourceContract = sourceWire.getServiceContract();
TargetInvoker invoker = service.createCallbackTargetInvoker(sourceContract, operation);
connect(outboundChain, inboundChain, invoker, false);
}
}
if (postProcessorRegistry != null) {