From 132aa8a77685ec92bc90c03f987650d275a7b639 Mon Sep 17 00:00:00 2001 From: lresende Date: Mon, 30 Sep 2013 06:59:11 +0000 Subject: 2.0.1 RC1 release tag git-svn-id: http://svn.us.apache.org/repos/asf/tuscany@1527464 13f79535-47bb-0310-9956-ffa450edef68 --- .../impl/CompositeComponentTypeBuilderImpl.java | 696 +++++++++++++++++++++ 1 file changed, 696 insertions(+) create mode 100644 sca-java-2.x/tags/2.0.1-RC1/modules/builder/src/main/java/org/apache/tuscany/sca/builder/impl/CompositeComponentTypeBuilderImpl.java (limited to 'sca-java-2.x/tags/2.0.1-RC1/modules/builder/src/main/java/org/apache/tuscany/sca/builder/impl/CompositeComponentTypeBuilderImpl.java') diff --git a/sca-java-2.x/tags/2.0.1-RC1/modules/builder/src/main/java/org/apache/tuscany/sca/builder/impl/CompositeComponentTypeBuilderImpl.java b/sca-java-2.x/tags/2.0.1-RC1/modules/builder/src/main/java/org/apache/tuscany/sca/builder/impl/CompositeComponentTypeBuilderImpl.java new file mode 100644 index 0000000000..83e007f39a --- /dev/null +++ b/sca-java-2.x/tags/2.0.1-RC1/modules/builder/src/main/java/org/apache/tuscany/sca/builder/impl/CompositeComponentTypeBuilderImpl.java @@ -0,0 +1,696 @@ +/* + * 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.builder.impl; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.logging.Logger; + +import javax.xml.namespace.QName; + +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.ComponentType; +import org.apache.tuscany.sca.assembly.Composite; +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.Multiplicity; +import org.apache.tuscany.sca.assembly.Reference; +import org.apache.tuscany.sca.assembly.SCABinding; +import org.apache.tuscany.sca.assembly.SCABindingFactory; +import org.apache.tuscany.sca.assembly.Service; +import org.apache.tuscany.sca.assembly.builder.BuilderContext; +import org.apache.tuscany.sca.assembly.builder.BuilderExtensionPoint; +import org.apache.tuscany.sca.assembly.builder.ContractBuilder; +import org.apache.tuscany.sca.assembly.builder.Messages; +import org.apache.tuscany.sca.core.ExtensionPointRegistry; +import org.apache.tuscany.sca.core.FactoryExtensionPoint; +import org.apache.tuscany.sca.core.UtilityExtensionPoint; +import org.apache.tuscany.sca.definitions.Definitions; +import org.apache.tuscany.sca.interfacedef.Compatibility; +import org.apache.tuscany.sca.interfacedef.IncompatibleInterfaceContractException; +import org.apache.tuscany.sca.interfacedef.InterfaceContract; +import org.apache.tuscany.sca.interfacedef.InterfaceContractMapper; +import org.apache.tuscany.sca.interfacedef.java.JavaInterfaceContract; +import org.apache.tuscany.sca.monitor.Monitor; +import org.apache.tuscany.sca.policy.ExtensionType; +import org.apache.tuscany.sca.policy.PolicySubject; + +/** + * @version $Rev$ $Date$ + */ + +// TODO - really implementation.composite component type builder - CompositeComponentTypeBuilder? + +public class CompositeComponentTypeBuilderImpl { + private static final Logger logger = Logger.getLogger(CompositeComponentTypeBuilderImpl.class.getName()); + + protected static final String SCA11_NS = "http://docs.oasis-open.org/ns/opencsa/sca/200912"; + protected static final String BINDING_SCA = "binding.sca"; + protected static final QName BINDING_SCA_QNAME = new QName(SCA11_NS, BINDING_SCA); + + private ComponentBuilderImpl componentBuilder; + private AssemblyFactory assemblyFactory; + private SCABindingFactory scaBindingFactory; + private InterfaceContractMapper interfaceContractMapper; + private BuilderExtensionPoint builders; + private ContractBuilder contractBuilder; + + public CompositeComponentTypeBuilderImpl(ExtensionPointRegistry registry) { + UtilityExtensionPoint utilities = registry.getExtensionPoint(UtilityExtensionPoint.class); + + FactoryExtensionPoint modelFactories = registry.getExtensionPoint(FactoryExtensionPoint.class); + assemblyFactory = modelFactories.getFactory(AssemblyFactory.class); + scaBindingFactory = modelFactories.getFactory(SCABindingFactory.class); + + interfaceContractMapper = utilities.getUtility(InterfaceContractMapper.class); + builders = registry.getExtensionPoint(BuilderExtensionPoint.class); + contractBuilder = builders.getContractBuilder(); + } + + public void setComponentBuilder(ComponentBuilderImpl componentBuilder) { + this.componentBuilder = componentBuilder; + } + + /** + * Calculate the component type for the provided implementation + * + * @param implementation + * @return component type + */ + public void createComponentType(Component outerComponent, Composite composite, BuilderContext context) { + + Monitor monitor = context.getMonitor(); + monitor.pushContext("Composite: " + composite.getName().toString()); + + try { + // first make sure that each child component has been properly configured based + // on its own component type + for (Component component : composite.getComponents()) { + + // Check for duplicate component names + if (component != composite.getComponent(component.getName())) { + Monitor.error(monitor, + this, + Messages.ASSEMBLY_VALIDATION, + "DuplicateComponentName", + composite.getName().toString(), + component.getName()); + } + + // do any work we need to do before we configure the component + // Anything that needs to be pushed down the promotion + // hierarchy must be done before we configure the component + + // Push down the autowire flag from the composite to components + if (component.getAutowire() == null) { + component.setAutowire(composite.getAutowire()); + } + + // configure the component from its component type + componentBuilder.configureComponentFromComponentType(outerComponent, composite, component, context); + } + + // create the composite component type based on the promoted artifacts + // from the components that it contains + + // index all the components, services and references in the + // component type so that they are easy to find + Map components = new HashMap(); + Map componentServices = new HashMap(); + Map componentReferences = new HashMap(); + indexComponentsServicesAndReferences(composite, components, componentServices, componentReferences); + + // services + calculateServices(composite, components, componentServices, context); + + // references + calculateReferences(composite, components, componentReferences, context); + + // properties + // Properties on the composite component are unaffected by properties + // on child components. Instead child component properties might take their + // values from composite properties. Hence there is nothing to do here. + //calculateProperties(composite, components); + + } finally { + monitor.popContext(); + } + } + + /** + * Index components, services and references inside a composite. + * + * @param composite + * @param components + * @param componentServices + * @param componentReferences + */ + private void indexComponentsServicesAndReferences(Composite composite, + Map components, + Map componentServices, + Map componentReferences) { + + for (Component component : composite.getComponents()) { + + // Index components by name + components.put(component.getName(), component); + + ComponentService nonCallbackService = null; + int nonCallbackServices = 0; + for (ComponentService componentService : component.getServices()) { + + // Index component services by component name / service name + String uri = component.getName() + '/' + componentService.getName(); + componentServices.put(uri, componentService); + + // count how many non-callback services there are + // if there is only one the component name also acts as the service name + if (!componentService.isForCallback()) { + + // Check how many non callback non-promoted services we have + if (nonCallbackServices == 0) { + nonCallbackService = componentService; + } + nonCallbackServices++; + } + } + + if (nonCallbackServices == 1) { + // If we have a single non callback service, index it by + // component name as well + componentServices.put(component.getName(), nonCallbackService); + } + + // Index references by component name / reference name + for (ComponentReference componentReference : component.getReferences()) { + String uri = component.getName() + '/' + componentReference.getName(); + componentReferences.put(uri, componentReference); + } + } + } + + /** + * Connect the services in the component type to the component services that + * they promote + * + * @param componentType + * @param component + */ + private void calculateServices(ComponentType componentType, + Map components, + Map componentServices, + BuilderContext context) { + + Monitor monitor = context.getMonitor(); + + // Connect this component type's services to the + // services from child components which it promotes + connectPromotedServices(componentType, components, componentServices, monitor); + + // look at each component type service in turn and + // calculate its configuration based on OASIS rules + for (Service service : componentType.getServices()) { + CompositeService compositeService = (CompositeService)service; + ComponentService promotedComponentService = compositeService.getPromotedService(); + + // promote interface contracts + calculatePromotedServiceInterfaceContract(compositeService, promotedComponentService, context); + + // promote bindings + calculatePromotedBindings(compositeService, promotedComponentService); + + componentBuilder.policyBuilder.configure(compositeService, context); + } + } + + /** + * Connect the references in the component type to the component references that + * they promote + * + * @param componentType + * @param component + */ + private void calculateReferences(ComponentType componentType, + Map components, + Map componentReferences, + BuilderContext context) { + Monitor monitor = context.getMonitor(); + // Connect this component type's references to the + // references from child components which it promotes + connectPromotedReferences(componentType, components, componentReferences, monitor); + + // look at each component type reference in turn and + // calculate its configuration based on OASIS rules + for (Reference reference : componentType.getReferences()) { + CompositeReference compositeReference = (CompositeReference)reference; + List promotedReferences = compositeReference.getPromotedReferences(); + + for (ComponentReference promotedComponentReference : promotedReferences) { + + // promote multiplicity + reconcileReferenceMultiplicity(componentType, compositeReference, promotedComponentReference, monitor); + + // check nonOverridable + validateNonOverridable(componentType, compositeReference, promotedComponentReference, monitor); + + // promote interface contracts + calculatePromotedReferenceInterfaceContract(compositeReference, promotedComponentReference, context); + + // promote bindings + // Don't need to promote reference bindings as any lower level binding will + // already be targeting the correct service without need for promotion + //calculatePromotedBindings(compositeReference, promotedComponentReference); + } + + componentBuilder.policyBuilder.configure(compositeReference, context); + } + } + + /** + * Connect the services in the component type to the component services that + * they promote + * + * @param componentType + * @param component + */ + private void connectPromotedServices(ComponentType componentType, + Map components, + Map componentServices, + Monitor monitor) { + + for (Service service : componentType.getServices()) { + // Connect composite (component type) services to the component services + // that they promote + CompositeService compositeService = (CompositeService)service; + ComponentService componentService = compositeService.getPromotedService(); + if (componentService != null && componentService.isUnresolved()) { + // get the name of the promoted component/service + String promotedComponentName = compositeService.getPromotedComponent().getName(); + String promotedServiceName; + if (componentService.getName() != null) { + if (compositeService.isForCallback()) { + // For callbacks the name already has the form "componentName/servicename" + promotedServiceName = componentService.getName(); + } else { + promotedServiceName = promotedComponentName + '/' + componentService.getName(); + } + } else { + promotedServiceName = promotedComponentName; + } + + // find the promoted service + ComponentService promotedService = componentServices.get(promotedServiceName); + + if (promotedService != null) { + + // Point to the resolved component + Component promotedComponent = components.get(promotedComponentName); + compositeService.setPromotedComponent(promotedComponent); + + // Point to the resolved component service + compositeService.setPromotedService(promotedService); + } else { + Monitor.error(monitor, + this, + Messages.ASSEMBLY_VALIDATION, + "PromotedServiceNotFound", + ((Composite)componentType).getName().toString(), + promotedServiceName); + } + } + } + } + + /** + * Connect the references in the component type to the component references that + * they promote + * + * @param componentType + * @param component + */ + private void connectPromotedReferences(ComponentType componentType, + Map components, + Map componentReferences, + Monitor monitor) { + + // Connect composite (component type) references to the component references that they promote + for (Reference reference : componentType.getReferences()) { + CompositeReference compositeReference = (CompositeReference)reference; + List promotedReferences = compositeReference.getPromotedReferences(); + for (int i = 0, n = promotedReferences.size(); i < n; i++) { + ComponentReference componentReference = promotedReferences.get(i); + if (componentReference.isUnresolved()) { + String componentReferenceName = componentReference.getName(); + componentReference = componentReferences.get(componentReferenceName); + if (componentReference != null) { + // Set the promoted component + Component promotedComponent = compositeReference.getPromotedComponents().get(i); + promotedComponent = components.get(promotedComponent.getName()); + compositeReference.getPromotedComponents().set(i, promotedComponent); + + componentReference.setPromoted(true); + + // Point to the resolved component reference + promotedReferences.set(i, componentReference); + } else { + Monitor.error(monitor, + this, + Messages.ASSEMBLY_VALIDATION, + "PromotedReferenceNotFound", + ((Composite)componentType).getName().toString(), + componentReferenceName); + } + } + } + } + } + + /** + * Create a default SCA binding in the case that no binding + * is specified by the user + * + * @param contract + * @param definitions + */ + protected void createSCABinding(Contract contract, Definitions definitions) { + + SCABinding scaBinding = scaBindingFactory.createSCABinding(); + scaBinding.setName(contract.getName()); + + if (definitions != null) { + for (ExtensionType attachPointType : definitions.getBindingTypes()) { + if (attachPointType.getType().equals(BINDING_SCA_QNAME)) { + ((PolicySubject)scaBinding).setExtensionType(attachPointType); + } + } + } + + contract.getBindings().add(scaBinding); + contract.setOverridingBindings(false); + } + + /** + * The following methods implement rules that the OASIS specification defined explicitly + * to control how configuration from a component type is inherited by a component + */ + + /** + * Interface contract from higher in the implementation hierarchy takes precedence. + * When it comes to checking compatibility the top level service interface is a + * subset of the promoted service interface so treat the top level interface as + * the source + * + * @param topContract the top contract + * @param bottomContract the bottom contract + */ + private void calculatePromotedServiceInterfaceContract(Service topContract, Service bottomContract, BuilderContext context) { + // Use the interface contract from the bottom level contract if + // none is specified on the top level contract + InterfaceContract topInterfaceContract = topContract.getInterfaceContract(); + InterfaceContract bottomInterfaceContract = bottomContract.getInterfaceContract(); + + if (topInterfaceContract == null) { + topContract.setInterfaceContract(bottomInterfaceContract); + } else if (bottomInterfaceContract != null) { + // Check that the top and bottom interface contracts are compatible + boolean isCompatible = true; + String incompatibilityReason = ""; + try{ + isCompatible = checkSubsetCompatibility(topInterfaceContract, bottomInterfaceContract, context); + } catch (IncompatibleInterfaceContractException ex){ + isCompatible = false; + incompatibilityReason = ex.getMessage(); + } + if (!isCompatible) { + Monitor.error(context.getMonitor(), + this, + Messages.ASSEMBLY_VALIDATION, + "ServiceInterfaceNotSubSet", + topContract.getName(), + incompatibilityReason); + } + + // TODO - there is an issue with the following code if the + // contracts of of different types. Need to use the + // normalized form + + // fix up the forward interface based on the promoted component + // Someone might have manually specified a callback interface but + // left out the forward interface + if (topInterfaceContract.getInterface() == null){ + topInterfaceContract.setInterface(bottomInterfaceContract.getInterface()); + } + + // fix up the callback interface based on the promoted component + // Someone might have manually specified a forward interface but + // left out the callback interface + if (topInterfaceContract.getCallbackInterface() == null){ + topInterfaceContract.setCallbackInterface(bottomInterfaceContract.getCallbackInterface()); + } + } + } + + /** + * Interface contract from higher in the implementation hierarchy takes precedence. + * When it comes to checking compatibility the top level reference interface is a + * superset of the promoted reference interface so treat the promoted + * (bottom) interface as the source + * + * @param topContract the top contract + * @param bottomContract the bottom contract + */ + private void calculatePromotedReferenceInterfaceContract(Reference topContract, Reference bottomContract, BuilderContext context) { + // Use the interface contract from the bottom level contract if + // none is specified on the top level contract + InterfaceContract topInterfaceContract = topContract.getInterfaceContract(); + InterfaceContract bottomInterfaceContract = bottomContract.getInterfaceContract(); + + if (topInterfaceContract == null) { + topContract.setInterfaceContract(bottomInterfaceContract); + } else if (bottomInterfaceContract != null) { + // Check that the top and bottom interface contracts are compatible + boolean isCompatible = true; + String incompatibilityReason = ""; + try{ + isCompatible = checkSubsetCompatibility(bottomInterfaceContract, topInterfaceContract, context); + } catch (IncompatibleInterfaceContractException ex){ + isCompatible = false; + incompatibilityReason = ex.getMessage(); + } + if (!isCompatible) { + Monitor.error(context.getMonitor(), + this, + Messages.ASSEMBLY_VALIDATION, + "ReferenceInterfaceNotSubSet", + topContract.getName(), + incompatibilityReason); + } + + // TODO - there is an issue with the following code if the + // contracts of of different types. Need to use the + // normalized form + + // fix up the forward interface based on the promoted component + // Someone might have manually specified a callback interface but + // left out the forward interface + if (topInterfaceContract.getInterface() == null){ + topInterfaceContract.setInterface(bottomInterfaceContract.getInterface()); + } + + // fix up the callback interface based on the promoted component + // Someone might have manually specified a forward interface but + // left out the callback interface + if (topInterfaceContract.getCallbackInterface() == null){ + topInterfaceContract.setCallbackInterface(bottomInterfaceContract.getCallbackInterface()); + } + } + } + + /** + * Bindings from higher in the implementation hierarchy take precedence + * + * @param compositeService + * @param promotedComponentService + */ + private void calculatePromotedBindings(CompositeService compositeService, ComponentService promotedComponentService) { + // forward bindings + if (compositeService.getBindings().isEmpty()) { + for (Binding binding : promotedComponentService.getBindings()) { + try { + compositeService.getBindings().add((Binding)binding.clone()); + } catch (CloneNotSupportedException ex) { + // this binding can't be used in the promoted service + } + } + } + + if (compositeService.getBindings().isEmpty()) { + createSCABinding(compositeService, null); + } + + // callback bindings + if (promotedComponentService.getCallback() != null) { + if (compositeService.getCallback() != null) { + compositeService.getCallback().getBindings().clear(); + } else { + compositeService.setCallback(assemblyFactory.createCallback()); + } + + for (Binding binding : promotedComponentService.getCallback().getBindings()) { + try { + compositeService.getCallback().getBindings().add((Binding)binding.clone()); + } catch (CloneNotSupportedException ex) { + // this binding can't be used in the promoted service + } + } + } + } + + private void reconcileReferenceMultiplicity(ComponentType componentType, + Reference compositeReference, + Reference promotedComponentReference, + Monitor monitor) { + if (compositeReference.getMultiplicity() != null) { + if (!isValidMultiplicityOverride(promotedComponentReference.getTargets().size() > 0, + promotedComponentReference.getMultiplicity(), + compositeReference.getMultiplicity())) { + Monitor.error(monitor, + this, + Messages.ASSEMBLY_VALIDATION, + "CompositeReferenceIncompatibleMultiplicity", + componentType.getURI(), + compositeReference.getName(), + promotedComponentReference.getName()); + } + } else { + compositeReference.setMultiplicity(promotedComponentReference.getMultiplicity()); + } + } + + private boolean isValidMultiplicityOverride(boolean componentRefHasTarget, + Multiplicity componentRefMul, + Multiplicity compositeRefMul) { + if ((componentRefMul != null) && + (compositeRefMul != null) && + componentRefMul != compositeRefMul) { + if (componentRefHasTarget){ + switch (componentRefMul) { + case ZERO_ONE: + return compositeRefMul == Multiplicity.ZERO_ONE || + compositeRefMul == Multiplicity.ONE_ONE; + case ONE_ONE: + return compositeRefMul == Multiplicity.ZERO_ONE || + compositeRefMul == Multiplicity.ONE_ONE; + case ZERO_N: + return true; + case ONE_N: + return true; + default: + return false; + } + } else { + switch (componentRefMul) { + case ZERO_ONE: + return compositeRefMul == Multiplicity.ONE_ONE; + case ONE_ONE: + return compositeRefMul == Multiplicity.ONE_ONE; + case ZERO_N: + return true; + case ONE_N: + return compositeRefMul == Multiplicity.ONE_ONE || + compositeRefMul == Multiplicity.ONE_N; + + default: + return false; + } + } + } else { + return true; + } + } + + /** + * ASM50042 - Checks that if a component reference with multiplicity="1..1" is marked + * as nonOveridable then there are no composite references that promote it + * + * @param componentType + * @param compositeReference + * @param promotedComponentReference + * @param monitor + */ + private void validateNonOverridable(ComponentType componentType, + Reference compositeReference, + Reference promotedComponentReference, + Monitor monitor){ + if ((promotedComponentReference.getMultiplicity() == Multiplicity.ONE_ONE) && + (((ComponentReference)promotedComponentReference)).isNonOverridable() == true) { + Monitor.error(monitor, + this, + Messages.ASSEMBLY_VALIDATION, + "CompositeReferencePromotesNonOverridableReference", + componentType.getURI(), + compositeReference.getName(), + promotedComponentReference.getName()); + } + } + + /** + * A local wrapper for the interface contract mapper as we need to normalize the + * interface contracts if appropriate and the mapper doesn't have the right + * dependencies to be able to do it. + * + * Sometimes the two interfaces can be presented using different IDLs, for example + * Java and WSDL. In this case interfaces are converted so that they are both WSDL1.1 interfaces + * and they are then compared. The generated WSDL is cached on the interface object for + * any subsequent matching + * + * @param contractA + * @param contractB + * @return true if the interface contracts match + */ + private boolean checkSubsetCompatibility(InterfaceContract contractA, InterfaceContract contractB, BuilderContext context) + throws IncompatibleInterfaceContractException { + + if (contractA.getClass() != contractB.getClass()) { + + if (contractA instanceof JavaInterfaceContract){ + contractBuilder.build(contractA, context); + contractA = ((JavaInterfaceContract)contractA).getNormalizedWSDLContract(); + } + + if (contractB instanceof JavaInterfaceContract){ + contractBuilder.build(contractB, context); + contractB = ((JavaInterfaceContract)contractB).getNormalizedWSDLContract(); + } + } + + return interfaceContractMapper.checkCompatibility(contractA, + contractB, + Compatibility.SUBSET, + false, + false); + } + +} //end class -- cgit v1.2.3