From a33d2090e59ac59800a0147ba514dc182aa67ff5 Mon Sep 17 00:00:00 2001 From: edwardsmj Date: Wed, 27 May 2009 10:27:08 +0000 Subject: First steps towards implementing new method for calculating Endpoints and EndpointReferences - not running in mainstream yet git-svn-id: http://svn.us.apache.org/repos/asf/tuscany@779089 13f79535-47bb-0310-9956-ffa450edef68 --- .../tuscany/sca/assembly/ComponentReference.java | 7 + .../impl/ComponentConfigurationBuilderImpl.java | 37 +- ...onentReferenceEndpointReferenceBuilderImpl.java | 620 ++++++++++++++++++--- .../impl/ComponentReferenceWireBuilderImpl.java | 3 +- .../impl/ComponentServiceEndpointBuilderImpl.java | 208 +++++-- .../impl/CompositePromotionBuilderImpl.java | 16 +- .../builder/impl/ReferenceConfigurationUtil.java | 72 ++- .../sca/assembly/impl/ComponentReferenceImpl.java | 21 +- .../assembly-validation-messages.properties | 2 + 9 files changed, 815 insertions(+), 171 deletions(-) (limited to 'java/sca') diff --git a/java/sca/modules/assembly/src/main/java/org/apache/tuscany/sca/assembly/ComponentReference.java b/java/sca/modules/assembly/src/main/java/org/apache/tuscany/sca/assembly/ComponentReference.java index fa31657d0f..592eb4b90b 100644 --- a/java/sca/modules/assembly/src/main/java/org/apache/tuscany/sca/assembly/ComponentReference.java +++ b/java/sca/modules/assembly/src/main/java/org/apache/tuscany/sca/assembly/ComponentReference.java @@ -105,5 +105,12 @@ public interface ComponentReference extends Reference { * @param nonOverridable */ void setNonOverridable(boolean nonOverridable); + + /** + * Sets whether this Component Reference is promoted + * @param isPromoted - true if the component reference is promoted + */ + void setPromoted( boolean isPromoted ); + boolean isPromoted(); } diff --git a/java/sca/modules/assembly/src/main/java/org/apache/tuscany/sca/assembly/builder/impl/ComponentConfigurationBuilderImpl.java b/java/sca/modules/assembly/src/main/java/org/apache/tuscany/sca/assembly/builder/impl/ComponentConfigurationBuilderImpl.java index 7677fdfb1b..fc769f5037 100644 --- a/java/sca/modules/assembly/src/main/java/org/apache/tuscany/sca/assembly/builder/impl/ComponentConfigurationBuilderImpl.java +++ b/java/sca/modules/assembly/src/main/java/org/apache/tuscany/sca/assembly/builder/impl/ComponentConfigurationBuilderImpl.java @@ -317,31 +317,34 @@ public class ComponentConfigurationBuilderImpl extends BaseBuilderImpl implement } /** - * For all the services with callbacks, create a corresponding callback - * reference. + * For all the services with callbacks, create a corresponding callback reference. * * @param component + * @param componentReferences */ private void configureCallbackReferences(Component component, Map componentReferences) { for (ComponentService service : component.getServices()) { - if (service.getInterfaceContract() != null && // can be null in - // unit tests - service.getInterfaceContract().getCallbackInterface() != null) { - ComponentReference reference = - componentReferences.get(service.getName()); + if (service.getInterfaceContract() != null && // can be null in unit tests + service.getInterfaceContract().getCallbackInterface() != null) { + ComponentReference reference = componentReferences.get(service.getName()); if (reference == null) { reference = createCallbackReference(component, service); - } - if (service.getCallback() != null) { - if (reference.getBindings().isEmpty()) { + } // end if + // Set the bindings of the callback reference + if ( reference.getBindings().isEmpty() ) { + // If there are specific callback bindings set, use them + if (service.getCallback() != null) { reference.getBindings().addAll(service.getCallback().getBindings()); - } - } + } else { + // otherwise use the bindings on the forward service + reference.getBindings().addAll(service.getBindings()); + } // end if + } // end if service.setCallbackReference(reference); - } - } - } + } // end if + } // end for + } // end method configureCallbackReferences /** * Create a callback reference for a component service @@ -373,7 +376,9 @@ public class ComponentConfigurationBuilderImpl extends BaseBuilderImpl implement implCompReference.getPromotedComponents().add(((CompositeService) implService).getPromotedComponent()); // Set the promoted service ComponentReference promotedReference = assemblyFactory.createComponentReference(); - promotedReference.setName(((CompositeService)implService).getPromotedService().getName()); + String promotedRefName = ((CompositeService) implService).getPromotedComponent().getName() + "/" + + ((CompositeService)implService).getPromotedService().getName(); + promotedReference.setName(promotedRefName); promotedReference.setUnresolved(true); implCompReference.getPromotedReferences().add(promotedReference); implReference = implCompReference; diff --git a/java/sca/modules/assembly/src/main/java/org/apache/tuscany/sca/assembly/builder/impl/ComponentReferenceEndpointReferenceBuilderImpl.java b/java/sca/modules/assembly/src/main/java/org/apache/tuscany/sca/assembly/builder/impl/ComponentReferenceEndpointReferenceBuilderImpl.java index e420fdcbe9..52b0f79775 100644 --- a/java/sca/modules/assembly/src/main/java/org/apache/tuscany/sca/assembly/builder/impl/ComponentReferenceEndpointReferenceBuilderImpl.java +++ b/java/sca/modules/assembly/src/main/java/org/apache/tuscany/sca/assembly/builder/impl/ComponentReferenceEndpointReferenceBuilderImpl.java @@ -6,19 +6,20 @@ * 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. + * under the License. */ package org.apache.tuscany.sca.assembly.builder.impl; +import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -29,16 +30,21 @@ 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.CompositeReference; import org.apache.tuscany.sca.assembly.Endpoint2; import org.apache.tuscany.sca.assembly.EndpointReference2; import org.apache.tuscany.sca.assembly.Implementation; import org.apache.tuscany.sca.assembly.Multiplicity; +import org.apache.tuscany.sca.assembly.Reference; import org.apache.tuscany.sca.assembly.SCABinding; import org.apache.tuscany.sca.assembly.builder.CompositeBuilder; import org.apache.tuscany.sca.assembly.builder.CompositeBuilderException; import org.apache.tuscany.sca.definitions.Definitions; +import org.apache.tuscany.sca.interfacedef.InterfaceContract; import org.apache.tuscany.sca.interfacedef.InterfaceContractMapper; import org.apache.tuscany.sca.monitor.Monitor; +import org.apache.tuscany.sca.policy.Intent; +import org.apache.tuscany.sca.policy.PolicySet; /** * A composite builder that creates endpoint reference models. @@ -47,7 +53,11 @@ import org.apache.tuscany.sca.monitor.Monitor; */ public class ComponentReferenceEndpointReferenceBuilderImpl extends BaseBuilderImpl implements CompositeBuilder { - + Monitor monitor; + // Testing + //boolean useNew = true; + boolean useNew = false; + public ComponentReferenceEndpointReferenceBuilderImpl(AssemblyFactory assemblyFactory, InterfaceContractMapper interfaceContractMapper) { super(assemblyFactory, null, null, null, interfaceContractMapper); } @@ -58,47 +68,48 @@ public class ComponentReferenceEndpointReferenceBuilderImpl extends BaseBuilderI /** * Create endpoint references for all component references. - * + * * @param composite */ - public void build(Composite composite, Definitions definitions, Monitor monitor) throws CompositeBuilderException + public void build(Composite composite, Definitions definitions, Monitor monitor) throws CompositeBuilderException { - // process top level composite references - // TODO - I don't think OASIS allows for these - // - //processCompositeReferences(composite); - - // process component services - processComponentReferences(composite, monitor); + this.monitor = monitor; + + + // process component services + processComponentReferences(composite); } - - private void processCompositeReferences(Composite composite) { - // TODO do we need this for OASIS? - } - - private void processComponentReferences(Composite composite, Monitor monitor) { - + + private void processComponentReferences(Composite composite) { + // index all of the components in the composite Map components = new HashMap(); indexComponents(composite, components); - + // index all of the services in the composite Map componentServices = new HashMap(); indexServices(composite, componentServices); - + // create endpoint references for each component's references for (Component component : composite.getComponents()) { + + for (ComponentReference reference : component.getReferences()) { + createReferenceEndpointReferences2( composite, component, reference, components, componentServices); + } // end for + // recurse for composite implementations Implementation implementation = component.getImplementation(); if (implementation instanceof Composite) { - processComponentReferences((Composite)implementation, monitor); + processComponentReferences((Composite)implementation); } - + // create endpoint references to represent the component reference for (ComponentReference reference : component.getReferences()) { - - createReferenceEndpointReferences(composite, component, reference, components, componentServices, monitor); - + + if( !useNew ) { + createReferenceEndpointReferences(composite, component, reference, components, componentServices); + } // end if + // fix up links between endpoints and endpoint references that represent callbacks for (ComponentService service : component.getServices()){ if ((service.getInterfaceContract() != null) && @@ -114,29 +125,28 @@ public class ComponentReferenceEndpointReferenceBuilderImpl extends BaseBuilderI } // end for } // end for } // end method processCompoenntReferences - - private void createReferenceEndpointReferences(Composite composite, - Component component, - ComponentReference reference, + + private void createReferenceEndpointReferences(Composite composite, + Component component, + ComponentReference reference, Map components, - Map componentServices, - Monitor monitor) + Map componentServices) { - // Get reference targets + // Get reference targets List refTargets = getReferenceTargets( reference ); - if (reference.getAutowire() == Boolean.TRUE && + if (reference.getAutowire() == Boolean.TRUE && reference.getTargets().isEmpty()) { // Find suitable targets in the current composite for an // autowired reference Multiplicity multiplicity = reference.getMultiplicity(); for (Component targetComponent : composite.getComponents()) { - + // Prevent autowire connecting to self if( targetComponent == component ) continue; - + for (ComponentService targetComponentService : targetComponent.getServices()) { - if (reference.getInterfaceContract() == null || + if (reference.getInterfaceContract() == null || interfaceContractMapper.isCompatible(reference.getInterfaceContract(), targetComponentService.getInterfaceContract())) { // create endpoint reference - with a dummy endpoint which will be replaced when policies @@ -146,7 +156,7 @@ public class ComponentReferenceEndpointReferenceBuilderImpl extends BaseBuilderI reference.getEndpointReferences().add(endpointRef); // Stop with the first match for 0..1 and 1..1 references - if (multiplicity == Multiplicity.ZERO_ONE || + if (multiplicity == Multiplicity.ZERO_ONE || multiplicity == Multiplicity.ONE_ONE) { break; } // end if @@ -154,34 +164,34 @@ public class ComponentReferenceEndpointReferenceBuilderImpl extends BaseBuilderI } // end for } // end for - if (multiplicity == Multiplicity.ONE_N || + if (multiplicity == Multiplicity.ONE_N || multiplicity == Multiplicity.ONE_ONE) { if (reference.getEndpointReferences().size() == 0) { warning(monitor, "NoComponentReferenceTarget", - reference, + reference, reference.getName()); } } } else if (!refTargets.isEmpty()) { - // Check that the component reference does not mix the use of endpoint references - // specified via the target attribute with the presence of binding elements + // Check that the component reference does not mix the use of endpoint references + // specified via the target attribute with the presence of binding elements if( bindingsIdentifyTargets( reference ) ) { warning(monitor, "ReferenceEndPointMixWithTarget", composite, composite.getName().toString(), component.getName(), reference.getName()); } // Resolve targets specified on the component reference - for (ComponentService target : refTargets) { - + for (ComponentService target : refTargets) { + String targetName = target.getName(); ComponentService targetComponentService = componentServices.get(targetName); - + Component targetComponent = getComponentFromTargetName( components, targetName ); if (targetComponentService != null) { // Check that target component service provides a superset of the component reference interface - if (reference.getInterfaceContract() == null || + if (reference.getInterfaceContract() == null || interfaceContractMapper.isCompatible(reference.getInterfaceContract(), targetComponentService.getInterfaceContract())) { @@ -192,9 +202,9 @@ public class ComponentReferenceEndpointReferenceBuilderImpl extends BaseBuilderI reference.getEndpointReferences().add(endpointRef); } else { warning(monitor, "ReferenceIncompatibleInterface", - composite, + composite, composite.getName().toString(), - component.getName() + "." + reference.getName(), + component.getName() + "." + reference.getName(), targetName); } } else { @@ -203,14 +213,14 @@ public class ComponentReferenceEndpointReferenceBuilderImpl extends BaseBuilderI endpointRef.setTargetEndpoint(createEndpoint(true)); reference.getEndpointReferences().add(endpointRef); warning(monitor, "ComponentReferenceTargetNotFound", - composite, + composite, composite.getName().toString(), targetName); } // end if } // end for } // end if - // if no endpoints have found so far the bindings hold the targets. + // if no endpoints have found so far the bindings hold the targets. if (reference.getEndpointReferences().isEmpty()) { for (Binding binding : reference.getBindings()) { @@ -222,10 +232,10 @@ public class ComponentReferenceEndpointReferenceBuilderImpl extends BaseBuilderI // Regular forward references are UNWIRED with no endpoint if they have an SCABinding with NO targets // and NO URI set - but Callbacks with an SCABinding are wired and need an endpoint if( !reference.isCallback() && (binding instanceof SCABinding) ) continue; - + // create endpoint reference for manually configured bindings with a resolved endpoint to // signify that this reference is pointing at some unwired endpoint - EndpointReference2 endpointRef = createEndpointRef( component, reference, + EndpointReference2 endpointRef = createEndpointRef( component, reference, binding, null, false ); endpointRef.setTargetEndpoint(createEndpoint(false)); reference.getEndpointReferences().add(endpointRef); @@ -243,14 +253,14 @@ public class ComponentReferenceEndpointReferenceBuilderImpl extends BaseBuilderI ComponentService targetComponentService = componentServices.get(uri); Component targetComponent = getComponentFromTargetName( components, uri ); - // If the binding URI matches a component in the composite, configure an endpoint reference with - // this component as the target. + // If the binding URI matches a component in the composite, configure an endpoint reference with + // this component as the target. // If not, the binding URI is assumed to reference an external service if (targetComponentService != null) { // Check that the target component service provides // a superset of the component reference interface - if (reference.getInterfaceContract() == null || + if (reference.getInterfaceContract() == null || interfaceContractMapper.isCompatible(reference.getInterfaceContract(), targetComponentService.getInterfaceContract())) { // create endpoint reference with dummy endpoint which will be replaced when policies @@ -260,24 +270,489 @@ public class ComponentReferenceEndpointReferenceBuilderImpl extends BaseBuilderI reference.getEndpointReferences().add(endpointRef); } else { warning(monitor, "ReferenceIncompatibleInterface", - composite, + composite, composite.getName().toString(), - reference.getName(), + reference.getName(), uri); } } else { - // create endpoint reference for manually configured bindings with resolved endpoint + // create endpoint reference for manually configured bindings with resolved endpoint // to signify that this reference is pointing at some unwired endpoint EndpointReference2 endpointRef = createEndpointRef( component, reference, binding, null, false ); endpointRef.setTargetEndpoint(createEndpoint( false )); reference.getEndpointReferences().add(endpointRef); - } // end if + } // end if } } } // end method + + /** + * Create Endpoint References for a component reference inside a given composite + * @param composite - the composite + * @param component - the component + * @param reference - the component reference + * @param components - a map of the components in the composite + * @param componentServices - a map of the component services in the composite + */ + private void createReferenceEndpointReferences2(Composite composite, + Component component, + ComponentReference reference, + Map components, + Map componentServices) + { + // Find all the leafmost component references related to this component reference + EndpointrefInfo refInfo = gatherEndpointrefInfo( component, reference, null ); + + List endpoints = getReferenceEndpoints( composite, component, + reference, components, componentServices ); + + Multiplicity multiplicity = reference.getMultiplicity(); + if (multiplicity == Multiplicity.ONE_N || multiplicity == Multiplicity.ONE_ONE) { + // If there are no endpoints defined and also no endpoint references already present + // then this reference is unwired, which is an error - the existing endpoint references + // will have been attached to a nested reference when a promoting reference has its endpoint + // references computed + if (endpoints.size() == 0 && !reference.isPromoted() ) { + warning(monitor, "ReferenceWithoutTargets", reference, + composite.getName().toString(), reference.getName()); + } // end if + } // end if + + // An endpoint reference is created for the combination of each leafmost component reference and + // each discovered endpoint + for( int i = 0; i < refInfo.getRefs().size(); i++ ) { + Component leafComponent = refInfo.getComponents().get(i); + ComponentReference leafReference = refInfo.getRefs().get(i); + boolean unresolved = false; + + for( Endpoint2 endpoint : endpoints ) { + if( endpoint.isUnresolved() && endpoint.getComponent() == null && endpoint.getService() == null ) { + unresolved = true; + } else { + unresolved = false; + } // end if + // Create an EndpointReference pointing at the endpoint + EndpointReference2 endRef = createEndpointRef( leafComponent, leafReference, + endpoint.getBinding(), endpoint, unresolved); + // Add the EndpointReference to the top level AND the leaf level reference, if not the same!! + if( useNew ) { + leafReference.getEndpointReferences().add( endRef ); + if( leafReference != reference ) { + reference.getEndpointReferences().add( endRef ); + } // end if + } // end if + // (Debug) For the moment, print out the results + System.out.println( "Created endpointRef. Component = " + component.getName() + " Reference = " + + reference.getName() + " LeafComponent = " + endRef.getComponent().getName() + " LeafReference = " + + endRef.getReference().getName() + " Binding = " + endRef.getBinding() + " target Component = " + + endpoint.getComponent() + " target Service = " + endpoint.getService() ); + } // end for + } // end for + + } // end method createReferenceEndpointReferences2 + + private List getReferenceEndpoints(Composite composite, Component component, + ComponentReference reference, Map components, + Map componentServices ) { + // Target services for a component reference are specified in one of a number of ways, in order: + // 1. Component services declared by the @target attribute of the reference + // 2. Service endpoints inside or outside the domain through bindings with configured endpoints + // 3. If @autowire=true is declared, component services within the composite containing the component which + // are compatible with the reference + // 1. takes precedence over 2. - 3. is only used if neither of the other applies + + List endpoints = new ArrayList(); + + // Get targets for references that are callbacks... + if( getReferenceCallbackEndpoints( composite, component, reference, + components, componentServices, endpoints ) ) { + + // Get reference targets declared by @target attribute + } else if ( getReferenceTargetEndpoints( composite, component, reference, + components, componentServices, endpoints ) ) { + + // TODO - need to ensure that elements are handled correctly + // Get reference targets identified by configured subelements + } else if ( getReferenceBindingEndpoints( composite, component, reference, + components, componentServices, endpoints )) { + + // Get reference targets identified by @autowire + } else { + getReferenceAutowireEndpoints( composite, component, reference, + components, componentServices, endpoints ); + } // end if + return endpoints; + } // end method getReferenceEndpoints + + /** + * Gets the callback endpoints of a reference that is a callback reference + * @param composite - the composite + * @param component - the component + * @param reference - the reference + * @param components - a mapped list of the components in the composite + * @param componentServices - a mapped list of the componentServices in the composite + * @param endpoints - a list of the endpoints (in/out parameter) + * @return - true if the reference is a callback reference, false otherwise + */ + private boolean getReferenceCallbackEndpoints( Composite composite, Component component, + ComponentReference reference, Map components, + Map componentServices, List endpoints ) { + // Only if this reference is a callback are there any endpoints of this kind + if( reference.isCallback() ) { + // add an unresolved endpoint reference with an unresolved endpoint to go with it + // there will be one of these for each binding on the reference + for( Binding binding : reference.getBindings() ) { + Endpoint2 endpoint = createEndpoint(true); + endpoint.setBinding(binding); + endpoints.add( endpoint ); + } // end for + return true; + } else { + return false; + } // end if + + } // end method getReferenceCallbackEndpoints + + /** + * Gets the endpoints for the services identified by the @target attribute of a reference + * @param composite - the composite + * @param component - the component + * @param reference - the component reference + * @param components - a mapped list of the components in the composite + * @param componentServices - a mapped list of the componentServices in the composite + * @param endpoints - a list of the endpoints (in/out parameter) + * @return true if the @target attribute was set, false otherwise + */ + private boolean getReferenceTargetEndpoints( Composite composite, Component component, + ComponentReference reference, Map components, + Map componentServices, List endpoints ) { + + List refTargets = getReferenceTargets( reference ); + if ( !refTargets.isEmpty() ) { + // Resolve targets specified on the component reference + for (ComponentService target : refTargets) { + + String targetName = target.getName(); + Component targetComponent = getComponentFromTargetName( components, targetName ); + ComponentService targetComponentService = componentServices.get(targetName); + + if (targetComponentService != null) { + // Check that target component service provides a superset of the component reference interface + if (InterfaceContractIsCompatible( reference, targetComponentService )) { + // create endpoint reference - with dummy endpoint which will be replaced when policies + // are matched and bindings are configured later + // TODO + Endpoint2 endpoint = selectTargetEndpoint( reference, targetComponentService ); + System.out.println("Selected Endpoint: component=" + endpoint.getComponent().getName() + + " service=" + endpoint.getService().getName() + + " binding=" + endpoint.getBinding().toString()); + Endpoint2 endpoint2 = createEndpoint(targetComponent, targetComponentService, true); + endpoint2.setBinding( endpoint.getBinding() ); + endpoints.add( endpoint2 ); + } else { + warning(monitor, "ReferenceIncompatibleInterface", + composite, composite.getName().toString(), + reference.getName(), targetName); + } + } else { + // add an unresolved endpoint reference with an unresolved endpoint to go with it + endpoints.add( createEndpoint(true) ); + warning(monitor, "ComponentReferenceTargetNotFound", + composite, composite.getName().toString(), + targetName); + } // end if + } // end for + return true; + } else { + return false; + } // end if + + } // end method getReferenceTargetEndpoints + + /** + * Selects one endpoint of a target service which is compatible with the policy requirements of a reference + * @param reference - the reference (carries policy data with it) + * @param service - the target service + * @return - an endpoint belonging to the service which is compatible with the reference. + * This will in practice select a particular binding on the service if there is more than one endpoint on the + * service. If there are no matches, this method returns null + */ + private Endpoint2 selectTargetEndpoint( ComponentReference reference, ComponentService service ) { + + // Return the first endpoint with a Binding which is compatible with the policy requirements on + // the reference + for( Endpoint2 endpoint : service.getEndpoints() ) { + return endpoint; + } //end for + + return null; + } // end method selectTargetEndpoint + + /** + * Gets the endpoints for the services identified by the subelements of a reference + * @param composite - the composite + * @param component - the component + * @param reference - the component reference + * @param components - a mapped list of the components in the composite + * @param componentServices - a mapped list of the componentServices in the composite + * @param endpoints - a list of the endpoints (in/out parameter) + * @return true if the subelements identify target services, false otherwise + */ + private boolean getReferenceBindingEndpoints( Composite composite, Component component, + ComponentReference reference, Map components, + Map componentServices, List endpoints ) { + // Get service endpoints declared by subelements + if( bindingsIdentifyTargets( reference ) ) { + for (Binding binding : reference.getBindings()) { + + String uri = binding.getURI(); + + // user hasn't put a uri on the binding so it's not a target name and the assumption is that + // the target is established via configuration of the binding element itself + if (uri == null) { + // Regular forward references are UNWIRED with no endpoint if they have an SCABinding with NO targets + // and NO URI set - but Callbacks with an SCABinding are wired and need an endpoint + if( !reference.isCallback() && (binding instanceof SCABinding) ) continue; + + // create an unwired endpoint containing the binding + Endpoint2 endpoint = createEndpoint( false ); + endpoint.setBinding( binding ); + endpoints.add( endpoint ); + continue; + } // end if + + // user might have put a local target name in the uri - see if it refers to a target we know about + // - if it does the reference binding will be matched with a service binding + // - if it doesn't it is assumed to be an external reference + if (uri.startsWith("/")) uri = uri.substring(1); + + // Resolve the target component and service + ComponentService targetComponentService = componentServices.get(uri); + Component targetComponent = getComponentFromTargetName( components, uri ); + + // If the binding URI matches a component in the composite, configure an endpoint reference with + // this component as the target. + // If not, the binding URI is assumed to reference an external service + if (targetComponentService != null) { + // Check that the target component service provides + // a superset of the component reference interface + if (InterfaceContractIsCompatible( reference, targetComponentService )) { + // create dummy endpoint which will be replaced when policies + // are matched and bindings are configured later + endpoints.add( createEndpoint(targetComponent, targetComponentService, true) ); + } else { + warning(monitor, "ReferenceIncompatibleInterface", + composite, composite.getName().toString(), + reference.getName(), uri); + } // end if + } else { + // create resolved endpoint to signify that this reference is pointing at some unwired endpoint + endpoints.add( createEndpoint( false ) ); + } // end if + } // end for + return true; + } else { + return false; + } // end if + + } // end method getReferenceBindingEndpoints /** - * Evaluates whether the bindings attached to a reference indentify one or more target services. + * Gets the endpoints for the services identified by the @autowire attribute of a reference + * @param composite - the composite + * @param component - the component + * @param reference - the component reference + * @param components - a mapped list of the components in the composite + * @param componentServices - a mapped list of the componentServices in the composite + * @param endpoints - a list of the endpoints (in/out parameter) + * @return true if the @autowire attribute was set, false otherwise + */ + private boolean getReferenceAutowireEndpoints( Composite composite, Component component, + ComponentReference reference, Map components, + Map componentServices, List endpoints ) { + // Get compatible target services if @autowire=true is specified + if ( reference.getAutowire() == Boolean.TRUE ) { + + Multiplicity multiplicity = reference.getMultiplicity(); + for (Component targetComponent : composite.getComponents()) { + + // Prevent autowire connecting to self + if( targetComponent == component ) continue; + + for (ComponentService targetComponentService : targetComponent.getServices()) { + if (InterfaceContractIsCompatible( reference, targetComponentService )) { + // create endpoint reference - with a dummy endpoint which will be replaced when policies + // are matched and bindings are configured later + endpoints.add( createEndpoint(targetComponent, targetComponentService, true) ); + + // Stop with the first match for 0..1 and 1..1 references + if (multiplicity == Multiplicity.ZERO_ONE || + multiplicity == Multiplicity.ONE_ONE) { + break; + } // end if + } // end if + } // end for + } // end for + return true; + } else { + return false; + } // end if + + } // end method getReferenceAutowireEndpoints + + /** + * Evaluates if the interface contract of a component service is a compatible superset of the interface contract + * of a component reference + * @param reference - the component reference + * @param service - the component service + * @return - true if the interface of the service is a compatible superset of the interface of the reference, false otherwise + */ + private boolean InterfaceContractIsCompatible( ComponentReference reference, ComponentService service ) { + if (reference.getInterfaceContract() == null ) return true; + return interfaceContractMapper.isCompatible(reference.getInterfaceContract(), + service.getInterfaceContract()); + } // end method InterfaceContractIsCompatible + + /** + * Gather the Endpoint reference information for a component reference + * - gathers information from deeper in the hierarchy for a component which is implemented by a composite + * @param component - the component + * @param reference - the component reference + * @param refInfo - a reference info datastructure where the endpoint reference information is gathered. Can be null, in + * which case this method will allocate and return an instance of refInfo. + * @return - an EndpointrefInfo - the same object as the refInfo parameter, unless that parameter is null in which case + * it is a new object + */ + private EndpointrefInfo gatherEndpointrefInfo( Component component, ComponentReference reference, EndpointrefInfo refInfo ) { + if( refInfo == null ) refInfo = new EndpointrefInfo(); + // Deal with the cases where there is an error in the configuration + if( reference.isUnresolved() ) return refInfo; + + refInfo.setContract(reference.getInterfaceContract()); + // RULE: If the interface contract is not already set at this level, then it must be + // identical across all the next level elements - otherwise they can be subsets + boolean equalInterfaces = false; + if( refInfo.getContract() == null ) equalInterfaces = true; + + refInfo.addIntents(reference.getRequiredIntents()); + if( reference.getReference() instanceof CompositeReference ) { + // It's a composite reference - get hold of the set of promoted references + CompositeReference compRef = (CompositeReference)reference.getReference(); + List components = compRef.getPromotedComponents(); + List componentRefs = compRef.getPromotedReferences(); + // Scan over all promoted references + for( int i = 0; i < componentRefs.size(); i++ ) { + refInfo.setContractEqual( equalInterfaces ); + gatherEndpointrefInfo( components.get(i), componentRefs.get(i), refInfo ); + } // end for + } else { + // Otherwise it's a leaf node reference which must be recorded as an endpoint reference + refInfo.addRef(reference); + refInfo.addComponent(component); + } // end if + // RULE: Any PolicySets at this level override PolicySets from lower levels + refInfo.setPolicySets(reference.getPolicySets()); + + return refInfo; + } // end method gatherEndpointrefInfo + + /** + * A class used to gather endpoint reference information for a component reference + * - handles the information in a promotion hierarchy where the component reference is implemented + * by a composite reference. + * @author MikeEdwards + */ + private class EndpointrefInfo { + private List components = new ArrayList(); + private List refs = new ArrayList(); + private InterfaceContract contract = null; + private List intents = new ArrayList(); + private List policySets = null; + private boolean contractEqual = false; + + /** + * Sets whether new contracts must be equal to the current contract or not + * @param isEqual - true means that Contracts must be equal to the current contract - false means that Contracts + * can be subsets of the current contract + */ + void setContractEqual( boolean isEqual ) { + contractEqual = isEqual; + } + + boolean getContractEqual() { + return contractEqual; + } + + List getPolicySets() { + return policySets; + } + + void setPolicySets(List policySets) { + this.policySets = policySets; + } + + List getComponents() { + return components; + } + + void addComponent(Component component) { + this.components.add( component ); + } + + List getRefs() { + return refs; + } + + void addRef(ComponentReference ref) { + this.refs.add( ref ); + } + + InterfaceContract getContract() { + return contract; + } + + /** + * Set the contract - with checking of the contract if a contract is already set + * @param contract - the contract to set + */ + void setContract(InterfaceContract contract) { + // Add the contract if there is no existing contract set + if( this.contract == null ) { + this.contract = contract; + } else { + // RULE: Raise an error if the new contract is not a subset of the existing contract + if( contractEqual ) { + // Contracts must be equal + if( !interfaceContractMapper.isEqual( this.contract, contract ) ) { + warning(monitor, "ReferencePromotionInterfacesNotEqual", + this.contract.toString(), contract.toString() ); + } // end if + } else { + // Contract must be subset + if( !interfaceContractMapper.isCompatible( contract, this.contract ) ) { + warning(monitor, "ReferencePromotionIncompatibleInterface", + this.contract.toString(), contract.toString() ); + } // end if + } // end if + } // end if + } + + List getIntents() { + return intents; + } + /** + * Accumulate intents + * @param intents + */ + void addIntents(List intents) { + this.intents.addAll( intents ); + } + + + } // end class EndpointrefInfo + + /** + * Evaluates whether the bindings attached to a reference identify one or more target services. * @param reference - the reference * @return true if the bindings identify a target, false otherwise */ @@ -285,12 +760,13 @@ public class ComponentReferenceEndpointReferenceBuilderImpl extends BaseBuilderI for( Binding binding : reference.getBindings() ) { // theBindings = theInfo.getBindings(); + // Create an endpoint for each binding which applies to this service + // and copy across the information relating to the endpoint. + for( Binding binding : theBindings ) { + Endpoint2 endpoint = assemblyFactory.createEndpoint(); + endpoint.setComponent(theInfo.getComponent()); + endpoint.setService(theInfo.getComponentService()); + endpoint.setBinding(binding); + endpoint.setInterfaceContract(theInfo.getInterfaceContract()); + endpoint.getRequiredIntents().addAll(theInfo.getIntents()); + endpoint.getPolicySets().addAll(theInfo.getPolicySets()); + endpoint.setUnresolved(false); + // Add the endpoint to the component service + if( useNew ) { + // Add to top level and leaf level services, if different + service.getEndpoints().add(endpoint); + ComponentService leafService = theInfo.getComponentService(); + if( service != leafService ) { + leafService.getEndpoints().add(endpoint); + } // end if + } // end if + System.out.println( "Endpoint created for Component = " + component.getName() + " Leaf component = " + + endpoint.getComponent().getName() + " service = " + + endpoint.getService().getName() + " binding = " + endpoint.getBinding() ); + } // end for + } // end for + // Handle composites as implementations + if( component.getImplementation() instanceof Composite ) { + processComponentServices2( (Composite) component.getImplementation() ); + } // end if + } // end for + } // end method processComponentServices2 + + /** + * Scan a component service for endpoint information, recursing down to the leafmost promoted service if the component service is + * implemented by a Composite service + * @param component - the component + * @param service - the component service + * @param theInfo - an EndpointInfo object in which the endpoint information is accumulated. If null on entry, a new EndpointInfo object is created + * @return - the EndpointInfo object containing the information about the component service + */ + private EndpointInfo scanComponentService( Component component, ComponentService service, EndpointInfo theInfo ) { + if( theInfo == null ) { + theInfo = new EndpointInfo(); + } // end if + + theInfo.setBindings(service.getBindings()); + theInfo.setInterfaceContract(service.getInterfaceContract()); + theInfo.setIntents(service.getRequiredIntents()); + theInfo.setPolicySets(service.getPolicySets()); + + Service implService = service.getService(); + if( implService instanceof CompositeService ) { + // If it is implemented by a Composite, scan through the promoted service + ComponentService promotedService = ((CompositeService)implService).getPromotedService(); + Component promotedComponent = ((CompositeService)implService).getPromotedComponent(); + if (promotedService != null) { + scanComponentService( promotedComponent, promotedService, theInfo ); + } else { + // If its a composite service with no promoted component service, it's an error + } // end if + } else { + // Otherwise the component and service are the ones at this level + theInfo.setComponent(component); + theInfo.setComponentService(service); + } //end if + + return theInfo; + } // end method scanPromotedComponentService + + private class EndpointInfo { + private Component leafComponent = null; + private ComponentService leafComponentService = null; + private List bindings = null; + private InterfaceContract contract; + private List intents = new Vector(); + private List policySets = null; + + void setComponent( Component component ){ + leafComponent = component; + } // end method + + Component getComponent() { + return leafComponent; + } // end method + + void setComponentService( ComponentService service ) { + leafComponentService = service; + } // end method + + ComponentService getComponentService() { + return leafComponentService; + } // end method + + void setBindings( List theBindings ) { + // RULE: Bindings from higher in the hierarchy take precedence + if( bindings == null ) { + bindings = theBindings; + } // end if + } // end method + + List getBindings() { + return bindings; + } // end method + + void setInterfaceContract( InterfaceContract theInterface ) { + // RULE: Interface contract from higher in the hierarchy takes precedence + if( contract == null ) { + contract = theInterface; + } // end if + } // end method + + InterfaceContract getInterfaceContract() { + return contract; + } // end method + + List getIntents() { + return intents; + } // end method + + void setIntents(List intents) { + // RULE: Intents accumulate from all levels in the hierarchy + this.intents.addAll( intents ); + } // end method + + List getPolicySets() { + return policySets; + } // end method + + void setPolicySets(List policySets) { + // RULE: Policy Sets from higher in the hierarchy override those lower + if( this.policySets == null ) { + this.policySets = policySets; + } // end if + } // end method + + + } // end class EndpointInfo -} +} // end class diff --git a/java/sca/modules/assembly/src/main/java/org/apache/tuscany/sca/assembly/builder/impl/CompositePromotionBuilderImpl.java b/java/sca/modules/assembly/src/main/java/org/apache/tuscany/sca/assembly/builder/impl/CompositePromotionBuilderImpl.java index c8ec86afae..e2f17f5efd 100644 --- a/java/sca/modules/assembly/src/main/java/org/apache/tuscany/sca/assembly/builder/impl/CompositePromotionBuilderImpl.java +++ b/java/sca/modules/assembly/src/main/java/org/apache/tuscany/sca/assembly/builder/impl/CompositePromotionBuilderImpl.java @@ -116,8 +116,7 @@ public class CompositePromotionBuilderImpl extends BaseBuilderImpl implements Co } } - // Connect composite services to the component services that they - // promote + // Connect composite services to the component services that they promote for (Service service : composite.getServices()) { CompositeService compositeService = (CompositeService)service; ComponentService componentService = compositeService.getPromotedService(); @@ -194,8 +193,7 @@ public class CompositePromotionBuilderImpl extends BaseBuilderImpl implements Co } } - // Connect composite references to the component references - // that they promote + // Connect composite references to the component references that they promote for (Reference reference : composite.getReferences()) { CompositeReference compositeReference = (CompositeReference)reference; List promotedReferences = compositeReference.getPromotedReferences(); @@ -210,20 +208,20 @@ public class CompositePromotionBuilderImpl extends BaseBuilderImpl implements Co promotedComponent = components.get(promotedComponent.getName()); compositeReference.getPromotedComponents().set(i, promotedComponent); + componentReference.setPromoted( true ); + // Point to the resolved component reference promotedReferences.set(i, componentReference); - // Use the interface contract from the component - // reference if none + // Use the interface contract from the component reference if none // is specified on the composite reference - InterfaceContract compositeReferenceInterfaceContract = compositeReference.getInterfaceContract(); InterfaceContract componentReferenceInterfaceContract = componentReference.getInterfaceContract(); if (compositeReferenceInterfaceContract == null) { compositeReference.setInterfaceContract(componentReferenceInterfaceContract); } else if (componentReferenceInterfaceContract != null) { - // Check the compositeInterfaceContract and componentInterfaceContract - boolean isCompatible = interfaceContractMapper.isCompatible(compositeReferenceInterfaceContract, componentReferenceInterfaceContract); + // Check that the componentInterfaceContract is a subset of the compositeInterfaceContract + boolean isCompatible = interfaceContractMapper.isCompatible( componentReferenceInterfaceContract, compositeReferenceInterfaceContract); if (!isCompatible) { warning(monitor, "ReferenceInterfaceNotSubSet", compositeReference, componentReferenceName); } diff --git a/java/sca/modules/assembly/src/main/java/org/apache/tuscany/sca/assembly/builder/impl/ReferenceConfigurationUtil.java b/java/sca/modules/assembly/src/main/java/org/apache/tuscany/sca/assembly/builder/impl/ReferenceConfigurationUtil.java index c1862e0380..1c6049ad89 100644 --- a/java/sca/modules/assembly/src/main/java/org/apache/tuscany/sca/assembly/builder/impl/ReferenceConfigurationUtil.java +++ b/java/sca/modules/assembly/src/main/java/org/apache/tuscany/sca/assembly/builder/impl/ReferenceConfigurationUtil.java @@ -27,6 +27,7 @@ import org.apache.tuscany.sca.assembly.AssemblyFactory; import org.apache.tuscany.sca.assembly.Binding; import org.apache.tuscany.sca.assembly.ComponentReference; import org.apache.tuscany.sca.assembly.CompositeReference; +import org.apache.tuscany.sca.assembly.EndpointReference2; import org.apache.tuscany.sca.assembly.Multiplicity; import org.apache.tuscany.sca.assembly.OptimizableBinding; import org.apache.tuscany.sca.assembly.Reference; @@ -157,37 +158,32 @@ abstract class ReferenceConfigurationUtil { } /** - * Override the bindings for a promoted reference from an outer component - * reference + * Override the bindings for a promoted reference from an outer component reference * - * @param reference - * @param promotedReference + * @param reference - the outer level reference + * @param promotedReference - the inner level promoted reference */ static void reconcileReferenceBindings(Reference reference, ComponentReference promotedReference, AssemblyFactory assemblyFactory, Monitor monitor) { - if (promotedReference.getMultiplicity() == Multiplicity.ONE_ONE || - promotedReference.getMultiplicity() == Multiplicity.ZERO_ONE) { - - // override the promoted endpoint references (and bindings) - // with configuration from the top level - - if (reference.getEndpointReferences().size() > 0){ - promotedReference.getEndpointReferences().clear(); - promotedReference.getEndpointReferences().addAll(reference.getEndpointReferences()); - } - - if (promotedReference.getEndpointReferences().size() > 1) { - warning(monitor, "ComponentReferenceMoreWire", promotedReference, promotedReference.getName()); - } - } else { - // merge the promoted endpoint reference with the those from the top level - if (reference.getEndpointReferences().size() > 0){ - promotedReference.getEndpointReferences().addAll(reference.getEndpointReferences()); - } - } + if (reference.getEndpointReferences().size() > 0){ + if (promotedReference.getMultiplicity() == Multiplicity.ONE_ONE || + promotedReference.getMultiplicity() == Multiplicity.ZERO_ONE) { + // Override any existing wires for 0..1 and 1..1 multiplicity + promotedReference.getEndpointReferences().clear(); + // For 0..1 and 1..1, there should not be more than 1 endpoint reference + if (reference.getEndpointReferences().size() > 1) { + warning(monitor, "ComponentReferenceMoreWire", promotedReference, promotedReference.getName()); + } // end if + } // end if + // Clone the EndpointReferences from the outer level and add to the promoted reference + for( EndpointReference2 epRef : reference.getEndpointReferences()){ + EndpointReference2 epRefClone = copyHigherReference( epRef, promotedReference ); + promotedReference.getEndpointReferences().add(epRefClone); + } // end for + } // end if Set callbackBindings = new HashSet(); if (promotedReference.getCallback() != null) { @@ -200,8 +196,28 @@ abstract class ReferenceConfigurationUtil { for (Binding binding : callbackBindings) { if ((!(binding instanceof OptimizableBinding)) || binding.getURI() != null) { promotedReference.getCallback().getBindings().add(binding); - } - } - } + } // end if + } // end for + } // end method reconcileReferenceBindings + + /** + * Copy a higher level EndpointReference down to a lower level reference which it promotes + * @param epRef - the endpoint reference + * @param promotedReference - the promoted reference + * @return - a copy of the EndpointReference with data merged from the promoted reference + */ + private static EndpointReference2 copyHigherReference( EndpointReference2 epRef, ComponentReference promotedReference ) { + EndpointReference2 epRefClone = null; + try { + epRefClone = (EndpointReference2) epRef.clone(); + } catch (Exception e) { + // Ignore (we know that EndpointReference2 can be cloned) + } // end try + // Copy across details of the inner reference + ComponentReference ref = epRefClone.getReference(); + //FIXME + epRefClone.setReference(promotedReference); + return epRefClone; + } // end copyHigherReference -} +} // end class diff --git a/java/sca/modules/assembly/src/main/java/org/apache/tuscany/sca/assembly/impl/ComponentReferenceImpl.java b/java/sca/modules/assembly/src/main/java/org/apache/tuscany/sca/assembly/impl/ComponentReferenceImpl.java index 2380bbf088..bb5b163762 100644 --- a/java/sca/modules/assembly/src/main/java/org/apache/tuscany/sca/assembly/impl/ComponentReferenceImpl.java +++ b/java/sca/modules/assembly/src/main/java/org/apache/tuscany/sca/assembly/impl/ComponentReferenceImpl.java @@ -35,11 +35,12 @@ import org.apache.tuscany.sca.interfacedef.InterfaceContract; * @version $Rev$ $Date$ */ public class ComponentReferenceImpl extends ReferenceImpl implements ComponentReference, Cloneable { - private Reference reference; - private Boolean autowire; - private boolean nonOverridable; - private List promotedAs = new ArrayList(); - private ComponentService callbackService; + private Reference reference; + private Boolean autowire; + private boolean nonOverridable; + private List promotedAs = new ArrayList(); + private ComponentService callbackService; + private boolean isPromoted = false; /** * Constructs a new component reference. @@ -108,4 +109,12 @@ public class ComponentReferenceImpl extends ReferenceImpl implements ComponentRe public void setNonOverridable(boolean nonOverridable) { this.nonOverridable = nonOverridable; } -} + + public void setPromoted( boolean isPromoted ) { + this.isPromoted = isPromoted; + } // end method setPromoted + + public boolean isPromoted() { + return isPromoted; + } +} // end class ComponentReferenceImpl diff --git a/java/sca/modules/assembly/src/main/resources/assembly-validation-messages.properties b/java/sca/modules/assembly/src/main/resources/assembly-validation-messages.properties index 77d8c6ee4c..cfa76800eb 100644 --- a/java/sca/modules/assembly/src/main/resources/assembly-validation-messages.properties +++ b/java/sca/modules/assembly/src/main/resources/assembly-validation-messages.properties @@ -35,6 +35,8 @@ PropertyOverrideManyAttribute = Component property many attribute incompatible w ReferenceNotFound = Reference not found for component reference: Component = {0} Reference = {1} ReferenceIncompatibleMultiplicity = Component reference multiplicity incompatible with reference multiplicity: Component = {0} Reference = {1} ReferenceIncompatibleInterface = Incompatible interfaces on component reference and target: Composite = {0} Reference = {1} Service = {2} +ReferencePromotionIncompatibleInterface = Promoted reference interface incompatible with promoting reference: Promoting interface = {0} Promoted = {1} +ReferencePromotionInterfacesNotEqual = Peer promoted references not equal: First interface = {0} second interface = {1} ReferenceIncompatibleComponentInterface = Component reference interface incompatible with implementation reference interface: Component = {0} Reference = {1} ServiceIncompatibleComponentInterface = Component service interface incompatible with implementation service interface: Component = {0} Service = {1} MultipleBindingsForService = Multiple bindings with the same name for a service: Service = {0} Binding name = {1} -- cgit v1.2.3