/*
* 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.runtime;
import org.apache.tuscany.sca.assembly.AssemblyFactory;
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.Composite;
import org.apache.tuscany.sca.assembly.Implementation;
import org.apache.tuscany.sca.assembly.SCABinding;
import org.apache.tuscany.sca.assembly.SCABindingFactory;
import org.apache.tuscany.sca.assembly.builder.CompositeBuilderException;
import org.apache.tuscany.sca.assembly.builder.CompositeBuilderMonitor;
import org.apache.tuscany.sca.assembly.builder.Problem;
import org.apache.tuscany.sca.assembly.builder.impl.CompositeBuilderImpl;
import org.apache.tuscany.sca.core.invocation.InvocationChainImpl;
import org.apache.tuscany.sca.core.invocation.NonBlockingInterceptor;
import org.apache.tuscany.sca.interfacedef.IncompatibleInterfaceContractException;
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.provider.BindingProviderFactory;
import org.apache.tuscany.sca.provider.ImplementationProvider;
import org.apache.tuscany.sca.provider.ImplementationProviderFactory;
import org.apache.tuscany.sca.provider.ProviderFactoryExtensionPoint;
import org.apache.tuscany.sca.provider.ReferenceBindingProvider;
import org.apache.tuscany.sca.provider.ServiceBindingProvider;
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.scope.ScopeRegistry;
import org.apache.tuscany.sca.scope.ScopedRuntimeComponent;
import org.apache.tuscany.sca.work.WorkScheduler;
/**
* @version $Rev: 538819 $ $Date: 2007-05-17 07:54:50 +0100 (Thu, 17 May 2007) $
*/
public class CompositeActivatorImpl implements CompositeActivator {
private final AssemblyFactory assemblyFactory;
private final SCABindingFactory scaBindingFactory;
private final InterfaceContractMapper interfaceContractMapper;
private final ScopeRegistry scopeRegistry;
private final WorkScheduler workScheduler;
private final RuntimeWireProcessor wireProcessor;
private final ProviderFactoryExtensionPoint providerFactories;
/**
* @param assemblyFactory
* @param interfaceContractMapper
* @param workContext
* @param workScheduler
* @param wirePostProcessorRegistry
*/
public CompositeActivatorImpl(AssemblyFactory assemblyFactory,
SCABindingFactory scaBindingFactory,
InterfaceContractMapper interfaceContractMapper,
ScopeRegistry scopeRegistry,
WorkScheduler workScheduler,
RuntimeWireProcessor wireProcessor,
ProviderFactoryExtensionPoint providerFactories) {
super();
this.assemblyFactory = assemblyFactory;
this.scaBindingFactory = scaBindingFactory;
this.interfaceContractMapper = interfaceContractMapper;
this.scopeRegistry = scopeRegistry;
this.workScheduler = workScheduler;
this.wireProcessor = wireProcessor;
this.providerFactories = providerFactories;
}
/**
* Configure a composite
*
* @param composite
* @throws IncompatibleInterfaceContractException
*/
@SuppressWarnings("unchecked")
protected void configureComposite(Composite composite) throws IncompatibleInterfaceContractException {
for (Component component : composite.getComponents()) {
for (ComponentService service : component.getServices()) {
for (Binding binding : service.getBindings()) {
BindingProviderFactory providerFactory = (BindingProviderFactory)providerFactories
.getProviderFactory(binding.getClass());
if (providerFactory != null) {
ServiceBindingProvider bindingProvider = providerFactory
.createServiceBindingProvider((RuntimeComponent)component,
(RuntimeComponentService)service,
binding);
if (bindingProvider != null) {
((RuntimeComponentService)service).setBindingProvider(binding, bindingProvider);
}
} else {
throw new IllegalStateException("Provider factory not found for class: " + binding.getClass()
.getName());
}
}
}
for (ComponentReference reference : component.getReferences()) {
for (Binding binding : reference.getBindings()) {
BindingProviderFactory providerFactory = (BindingProviderFactory)providerFactories
.getProviderFactory(binding.getClass());
if (providerFactory != null) {
ReferenceBindingProvider bindingProvider = providerFactory
.createReferenceBindingProvider((RuntimeComponent)component,
(RuntimeComponentReference)reference,
binding);
if (bindingProvider != null) {
((RuntimeComponentReference)reference).setBindingProvider(binding, bindingProvider);
}
} else {
throw new IllegalStateException("Provider factory not found for class: " + binding.getClass()
.getName());
}
}
}
Implementation implementation = component.getImplementation();
if (implementation instanceof Composite) {
configureComposite((Composite)implementation);
} else if (implementation != null) {
ImplementationProviderFactory providerFactory = (ImplementationProviderFactory)providerFactories
.getProviderFactory(implementation.getClass());
if (providerFactory != null) {
ImplementationProvider implementationProvider = providerFactory
.createImplementationProvider((RuntimeComponent)component, implementation);
if (implementationProvider != null) {
((RuntimeComponent)component).setImplementationProvider(implementationProvider);
}
} else {
throw new IllegalStateException("Provider factory not found for class: " + implementation
.getClass().getName());
}
setScopeContainer(component);
}
}
}
/**
* Start a composite
*/
protected void startComposite(Composite composite) {
for (Component component : composite.getComponents()) {
for (ComponentService service : component.getServices()) {
for (Binding binding : service.getBindings()) {
ServiceBindingProvider bindingProvider = ((RuntimeComponentService)service)
.getBindingProvider(binding);
if (bindingProvider != null) {
bindingProvider.start();
}
}
}
for (ComponentReference reference : component.getReferences()) {
for (Binding binding : reference.getBindings()) {
ReferenceBindingProvider bindingProvider = ((RuntimeComponentReference)reference)
.getBindingProvider(binding);
if (bindingProvider != null) {
bindingProvider.start();
}
}
}
Implementation implementation = component.getImplementation();
if (implementation instanceof Composite) {
startComposite((Composite)implementation);
} else {
ImplementationProvider implementationProvider = ((RuntimeComponent)component)
.getImplementationProvider();
if (implementationProvider != null) {
implementationProvider.start();
}
}
if (component instanceof ScopedRuntimeComponent) {
ScopedRuntimeComponent runtimeComponent = (ScopedRuntimeComponent)component;
if (runtimeComponent.getScopeContainer() != null) {
runtimeComponent.getScopeContainer().start();
}
}
}
}
public void stop(Composite composite) {
for (Component component : composite.getComponents()) {
for (ComponentService service : component.getServices()) {
for (Binding binding : service.getBindings()) {
ServiceBindingProvider bindingProvider = ((RuntimeComponentService)service)
.getBindingProvider(binding);
if (bindingProvider != null) {
bindingProvider.stop();
}
}
}
for (ComponentReference reference : component.getReferences()) {
for (Binding binding : reference.getBindings()) {
ReferenceBindingProvider bindingProvider = ((RuntimeComponentReference)reference)
.getBindingProvider(binding);
if (bindingProvider != null) {
bindingProvider.stop();
}
}
}
Implementation implementation = component.getImplementation();
if (implementation instanceof Composite) {
stop((Composite)implementation);
} else {
ImplementationProvider implementationProvider = ((RuntimeComponent)component)
.getImplementationProvider();
if (implementationProvider != null) {
implementationProvider.stop();
}
}
if (component instanceof ScopedRuntimeComponent) {
ScopedRuntimeComponent runtimeComponent = (ScopedRuntimeComponent)component;
if (runtimeComponent.getScopeContainer() != null) {
runtimeComponent.getScopeContainer().stop();
}
}
}
}
/**
* Create runtime wires for the composite
*
* @param composite
* @throws IncompatibleInterfaceContractException
*/
protected void createRuntimeWires(Composite composite) throws IncompatibleInterfaceContractException {
for (Component component : composite.getComponents()) {
Implementation implementation = component.getImplementation();
if (implementation instanceof Composite) {
// Recursively create runtime wires
createRuntimeWires((Composite)implementation);
} else {
// Create outbound wires for the component references
for (ComponentReference reference : component.getReferences()) {
for (Binding binding : reference.getBindings()) {
createWires(component, reference, binding);
}
}
// Create inbound wires for the component services
for (ComponentService service : component.getServices()) {
for (Binding binding : service.getBindings()) {
createWires(component, service, binding);
}
}
}
}
}
/**
* Get the effective interface contract for a reference binding
*
* @param reference
* @param binding
* @return
*/
private InterfaceContract getInterfaceContract(ComponentReference reference, Binding binding) {
InterfaceContract interfaceContract = reference.getInterfaceContract();
ReferenceBindingProvider provider = ((RuntimeComponentReference)reference).getBindingProvider(binding);
if (provider != null) {
InterfaceContract bindingContract = provider.getBindingInterfaceContract();
if (bindingContract != null) {
interfaceContract = bindingContract;
}
}
return interfaceContract;
}
/**
* Create the runtime wires for a reference binding
*
* @param component
* @param reference
* @param binding
*/
private void createWires(Component component, ComponentReference reference, Binding binding) {
if (!(reference instanceof RuntimeComponentReference)) {
return;
}
RuntimeComponentReference runtimeRef = (RuntimeComponentReference)reference;
InterfaceContract bindingContract = getInterfaceContract(reference, binding);
if (!(binding instanceof SCABinding)) {
InterfaceContract sourceContract = reference.getInterfaceContract();
// Component Reference --> External Service
EndpointReference wireSource = new EndpointReferenceImpl((RuntimeComponent)component,
(RuntimeComponentReference)reference, binding,
sourceContract);
EndpointReference wireTarget = new EndpointReferenceImpl(null, null, binding, bindingContract);
RuntimeWire wire = new RuntimeWireImpl(wireSource, wireTarget);
for (Operation operation : sourceContract.getInterface().getOperations()) {
Operation targetOperation = interfaceContractMapper.map(bindingContract.getInterface(), operation);
InvocationChain chain = new InvocationChainImpl(operation, targetOperation);
if (operation.isNonBlocking()) {
chain.addInterceptor(new NonBlockingInterceptor(workScheduler));
}
addBindingInterceptor(component, reference, binding, chain, operation, false);
wire.getInvocationChains().add(chain);
}
if (sourceContract.getCallbackInterface() != null) {
for (Operation operation : sourceContract.getCallbackInterface().getOperations()) {
Operation targetOperation = interfaceContractMapper.map(bindingContract.getCallbackInterface(),
operation);
InvocationChain chain = new InvocationChainImpl(operation, targetOperation);
if (operation.isNonBlocking()) {
chain.addInterceptor(new NonBlockingInterceptor(workScheduler));
}
addBindingInterceptor(component, reference, binding, chain, operation, true);
wire.getCallbackInvocationChains().add(chain);
}
}
runtimeRef.getRuntimeWires().add(wire);
wireProcessor.process(wire);
}
for (ComponentService service : reference.getTargets()) {
Component target = null;
SCABinding scaBinding = service.getBinding(SCABinding.class);
if (scaBinding != null) {
target = scaBinding.getComponent();
}
// FIXME: [rfeng] Ignore unresolved services
if (service.isUnresolved()) {
continue;
}
// FIXME: [rfeng] We might need a better way to get the impl interface contract
InterfaceContract targetContract = service.getService().getInterfaceContract();
EndpointReference wireSource = new EndpointReferenceImpl((RuntimeComponent)component,
(RuntimeComponentReference)reference, binding,
bindingContract);
EndpointReference wireTarget = new EndpointReferenceImpl((RuntimeComponent)target,
(RuntimeComponentService)service, binding,
targetContract);
RuntimeWire wire = new RuntimeWireImpl(wireSource, wireTarget);
for (Operation operation : bindingContract.getInterface().getOperations()) {
Operation targetOperation = interfaceContractMapper.map(targetContract.getInterface(), operation);
InvocationChain chain = new InvocationChainImpl(operation, targetOperation);
if (operation.isNonBlocking()) {
chain.addInterceptor(new NonBlockingInterceptor(workScheduler));
}
addBindingInterceptor(component, reference, binding, chain, operation, false);
if (target != null) {
addImplementationInterceptor(target, service, chain, targetOperation, false);
}
wire.getInvocationChains().add(chain);
}
if (bindingContract.getCallbackInterface() != null) {
if (reference.getName().startsWith("$self$.")) {
// No callback is needed
continue;
}
for (Operation operation : bindingContract.getCallbackInterface().getOperations()) {
Operation targetOperation = interfaceContractMapper.map(targetContract.getCallbackInterface(),
operation);
InvocationChain chain = new InvocationChainImpl(operation, targetOperation);
if (operation.isNonBlocking()) {
chain.addInterceptor(new NonBlockingInterceptor(workScheduler));
}
addBindingInterceptor(component, reference, binding, chain, operation, true);
addImplementationInterceptor(component, null, chain, targetOperation, true);
wire.getCallbackInvocationChains().add(chain);
}
}
runtimeRef.getRuntimeWires().add(wire);
if (!wire.getCallbackInvocationChains().isEmpty()) {
if (wire.getTarget().getContract() != null) {
((RuntimeComponentService) wire.getTarget().getContract()).getCallbackWires().add(wire);
}
}
wireProcessor.process(wire);
}
}
/**
* Get the effective interface contract for the service binding
*
* @param service
* @param binding
* @return
*/
private InterfaceContract getInterfaceContract(ComponentService service, Binding binding) {
InterfaceContract interfaceContract = service.getInterfaceContract();
ServiceBindingProvider provider = ((RuntimeComponentService)service).getBindingProvider(binding);
if (provider != null) {
InterfaceContract bindingContract = provider.getBindingInterfaceContract();
if (bindingContract != null) {
interfaceContract = bindingContract;
}
}
return interfaceContract;
}
/**
* Create runtime wires for a service binding
*
* @param component
* @param service
* @param binding
*/
private void createWires(Component component, ComponentService service, Binding binding) {
if (!(service instanceof RuntimeComponentService)) {
return;
}
RuntimeComponentService runtimeService = (RuntimeComponentService)service;
// FIXME: [rfeng] We might need a better way to get the impl interface contract
InterfaceContract targetContract = service.getService().getInterfaceContract();
InterfaceContract sourceContract = getInterfaceContract(service, binding);
EndpointReference wireSource = new EndpointReferenceImpl(null, null, binding, sourceContract);
EndpointReference wireTarget = new EndpointReferenceImpl((RuntimeComponent)component,
(RuntimeComponentService)service, binding,
targetContract);
RuntimeWire wire = new RuntimeWireImpl(wireSource, wireTarget);
for (Operation operation : sourceContract.getInterface().getOperations()) {
Operation targetOperation = interfaceContractMapper.map(targetContract.getInterface(), operation);
InvocationChain chain = new InvocationChainImpl(operation, targetOperation);
/* lresende */
if (operation.isNonBlocking()) {
chain.addInterceptor(new NonBlockingInterceptor(workScheduler));
}
addImplementationInterceptor(component, service, chain, targetOperation, false);
wire.getInvocationChains().add(chain);
}
// if (sourceContract.getCallbackInterface() != null) {
// for (Operation operation :
// sourceContract.getCallbackInterface().getOperations()) {
// Operation targetOperation =
// interfaceContractMapper.map(targetContract.getCallbackInterface(),
// operation);
// InvocationChain chain = new InvocationChainImpl(operation,
// targetOperation);
// if (operation.isNonBlocking()) {
// chain.addInterceptor(new NonBlockingInterceptor(workScheduler,
// workContext));
// }
// addImplementationInterceptor(component, service, chain, operation,
// true);
// wire.getCallbackInvocationChains().add(chain);
// }
// }
runtimeService.getRuntimeWires().add(wire);
wireProcessor.process(wire);
}
/**
* Add the interceptor for a component implementation
*
* @param component
* @param service
* @param chain
* @param operation
* @param isCallback
*/
private void addImplementationInterceptor(Component component,
ComponentService service,
InvocationChain chain,
Operation operation,
boolean isCallback) {
ImplementationProvider provider = ((RuntimeComponent)component).getImplementationProvider();
if (provider != null) {
Invoker invoker = null;
if (!isCallback) {
invoker = provider.createInvoker((RuntimeComponentService)service, operation);
} else {
invoker = provider.createCallbackInvoker(operation);
}
chain.addInvoker(invoker);
}
}
/**
* Add the interceptor for a binding
*
* @param component
* @param reference
* @param binding
* @param chain
* @param operation
* @param isCallback
*/
private void addBindingInterceptor(Component component,
ComponentReference reference,
Binding binding,
InvocationChain chain,
Operation operation,
boolean isCallback) {
ReferenceBindingProvider provider = ((RuntimeComponentReference)reference).getBindingProvider(binding);
if (provider != null) {
Invoker invoker = provider.createInvoker(operation, isCallback);
if (invoker != null) {
chain.addInvoker(invoker);
}
}
}
private void setScopeContainer(Component component) {
if (!(component instanceof ScopedRuntimeComponent)) {
return;
}
ScopedRuntimeComponent runtimeComponent = (ScopedRuntimeComponent)component;
runtimeComponent.setScopeContainer(scopeRegistry.getScopeContainer(runtimeComponent));
}
protected void buildComposite(Composite composite) throws CompositeBuilderException {
CompositeBuilderMonitor monitor = new CompositeBuilderMonitor() {
public void problem(Problem problem) {
// Uncommenting the following two lines can be useful to detect
// and troubleshoot SCA assembly XML composite configuration
// problems.
System.out.println("Composite assembly problem: " + problem.getMessage());
}
};
CompositeBuilderImpl builder = new CompositeBuilderImpl(assemblyFactory, scaBindingFactory, interfaceContractMapper, monitor);
builder.build(composite);
// if (!problems.isEmpty()) {
// throw new VariantRuntimeException(new RuntimeException("Problems in
// the composite..."));
// }
}
public void activate(Composite composite) throws ActivationException {
try {
buildComposite(composite);
configureComposite(composite);
createRuntimeWires(composite);
} catch (Exception e) {
throw new ActivationException(e);
}
}
public void deactivate(Composite composite) throws ActivationException {
}
public void start(Composite composite) throws ActivationException {
try {
startComposite(composite);
} catch (Exception e) {
throw new ActivationException(e);
}
}
}