| /* |
| * 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.impl; |
| |
| import java.io.ByteArrayOutputStream; |
| import java.io.Externalizable; |
| import java.io.IOException; |
| import java.io.ObjectInput; |
| import java.io.ObjectOutput; |
| import java.io.StringReader; |
| import java.lang.reflect.InvocationTargetException; |
| import java.util.ArrayList; |
| import java.util.List; |
| import java.util.Map; |
| import java.util.concurrent.ConcurrentHashMap; |
| |
| import javax.wsdl.xml.WSDLWriter; |
| import javax.xml.namespace.QName; |
| import javax.xml.stream.XMLStreamException; |
| import javax.xml.stream.XMLStreamReader; |
| import javax.xml.transform.stream.StreamSource; |
| |
| 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.CompositeReference; |
| import org.apache.tuscany.sca.assembly.CompositeService; |
| import org.apache.tuscany.sca.assembly.Contract; |
| import org.apache.tuscany.sca.assembly.Endpoint; |
| import org.apache.tuscany.sca.assembly.EndpointReference; |
| import org.apache.tuscany.sca.assembly.Reference; |
| import org.apache.tuscany.sca.assembly.Service; |
| import org.apache.tuscany.sca.assembly.builder.BindingBuilder; |
| import org.apache.tuscany.sca.assembly.builder.BuilderContext; |
| import org.apache.tuscany.sca.assembly.builder.BuilderExtensionPoint; |
| import org.apache.tuscany.sca.assembly.impl.EndpointImpl; |
| import org.apache.tuscany.sca.context.CompositeContext; |
| import org.apache.tuscany.sca.contribution.processor.ContributionReadException; |
| import org.apache.tuscany.sca.contribution.processor.ProcessorContext; |
| import org.apache.tuscany.sca.contribution.processor.StAXArtifactProcessor; |
| import org.apache.tuscany.sca.contribution.processor.StAXArtifactProcessorExtensionPoint; |
| import org.apache.tuscany.sca.contribution.processor.ValidatingXMLInputFactory; |
| import org.apache.tuscany.sca.core.ExtensionPointRegistry; |
| import org.apache.tuscany.sca.core.ExtensionPointRegistryLocator; |
| import org.apache.tuscany.sca.core.FactoryExtensionPoint; |
| import org.apache.tuscany.sca.core.UtilityExtensionPoint; |
| import org.apache.tuscany.sca.core.assembly.RuntimeAssemblyFactory; |
| import org.apache.tuscany.sca.core.invocation.AsyncResponseService; |
| import org.apache.tuscany.sca.core.invocation.Constants; |
| import org.apache.tuscany.sca.core.invocation.ExtensibleWireProcessor; |
| import org.apache.tuscany.sca.core.invocation.NonBlockingInterceptor; |
| import org.apache.tuscany.sca.core.invocation.RuntimeInvoker; |
| import org.apache.tuscany.sca.core.invocation.impl.InvocationChainImpl; |
| import org.apache.tuscany.sca.core.invocation.impl.PhaseManager; |
| import org.apache.tuscany.sca.interfacedef.Compatibility; |
| import org.apache.tuscany.sca.interfacedef.InterfaceContract; |
| import org.apache.tuscany.sca.interfacedef.InterfaceContractMapper; |
| import org.apache.tuscany.sca.interfacedef.InvalidInterfaceException; |
| import org.apache.tuscany.sca.interfacedef.Operation; |
| import org.apache.tuscany.sca.interfacedef.java.JavaInterfaceContract; |
| import org.apache.tuscany.sca.interfacedef.java.JavaInterfaceFactory; |
| import org.apache.tuscany.sca.interfacedef.wsdl.WSDLDefinition; |
| import org.apache.tuscany.sca.interfacedef.wsdl.WSDLInterface; |
| import org.apache.tuscany.sca.interfacedef.wsdl.WSDLInterfaceContract; |
| import org.apache.tuscany.sca.invocation.Interceptor; |
| import org.apache.tuscany.sca.invocation.InterceptorAsync; |
| import org.apache.tuscany.sca.invocation.InvocationChain; |
| import org.apache.tuscany.sca.invocation.Invoker; |
| import org.apache.tuscany.sca.invocation.InvokerAsyncResponse; |
| import org.apache.tuscany.sca.invocation.Message; |
| import org.apache.tuscany.sca.invocation.MessageFactory; |
| import org.apache.tuscany.sca.invocation.Phase; |
| import org.apache.tuscany.sca.provider.BindingProviderFactory; |
| import org.apache.tuscany.sca.provider.EndpointAsyncProvider; |
| import org.apache.tuscany.sca.provider.EndpointProvider; |
| import org.apache.tuscany.sca.provider.ImplementationAsyncProvider; |
| import org.apache.tuscany.sca.provider.ImplementationProvider; |
| import org.apache.tuscany.sca.provider.OptimisingBindingProvider; |
| import org.apache.tuscany.sca.provider.PolicyProvider; |
| import org.apache.tuscany.sca.provider.PolicyProviderFactory; |
| import org.apache.tuscany.sca.provider.ProviderFactoryExtensionPoint; |
| import org.apache.tuscany.sca.provider.ServiceBindingProvider; |
| import org.apache.tuscany.sca.runtime.DomainRegistry; |
| import org.apache.tuscany.sca.runtime.DomainRegistryFactory; |
| import org.apache.tuscany.sca.runtime.EndpointSerializer; |
| import org.apache.tuscany.sca.runtime.ExtensibleDomainRegistryFactory; |
| import org.apache.tuscany.sca.runtime.RuntimeComponent; |
| import org.apache.tuscany.sca.runtime.RuntimeComponentService; |
| import org.apache.tuscany.sca.runtime.RuntimeEndpoint; |
| import org.apache.tuscany.sca.runtime.RuntimeEndpointReference; |
| import org.apache.tuscany.sca.runtime.RuntimeWireProcessor; |
| import org.apache.tuscany.sca.runtime.RuntimeWireProcessorExtensionPoint; |
| import org.apache.tuscany.sca.work.WorkScheduler; |
| import org.oasisopen.sca.ServiceRuntimeException; |
| |
| /** |
| * Runtime model for Endpoint that supports java serialization |
| */ |
| public class RuntimeEndpointImpl extends EndpointImpl implements RuntimeEndpoint, Externalizable { |
| private static final long serialVersionUID = 1L; |
| private transient CompositeContext compositeContext; |
| private transient RuntimeWireProcessor wireProcessor; |
| private transient ProviderFactoryExtensionPoint providerFactories; |
| private transient InterfaceContractMapper interfaceContractMapper; |
| private transient WorkScheduler workScheduler; |
| private transient PhaseManager phaseManager; |
| private transient MessageFactory messageFactory; |
| private transient RuntimeInvoker invoker; |
| private transient EndpointSerializer serializer; |
| |
| private transient List<InvocationChain> chains; |
| private transient Map<Operation, InvocationChain> invocationChainMap = |
| new ConcurrentHashMap<Operation, InvocationChain>(); |
| private transient InvocationChain bindingInvocationChain; |
| |
| private transient ServiceBindingProvider bindingProvider; |
| private transient List<PolicyProvider> policyProviders; |
| private String xml; |
| private String wsdl; |
| |
| protected InterfaceContract bindingInterfaceContract; |
| protected InterfaceContract serviceInterfaceContract; |
| |
| private RuntimeEndpoint delegateEndpoint; |
| |
| /** |
| * No-arg constructor for Java serialization |
| */ |
| public RuntimeEndpointImpl() { |
| super(null); |
| } |
| |
| public RuntimeEndpointImpl(ExtensionPointRegistry registry) { |
| super(registry); |
| } |
| |
| protected void copyFrom(RuntimeEndpointImpl copy) { |
| this.xml = copy.xml; |
| |
| this.component = copy.component; |
| this.service = copy.service; |
| this.interfaceContract = copy.interfaceContract; |
| this.serviceInterfaceContract = copy.serviceInterfaceContract; |
| |
| this.binding = copy.binding; |
| this.bindingInterfaceContract = copy.interfaceContract; |
| this.bindingInvocationChain = copy.bindingInvocationChain; |
| |
| this.callbackEndpointReferences = copy.callbackEndpointReferences; |
| |
| this.requiredIntents = copy.requiredIntents; |
| this.policySets = copy.policySets; |
| |
| this.uri = copy.uri; |
| this.remote = copy.remote; |
| this.unresolved = copy.unresolved; |
| |
| this.chains = copy.chains; |
| this.invocationChainMap = copy.invocationChainMap; |
| this.bindingProvider = copy.bindingProvider; |
| this.policyProviders = copy.policyProviders; |
| |
| if (this.compositeContext == null && copy.compositeContext != null) { |
| bind(copy.compositeContext); |
| } |
| } |
| |
| public void bind(CompositeContext compositeContext) { |
| this.compositeContext = compositeContext; |
| bind(compositeContext.getExtensionPointRegistry(), compositeContext.getEndpointRegistry()); |
| } |
| |
| public void bind(ExtensionPointRegistry registry, DomainRegistry domainRegistry) { |
| if (compositeContext == null) { |
| compositeContext = new CompositeContext(registry, domainRegistry); |
| } |
| |
| // if interfaceContractMapper is already initialized then all the rest will be too |
| if (interfaceContractMapper != null) { |
| return; |
| } |
| this.registry = registry; |
| UtilityExtensionPoint utilities = registry.getExtensionPoint(UtilityExtensionPoint.class); |
| this.interfaceContractMapper = utilities.getUtility(InterfaceContractMapper.class); |
| this.workScheduler = utilities.getUtility(WorkScheduler.class); |
| this.wireProcessor = |
| new ExtensibleWireProcessor(registry.getExtensionPoint(RuntimeWireProcessorExtensionPoint.class)); |
| |
| this.messageFactory = registry.getExtensionPoint(FactoryExtensionPoint.class).getFactory(MessageFactory.class); |
| this.invoker = new RuntimeInvoker(registry, this); |
| |
| this.phaseManager = utilities.getUtility(PhaseManager.class); |
| this.serializer = utilities.getUtility(EndpointSerializer.class); |
| this.providerFactories = registry.getExtensionPoint(ProviderFactoryExtensionPoint.class); |
| this.builders = registry.getExtensionPoint(BuilderExtensionPoint.class); |
| this.contractBuilder = builders.getContractBuilder(); |
| } |
| |
| public void unbind() { |
| compositeContext = null; |
| bindingInvocationChain = null; |
| chains = null; |
| bindingProvider = null; |
| policyProviders = null; |
| invocationChainMap.clear(); |
| } |
| |
| public synchronized List<InvocationChain> getInvocationChains() { |
| if (chains == null) { |
| initInvocationChains(); |
| } |
| return chains; |
| } |
| |
| public synchronized InvocationChain getBindingInvocationChain() { |
| if (bindingInvocationChain == null) { |
| bindingInvocationChain = new InvocationChainImpl(null, null, false, phaseManager, isAsyncInvocation()); |
| initServiceBindingInvocationChains(); |
| } |
| |
| // Init the operation invocation chains now. We know they will |
| // be needed as well as the binding invocation chain and this |
| // makes the wire processors run |
| getInvocationChains(); |
| |
| return bindingInvocationChain; |
| } |
| |
| /** |
| * A dummy invocation chain representing null as ConcurrentHashMap doesn't allow null values |
| */ |
| private static final InvocationChain NULL_CHAIN = new InvocationChainImpl(null, null, false, null, false); |
| |
| public InvocationChain getInvocationChain(Operation operation) { |
| InvocationChain cached = invocationChainMap.get(operation); |
| if (cached == null) { |
| for (InvocationChain chain : getInvocationChains()) { |
| Operation op = chain.getTargetOperation(); |
| |
| // We used to check compatibility here but this is now validated when the |
| // chain is created. As the chain operations are the real interface types |
| // they may be incompatible just because they are described in different |
| // IDLs |
| if (operation.getInterface().isRemotable()) { |
| if (operation.getName().equals(op.getName())) { |
| invocationChainMap.put(operation, chain); |
| return chain; |
| } |
| if (interfaceContractMapper.isCompatible(operation, op, Compatibility.SUBSET)) { |
| invocationChainMap.put(operation, chain); |
| return chain; |
| } |
| } else { |
| // [rfeng] We need to run the compatibility check for local operations as they |
| // can be overloaded |
| if (interfaceContractMapper.isCompatible(operation, op, Compatibility.SUBSET)) { |
| invocationChainMap.put(operation, chain); |
| return chain; |
| } |
| } |
| } |
| // Cache it with the NULL_CHAIN to avoid NPE |
| invocationChainMap.put(operation, NULL_CHAIN); |
| return null; |
| } else { |
| if (cached == NULL_CHAIN) { |
| cached = null; |
| } |
| return cached; |
| } |
| } |
| |
| public Message invoke(Message msg) { |
| // Deal with async callback |
| // Ensure invocation chains are built... |
| getInvocationChains(); |
| // async callback handling |
| if( this.isAsyncInvocation() && !this.getCallbackEndpointReferences().isEmpty() ) { |
| RuntimeEndpointReference asyncEPR = (RuntimeEndpointReference) this.getCallbackEndpointReferences().get(0); |
| // Place a link to the callback EPR into the message headers... |
| msg.getHeaders().put(Constants.ASYNC_CALLBACK, asyncEPR ); |
| } |
| // end of async callback handling |
| return invoker.invokeBinding(msg); |
| } |
| |
| public Object invoke(Operation operation, Object[] args) throws InvocationTargetException { |
| return invoker.invoke(operation, args); |
| } |
| |
| public Message invoke(Operation operation, Message msg) { |
| return invoker.invoke(operation, msg); |
| } |
| |
| public void invokeAsync(Message msg){ |
| invoker.invokeBindingAsync(msg); |
| } // end method invokeAsync(Message) |
| |
| public void invokeAsync(Operation operation, Message msg){ |
| msg.setOperation(operation); |
| invoker.invokeAsync(msg); |
| } // end method invokeAsync(Operation, Message) |
| |
| public void invokeAsyncResponse(Message msg){ |
| resolve(); |
| invoker.invokeAsyncResponse(msg); |
| } |
| |
| /** |
| * Navigate the component/componentType inheritance chain to find the leaf contract |
| * @param contract |
| * @return |
| */ |
| private Contract getLeafContract(Contract contract) { |
| Contract prev = null; |
| Contract current = contract; |
| while (current != null) { |
| prev = current; |
| if (current instanceof ComponentReference) { |
| current = ((ComponentReference)current).getReference(); |
| } else if (current instanceof CompositeReference) { |
| current = ((CompositeReference)current).getPromotedReferences().get(0); |
| } else if (current instanceof ComponentService) { |
| current = ((ComponentService)current).getService(); |
| } else if (current instanceof CompositeService) { |
| current = ((CompositeService)current).getPromotedService(); |
| } else { |
| break; |
| } |
| if (current == null) { |
| return prev; |
| } |
| } |
| return current; |
| } |
| |
| /** |
| * Initialize the invocation chains |
| */ |
| private void initInvocationChains() { |
| chains = new ArrayList<InvocationChain>(); |
| InterfaceContract sourceContract = getBindingInterfaceContract(); |
| |
| // It's the service wire |
| RuntimeComponentService service = (RuntimeComponentService)getService(); |
| RuntimeComponent serviceComponent = (RuntimeComponent)getComponent(); |
| |
| //InterfaceContract targetContract = getInterfaceContract(); |
| // TODO - EPR - why is this looking at the component types. The endpoint should have the right interface contract by this time |
| InterfaceContract targetContract = getComponentTypeServiceInterfaceContract(); |
| // setInterfaceContract(targetContract); |
| validateServiceInterfaceCompatibility(); |
| 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, false, phaseManager, isAsyncInvocation()); |
| if (operation.isNonBlocking()) { |
| addNonBlockingInterceptor(chain); |
| } |
| addServiceBindingInterceptor(chain, operation); |
| addImplementationInterceptor(serviceComponent, service, chain, targetOperation); |
| chains.add(chain); |
| |
| // Handle cases where the operation is an async server |
| if( targetOperation.isAsyncServer() ) { |
| createAsyncServerCallback(); |
| } // end if |
| } |
| |
| wireProcessor.process(this); |
| |
| // If we have to support async and there is no binding chain |
| // then set the response path to point directly to the |
| // binding provided async response handler |
| if (isAsyncInvocation() && |
| bindingInvocationChain == null){ |
| // fix up the operation chain response path to point back to the |
| // binding provided async response handler |
| ServiceBindingProvider serviceBindingProvider = getBindingProvider(); |
| if (serviceBindingProvider instanceof EndpointAsyncProvider){ |
| EndpointAsyncProvider asyncEndpointProvider = (EndpointAsyncProvider)serviceBindingProvider; |
| InvokerAsyncResponse asyncResponseInvoker = asyncEndpointProvider.createAsyncResponseInvoker(); |
| |
| for (InvocationChain chain : getInvocationChains()){ |
| Invoker invoker = chain.getHeadInvoker(); |
| if (invoker instanceof InterceptorAsync){ |
| ((InterceptorAsync)invoker).setPrevious(asyncResponseInvoker); |
| } else { |
| //TODO - throw error once the old async code is removed |
| } // end if |
| } // end for |
| } else { |
| // TODO - throw error once the old async code is removed |
| } // end if |
| } // end if |
| |
| ServiceBindingProvider provider = getBindingProvider(); |
| if ((provider != null) && (provider instanceof OptimisingBindingProvider)) { |
| //TODO - remove this comment once optimisation codepath is tested |
| ((OptimisingBindingProvider)provider).optimiseBinding( this ); |
| } // end if |
| |
| } // end method initInvocationChains |
| |
| /** |
| * Creates the async callback for this Endpoint, if it does not already exist |
| * and stores it into the Endpoint |
| */ |
| public void createAsyncServerCallback( ) { |
| // No need to create a callback if the Binding supports async natively... |
| if( hasNativeAsyncBinding(this) ) return; |
| |
| // Check to see if the callback already exists |
| if( asyncCallbackExists( this ) ) return; |
| |
| RuntimeEndpointReference asyncEPR = createAsyncEPR( this ); |
| |
| // Store the new callback EPR into the Endpoint |
| this.getCallbackEndpointReferences().add(asyncEPR); |
| |
| // Also store the callback EPR into the DomainRegistry |
| DomainRegistry epReg = getEndpointRegistry( registry ); |
| if( epReg != null ) epReg.addEndpointReference(asyncEPR); |
| } // end method createAsyncServerCallback |
| |
| public RuntimeEndpointReference getAsyncServerCallback() { |
| |
| return (RuntimeEndpointReference) this.getCallbackEndpointReferences().get(0); |
| } // end method getAsyncServerCallback |
| |
| |
| /** |
| * Indicates if a given endpoint has a Binding that supports native async invocation |
| * @param endpoint - the endpoint |
| * @return - true if the endpoint has a binding that supports native async, false otherwise |
| */ |
| private boolean hasNativeAsyncBinding(RuntimeEndpoint endpoint) { |
| ServiceBindingProvider provider = endpoint.getBindingProvider(); |
| if( provider instanceof EndpointAsyncProvider ) { |
| EndpointAsyncProvider asyncProvider = (EndpointAsyncProvider) provider; |
| if( asyncProvider.supportsNativeAsync() ) return true; |
| } // end if |
| return false; |
| } // end method hasNativeAsyncBinding |
| |
| /** |
| * Creates the Endpoint object for the async callback |
| * @param endpoint - the endpoint which has the async server operations |
| * @return the EndpointReference object representing the callback |
| */ |
| private RuntimeEndpointReference createAsyncEPR( RuntimeEndpoint endpoint ){ |
| CompositeContext compositeContext = endpoint.getCompositeContext(); |
| RuntimeAssemblyFactory assemblyFactory = getAssemblyFactory( compositeContext ); |
| RuntimeEndpointReference epr = (RuntimeEndpointReference)assemblyFactory.createEndpointReference(); |
| epr.bind( compositeContext ); |
| |
| // Create pseudo-component |
| epr.setComponent(component); |
| |
| // Create pseudo-reference |
| ComponentReference reference = assemblyFactory.createComponentReference(); |
| ExtensionPointRegistry registry = compositeContext.getExtensionPointRegistry(); |
| FactoryExtensionPoint modelFactories = registry.getExtensionPoint(FactoryExtensionPoint.class); |
| JavaInterfaceFactory javaInterfaceFactory = (JavaInterfaceFactory)modelFactories.getFactory(JavaInterfaceFactory.class); |
| JavaInterfaceContract interfaceContract = javaInterfaceFactory.createJavaInterfaceContract(); |
| try { |
| interfaceContract.setInterface(javaInterfaceFactory.createJavaInterface(AsyncResponseService.class)); |
| } catch (InvalidInterfaceException e1) { |
| // Nothing to do here - will not happen |
| } // end try |
| reference.setInterfaceContract(interfaceContract); |
| String referenceName = endpoint.getService().getName() + "_asyncCallback"; |
| reference.setName(referenceName); |
| reference.setForCallback(true); |
| // Add in "implementation" reference (really a dummy, but with correct interface) |
| Reference implReference = assemblyFactory.createReference(); |
| implReference.setInterfaceContract(interfaceContract); |
| implReference.setName(referenceName); |
| implReference.setForCallback(true); |
| |
| reference.setReference(implReference); |
| // Set the created ComponentReference into the EPR |
| epr.setReference(reference); |
| |
| // Create a binding |
| Binding binding = createMatchingBinding( endpoint.getBinding(), (RuntimeComponent)endpoint.getComponent(), reference, registry ); |
| epr.setBinding(binding); |
| |
| // Need to establish policies here (binding has some...) |
| epr.getRequiredIntents().addAll( endpoint.getRequiredIntents() ); |
| epr.getPolicySets().addAll( endpoint.getPolicySets() ); |
| |
| // Attach a dummy endpoint to the epr |
| RuntimeEndpoint ep = (RuntimeEndpoint)assemblyFactory.createEndpoint(); |
| ep.setUnresolved(false); |
| epr.setTargetEndpoint(ep); |
| //epr.setStatus(EndpointReference.Status.RESOLVED_BINDING); |
| epr.setStatus(EndpointReference.Status.WIRED_TARGET_FOUND_AND_MATCHED); |
| epr.setUnresolved(false); |
| |
| // Set the URI for the EPR |
| String eprURI = endpoint.getComponent().getName() + "#reference-binding(" + referenceName + "/" + referenceName + ")"; |
| epr.setURI(eprURI); |
| |
| return epr; |
| } // end method RuntimeEndpointReference |
| |
| private boolean asyncCallbackExists( RuntimeEndpoint endpoint ) { |
| if( endpoint.getCallbackEndpointReferences().isEmpty() ) return false; |
| return true; |
| } // end method asyncCallbackExists |
| |
| /** |
| * Create a matching binding to a supplied binding |
| * - the matching binding has the same binding type, but is for the supplied component and service |
| * @param matchBinding - the binding to match |
| * @param component - the component |
| * @param service - the service |
| * @param registry - registry for extensions |
| * @return - the matching binding, or null if it could not be created |
| */ |
| @SuppressWarnings("unchecked") |
| private Binding createMatchingBinding( Binding matchBinding, RuntimeComponent component, |
| ComponentReference reference, ExtensionPointRegistry registry ) { |
| // Since there is no simple way to obtain a Factory for a binding where the type is not known ahead of |
| // time, the process followed here is to generate the <binding.xxx/> XML element from the binding type QName |
| // and then read the XML using the processor for that XML... |
| QName bindingName = matchBinding.getType(); |
| String bindingXML = "<ns1:" + bindingName.getLocalPart() + " xmlns:ns1='" + bindingName.getNamespaceURI() + "'/>"; |
| |
| StAXArtifactProcessorExtensionPoint processors = registry.getExtensionPoint(StAXArtifactProcessorExtensionPoint.class); |
| StAXArtifactProcessor<?> processor = (StAXArtifactProcessor<?>)processors.getProcessor(bindingName); |
| |
| FactoryExtensionPoint modelFactories = registry.getExtensionPoint(FactoryExtensionPoint.class); |
| ValidatingXMLInputFactory inputFactory = modelFactories.getFactory(ValidatingXMLInputFactory.class); |
| StreamSource source = new StreamSource( new StringReader(bindingXML) ); |
| |
| ProcessorContext context = new ProcessorContext(); |
| try { |
| XMLStreamReader reader = inputFactory.createXMLStreamReader(source); |
| reader.next(); |
| Binding newBinding = (Binding) processor.read(reader, context ); |
| newBinding.setName(reference.getName()); |
| |
| // Create a URI address for the callback based on the Component_Name/Reference_Name pattern |
| //String callbackURI = "/" + component.getName() + "/" + reference.getName(); |
| //newBinding.setURI(callbackURI); |
| |
| BuilderExtensionPoint builders = registry.getExtensionPoint(BuilderExtensionPoint.class); |
| BindingBuilder builder = builders.getBindingBuilder(newBinding.getType()); |
| if (builder != null) { |
| org.apache.tuscany.sca.assembly.builder.BuilderContext builderContext = new BuilderContext(registry); |
| builder.build(component, reference, newBinding, builderContext, true); |
| } // end if |
| |
| return newBinding; |
| } catch (ContributionReadException e) { |
| e.printStackTrace(); |
| } catch (XMLStreamException e) { |
| e.printStackTrace(); |
| } |
| |
| return null; |
| } // end method createMatchingBinding |
| |
| /** |
| * Gets a RuntimeAssemblyFactory from the CompositeContext |
| * @param compositeContext |
| * @return the RuntimeAssemblyFactory |
| */ |
| private RuntimeAssemblyFactory getAssemblyFactory( CompositeContext compositeContext ) { |
| ExtensionPointRegistry registry = compositeContext.getExtensionPointRegistry(); |
| FactoryExtensionPoint modelFactories = registry.getExtensionPoint(FactoryExtensionPoint.class); |
| return (RuntimeAssemblyFactory)modelFactories.getFactory(AssemblyFactory.class); |
| } // end method RuntimeAssemblyFactory |
| |
| /** |
| * Check that endpoint has compatible interface at the component and binding ends. |
| * The user can specify the interfaces at both ends so there is a danger that they won't be compatible. |
| */ |
| public void validateServiceInterfaceCompatibility() { |
| |
| InterfaceContract serviceContract = getComponentServiceInterfaceContract(); |
| InterfaceContract bindingContract = getBindingInterfaceContract(); |
| |
| if ((serviceContract != bindingContract) && |
| (serviceContract != null) && (bindingContract != null)) { |
| |
| boolean bindingHasCallback = bindingContract.getCallbackInterface() != null; |
| |
| try { |
| |
| // Use the normalized contract if the interface types are different or if |
| // a normalized contract has been previously generate, for example, by virtue |
| // of finding a JAXWS annotation on a Java class that references a WSDL file |
| if (serviceContract.getClass() != bindingContract.getClass() || |
| serviceContract.getNormalizedWSDLContract() != null || |
| bindingContract.getNormalizedWSDLContract() != null) { |
| interfaceContractMapper.checkCompatibility(getGeneratedWSDLContract(serviceContract), |
| getGeneratedWSDLContract(bindingContract), |
| Compatibility.SUBSET, |
| !bindingHasCallback, // ignore callbacks if binding doesn't have one |
| false); |
| } else { |
| interfaceContractMapper.checkCompatibility(serviceContract, |
| bindingContract, |
| Compatibility.SUBSET, |
| !bindingHasCallback, // ignore callbacks if binding doesn't have one |
| false); |
| } |
| } catch (Exception ex){ |
| throw new ServiceRuntimeException("Component " + |
| this.getComponent().getName() + |
| " Service " + |
| getService().getName() + |
| " interface is incompatible with the interface of the service binding - " + |
| getBinding().getName() + |
| " - " + |
| ex.getMessage() + |
| " - [" + this.toString() + "]"); |
| } |
| } |
| |
| } |
| |
| private void initServiceBindingInvocationChains() { |
| |
| // add the binding interceptors to the service binding wire |
| ServiceBindingProvider provider = getBindingProvider(); |
| if ((provider != null) && (provider instanceof EndpointProvider)) { |
| ((EndpointProvider)provider).configure(); |
| } |
| |
| // add the policy interceptors to the service binding wire |
| List<PolicyProvider> pps = getPolicyProviders(); |
| if (pps != null) { |
| for (PolicyProvider p : pps) { |
| Interceptor interceptor = p.createBindingInterceptor(); |
| if (interceptor != null) { |
| bindingInvocationChain.addInterceptor(interceptor); |
| } // end if |
| } // end for |
| } // end if |
| |
| // This is strategically placed before the RuntimeInvoker is added to the end of the |
| // binding chain as the RuntimeInvoker doesn't need to take part in the response |
| // processing and doesn't implement InvokerAsyncResponse |
| ServiceBindingProvider serviceBindingProvider = getBindingProvider(); |
| if (isAsyncInvocation() && |
| serviceBindingProvider instanceof EndpointAsyncProvider && |
| ((EndpointAsyncProvider)serviceBindingProvider).supportsNativeAsync()){ |
| // fix up the invocation chains to point back to the |
| // binding chain so that async response messages |
| // are processed correctly |
| for (InvocationChain chain : getInvocationChains()){ |
| Invoker invoker = chain.getHeadInvoker(); |
| ((InterceptorAsync)invoker).setPrevious((InvokerAsyncResponse)bindingInvocationChain.getTailInvoker()); |
| } // end for |
| |
| // fix up the binding chain response path to point back to the |
| // binding provided async response handler |
| EndpointAsyncProvider asyncEndpointProvider = (EndpointAsyncProvider)serviceBindingProvider; |
| InvokerAsyncResponse asyncResponseInvoker = asyncEndpointProvider.createAsyncResponseInvoker(); |
| ((InterceptorAsync)bindingInvocationChain.getHeadInvoker()).setPrevious(asyncResponseInvoker); |
| } // end if |
| |
| // Add the runtime invoker to the end of the binding chain. |
| // It mediates between the binding chain and selects the |
| // correct invocation chain based on the operation that's |
| // been selected |
| bindingInvocationChain.addInvoker(invoker); |
| |
| } // end method initServiceBindingInvocationChains |
| |
| /** |
| * Add the interceptor for a binding |
| * |
| * @param reference |
| * @param binding |
| * @param chain |
| * @param operation |
| */ |
| private void addServiceBindingInterceptor(InvocationChain chain, Operation operation) { |
| List<PolicyProvider> pps = getPolicyProviders(); |
| if (pps != null) { |
| for (PolicyProvider p : pps) { |
| Interceptor interceptor = p.createInterceptor(operation); |
| if (interceptor != null) { |
| chain.addInterceptor(interceptor); |
| } |
| } |
| } |
| } |
| |
| /** |
| * Add a non-blocking interceptor if the service binding needs it |
| * |
| * @param service |
| * @param binding |
| * @param chain |
| */ |
| private void addNonBlockingInterceptor(InvocationChain chain) { |
| ServiceBindingProvider provider = getBindingProvider(); |
| if (provider != null) { |
| if (!provider.supportsOneWayInvocation()) { |
| chain.addInterceptor(Phase.SERVICE, 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) { |
| |
| if (service.getService() instanceof CompositeService) { |
| CompositeService compositeService = (CompositeService)service.getService(); |
| component = getPromotedComponent(compositeService); |
| service = getPromotedComponentService(compositeService); |
| } |
| |
| ImplementationProvider provider = ((RuntimeComponent)component).getImplementationProvider(); |
| |
| if (provider != null) { |
| Invoker invoker = null; |
| RuntimeComponentService runtimeService = (RuntimeComponentService)service; |
| if (runtimeService.getName().endsWith("_asyncCallback")){ |
| if (provider instanceof ImplementationAsyncProvider){ |
| invoker = (Invoker)((ImplementationAsyncProvider)provider).createAsyncResponseInvoker(operation); |
| } else { |
| // TODO - This should be an error but taking account of the |
| // existing non-native async support |
| invoker = provider.createInvoker((RuntimeComponentService)service, operation); |
| /* |
| throw new ServiceRuntimeException("Component " + |
| this.getComponent().getName() + |
| " Service " + |
| getService().getName() + |
| " implementation provider doesn't implement ImplementationAsyncProvider but the implementation uses a " + |
| "refrence interface with the asyncInvocation intent set" + |
| " - [" + this.toString() + "]"); |
| */ |
| } |
| } else if (isAsyncInvocation() && |
| provider instanceof ImplementationAsyncProvider){ |
| invoker = (Invoker)((ImplementationAsyncProvider)provider).createAsyncInvoker((RuntimeComponentService)service, operation); |
| } else { |
| invoker = provider.createInvoker((RuntimeComponentService)service, operation); |
| } |
| chain.addInvoker(invoker); |
| } |
| |
| List<PolicyProvider> pps = ((RuntimeComponent)component).getPolicyProviders(); |
| if (pps != null) { |
| for (PolicyProvider p : pps) { |
| Interceptor interceptor = p.createInterceptor(operation); |
| if (interceptor != null) { |
| chain.addInterceptor(interceptor); |
| } |
| } |
| } |
| } |
| |
| /** |
| * @see java.lang.Object#clone() |
| */ |
| @Override |
| public Object clone() throws CloneNotSupportedException { |
| RuntimeEndpointImpl copy = (RuntimeEndpointImpl)super.clone(); |
| copy.invoker = new RuntimeInvoker(registry, copy); |
| return copy; |
| } |
| |
| /** |
| * Follow a service promotion chain down to the inner most (non composite) |
| * component service. |
| * |
| * @param topCompositeService |
| * @return |
| */ |
| private ComponentService getPromotedComponentService(CompositeService compositeService) { |
| ComponentService componentService = compositeService.getPromotedService(); |
| if (componentService != null) { |
| Service service = componentService.getService(); |
| if (componentService.getName() != null && service instanceof CompositeService) { |
| |
| // Continue to follow the service promotion chain |
| return getPromotedComponentService((CompositeService)service); |
| |
| } else { |
| |
| // Found a non-composite service |
| return componentService; |
| } |
| } else { |
| |
| // No promoted service |
| return null; |
| } |
| } |
| |
| /** |
| * Follow a service promotion chain down to the innermost (non-composite) component. |
| * |
| * @param compositeService |
| * @return |
| */ |
| private Component getPromotedComponent(CompositeService compositeService) { |
| ComponentService componentService = compositeService.getPromotedService(); |
| if (componentService != null) { |
| Service service = componentService.getService(); |
| if (componentService.getName() != null && service instanceof CompositeService) { |
| |
| // Continue to follow the service promotion chain |
| return getPromotedComponent((CompositeService)service); |
| |
| } else { |
| |
| // Found a non-composite service |
| return compositeService.getPromotedComponent(); |
| } |
| } else { |
| |
| // No promoted service |
| return null; |
| } |
| } |
| |
| public synchronized ServiceBindingProvider getBindingProvider() { |
| resolve(); |
| if (bindingProvider == null) { |
| BindingProviderFactory factory = |
| (BindingProviderFactory)providerFactories.getProviderFactory(getBinding().getClass()); |
| if (factory == null) { |
| throw new ServiceRuntimeException("No provider factory is registered for binding " + getBinding() |
| .getType()); |
| } |
| this.bindingProvider = factory.createServiceBindingProvider(this); |
| } |
| return bindingProvider; |
| } |
| |
| public synchronized List<PolicyProvider> getPolicyProviders() { |
| resolve(); |
| if (policyProviders == null) { |
| policyProviders = new ArrayList<PolicyProvider>(); |
| for (PolicyProviderFactory factory : providerFactories.getPolicyProviderFactories()) { |
| PolicyProvider provider = factory.createServicePolicyProvider(this); |
| if (provider != null) { |
| policyProviders.add(provider); |
| } |
| } |
| } |
| return policyProviders; |
| } |
| |
| public void setBindingProvider(ServiceBindingProvider provider) { |
| this.bindingProvider = provider; |
| } |
| |
| public Contract getContract() { |
| return getService(); |
| } |
| |
| public CompositeContext getCompositeContext() { |
| return compositeContext; |
| } |
| |
| @Override |
| protected void reset() { |
| super.reset(); |
| this.xml = null; |
| } |
| |
| @Override |
| protected synchronized void resolve() { |
| if (xml != null && component == null) { |
| if (compositeContext == null) { |
| compositeContext = CompositeContext.getCurrentCompositeContext(); |
| if (compositeContext != null) { |
| bind(compositeContext); |
| } |
| } // end if |
| if (serializer != null) { |
| RuntimeEndpointImpl ep = (RuntimeEndpointImpl)serializer.readEndpoint(xml); |
| copyFrom(ep); |
| } else { |
| // In this case, we assume that we're running on a detached (non Tuscany) thread and |
| // as a result we need to connect back to the Tuscany environment... |
| ExtensionPointRegistry registry = ExtensionPointRegistryLocator.getExtensionPointRegistry(); |
| if( registry != null ) { |
| this.registry = registry; |
| UtilityExtensionPoint utilities = registry.getExtensionPoint(UtilityExtensionPoint.class); |
| this.interfaceContractMapper = utilities.getUtility(InterfaceContractMapper.class); |
| this.serializer = utilities.getUtility(EndpointSerializer.class); |
| RuntimeEndpointImpl ep = (RuntimeEndpointImpl)serializer.readEndpoint(xml); |
| // Find the actual Endpoint in the DomainRegistry |
| ep = findActualEP( ep, registry ); |
| if( ep != null ){ |
| copyFrom( ep ); |
| } // end if |
| } // end if |
| } // end if |
| setNormalizedWSDLContract(); |
| } // end if |
| super.resolve(); |
| } // end method resolve |
| |
| /** |
| * Find the actual Endpoint in the DomainRegistry which corresponds to the configuration described |
| * in a deserialized Endpoint |
| * @param ep The deserialized endpoint |
| * @param registry - the main extension point Registry |
| * @return the corresponding Endpoint from the DomainRegistry, or null if no match can be found |
| */ |
| private RuntimeEndpointImpl findActualEP(RuntimeEndpointImpl ep, |
| ExtensionPointRegistry registry) { |
| DomainRegistry domainRegistry = getEndpointRegistry( registry ); |
| |
| if( domainRegistry == null ) return null; |
| |
| for( Endpoint endpoint : domainRegistry.findEndpoint(ep.getURI()) ) { |
| // TODO: For the present, simply return the first matching endpoint |
| return (RuntimeEndpointImpl) endpoint; |
| } // end for |
| |
| return null; |
| } // end method findActualEP |
| |
| /** |
| * Get the DomainRegistry |
| * @param registry - the ExtensionPoint registry |
| * @return the DomainRegistry - will be null if the DomainRegistry cannot be found |
| */ |
| private DomainRegistry getEndpointRegistry( ExtensionPointRegistry registry) { |
| DomainRegistryFactory domainRegistryFactory = ExtensibleDomainRegistryFactory.getInstance(registry); |
| |
| if( domainRegistryFactory == null ) return null; |
| |
| // TODO: For the moment, just use the first (and only!) DomainRegistry... |
| DomainRegistry domainRegistry = (DomainRegistry) domainRegistryFactory.getEndpointRegistries().toArray()[0]; |
| |
| return domainRegistry; |
| } // end method |
| |
| public InterfaceContract getBindingInterfaceContract() { |
| resolve(); |
| if (bindingInterfaceContract != null) { |
| return bindingInterfaceContract; |
| } |
| bindingInterfaceContract = getBindingProvider().getBindingInterfaceContract(); |
| if (bindingInterfaceContract == null) { |
| bindingInterfaceContract = getComponentServiceInterfaceContract(); |
| } |
| if (bindingInterfaceContract == null) { |
| bindingInterfaceContract = getComponentTypeServiceInterfaceContract(); |
| } |
| return bindingInterfaceContract; |
| } |
| |
| public InterfaceContract getComponentTypeServiceInterfaceContract() { |
| resolve(); |
| if (serviceInterfaceContract != null) { |
| return serviceInterfaceContract; |
| } |
| if (service == null) { |
| return getComponentServiceInterfaceContract(); |
| } |
| serviceInterfaceContract = getLeafContract(service).getInterfaceContract(); |
| if (serviceInterfaceContract == null) { |
| serviceInterfaceContract = getComponentServiceInterfaceContract(); |
| } |
| return serviceInterfaceContract; |
| } |
| |
| public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException { |
| this.uri = in.readUTF(); |
| this.xml = in.readUTF(); |
| this.wsdl = in.readUTF(); |
| } |
| |
| public void writeExternal(ObjectOutput out) throws IOException { |
| out.writeUTF(getURI()); |
| if (serializer == null && xml != null) { |
| out.writeUTF(xml); |
| } else { |
| if (serializer != null) { |
| out.writeUTF(serializer.write(this)); |
| } else { |
| throw new IllegalStateException("No serializer is configured"); |
| } |
| } |
| |
| if (wsdl == null) { |
| wsdl = getWsdl(); |
| } |
| out.writeUTF(wsdl); |
| } |
| |
| public String getAsXML() { |
| if (xml == null) { |
| this.xml = serializer.write(this); |
| } |
| return xml; |
| } |
| |
| private String getWsdl() { |
| InterfaceContract ic = getComponentServiceInterfaceContract(); |
| if (ic == null || ic.getInterface() == null || !!!ic.getInterface().isRemotable()) { |
| return ""; |
| } |
| WSDLInterfaceContract wsdlIC = (WSDLInterfaceContract)getGeneratedWSDLContract(getComponentServiceInterfaceContract()); |
| if (wsdlIC == null) { |
| return ""; |
| } |
| WSDLInterface wsdl = (WSDLInterface)wsdlIC.getInterface(); |
| WSDLDefinition d = wsdl.getWsdlDefinition(); |
| ByteArrayOutputStream outStream = new ByteArrayOutputStream(); |
| try { |
| WSDLWriter writer = javax.wsdl.factory.WSDLFactory.newInstance().newWSDLWriter(); |
| writer.writeWSDL(d.getDefinition(), outStream); |
| } catch (Exception e){ |
| throw new RuntimeException(e); |
| } |
| return outStream.toString(); |
| } |
| |
| private void setNormalizedWSDLContract() { |
| if (wsdl == null || wsdl.length() < 1) { |
| return; |
| } |
| InterfaceContract ic = getComponentServiceInterfaceContract(); |
| if (ic != null) { |
| // ic.setNormalizedWSDLContract(WSDLHelper.createWSDLInterfaceContract(registry, wsdl)); |
| } |
| } |
| |
| public InterfaceContract getGeneratedWSDLContract(InterfaceContract interfaceContract) { |
| |
| if ( interfaceContract.getNormalizedWSDLContract() == null){ |
| if (getComponentServiceInterfaceContract() instanceof JavaInterfaceContract){ |
| if (contractBuilder == null){ |
| throw new ServiceRuntimeException("Contract builder not found while calculating WSDL contract for " + this.toString()); |
| } |
| contractBuilder.build(interfaceContract, null); |
| } |
| } |
| |
| return interfaceContract.getNormalizedWSDLContract(); |
| } |
| |
| @Override |
| public RuntimeEndpoint getDelegateEndpoint() { |
| return delegateEndpoint; |
| } |
| |
| @Override |
| public void setDelegateEndpoint(RuntimeEndpoint delegateEndpoint) { |
| this.delegateEndpoint = delegateEndpoint; |
| } |
| } |