| /* |
| * 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.context; |
| |
| import java.io.Externalizable; |
| import java.io.IOException; |
| import java.io.ObjectInput; |
| import java.io.ObjectOutput; |
| import java.security.AccessController; |
| import java.security.PrivilegedAction; |
| import java.util.ArrayList; |
| import java.util.List; |
| import java.util.UUID; |
| |
| import javax.xml.stream.XMLStreamReader; |
| |
| import org.apache.tuscany.sca.assembly.Binding; |
| import org.apache.tuscany.sca.assembly.Component; |
| import org.apache.tuscany.sca.assembly.ComponentService; |
| import org.apache.tuscany.sca.assembly.CompositeService; |
| import org.apache.tuscany.sca.assembly.ConfiguredOperation; |
| import org.apache.tuscany.sca.assembly.OperationsConfigurator; |
| import org.apache.tuscany.sca.assembly.OptimizableBinding; |
| import org.apache.tuscany.sca.assembly.Reference; |
| import org.apache.tuscany.sca.assembly.SCABinding; |
| import org.apache.tuscany.sca.assembly.Service; |
| import org.apache.tuscany.sca.assembly.builder.BindingBuilderExtension; |
| import org.apache.tuscany.sca.contribution.resolver.ModelResolver; |
| import org.apache.tuscany.sca.contribution.resolver.ResolverExtension; |
| import org.apache.tuscany.sca.core.assembly.BusinessInterfaceImpl; |
| import org.apache.tuscany.sca.core.assembly.CompositeActivator; |
| import org.apache.tuscany.sca.core.assembly.CompositeActivatorImpl; |
| import org.apache.tuscany.sca.core.assembly.EndpointReferenceImpl; |
| import org.apache.tuscany.sca.core.assembly.EndpointWireImpl; |
| import org.apache.tuscany.sca.core.assembly.ReferenceParametersImpl; |
| import org.apache.tuscany.sca.core.conversation.ConversationManager; |
| import org.apache.tuscany.sca.core.conversation.ConversationState; |
| import org.apache.tuscany.sca.core.conversation.ExtendedConversation; |
| import org.apache.tuscany.sca.core.factory.ObjectCreationException; |
| import org.apache.tuscany.sca.core.invocation.ProxyFactory; |
| import org.apache.tuscany.sca.interfacedef.Interface; |
| import org.apache.tuscany.sca.interfacedef.InterfaceContract; |
| import org.apache.tuscany.sca.interfacedef.java.JavaInterface; |
| import org.apache.tuscany.sca.policy.PolicySet; |
| import org.apache.tuscany.sca.policy.PolicySetAttachPoint; |
| import org.apache.tuscany.sca.runtime.BusinessInterface; |
| import org.apache.tuscany.sca.runtime.EndpointReference; |
| import org.apache.tuscany.sca.runtime.ReferenceParameters; |
| import org.apache.tuscany.sca.runtime.RuntimeComponent; |
| import org.apache.tuscany.sca.runtime.RuntimeComponentReference; |
| import org.apache.tuscany.sca.runtime.RuntimeWire; |
| import org.osoa.sca.CallableReference; |
| import org.osoa.sca.Conversation; |
| import org.osoa.sca.ServiceRuntimeException; |
| |
| /** |
| * Base class for implementations of service and callback references. |
| * |
| * @version $Rev$ $Date$ |
| * @param <B> the type of the business interface |
| */ |
| public class CallableReferenceImpl<B> implements CallableReference<B>, Externalizable { |
| static final long serialVersionUID = -521548304761848325L; |
| protected transient CompositeActivator compositeActivator; |
| protected transient ProxyFactory proxyFactory; |
| protected transient Class<B> businessInterface; |
| protected transient Object proxy; |
| |
| // if the wire targets a conversational service this holds the conversation state |
| protected transient ConversationManager conversationManager; |
| protected transient ExtendedConversation conversation; |
| protected transient Object conversationID; |
| protected Object callbackID; // The callbackID should be serializable |
| |
| protected transient RuntimeComponent component; |
| protected transient RuntimeComponentReference reference; |
| protected transient Binding binding; |
| |
| protected String scdl; |
| |
| private transient RuntimeComponentReference clonedRef; |
| private transient ReferenceParameters refParams; |
| private transient XMLStreamReader xmlReader; |
| |
| private transient RuntimeWire endpointWire; |
| |
| /* |
| * Public constructor for Externalizable serialization/deserialization |
| */ |
| public CallableReferenceImpl() { |
| super(); |
| } |
| |
| /* |
| * Public constructor for use by XMLStreamReader2CallableReference |
| */ |
| public CallableReferenceImpl(XMLStreamReader xmlReader) throws Exception { |
| this.xmlReader = xmlReader; |
| resolve(); |
| } |
| |
| protected CallableReferenceImpl(Class<B> businessInterface, |
| RuntimeComponent component, |
| RuntimeComponentReference reference, |
| Binding binding, |
| ProxyFactory proxyFactory, |
| CompositeActivator compositeActivator) { |
| this.proxyFactory = proxyFactory; |
| this.businessInterface = businessInterface; |
| this.component = component; |
| this.reference = reference; |
| this.binding = binding; |
| // FIXME: The SCA Specification is not clear how we should handle multiplicity |
| // for CallableReference |
| if (this.binding == null) { |
| this.binding = this.reference.getBinding(SCABinding.class); |
| if (this.binding == null) { |
| |
| // TODO: TUSCANY-2580: if the refernece doesn't have a binding yet then instead of NPE use a candidate one if its avaialable |
| if (reference.getBindings() != null && reference.getBindings().size() > 0) { |
| this.binding = this.reference.getBindings().get(0); |
| } else { |
| this.binding = this.reference.getEndpoints().get(0).getCandidateBindings().get(0); |
| if (this.reference.getEndpoints().get(0).getInterfaceContract() == null) { |
| this.reference.getEndpoints().get(0).setInterfaceContract(reference.getInterfaceContract()); |
| } |
| } |
| } |
| } |
| |
| // FIXME: Should we normalize the componentName/serviceName URI into an absolute SCA URI in the SCA binding? |
| // sca:component1/component11/component112/service1? |
| this.compositeActivator = compositeActivator; |
| this.conversationManager = this.compositeActivator.getConversationManager(); |
| initCallbackID(); |
| } |
| |
| public CallableReferenceImpl(Class<B> businessInterface, RuntimeWire wire, ProxyFactory proxyFactory) { |
| this.proxyFactory = proxyFactory; |
| this.businessInterface = businessInterface; |
| bind(wire); |
| } |
| |
| public RuntimeWire getRuntimeWire() { |
| try { |
| resolve(); |
| if (endpointWire != null){ |
| return endpointWire; |
| } else if (reference != null) { |
| return reference.getRuntimeWire(binding); |
| } else { |
| return null; |
| } |
| } catch (Exception e) { |
| throw new ServiceRuntimeException(e); |
| } |
| } |
| |
| protected void bind(RuntimeWire wire) { |
| if (wire != null) { |
| |
| if (wire instanceof EndpointWireImpl){ |
| endpointWire = wire; |
| } |
| this.component = wire.getSource().getComponent(); |
| this.reference = (RuntimeComponentReference)wire.getSource().getContract(); |
| this.binding = wire.getSource().getBinding(); |
| this.compositeActivator = ((ComponentContextImpl)component.getComponentContext()).getCompositeActivator(); |
| this.conversationManager = this.compositeActivator.getConversationManager(); |
| initCallbackID(); |
| } |
| } |
| |
| protected void initCallbackID() { |
| if (reference.getInterfaceContract() != null) { |
| if (reference.getInterfaceContract().getCallbackInterface() != null) { |
| this.callbackID = createCallbackID(); |
| } |
| } |
| } |
| |
| public B getProxy() throws ObjectCreationException { |
| try { |
| if (proxy == null) { |
| proxy = createProxy(); |
| } |
| return businessInterface.cast(proxy); |
| } catch (Exception e) { |
| throw new ObjectCreationException(e); |
| } |
| } |
| |
| public void setProxy(Object proxy) { |
| this.proxy = proxy; |
| } |
| |
| protected Object createProxy() throws Exception { |
| return proxyFactory.createProxy(this); |
| } |
| |
| public B getService() { |
| try { |
| resolve(); |
| return getProxy(); |
| } catch (Exception e) { |
| throw new ServiceRuntimeException(e); |
| } |
| } |
| |
| public Class<B> getBusinessInterface() { |
| try { |
| resolve(); |
| return businessInterface; |
| } catch (Exception e) { |
| throw new ServiceRuntimeException(e); |
| } |
| } |
| |
| public boolean isConversational() { |
| try { |
| resolve(); |
| return reference == null ? false : reference.getInterfaceContract().getInterface().isConversational(); |
| } catch (Exception e) { |
| throw new ServiceRuntimeException(e); |
| } |
| } |
| |
| public Conversation getConversation() { |
| try { |
| // resolve from XML just in case this CallableReference is the result of |
| // passing a CallableReference as a parameter |
| resolve(); |
| |
| if (conversation == null || conversation.getState() == ConversationState.ENDED) { |
| conversation = null; |
| } |
| return conversation; |
| |
| } catch (Exception e) { |
| throw new ServiceRuntimeException(e); |
| } |
| } |
| |
| public Object getCallbackID() { |
| try { |
| resolve(); |
| return callbackID; |
| } catch (Exception e) { |
| throw new ServiceRuntimeException(e); |
| } |
| } |
| |
| /** |
| * @see java.io.Externalizable#readExternal(java.io.ObjectInput) |
| */ |
| public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException { |
| final boolean hasSCDL = in.readBoolean(); |
| if (hasSCDL) { |
| this.scdl = in.readUTF(); |
| } else { |
| this.scdl = null; |
| } |
| } |
| |
| /** |
| * @throws IOException |
| */ |
| private synchronized void resolve() throws Exception { |
| if ((scdl != null || xmlReader != null) && component == null && reference == null) { |
| ComponentContextHelper componentContextHelper = ComponentContextHelper.getCurrentComponentContextHelper(); |
| if (componentContextHelper != null) { |
| this.compositeActivator = ComponentContextHelper.getCurrentCompositeActivator(); |
| this.conversationManager = this.compositeActivator.getConversationManager(); |
| Component c; |
| if (xmlReader != null) { |
| c = componentContextHelper.fromXML(xmlReader); |
| xmlReader = null; // OK to GC this now |
| } else { |
| c = componentContextHelper.fromXML(scdl); |
| scdl = null; // OK to GC this now |
| } |
| this.component = (RuntimeComponent)c; |
| compositeActivator.configureComponentContext(this.component); |
| this.reference = (RuntimeComponentReference)c.getReferences().get(0); |
| this.reference.setComponent(this.component); |
| clonedRef = reference; |
| ReferenceParameters parameters = null; |
| BusinessInterface businessInterfaceExt = null; |
| for (Object ext : reference.getExtensions()) { |
| if (ext instanceof ReferenceParameters) { |
| parameters = (ReferenceParameters)ext; |
| } else if (ext instanceof BusinessInterface) { |
| // this extension will always be present |
| businessInterfaceExt = (BusinessInterface)ext; |
| } |
| } |
| if (parameters != null) { |
| refParams = parameters; |
| this.callbackID = parameters.getCallbackID(); |
| attachConversation(parameters.getConversationID()); |
| } |
| |
| for (Binding binding : reference.getBindings()) { |
| if (binding instanceof OptimizableBinding) { |
| // Resolve the Component |
| final String bindingURI = binding.getURI(); |
| final Component targetComponent = resolveComponentURI(bindingURI); |
| |
| // Find the Service |
| ComponentService targetService = resolveServiceURI(bindingURI, targetComponent); |
| |
| // if the target service is a promoted service then find the |
| // service it promotes |
| if ((targetService != null) && (targetService.getService() instanceof CompositeService)) { |
| CompositeService compositeService = (CompositeService) targetService.getService(); |
| // Find the promoted component service |
| ComponentService promotedComponentService = getPromotedComponentService(compositeService); |
| if (promotedComponentService != null && !promotedComponentService.isUnresolved()) { |
| targetService = promotedComponentService; |
| } |
| } |
| |
| OptimizableBinding optimizableBinding = (OptimizableBinding)binding; |
| optimizableBinding.setTargetComponent(targetComponent); |
| optimizableBinding.setTargetComponentService(targetService); |
| if (targetService != null) { |
| for (Binding serviceBinding : targetService.getBindings()) { |
| if (serviceBinding.getClass() == binding.getClass()) { |
| optimizableBinding.setTargetBinding(serviceBinding); |
| break; |
| } |
| } |
| } |
| } |
| } |
| // FIXME: The SCA Specification is not clear how we should handle multiplicity |
| // for CallableReference |
| if (binding == null) { |
| binding = reference.getBinding(SCABinding.class); |
| if (binding == null) { |
| binding = reference.getBindings().get(0); |
| } |
| } |
| |
| ModelResolver resolver = ((ResolverExtension)ComponentContextHelper.getCurrentComponent()).getModelResolver(); |
| componentContextHelper.resolveInterfaceContract(reference.getInterfaceContract(), resolver); |
| |
| Interface i = reference.getInterfaceContract().getInterface(); |
| if (i instanceof JavaInterface) { |
| JavaInterface javaInterface = (JavaInterface)i; |
| if (javaInterface.isUnresolved()) { |
| // Allow privileged access to get ClassLoader. Requires RuntimePermission in |
| // security policy. |
| ClassLoader classLoader = AccessController.doPrivileged(new PrivilegedAction<ClassLoader>() { |
| public ClassLoader run() { |
| return Thread.currentThread().getContextClassLoader(); |
| } |
| }); |
| javaInterface.setJavaClass(classLoader.loadClass(javaInterface.getName())); |
| compositeActivator.getJavaInterfaceFactory().createJavaInterface(javaInterface, |
| javaInterface.getJavaClass()); |
| //FIXME: If the interface needs XSDs to be loaded (e.g., for static SDO), |
| // this needs to be done here. We usually search for XSDs in the current |
| // contribution at resolve time. If we need to add code here to do this, |
| // we can resolve XSDs using the model resolver for the current component. |
| } |
| this.businessInterface = (Class<B>)javaInterface.getJavaClass(); |
| } else { |
| // Allow privileged access to get ClassLoader. Requires RuntimePermission in |
| // security policy. |
| ClassLoader classLoader = AccessController.doPrivileged(new PrivilegedAction<ClassLoader>() { |
| public ClassLoader run() { |
| return Thread.currentThread().getContextClassLoader(); |
| } |
| }); |
| businessInterface = (Class<B>)classLoader.loadClass(businessInterfaceExt.getInterface()); |
| reference.setReference(componentContextHelper.createReference(businessInterface)); |
| } |
| |
| componentContextHelper.resolveBinding(binding, resolver); |
| if (binding instanceof PolicySetAttachPoint) { |
| PolicySetAttachPoint policiedBinding = (PolicySetAttachPoint)binding; |
| List<PolicySet> policySets = policiedBinding.getPolicySets(); |
| resolvePolicySets(policySets, resolver); |
| List<PolicySet> applicablePolicySets = policiedBinding.getApplicablePolicySets(); |
| applicablePolicySets.addAll(policySets); |
| } |
| if (binding instanceof OperationsConfigurator) { |
| OperationsConfigurator opConfigurator = (OperationsConfigurator)binding; |
| for (ConfiguredOperation confOp : opConfigurator.getConfiguredOperations()) { |
| List<PolicySet> policySets = confOp.getPolicySets(); |
| resolvePolicySets(policySets, resolver); |
| List<PolicySet> applicablePolicySets = confOp.getApplicablePolicySets(); |
| applicablePolicySets.addAll(policySets); |
| } |
| } |
| if (binding instanceof BindingBuilderExtension) { |
| ((BindingBuilderExtension)binding).getBuilder().build(component, reference, binding, null); |
| } |
| this.proxyFactory = compositeActivator.getProxyFactory(); |
| } |
| } else if (compositeActivator == null || proxyFactory == null) { |
| this.compositeActivator = ComponentContextHelper.getCurrentCompositeActivator(); |
| if (this.compositeActivator != null) { |
| this.proxyFactory = this.compositeActivator.getProxyFactory(); |
| } |
| } |
| } |
| |
| /** |
| * Resolve policy sets attached to a specific SCA Construct |
| * @param policySets list of attached policy sets |
| * @param resolver |
| */ |
| private void resolvePolicySets(List<PolicySet> policySets, ModelResolver resolver) { |
| List<PolicySet> resolvedPolicySets = new ArrayList<PolicySet>(); |
| PolicySet resolvedPolicySet = null; |
| for (PolicySet policySet : policySets) { |
| if (policySet.isUnresolved()) { |
| resolvedPolicySet = resolver.resolveModel(PolicySet.class, policySet); |
| resolvedPolicySets.add(resolvedPolicySet); |
| } else { |
| resolvedPolicySets.add(policySet); |
| } |
| } |
| policySets.clear(); |
| policySets.addAll(resolvedPolicySets); |
| } |
| |
| /** |
| * 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; |
| } |
| } |
| |
| /** |
| * @see java.io.Externalizable#writeExternal(java.io.ObjectOutput) |
| */ |
| public void writeExternal(ObjectOutput out) throws IOException { |
| try { |
| final String xml = toXMLString(); |
| if (xml == null) { |
| out.writeBoolean(false); |
| } else { |
| out.writeBoolean(true); |
| out.writeUTF(xml); |
| } |
| } catch (Exception e) { |
| // e.printStackTrace(); |
| throw new IOException(e.toString()); |
| } |
| } |
| |
| public String toXMLString() throws IOException { |
| if (reference != null) { |
| if (clonedRef == null) { |
| try { |
| clonedRef = (RuntimeComponentReference)reference.clone(); |
| } catch (CloneNotSupportedException e) { |
| // will not happen |
| } |
| BusinessInterface bizInterface = new BusinessInterfaceImpl(); |
| bizInterface.setInterface(businessInterface.getName()); |
| clonedRef.getExtensions().add(bizInterface); |
| } |
| if (refParams == null) { |
| refParams = new ReferenceParametersImpl(); |
| |
| // remove any existing reference parameters from the clone |
| Object toRemove = null; |
| for (Object extension : clonedRef.getExtensions()){ |
| if (extension instanceof ReferenceParameters){ |
| toRemove = extension; |
| } |
| } |
| if (toRemove != null){ |
| clonedRef.getExtensions().remove(toRemove); |
| } |
| |
| // add the new reference parameter object |
| clonedRef.getExtensions().add(refParams); |
| } |
| refParams.setCallbackID(callbackID); |
| if (conversation != null){ |
| refParams.setConversationID(conversation.getConversationID()); |
| } |
| return ((CompositeActivatorImpl)compositeActivator).getComponentContextHelper() |
| .toXML(component, clonedRef); |
| } else { |
| return scdl; |
| } |
| } |
| |
| /** |
| * Create a callback id |
| * |
| * @return the callback id |
| */ |
| private String createCallbackID() { |
| return UUID.randomUUID().toString(); |
| } |
| |
| public void attachCallbackID(Object callbackID) { |
| this.callbackID = callbackID; |
| } |
| |
| public void attachConversationID(Object conversationID) { |
| this.conversationID = conversationID; |
| } |
| |
| public void attachConversation(ExtendedConversation conversation) { |
| this.conversation = conversation; |
| } |
| |
| public void attachConversation(Object conversationID) { |
| if (conversationID != null) { |
| ExtendedConversation conversation = conversationManager.getConversation(conversationID); |
| if (conversation == null){ |
| conversation = conversationManager.startConversation(conversationID); |
| } |
| this.conversation = conversation; |
| } else { |
| this.conversation = null; |
| } |
| } |
| |
| protected ReferenceParameters getReferenceParameters() { |
| ReferenceParameters parameters = new ReferenceParametersImpl(); |
| parameters.setCallbackID(callbackID); |
| if (getConversation() != null) { |
| parameters.setConversationID(conversation.getConversationID()); |
| } |
| return parameters; |
| } |
| |
| public EndpointReference getEndpointReference() { |
| try { |
| resolve(); |
| |
| // Use the interface contract of the reference on the component type |
| Reference componentTypeRef = reference.getReference(); |
| InterfaceContract sourceContract = |
| componentTypeRef == null ? reference.getInterfaceContract() : componentTypeRef.getInterfaceContract(); |
| sourceContract = sourceContract.makeUnidirectional(false); |
| EndpointReference epr = new EndpointReferenceImpl(component, reference, binding, sourceContract); |
| ReferenceParameters parameters = getReferenceParameters(); |
| epr.setReferenceParameters(parameters); |
| return epr; |
| } catch (Exception e) { |
| throw new ServiceRuntimeException(e); |
| } |
| } |
| |
| public XMLStreamReader getXMLReader() { |
| return xmlReader; |
| } |
| |
| /** |
| * Resolves the specified URI to a Component using the compositeActivator. |
| * There are two cases that we need to handle: |
| * <ul> |
| * <li>URI containing just Composite name(s) (i.e. no Service name specified) |
| * <li>URI containing Composite name(s) and a Service Name |
| * </ul> |
| * |
| * @param componentURI The URI of the Component to resolve |
| * @return The Component for the specified URI or null if not founds |
| */ |
| protected Component resolveComponentURI(String componentURI) { |
| // If the URI has come from a binding, it may well start with a '/'. We will need |
| // to remove this so we can match it to the composite names. |
| if (componentURI.startsWith("/")) { |
| componentURI = componentURI.substring(1); |
| } |
| |
| // First assume that we are dealing with a Component URI without a Service Name |
| Component component = compositeActivator.resolve(componentURI); |
| if (component != null) { |
| return component; |
| } |
| |
| // Perhaps we have a ComponentURI that has a ServiceName on the end of it |
| final int index = componentURI.lastIndexOf('/'); |
| if (index > -1) { |
| componentURI = componentURI.substring(0, index); |
| return compositeActivator.resolve(componentURI); |
| } |
| |
| // We could not resolve the Component URI |
| return null; |
| } |
| |
| /** |
| * Examines the Services on the specified Component and returns the Service that matches the |
| * specified Binding URI. |
| * |
| * @param bindingURI The Binding URI to resolve on the Component |
| * @param targetComponent The Component containing the Services |
| * @return The Service with the specified serviceName or null if no such Service found. |
| */ |
| protected ComponentService resolveServiceURI(String bindingURI, Component targetComponent) { |
| |
| ComponentService targetService = null; |
| |
| if (targetComponent != null) { |
| if (bindingURI.startsWith("/")) { |
| bindingURI = bindingURI.substring(1); |
| } |
| |
| final String componentURI = targetComponent.getURI(); |
| final String serviceName; |
| if (componentURI.equals(bindingURI)) { |
| // No service specified |
| serviceName = ""; |
| } else { |
| // Get the Service name from the Binding URI |
| serviceName = bindingURI.substring(componentURI.length() + 1); |
| } |
| |
| if ("".equals(serviceName)) { |
| targetService = ComponentContextHelper.getSingleService(targetComponent); |
| } else { |
| for (ComponentService service : targetComponent.getServices()) { |
| if (service.getName().equals(serviceName)) { |
| targetService = service; |
| break; |
| } |
| } |
| } |
| } |
| |
| return targetService; |
| } |
| } |