diff options
author | rfeng <rfeng@13f79535-47bb-0310-9956-ffa450edef68> | 2009-09-28 19:15:06 +0000 |
---|---|---|
committer | rfeng <rfeng@13f79535-47bb-0310-9956-ffa450edef68> | 2009-09-28 19:15:06 +0000 |
commit | 822a4036d5db031c0e10d462a954581b837f36c6 (patch) | |
tree | 81c044e719908d99aa9b5756ef439d09a253c8bb /java | |
parent | 133d3e4ddc679410ecd8d154ec43f5ff40654d58 (diff) |
Start to copy builders from assembly module
git-svn-id: http://svn.us.apache.org/repos/asf/tuscany@819680 13f79535-47bb-0310-9956-ffa450edef68
Diffstat (limited to 'java')
21 files changed, 5711 insertions, 4 deletions
diff --git a/java/sca/modules/builder/src/main/java/org/apache/tuscany/sca/builder/impl/BaseBuilderImpl.java b/java/sca/modules/builder/src/main/java/org/apache/tuscany/sca/builder/impl/BaseBuilderImpl.java new file mode 100644 index 0000000000..e78c0c46d5 --- /dev/null +++ b/java/sca/modules/builder/src/main/java/org/apache/tuscany/sca/builder/impl/BaseBuilderImpl.java @@ -0,0 +1,705 @@ +/* + * 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.Map; + +import javax.xml.namespace.QName; +import javax.xml.parsers.DocumentBuilderFactory; +import javax.xml.transform.TransformerFactory; + +import org.apache.tuscany.sca.assembly.AssemblyFactory; +import org.apache.tuscany.sca.assembly.Component; +import org.apache.tuscany.sca.assembly.ComponentProperty; +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.Contract; +import org.apache.tuscany.sca.assembly.Implementation; +import org.apache.tuscany.sca.assembly.Property; +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.BuilderExtensionPoint; +import org.apache.tuscany.sca.assembly.builder.CompositeBuilder; +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.InterfaceContract; +import org.apache.tuscany.sca.interfacedef.InterfaceContractMapper; +import org.apache.tuscany.sca.monitor.Monitor; +import org.apache.tuscany.sca.monitor.Problem; +import org.apache.tuscany.sca.monitor.Problem.Severity; +import org.apache.tuscany.sca.policy.ExtensionType; +import org.apache.tuscany.sca.policy.PolicySubject; +import org.w3c.dom.Document; + +/** + * Base class for Builder implementations + * + * @version $Rev$ $Date$ + */ +public abstract class BaseBuilderImpl implements CompositeBuilder { + protected static final String SCA11_NS = "http://docs.oasis-open.org/ns/opencsa/sca/200903"; + protected static final String BINDING_SCA = "binding.sca"; + protected static final QName BINDING_SCA_QNAME = new QName(SCA11_NS, BINDING_SCA); + + protected AssemblyFactory assemblyFactory; + protected SCABindingFactory scaBindingFactory; + protected InterfaceContractMapper interfaceContractMapper; + protected DocumentBuilderFactory documentBuilderFactory; + protected TransformerFactory transformerFactory; + protected BuilderExtensionPoint builders; + + protected BaseBuilderImpl(BuilderExtensionPoint builders, + AssemblyFactory assemblyFactory, + SCABindingFactory scaBindingFactory, + DocumentBuilderFactory documentBuilderFactory, + TransformerFactory transformerFactory, + InterfaceContractMapper interfaceContractMapper) { + this.builders = builders; + this.assemblyFactory = assemblyFactory; + this.scaBindingFactory = scaBindingFactory; + this.documentBuilderFactory = documentBuilderFactory; + this.transformerFactory = transformerFactory; + this.interfaceContractMapper = interfaceContractMapper; + } + + /** + * Construct a builder from the extension point registry + * @param registry + */ + protected BaseBuilderImpl(ExtensionPointRegistry registry) { + this.builders = registry.getExtensionPoint(BuilderExtensionPoint.class); + FactoryExtensionPoint factoryExtensionPoint = registry.getExtensionPoint(FactoryExtensionPoint.class); + this.assemblyFactory = factoryExtensionPoint.getFactory(AssemblyFactory.class); + this.scaBindingFactory = factoryExtensionPoint.getFactory(SCABindingFactory.class); + this.documentBuilderFactory = factoryExtensionPoint.getFactory(DocumentBuilderFactory.class); + this.transformerFactory = factoryExtensionPoint.getFactory(TransformerFactory.class); + this.interfaceContractMapper = + registry.getExtensionPoint(UtilityExtensionPoint.class).getUtility(InterfaceContractMapper.class); + } + + /** + * Report a warning. + * + * @param monitor + * @param problems + * @param message + * @param model + */ + protected void warning(Monitor monitor, String message, Object model, Object... messageParameters) { + if (monitor != null) { + Problem problem = + monitor.createProblem(this.getClass().getName(), + "assembly-validation-messages", + Severity.WARNING, + model, + message, + messageParameters); + monitor.problem(problem); + } + } + + /** + * Report a error. + * + * @param monitor + * @param problems + * @param message + * @param model + */ + protected void error(Monitor monitor, String message, Object model, Object... messageParameters) { + if (monitor != null) { + Problem problem = + monitor.createProblem(this.getClass().getName(), + "assembly-validation-messages", + Severity.ERROR, + model, + message, + messageParameters); + monitor.problem(problem); + } + } + + /** + * Report a exception. + * + * @param problems + * @param message + * @param model + */ + protected void error(Monitor monitor, String message, Object model, Exception ex) { + if (monitor != null) { + Problem problem = null; + problem = + monitor.createProblem(this.getClass().getName(), + "assembly-validation-messages", + Severity.ERROR, + model, + message, + ex); + monitor.problem(problem); + } + } + + /** + * Index components inside a composite + * + * @param composite + * @param componentServices + + */ + protected void indexComponents(Composite composite, Map<String, Component> components) { + for (Component component : composite.getComponents()) { + // Index components by name + components.put(component.getName(), component); + } + } + + /** + * Index services inside a composite + * + * @param composite + * @param componentServices + */ + protected void indexServices(Composite composite, Map<String, ComponentService> componentServices) { + + for (Component component : composite.getComponents()) { + + ComponentService nonCallbackService = null; + int nonCallbackServiceCount = 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 there are + if (!componentService.isForCallback()) { + + if (nonCallbackServiceCount == 0) { + nonCallbackService = componentService; + } + nonCallbackServiceCount++; + } + } + if (nonCallbackServiceCount == 1) { + // If we have a single non callback service, index it by + // component name as well + componentServices.put(component.getName(), nonCallbackService); + } + } + } + + /** + * Index components, services and references inside a composite. + * @param composite + * @param components + * @param componentServices + * @param componentReferences + */ + protected void indexComponentsServicesAndReferences(Composite composite, + Map<String, Component> components, + Map<String, ComponentService> componentServices, + Map<String, ComponentReference> 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); + + // TODO - EPR - $promoted$ no longer used but it doesn't do any harm here + boolean promotedService = false; + if (componentService.getName() != null && componentService.getName().indexOf("$promoted$") > -1) { + promotedService = true; + } + + // count how many non-callback, non-promoted services there are + // if there is only one the component name also acts as the service name + if ((!componentService.isForCallback()) && (!promotedService)) { + + // 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); + } + } + } + + protected void indexComponentPropertiesServicesAndReferences(Component component, + Map<String, ComponentService> componentServices, + Map<String, ComponentReference> componentReferences, + Map<String, ComponentProperty> componentProperties, + Monitor monitor) { + for (ComponentService componentService : component.getServices()) { + if (componentServices.containsKey(componentService.getName())) { + // [MJE 13/05/2009] Changed to "error" since allowing these violates the OASIS spec + error(monitor, "DuplicateComponentServiceName", component, component.getName(), componentService + .getName()); + } else { + componentServices.put(componentService.getName(), componentService); + } + } + for (ComponentReference componentReference : component.getReferences()) { + if (componentReferences.containsKey(componentReference.getName())) { + // [MJE 13/05/2009] Changed to "error" since allowing these violates the OASIS spec + error(monitor, "DuplicateComponentReferenceName", component, component.getName(), componentReference + .getName()); + } else { + componentReferences.put(componentReference.getName(), componentReference); + } + } + for (ComponentProperty componentProperty : component.getProperties()) { + if (componentProperties.containsKey(componentProperty.getName())) { + // [MJE 13/05/2009] Changed to "error" since allowing these violates the OASIS spec + error(monitor, "DuplicateComponentPropertyName", component, component.getName(), componentProperty + .getName()); + } else { + componentProperties.put(componentProperty.getName(), componentProperty); + } + } + + } + + protected void indexImplementationPropertiesServicesAndReferences(Component component, + Map<String, Service> services, + Map<String, Reference> references, + Map<String, Property> properties, + Monitor monitor) { + // First check that the component has a resolved implementation + Implementation implementation = component.getImplementation(); + if (implementation == null) { + // A component must have an implementation + error(monitor, "NoComponentImplementation", component, component.getName()); + + } else if (implementation.isUnresolved()) { + + // The implementation must be fully resolved + error(monitor, "UnresolvedComponentImplementation", component, component.getName(), implementation.getURI()); + + } else { + + // Index properties, services and references, also check for + // duplicates + for (Property property : implementation.getProperties()) { + if (properties.containsKey(property.getName())) { + // [MJE 13/05/2009] Changed to "error" since allowing these violates the OASIS spec + error(monitor, "DuplicateImplementationPropertyName", component, component.getName(), property + .getName()); + } else { + properties.put(property.getName(), property); + } + } + for (Service service : implementation.getServices()) { + if (services.containsKey(service.getName())) { + // [MJE 13/05/2009] Changed to "error" since allowing these violates the OASIS spec + error(monitor, "DuplicateImplementationServiceName", component, component.getName(), service + .getName()); + } else { + services.put(service.getName(), service); + } + } + for (Reference reference : implementation.getReferences()) { + if (references.containsKey(reference.getName())) { + // [MJE 13/05/2009] Changed to "error" since allowing these violates the OASIS spec + error(monitor, "DuplicateImplementationReferenceName", component, component.getName(), reference + .getName()); + } else { + references.put(reference.getName(), reference); + } + } + } + + } + + /** + * Reconcile component properties and the properties defined by the + * component type. + * + * @param component + * @param properties + * @param componentProperties + * @param problems + */ + protected void reconcileProperties(Component component, + Map<String, Property> properties, + Map<String, ComponentProperty> componentProperties, + Monitor monitor) { + + // Connect component properties to their properties + for (ComponentProperty componentProperty : component.getProperties()) { + Property property = properties.get(componentProperty.getName()); + if (property != null) { + componentProperty.setProperty(property); + } else { + error(monitor, "PropertyNotFound", component, component.getName(), componentProperty.getName()); + } + } + + // Create component properties for all properties + if (component.getImplementation() != null) { + for (Property property : component.getImplementation().getProperties()) { + if (!componentProperties.containsKey(property.getName())) { + ComponentProperty componentProperty = assemblyFactory.createComponentProperty(); + componentProperty.setName(property.getName()); + componentProperty.setValue(property.getValue()); + componentProperty.setMany(property.isMany()); + componentProperty.setMustSupply(property.isMustSupply()); + componentProperty.setXSDElement(property.getXSDElement()); + componentProperty.setXSDType(property.getXSDType()); + componentProperty.setProperty(property); + component.getProperties().add(componentProperty); + } + } + } + + // Reconcile component properties and their properties + for (ComponentProperty componentProperty : component.getProperties()) { + Property property = componentProperty.getProperty(); + if (property != null) { + + // Check that a component property does not override the + // mustSupply attribute + if (!property.isMustSupply() && componentProperty.isMustSupply()) { + warning(monitor, + "PropertyMustSupplyIncompatible", + component, + component.getName(), + componentProperty.getName()); + } + + // Default to the mustSupply attribute specified on the property + if (!componentProperty.isMustSupply()) + componentProperty.setMustSupply(property.isMustSupply()); + + // Default to the value specified on the component type property + if (!isPropertyValueSet(componentProperty)) { + componentProperty.setValue(property.getValue()); + } + + // Override the property value for the composite + if (component.getImplementation() instanceof Composite) { + property.setValue(componentProperty.getValue()); + } + + // Check that a value is supplied + if (!isPropertyValueSet(componentProperty) && property.isMustSupply()) { + error(monitor, "PropertyMustSupplyNull", component, component.getName(), componentProperty + .getName()); + } + + // Check that a component property does not override the + // many attribute + if (!property.isMany() && componentProperty.isMany()) { + + warning(monitor, "PropertyOverrideManyAttribute", component, component.getName(), componentProperty + .getName()); + } + + // Default to the many attribute defined on the property + componentProperty.setMany(property.isMany()); + + // Default to the type and element defined on the property + if (componentProperty.getXSDType() == null) { + componentProperty.setXSDType(property.getXSDType()); + } + if (componentProperty.getXSDElement() == null) { + componentProperty.setXSDElement(property.getXSDElement()); + } + + // Check that a type or element are specified + if (componentProperty.getXSDElement() == null && componentProperty.getXSDType() == null) { + warning(monitor, "NoTypeForComponentProperty", component, component.getName(), componentProperty + .getName()); + } + } + } + } + + /** + * Look to see if any value elements have been set into the property + * A bit involved as the value is stored as a DOM Document + * + * @param property the property to be tested + * @return true is values are present + */ + private boolean isPropertyValueSet(Property property) { + Document value = (Document)property.getValue(); + + if (value == null) { + return false; + } + + if (value.getFirstChild() == null) { + return false; + } + + if (value.getFirstChild().getChildNodes().getLength() == 0) { + return false; + } + + return true; + } + + /** + * Reconcile component references with the references defined on the + * component type. + * + * @param component + * @param references + * @param componentReferences + * @param monitor + */ + protected void reconcileReferences(Component component, + Map<String, Reference> references, + Map<String, ComponentReference> componentReferences, + Monitor monitor) { + + // Connect each component reference to the corresponding reference + for (ComponentReference componentReference : component.getReferences()) { + if (componentReference.getReference() != null || componentReference.isForCallback()) { + continue; + } + Reference reference = references.get(componentReference.getName()); + if (reference != null) { + componentReference.setReference(reference); + } else { + if (!componentReference.getName().startsWith("$self$.")) { + error(monitor, "ReferenceNotFound", component, component.getName(), componentReference.getName()); + } + } + } + + // Create a Component reference for each reference for which there is no declared Component reference + if (component.getImplementation() != null) { + for (Reference reference : component.getImplementation().getReferences()) { + if (!componentReferences.containsKey(reference.getName())) { + ComponentReference componentReference = assemblyFactory.createComponentReference(); + componentReference.setForCallback(reference.isForCallback()); + componentReference.setName(reference.getName()); + componentReference.setReference(reference); + component.getReferences().add(componentReference); + } + } + } + + // Reconcile each component reference with its reference + for (ComponentReference componentReference : component.getReferences()) { + Reference reference = componentReference.getReference(); + if (reference != null) { + // Reconcile multiplicity + if (componentReference.getMultiplicity() != null) { + if (!ReferenceConfigurationUtil.isValidMultiplicityOverride(reference.getMultiplicity(), + componentReference.getMultiplicity())) { + error(monitor, + "ReferenceIncompatibleMultiplicity", + component, + component.getName(), + componentReference.getName()); + } + } else { + componentReference.setMultiplicity(reference.getMultiplicity()); + } + + // Reconcile interface + InterfaceContract interfaceContract = reference.getInterfaceContract(); + if (componentReference.getInterfaceContract() != null) { + if (interfaceContract != null && !componentReference.getInterfaceContract().equals(reference + .getInterfaceContract())) { + if (!interfaceContractMapper.isCompatible(interfaceContract, componentReference + .getInterfaceContract())) { + error(monitor, + "ReferenceIncompatibleComponentInterface", + component, + component.getName(), + componentReference.getName()); + } + } + } else { + componentReference.setInterfaceContract(interfaceContract); + } + + // Reconcile bindings + if (componentReference.getBindings().isEmpty()) { + componentReference.getBindings().addAll(reference.getBindings()); + } + + // Reconcile callback bindings + if (componentReference.getCallback() == null) { + componentReference.setCallback(reference.getCallback()); + if (componentReference.getCallback() == null) { + // Create an empty callback to avoid null check + componentReference.setCallback(assemblyFactory.createCallback()); + } + + } else if (componentReference.getCallback().getBindings().isEmpty() && reference.getCallback() != null) { + componentReference.getCallback().getBindings().addAll(reference.getCallback().getBindings()); + } + + // Propagate autowire setting from the component + if (componentReference.getAutowire() == null) { + componentReference.setAutowire(component.getAutowire()); + } + + // Reconcile targets + if (componentReference.getTargets().isEmpty()) { + componentReference.getTargets().addAll(reference.getTargets()); + } + } + } + } + + /** + * Reconcile component services and services defined on the component type. + * + * @param component + * @param services + * @param componentServices + * @param monitor + */ + protected void reconcileServices(Component component, + Map<String, Service> services, + Map<String, ComponentService> componentServices, + Monitor monitor) { + + // Connect each component service to the corresponding service + for (ComponentService componentService : component.getServices()) { + if (componentService.getService() != null || componentService.isForCallback()) { + continue; + } + Service service = services.get(componentService.getName()); + if (service != null) { + componentService.setService(service); + } else { + warning(monitor, "ServiceNotFoundForComponentService", component, component.getName(), componentService + .getName()); + } + } + + // Create a component service for each service + if (component.getImplementation() != null) { + for (Service service : component.getImplementation().getServices()) { + if (!componentServices.containsKey(service.getName())) { + ComponentService componentService = assemblyFactory.createComponentService(); + componentService.setForCallback(service.isForCallback()); + String name = service.getName(); + componentService.setName(name); + componentService.setService(service); + component.getServices().add(componentService); + componentServices.put(name, componentService); + } + } + } + + //Reconcile each component service with its service + for (ComponentService componentService : component.getServices()) { + Service service = componentService.getService(); + if (service != null) { + // Reconcile interface + InterfaceContract interfaceContract = service.getInterfaceContract(); + if (componentService.getInterfaceContract() != null) { + if (interfaceContract != null && !componentService.getInterfaceContract().equals(interfaceContract)) { + if (!interfaceContractMapper.isCompatible(componentService.getInterfaceContract(), + interfaceContract)) { + // MJE, 16/05/2009 - Upgraded from "warning" to "error" since this is a fatal problem - TUSCANY-3036 + error(monitor, + "ServiceIncompatibleComponentInterface", + component, + component.getName(), + componentService.getName()); + } + } + } else { + componentService.setInterfaceContract(interfaceContract); + } + + // Reconcile bindings + if (componentService.getBindings().isEmpty()) { + componentService.getBindings().addAll(service.getBindings()); + } + + // Reconcile callback bindings + if (componentService.getCallback() == null) { + componentService.setCallback(service.getCallback()); + if (componentService.getCallback() == null) { + // Create an empty callback to avoid null check + componentService.setCallback(assemblyFactory.createCallback()); + } + } else if (componentService.getCallback().getBindings().isEmpty() && service.getCallback() != null) { + componentService.getCallback().getBindings().addAll(service.getCallback().getBindings()); + } + } + } + } + + protected void attachSCABinding(Contract contract, Definitions definitions) { + if (!contract.getBindings().isEmpty()) { + contract.setOverridingBindings(true); + // No need to set binding.sca + return; + } + contract.setOverridingBindings(false); + + // Only add binding.sca for services + // FIXME: The latest OASIS spec only adds binding.sca to services + /* + if (!(contract instanceof Service)) { + return; + } + */ + SCABinding scaBinding = scaBindingFactory.createSCABinding(); + + if (definitions != null) { + for (ExtensionType attachPointType : definitions.getBindingTypes()) { + if (attachPointType.getType().equals(BINDING_SCA_QNAME)) { + ((PolicySubject)scaBinding).setExtensionType(attachPointType); + } + } + } + + contract.getBindings().add(scaBinding); + } +} diff --git a/java/sca/modules/builder/src/main/java/org/apache/tuscany/sca/builder/impl/BindingURIBuilderImpl.java b/java/sca/modules/builder/src/main/java/org/apache/tuscany/sca/builder/impl/BindingURIBuilderImpl.java new file mode 100644 index 0000000000..88b5c126fc --- /dev/null +++ b/java/sca/modules/builder/src/main/java/org/apache/tuscany/sca/builder/impl/BindingURIBuilderImpl.java @@ -0,0 +1,509 @@ +/* + * 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.net.URI; +import java.net.URISyntaxException; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import javax.xml.namespace.QName; + +import org.apache.tuscany.sca.assembly.Binding; +import org.apache.tuscany.sca.assembly.Component; +import org.apache.tuscany.sca.assembly.ComponentReference; +import org.apache.tuscany.sca.assembly.ComponentService; +import org.apache.tuscany.sca.assembly.Composite; +import org.apache.tuscany.sca.assembly.Contract; +import org.apache.tuscany.sca.assembly.Implementation; +import org.apache.tuscany.sca.assembly.Reference; +import org.apache.tuscany.sca.assembly.Service; +import org.apache.tuscany.sca.assembly.builder.CompositeBuilderException; +import org.apache.tuscany.sca.core.ExtensionPointRegistry; +import org.apache.tuscany.sca.core.UtilityExtensionPoint; +import org.apache.tuscany.sca.definitions.Definitions; +import org.apache.tuscany.sca.monitor.Monitor; +import org.apache.tuscany.sca.monitor.MonitorFactory; + +/** + * Configuration of binding URIs. + * + * @version $Rev$ $Date$ + */ +public class BindingURIBuilderImpl { + + private Monitor monitor; + + public BindingURIBuilderImpl(ExtensionPointRegistry registry) { + UtilityExtensionPoint utilities = registry.getExtensionPoint(UtilityExtensionPoint.class); + MonitorFactory monitorFactory = utilities.getUtility(MonitorFactory.class); + monitor = monitorFactory.createMonitor(); + } + + /** + * Called by CompositeBindingURIBuilderImpl + * + * @param composite the composite to be configured + */ + protected void configureBindingURIsAndNames(Composite composite, Definitions definitions, Monitor monitor) + throws CompositeBuilderException { + configureBindingURIs(composite, null, definitions, null, monitor); + configureBindingNames(composite, monitor); + } + + /** + * Fully resolve the binding URIs based on available information. This includes information + * from the ".composite" files, from resources associated with the binding, e.g. WSDL files, + * from any associated policies and from the default information for each binding type. + * + * @param composite the composite to be configured + * @param defaultBindings list of default binding configurations + */ + protected void configureBindingURIs(Composite composite, + Definitions definitions, + Map<QName, List<String>> defaultBindings, + Monitor monitor) throws CompositeBuilderException { + configureBindingURIs(composite, null, definitions, defaultBindings, monitor); + } + + /** + * Fully resolve the binding URIs based on available information. This includes information + * from the ".composite" files, from resources associated with the binding, e.g. WSDL files, + * from any associated policies and from the default information for each binding type. + * + * NOTE: This method repeats some of the processing performed by the configureComponents() + * method above. The duplication is needed because NodeConfigurationServiceImpl + * calls this method without previously calling configureComponents(). In the + * normal builder sequence used by CompositeBuilderImpl, both of these methods + * are called. + * + * TODO: Share the URL calculation algorithm with the configureComponents() method above + * although keeping the configureComponents() methods signature as is because when + * a composite is actually build in a node the node default information is currently + * available + * + * @param composite the composite to be configured + * @param uri the path to the composite provided through any nested composite component implementations + * @param defaultBindings list of default binding configurations + */ + private void configureBindingURIs(Composite composite, + String uri, + Definitions definitions, + Map<QName, List<String>> defaultBindings, + Monitor monitor) throws CompositeBuilderException { + + String parentComponentURI = uri; + + monitor.pushContext("Composite: " + composite.getName().toString()); + try { + // Process nested composites recursively + for (Component component : composite.getComponents()) { + + // Initialize component URI + String componentURI; + if (parentComponentURI == null) { + componentURI = component.getName(); + } else { + componentURI = URI.create(parentComponentURI + '/').resolve(component.getName()).toString(); + } + component.setURI(componentURI); + + Implementation implementation = component.getImplementation(); + if (implementation instanceof Composite) { + // Process nested composite + configureBindingURIs((Composite)implementation, componentURI, definitions, defaultBindings, monitor); + } + } + + // Initialize composite service binding URIs + List<Service> compositeServices = composite.getServices(); + for (Service service : compositeServices) { + + constructBindingNames(service, monitor); + + // Initialize binding names and URIs + for (Binding binding : service.getBindings()) { + constructBindingURI(parentComponentURI, composite, service, binding, defaultBindings, monitor); + } + } + + // Initialize component service binding URIs + for (Component component : composite.getComponents()) { + + monitor.pushContext("Component: " + component.getName()); + + try { + + for (ComponentService service : component.getServices()) { + + constructBindingNames(service, monitor); + + // Initialize binding names and URIs + for (Binding binding : service.getBindings()) { + constructBindingURI(component, service, binding, defaultBindings, monitor); + } + } + } finally { + monitor.popContext(); + } + } + } finally { + monitor.popContext(); + } + } + + /** + * Add default names for callback bindings and reference bindings. Needs to be + * separate from configureBindingURIs() because configureBindingURIs() is called + * by NodeConfigurationServiceImpl as well as by CompositeBuilderImpl. + */ + private void configureBindingNames(Composite composite, Monitor monitor) { + + // Process nested composites recursively + for (Component component : composite.getComponents()) { + + Implementation implementation = component.getImplementation(); + if (implementation instanceof Composite) { + + // Process nested composite + configureBindingNames((Composite)implementation, monitor); + } + } + + // Initialize composite service callback binding names + for (Service service : composite.getServices()) { + constructBindingNames(service, monitor); + } + + // Initialize composite reference binding names + for (Reference reference : composite.getReferences()) { + constructBindingNames(reference, monitor); + } + + // Initialize component service and reference binding names + for (Component component : composite.getComponents()) { + + // Initialize component service callback binding names + for (ComponentService service : component.getServices()) { + constructBindingNames(service, monitor); + } + + // Initialize component reference binding names + for (ComponentReference reference : component.getReferences()) { + // Initialize binding names + constructBindingNames(reference, monitor); + } + } + } + + /** + * If a binding name is not provided by the user, construct it based on the service + * or reference name + * + * @param contract the service or reference + */ + private void constructBindingNames(Contract contract, Monitor monitor) { + List<Binding> bindings = contract.getBindings(); + Map<String, Binding> bindingMap = new HashMap<String, Binding>(); + for (Binding binding : bindings) { + // set the default binding name if one is required + // if there is no name on the binding then set it to the service or reference name + if (binding.getName() == null) { + binding.setName(contract.getName()); + } + Binding existed = bindingMap.put(binding.getName(), binding); + // Check that multiple bindings do not have the same name + if (existed != null && existed != binding) { + if (contract instanceof Service) { + Monitor.error(monitor, this, "assembly-validation-messages", "MultipleBindingsForService", contract + .getName(), binding.getName()); + } else { + Monitor.error(monitor, + this, + "assembly-validation-messages", + "MultipleBindingsForReference", + contract.getName(), + binding.getName()); + } + } + } + + if (contract.getCallback() != null) { + bindings = contract.getCallback().getBindings(); + bindingMap.clear(); + for (Binding binding : bindings) { + // set the default binding name if one is required + // if there is no name on the binding then set it to the service or reference name + if (binding.getName() == null) { + binding.setName(contract.getName()); + } + Binding existed = bindingMap.put(binding.getName(), binding); + // Check that multiple bindings do not have the same name + if (existed != null && existed != binding) { + if (contract instanceof Service) { + Monitor.error(monitor, + this, + "assembly-validation-messages", + "MultipleBindingsForServiceCallback", + contract.getName(), + binding.getName()); + } else { + Monitor.error(monitor, + this, + "assembly-validation-messages", + "MultipleBindingsForReferenceCallback", + contract.getName(), + binding.getName()); + } + } + } + } + } + + /** + * URI construction for composite bindings based on Assembly Specification section 1.7.2, This method + * assumes that the component URI part of the binding URI is formed from the part to the + * composite in question and just calls the generic constructBindingURI method with this + * information + * + * @param parentComponentURI + * @param composite + * @param service + * @param binding + * @param defaultBindings + */ + private void constructBindingURI(String parentComponentURI, + Composite composite, + Service service, + Binding binding, + Map<QName, List<String>> defaultBindings, + Monitor monitor) throws CompositeBuilderException { + // This is a composite service so there is no component to provide a component URI + // The path to this composite (through nested composites) is used. + constructBindingURI(parentComponentURI, service, binding, defaultBindings, monitor); + } + + /** + * URI construction for component bindings based on Assembly Specification section 1.7.2. This method + * calculates the component URI part based on component information before calling the generic + * constructBindingURI method + * + * @param component the component that holds the service + * @param service the service that holds the binding + * @param binding the binding for which the URI is being constructed + * @param defaultBindings the list of default binding configurations + */ + private void constructBindingURI(Component component, + Service service, + Binding binding, + Map<QName, List<String>> defaultBindings, + Monitor monitor) throws CompositeBuilderException { + constructBindingURI(component.getURI(), service, binding, defaultBindings, monitor); + } + + /** + * Generic URI construction for bindings based on Assembly Specification section 1.7.2 + * + * @param componentURIString the string version of the URI part that comes from the component name + * @param service the service in question + * @param binding the binding for which the URI is being constructed + * @param includeBindingName when set true the serviceBindingURI part should be used + * @param defaultBindings the list of default binding configurations + * @throws CompositeBuilderException + */ + private void constructBindingURI(String componentURIString, + Service service, + Binding binding, + Map<QName, List<String>> defaultBindings, + Monitor monitor) throws CompositeBuilderException { + + try { + + boolean includeBindingName = !service.getName().equals(binding.getName()); + + // calculate the service binding URI + URI bindingURI; + if (binding.getURI() != null) { + bindingURI = new URI(binding.getURI()); + + // if the user has provided an absolute binding URI then use it + if (bindingURI.isAbsolute()) { + binding.setURI(bindingURI.toString()); + return; + } + } else { + bindingURI = null; + } + + String serviceName = service.getName(); + // Get the service binding name + String bindingName; + if (binding.getName() != null) { + bindingName = binding.getName(); + } else { + bindingName = serviceName; + } + + // calculate the component URI + URI componentURI; + if (componentURIString != null) { + componentURI = new URI(addSlashToPath(componentURIString)); + } else { + componentURI = null; + } + + // if the user has provided an absolute component URI then use it + if (componentURI != null && componentURI.isAbsolute()) { + binding.setURI(constructBindingURI(null, + componentURI, + bindingURI, + serviceName, + includeBindingName, + bindingName)); + return; + } + + // calculate the base URI + URI baseURI = null; + if (defaultBindings != null) { + List<String> uris = defaultBindings.get(binding.getType()); + if (uris != null && uris.size() > 0) { + baseURI = new URI(addSlashToPath(uris.get(0))); + } + } + + binding.setURI(constructBindingURI(baseURI, + componentURI, + bindingURI, + serviceName, + includeBindingName, + bindingName)); + } catch (URISyntaxException ex) { + Monitor.error(monitor, + this, + "assembly-validation-messages", + "URLSyntaxException", + componentURIString, + service.getName(), + binding.getName()); + } + } + + /** + * Use to ensure that URI paths end in "/" as here we want to maintain the + * last path element of an base URI when other URI are resolved against it. This is + * not the default behaviour of URI resolution as defined in RFC 2369 + * + * @param path the path string to which the "/" is to be added + * @return the resulting path with a "/" added if it not already there + */ + private static String addSlashToPath(String path) { + if (path.endsWith("/") || path.endsWith("#")) { + return path; + } else { + return path + "/"; + } + } + + /** + * Concatenate binding URI parts together based on Assembly Specification section 1.7.2 + * + * @param baseURI the base of the binding URI + * @param componentURI the middle part of the binding URI derived from the component name + * @param bindingURI the end part of the binding URI + * @param includeBindingName when set true the binding name part should be used + * @param bindingName the binding name + * @return the resulting URI as a string + */ + private static String constructBindingURI(URI baseURI, + URI componentURI, + URI bindingURI, + String serviceName, + boolean includeBindingName, + String bindingName) { + String name = includeBindingName ? serviceName + "/" + bindingName : serviceName; + String uriString; + + if (baseURI == null) { + if (componentURI == null) { + if (bindingURI != null) { + uriString = name + "/" + bindingURI.toString(); + } else { + uriString = name; + } + } else { + if (bindingURI != null) { + if (bindingURI.toString().startsWith("/")) { + uriString = componentURI.resolve(bindingURI).toString(); + } else { + uriString = componentURI.resolve(name + "/" + bindingURI).toString(); + } + } else { + uriString = componentURI.resolve(name).toString(); + } + } + } else { + if (componentURI == null) { + if (bindingURI != null) { + uriString = basedURI(baseURI, bindingURI).toString(); + } else { + uriString = basedURI(baseURI, URI.create(name)).toString(); + } + } else { + if (bindingURI != null) { + uriString = basedURI(baseURI, componentURI.resolve(bindingURI)).toString(); + } else { + uriString = basedURI(baseURI, componentURI.resolve(name)).toString(); + } + } + } + + // tidy up by removing any trailing "/" + if (uriString.endsWith("/")) { + uriString = uriString.substring(0, uriString.length() - 1); + } + + URI uri = URI.create(uriString); + if (!uri.isAbsolute()) { + uri = URI.create("/").resolve(uri); + } + return uri.toString(); + } + + /** + * Combine a URI with a base URI. + * + * @param baseURI + * @param uri + * @return + */ + private static URI basedURI(URI baseURI, URI uri) { + if (uri.getScheme() != null) { + return uri; + } + String str = uri.toString(); + if (str.startsWith("/")) { + str = str.substring(1); + } + return URI.create(baseURI.toString() + str).normalize(); + } + +} diff --git a/java/sca/modules/builder/src/main/java/org/apache/tuscany/sca/builder/impl/ComponentBuilderImpl.java b/java/sca/modules/builder/src/main/java/org/apache/tuscany/sca/builder/impl/ComponentBuilderImpl.java new file mode 100644 index 0000000000..eac88b88b5 --- /dev/null +++ b/java/sca/modules/builder/src/main/java/org/apache/tuscany/sca/builder/impl/ComponentBuilderImpl.java @@ -0,0 +1,1001 @@ +/* + * 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.io.InputStream; +import java.net.URI; +import java.net.URL; +import java.net.URLConnection; + +import javax.xml.namespace.QName; +import javax.xml.parsers.DocumentBuilderFactory; +import javax.xml.parsers.ParserConfigurationException; +import javax.xml.transform.Source; +import javax.xml.transform.TransformerFactory; +import javax.xml.transform.dom.DOMResult; +import javax.xml.transform.sax.SAXSource; +import javax.xml.xpath.XPathConstants; +import javax.xml.xpath.XPathExpression; +import javax.xml.xpath.XPathExpressionException; + +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.ComponentProperty; +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.CompositeService; +import org.apache.tuscany.sca.assembly.Contract; +import org.apache.tuscany.sca.assembly.Implementation; +import org.apache.tuscany.sca.assembly.Multiplicity; +import org.apache.tuscany.sca.assembly.Property; +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.BuilderExtensionPoint; +import org.apache.tuscany.sca.assembly.builder.ImplementationBuilder; +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.InterfaceContract; +import org.apache.tuscany.sca.interfacedef.InterfaceContractMapper; +import org.apache.tuscany.sca.monitor.Monitor; +import org.apache.tuscany.sca.monitor.MonitorFactory; +import org.apache.tuscany.sca.policy.ExtensionType; +import org.apache.tuscany.sca.policy.PolicySubject; +import org.w3c.dom.Document; +import org.w3c.dom.Element; +import org.w3c.dom.Node; +import org.xml.sax.InputSource; + +/** + * @version $Rev$ $Date$ + */ +public class ComponentBuilderImpl { + protected static final String SCA11_NS = "http://docs.oasis-open.org/ns/opencsa/sca/200903"; + protected static final String BINDING_SCA = "binding.sca"; + protected static final QName BINDING_SCA_QNAME = new QName(SCA11_NS, BINDING_SCA); + + private CompositeComponentTypeBuilderImpl componentTypeBuilder; + private Monitor monitor; + private AssemblyFactory assemblyFactory; + private SCABindingFactory scaBindingFactory; + private DocumentBuilderFactory documentBuilderFactory; + protected TransformerFactory transformerFactory; + private InterfaceContractMapper interfaceContractMapper; + private BuilderExtensionPoint builders; + + public ComponentBuilderImpl(ExtensionPointRegistry registry) { + UtilityExtensionPoint utilities = registry.getExtensionPoint(UtilityExtensionPoint.class); + MonitorFactory monitorFactory = utilities.getUtility(MonitorFactory.class); + monitor = monitorFactory.createMonitor(); + + FactoryExtensionPoint modelFactories = registry.getExtensionPoint(FactoryExtensionPoint.class); + assemblyFactory = modelFactories.getFactory(AssemblyFactory.class); + scaBindingFactory = modelFactories.getFactory(SCABindingFactory.class); + documentBuilderFactory = modelFactories.getFactory(DocumentBuilderFactory.class); + transformerFactory = modelFactories.getFactory(TransformerFactory.class); + + interfaceContractMapper = utilities.getUtility(InterfaceContractMapper.class); + + builders = registry.getExtensionPoint(BuilderExtensionPoint.class); + } + + public void setComponentTypeBuilder(CompositeComponentTypeBuilderImpl componentTypeBuilder) { + this.componentTypeBuilder = componentTypeBuilder; + } + + /** + * Configure the component based on its component type using OASIS rules + * + * @Param parentComposite the composite that contains the component being configured. Required for property processing + * @param component the component to be configured + */ + public void configureComponentFromComponentType(Composite parentComposite, Component component) { + + // do any work we need to do before we calculate the component type + // for this component. Anything that needs to be pushed down the promotion + // hierarchy must be done before we calculate the component type + + // first carry out any implementation specific builder processing + Implementation impl = component.getImplementation(); + if (impl != null) { + ImplementationBuilder builder = builders.getImplementationBuilder(impl.getClass()); + if (builder != null) { + builder.build(component, impl, monitor); + } + } + + // Properties on the composite component type are not affected by the components + // that the composite contains. Instead the child components might source + // composite level property values. Hence we have to calculate whether the component + // type property value should be overridden by this component's property value + // before we go ahead and calculate the component type + configureProperties(parentComposite, component); + + // create the component type for this component + // taking any nested composites into account + createComponentType(component); + + // configure services based on the calculated component type + configureServices(component); + + // configure services based on the calculated component type + configureReferences(component); + } + + /** + * Use the component type builder to build the component type for + * this component. + * + * @param component + */ + private void createComponentType(Component component) { + Implementation implementation = component.getImplementation(); + if (implementation instanceof Composite) { + componentTypeBuilder.createComponentType((Composite)implementation); + } + } + + /** + * Configure this component's services based on the services in its + * component type and the configuration from the composite file + * + * @param component + */ + private void configureServices(Component component) { + + // If the component type has services that are not described in this + // component then create services for this component + addServicesFromComponentType(component); + + // Connect this component's services to the + // services from its component type + connectServicesToComponentType(component); + + // look at each component service in turn and calculate its + // configuration based on OASIS rules + for (ComponentService componentService : component.getServices()) { + Service componentTypeService = componentService.getService(); + + if (componentTypeService == null) { + // raise error? + // can be null in some of the assembly-xml unit tests + continue; + } + + // interface contracts + calculateInterfaceContract(componentService, componentTypeService); + + // bindings + calculateBindings(componentService, componentTypeService); + + // add callback reference model objects + createCallbackReference(component, componentService); + + // intents - done later in CompositePolicyBuilder - discuss with RF + //calculateIntents(componentService, + // componentTypeService); + + // policy sets - done later in CompositePolicyBuilder - discuss with RF + // calculatePolicySets(componentService, + // componentTypeService); + + } + } + + /** + * Configure this component's references based on the references in its + * component type and the configuration from the composite file + * + * @param component + */ + private void configureReferences(Component component) { + + // If the component type has references that are not described in this + // component then create references for this component + addReferencesFromComponentType(component); + + // Connect this component's references to the + // references from its component type + connectReferencesToComponentType(component); + + // look at each component reference in turn and calculate its + // configuration based on OASIS rules + for (ComponentReference componentReference : component.getReferences()) { + Reference componentTypeReference = componentReference.getReference(); + + if (componentTypeReference == null) { + // raise error? + // can be null in some of the assembly-xml unit tests + continue; + } + + // reference multiplicity + reconcileReferenceMultiplicity(component, componentReference, componentTypeReference); + + // interface contracts + calculateInterfaceContract(componentReference, componentTypeReference); + + // bindings + // We don't have to do anything with reference bindings. You've either + // specified one or you haven't + //calculateBindings(componentService, + // componentTypeService); + + // add callback service model objects + createCallbackService(component, componentReference); + + // intents - done later in CompositePolicyBuilder - discuss with RF + //calculateIntents(componentService, + // componentTypeService); + + // policy sets - done later in CompositePolicyBuilder - discuss with RF + // calculatePolicySets(componentService, + // componentTypeService); + + // Propagate autowire setting from the component down the structural + // hierarchy + if (componentReference.getAutowire() == null) { + componentReference.setAutowire(component.getAutowire()); + } + + // Reconcile targets copying then up the promotion hierarchy + if (componentReference.getTargets().isEmpty()) { + componentReference.getTargets().addAll(componentTypeReference.getTargets()); + } + + } + } + + /** + * Configure this component's properties based on the properties in its + * component type and the configuration from the composite file + * + * @param component + */ + private void configureProperties(Composite parentComposite, Component component) { + // If the component type has properties that are not described in this + // component then create properties for this component + addPropertiesFromComponentType(component); + + // Connect this component's properties to the + // properties from its component type + connectReferencesToComponentType(component); + + // Reconcile component properties and their component type properties + for (ComponentProperty componentProperty : component.getProperties()) { + reconcileComponentPropertyWithComponentType(component, componentProperty); + + // configure the property value based on the @source attribute + // At the moment this is done in the parent composite component + // type calculation a + processPropertySourceAttribute(parentComposite, component, componentProperty); + + // configure the property value based on the @file attribute + processPropertyFileAttribute(component, componentProperty); + } + } + + private void addServicesFromComponentType(Component component) { + + // Create a component service for each service + if (component.getImplementation() != null) { + for (Service service : component.getImplementation().getServices()) { + ComponentService componentService = (ComponentService)component.getService(service.getName()); + + // if the component doesn't have a service with the same name as the + // component type service then create one + if (componentService == null) { + componentService = assemblyFactory.createComponentService(); + componentService.setForCallback(service.isForCallback()); + String name = service.getName(); + componentService.setName(name); + component.getServices().add(componentService); + } + } + } + } + + private void addReferencesFromComponentType(Component component) { + + // Create a component reference for each reference + if (component.getImplementation() != null) { + for (Reference reference : component.getImplementation().getReferences()) { + ComponentReference componentReference = (ComponentReference)component.getReference(reference.getName()); + + // if the component doesn't have a reference with the same name as the + // component type reference then create one + if (componentReference == null) { + componentReference = assemblyFactory.createComponentReference(); + componentReference.setForCallback(reference.isForCallback()); + componentReference.setName(reference.getName()); + componentReference.setReference(reference); + component.getReferences().add(componentReference); + } + } + } + } + + private void addPropertiesFromComponentType(Component component) { + + // Create component property for each property + if (component.getImplementation() != null) { + for (Property property : component.getImplementation().getProperties()) { + ComponentProperty componentProperty = (ComponentProperty)component.getProperty(property.getName()); + + // if the component doesn't have a property with the same name as + // the component type property then create one + if (componentProperty == null) { + componentProperty = assemblyFactory.createComponentProperty(); + componentProperty.setName(property.getName()); + componentProperty.setValue(property.getValue()); + componentProperty.setMany(property.isMany()); + componentProperty.setMustSupply(property.isMustSupply()); + componentProperty.setXSDElement(property.getXSDElement()); + componentProperty.setXSDType(property.getXSDType()); + componentProperty.setProperty(property); + component.getProperties().add(componentProperty); + } + } + } + } + + private void connectServicesToComponentType(Component component) { + + // Connect each component service to the corresponding component type service + for (ComponentService componentService : component.getServices()) { + if (componentService.getService() != null || componentService.isForCallback()) { + continue; + } + + if (component.getImplementation() == null) { + // is null in some of our basic unit tests + continue; + } + + Service service = component.getImplementation().getService(componentService.getName()); + + if (service != null) { + componentService.setService(service); + } else { + Monitor.error(monitor, + this, + "assembly-validation-messages", + "ServiceNotFoundForComponentService", + component.getName(), + componentService.getName()); + } + } + } + + private void connectReferencesToComponentType(Component component) { + + // Connect each component reference to the corresponding component type reference + for (ComponentReference componentReference : component.getReferences()) { + if (componentReference.getReference() != null || componentReference.isForCallback()) { + continue; + } + + if (component.getImplementation() == null) { + // is null in some of our basic unit tests + continue; + } + + Reference reference = component.getImplementation().getReference(componentReference.getName()); + + if (reference != null) { + componentReference.setReference(reference); + } else { + Monitor.error(monitor, + this, + "assembly-validation-messages", + "ReferenceNotFoundForComponentReference", + component.getName(), + componentReference.getName()); + } + } + } + + private void connectPropertiesToComponentType(Component component) { + // Connect each component property to the corresponding component type property + for (ComponentProperty componentProperty : component.getProperties()) { + Property property = component.getImplementation().getProperty(componentProperty.getName()); + if (property != null) { + componentProperty.setProperty(property); + } else { + Monitor.error(monitor, + this, + "assembly-validation-messages", + "PropertyNotFound", + component.getName(), + componentProperty.getName()); + } + } + } + + private void reconcileReferenceMultiplicity(Component component, + Reference componentReference, + Reference componentTypeReference) { + if (componentReference.getMultiplicity() != null) { + if (!isValidMultiplicityOverride(componentTypeReference.getMultiplicity(), componentReference + .getMultiplicity())) { + Monitor.error(monitor, + this, + "assembly-validation-messages", + "ReferenceIncompatibleMultiplicity", + component.getName(), + componentReference.getName()); + } + } else { + componentReference.setMultiplicity(componentTypeReference.getMultiplicity()); + } + } + + private void reconcileComponentPropertyWithComponentType(Component component, ComponentProperty componentProperty) { + Property componentTypeProperty = componentProperty.getProperty(); + if (componentTypeProperty != null) { + + // Check that a component property does not override the + // mustSupply attribute + if (!componentTypeProperty.isMustSupply() && componentProperty.isMustSupply()) { + Monitor.error(monitor, + this, + "assembly-validation-messages", + "PropertyMustSupplyIncompatible", + component.getName(), + componentProperty.getName()); + } + + // Default to the mustSupply attribute specified on the property + if (!componentProperty.isMustSupply()) + componentProperty.setMustSupply(componentTypeProperty.isMustSupply()); + + // Default to the value specified on the component type property + if (!isPropertyValueSet(componentProperty)) { + componentProperty.setValue(componentTypeProperty.getValue()); + } + + // Override the property value for the composite + if (component.getImplementation() instanceof Composite) { + componentTypeProperty.setValue(componentProperty.getValue()); + } + + // Check that a value is supplied + if (!isPropertyValueSet(componentProperty) && componentTypeProperty.isMustSupply()) { + Monitor.error(monitor, this, "assembly-validation-messages", "PropertyMustSupplyNull", component + .getName(), componentProperty.getName()); + } + + // Check that a component property does not override the + // many attribute + if (!componentTypeProperty.isMany() && componentProperty.isMany()) { + Monitor.error(monitor, this, "assembly-validation-messages", "PropertyOverrideManyAttribute", component + .getName(), componentProperty.getName()); + } + + // Default to the many attribute defined on the property + componentProperty.setMany(componentTypeProperty.isMany()); + + // Default to the type and element defined on the property + if (componentProperty.getXSDType() == null) { + componentProperty.setXSDType(componentTypeProperty.getXSDType()); + } + if (componentProperty.getXSDElement() == null) { + componentProperty.setXSDElement(componentTypeProperty.getXSDElement()); + } + + // Check that a type or element are specified + if (componentProperty.getXSDElement() == null && componentProperty.getXSDType() == null) { + Monitor.error(monitor, this, "assembly-validation-messages", "NoTypeForComponentProperty", component + .getName(), componentProperty.getName()); + } + } + } + + /** + * If the property has a source attribute use this to retrieve the value from a + * property in the parent composite + + * + * @param parentCompoent the composite that contains the component + * @param component + * @param componentProperty + */ + private void processPropertySourceAttribute(Composite parentComposite, + Component component, + ComponentProperty componentProperty) { + String source = componentProperty.getSource(); + + if (source != null) { + // $<name>/... + int index = source.indexOf('/'); + if (index == -1) { + // Tolerating $prop + source = source + "/"; + index = source.length() - 1; + } + if (source.charAt(0) == '$') { + String name = source.substring(1, index); + Property compositeProp = parentComposite.getProperty(name); + if (compositeProp == null) { + Monitor.error(monitor, + this, + "assembly-validation-messages", + "PropertySourceNotFound", + source, + componentProperty.getName(), + component.getName()); + } + + Document compositePropDefValues = (Document)compositeProp.getValue(); + + try { + // FIXME: How to deal with namespaces? + Document node = + evaluateXPath(compositePropDefValues, + componentProperty.getSourceXPathExpression(), + documentBuilderFactory); + + if (node != null) { + componentProperty.setValue(node); + } + } catch (Exception ex) { + Monitor.error(monitor, + this, + "assembly-validation-messages", + "PropertySourceXpathInvalid", + source, + componentProperty.getName(), + component.getName(), + ex.toString()); + } + } else { + Monitor.error(monitor, + this, + "assembly-validation-messages", + "PropertySourceValueInvalid", + source, + componentProperty.getName(), + component.getName()); + } + } + } + + /** + * If the property has a file attribute use this to retrieve the value from a + * local file + + * + * @param parentCompoent the composite that contains the component + * @param component + */ + private void processPropertyFileAttribute(Component component, ComponentProperty componentProperty) { + String file = componentProperty.getFile(); + if (file != null) { + try { + URI uri = URI.create(file); + // URI resolution for relative URIs is done when the composite is resolved. + URL url = uri.toURL(); + URLConnection connection = url.openConnection(); + connection.setUseCaches(false); + InputStream is = null; + try { + is = connection.getInputStream(); + + Source streamSource = new SAXSource(new InputSource(is)); + DOMResult result = new DOMResult(); + javax.xml.transform.Transformer transformer = transformerFactory.newTransformer(); + transformer.transform(streamSource, result); + + Document document = (Document)result.getNode(); + + // TUSCANY-2377, Add a fake value element so it's consistent with + // the DOM tree loaded from inside SCDL + Element root = document.createElementNS(null, "value"); + root.appendChild(document.getDocumentElement()); + document.appendChild(root); + componentProperty.setValue(document); + } finally { + if (is != null) { + is.close(); + } + } + } catch (Exception ex) { + Monitor.error(monitor, + this, + "assembly-validation-messages", + "PropertyFileValueInvalid", + file, + componentProperty.getName(), + component.getName(), + ex.toString()); + } + } + + } + + /** + * Evaluate an XPath expression against a Property value, returning the result as a Property value + * @param node - the document root element of a Property value + * @param expression - the XPath expression + * @param documentBuilderFactory - a DOM document builder factory + * @return - a DOM Document representing the result of the evaluation as a Property value + * @throws XPathExpressionException + * @throws ParserConfigurationException + */ + private Document evaluateXPath(Document node, + XPathExpression expression, + DocumentBuilderFactory documentBuilderFactory) throws XPathExpressionException, + ParserConfigurationException { + + // The document element is a <sca:property/> element + Node property = node.getDocumentElement(); + // The first child of the <property/> element is a <value/> element + Node value = property.getFirstChild(); + + Node result = (Node)expression.evaluate(value, XPathConstants.NODE); + if (result == null) { + return null; + } + + if (result instanceof Document) { + return (Document)result; + } else { + Document document = documentBuilderFactory.newDocumentBuilder().newDocument(); + Element newProperty = document.createElementNS(SCA11_NS, "property"); + + if (result.getNodeType() == Node.ELEMENT_NODE) { + // If the result is a <value/> element, use it directly in the result + newProperty.appendChild(document.importNode(result, true)); + } else { + // If the result is not a <value/> element, create a <value/> element to contain the result + Element newValue = document.createElementNS(SCA11_NS, "value"); + newValue.appendChild(document.importNode(result, true)); + newProperty.appendChild(newValue); + } // end if + document.appendChild(newProperty); + + return document; + } + } + + /** + * Create a callback reference for a component service + * + * @param component + * @param service + */ + private void createCallbackReference(Component component, ComponentService service) { + + // if the service has a callback interface create a reference + // to represent the callback + if (service.getInterfaceContract() != null && // can be null in unit tests + service.getInterfaceContract().getCallbackInterface() != null) { + + ComponentReference callbackReference = assemblyFactory.createComponentReference(); + callbackReference.setForCallback(true); + callbackReference.setName(service.getName()); + try { + InterfaceContract contract = (InterfaceContract)service.getInterfaceContract().clone(); + contract.setInterface(contract.getCallbackInterface()); + contract.setCallbackInterface(null); + callbackReference.setInterfaceContract(contract); + } catch (CloneNotSupportedException e) { + // will not happen + } + Service implService = service.getService(); + if (implService != null) { + + // If the implementation service is a CompositeService, ensure that the Reference that is + // created is a CompositeReference, otherwise create a Reference + Reference implReference; + if (implService instanceof CompositeService) { + CompositeReference implCompReference = assemblyFactory.createCompositeReference(); + // Set the promoted component from the promoted component of the composite service + implCompReference.getPromotedComponents().add(((CompositeService)implService) + .getPromotedComponent()); + // Set the promoted service + ComponentReference promotedReference = assemblyFactory.createComponentReference(); + String promotedRefName = + ((CompositeService)implService).getPromotedComponent().getName() + "/" + + ((CompositeService)implService).getPromotedService().getName(); + promotedReference.setName(promotedRefName); + promotedReference.setUnresolved(true); + implCompReference.getPromotedReferences().add(promotedReference); + implReference = implCompReference; + // Add the composite reference to the composite implementation artifact + Implementation implementation = component.getImplementation(); + if (implementation != null && implementation instanceof Composite) { + ((Composite)implementation).getReferences().add(implCompReference); + } + } else { + implReference = assemblyFactory.createReference(); + } + + implReference.setName(implService.getName()); + try { + InterfaceContract implContract = (InterfaceContract)implService.getInterfaceContract().clone(); + implContract.setInterface(implContract.getCallbackInterface()); + implContract.setCallbackInterface(null); + implReference.setInterfaceContract(implContract); + } catch (CloneNotSupportedException e) { + // will not happen + } + callbackReference.setReference(implReference); + } + component.getReferences().add(callbackReference); + + // Set the bindings of the callback reference + if (callbackReference.getBindings().isEmpty()) { + // If there are specific callback bindings set in the SCDL service + // callback element then use them + if (service.getCallback() != null && service.getCallback().getBindings().size() > 0) { + callbackReference.getBindings().addAll(service.getCallback().getBindings()); + } else { + // otherwise create a default binding which + // will cause the EPR for this reference to be + // marked as EndpointReference.NOT_CONFIGURED + createSCABinding(callbackReference, null); + + // TODO - should really use the forward binding here but + // awaiting OASIS decision on what's going to + // happen with callbacks + } + } + service.setCallbackReference(callbackReference); + } + } + + /** + * Create a callback service for a component reference + * + * @param component + * @param service + */ + private void createCallbackService(Component component, ComponentReference reference) { + if (reference.getInterfaceContract() != null && // can be null in unit tests + reference.getInterfaceContract().getCallbackInterface() != null) { + ComponentService componentService = assemblyFactory.createComponentService(); + componentService.setForCallback(true); + componentService.setName(reference.getName()); + try { + InterfaceContract contract = (InterfaceContract)reference.getInterfaceContract().clone(); + contract.setInterface(contract.getCallbackInterface()); + contract.setCallbackInterface(null); + componentService.setInterfaceContract(contract); + } catch (CloneNotSupportedException e) { + // will not happen + } + Reference implReference = reference.getReference(); + if (implReference != null) { + // If the implementation reference is a CompositeReference, ensure that the Service that is + // created is a CompositeService, otherwise create a Service + Service implService; + if (implReference instanceof CompositeReference) { + CompositeService implCompService = assemblyFactory.createCompositeService(); + // TODO The reality here is that the composite reference which has the callback COULD promote more than + // one component reference - and there must be a separate composite callback service for each of these component + // references + // Set the promoted component from the promoted component of the composite reference + implCompService.setPromotedComponent(((CompositeReference)implReference).getPromotedComponents() + .get(0)); + implCompService.setForCallback(true); + // Set the promoted service + ComponentService promotedService = assemblyFactory.createComponentService(); + promotedService.setName(((CompositeReference)implReference).getPromotedReferences().get(0) + .getName()); + promotedService.setUnresolved(true); + promotedService.setForCallback(true); + implCompService.setPromotedService(promotedService); + implService = implCompService; + // Add the composite service to the composite implementation artifact + Implementation implementation = component.getImplementation(); + if (implementation != null && implementation instanceof Composite) { + ((Composite)implementation).getServices().add(implCompService); + } // end if + // + } else { + implService = assemblyFactory.createService(); + } // end if + // + implService.setName(implReference.getName()); + try { + InterfaceContract implContract = (InterfaceContract)implReference.getInterfaceContract().clone(); + implContract.setInterface(implContract.getCallbackInterface()); + implContract.setCallbackInterface(null); + implService.setInterfaceContract(implContract); + } catch (CloneNotSupportedException e) { + // will not happen + } + componentService.setService(implService); + } + component.getServices().add(componentService); + + // configure bindings for the callback service + if (componentService.getBindings().isEmpty()) { + if (reference.getCallback() != null && reference.getCallback().getBindings().size() > 0) { + // set bindings of the callback service based on the information provided in + // SCDL reference callback element + componentService.getBindings().addAll(reference.getCallback().getBindings()); + } else if (reference.getBindings().size() > 0) { + // use any bindings explicitly declared on the forward reference + for (Binding binding : reference.getBindings()) { + try { + Binding clonedBinding = (Binding)binding.clone(); + // binding uri will be calculated during runtime build + clonedBinding.setURI(null); + componentService.getBindings().add(clonedBinding); + } catch (CloneNotSupportedException ex) { + + } + } + } else { + // TODO - should use the binding resolved from the service but + // waiting for OASIS to decide what to do about callbacks + // create a default binding + createSCABinding(componentService, null); + } + } + + reference.setCallbackService(componentService); + } + } + + /** + * 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(); + + 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); + } + + /** + * Look to see if any value elements have been set into the property + * A bit involved as the value is stored as a DOM Document + * + * @param property the property to be tested + * @return true is values are present + */ + private boolean isPropertyValueSet(Property property) { + Document value = (Document)property.getValue(); + + if (value == null) { + return false; + } + + if (value.getFirstChild() == null) { + return false; + } + + if (value.getFirstChild().getChildNodes().getLength() == 0) { + return false; + } + + return true; + } + + private boolean isValidMultiplicityOverride(Multiplicity definedMul, Multiplicity overridenMul) { + if (definedMul != overridenMul) { + switch (definedMul) { + case ZERO_N: + return overridenMul == Multiplicity.ZERO_ONE || overridenMul == Multiplicity.ONE_ONE + || overridenMul == Multiplicity.ONE_N; + case ONE_N: + return overridenMul == Multiplicity.ONE_ONE; + case ZERO_ONE: + return overridenMul == Multiplicity.ONE_ONE; + default: + return false; + } + } else { + return true; + } + } + + /** + * The following methods implement rules that the OASIS specification defined explicitly + * to control how configuration from a component type is inherited by a component + */ + + /** + * OASIS RULE: Interface contract from higher in the implementation hierarchy takes precedence + * + * @param topContract the top contract + * @param bottomContract the bottom contract + */ + private void calculateInterfaceContract(Contract topContract, Contract bottomContract) { + + // 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 = interfaceContractMapper.isCompatible(topInterfaceContract, bottomInterfaceContract); + if (!isCompatible) { + if (topContract instanceof Reference) { + Monitor.error(monitor, + this, + "assembly-validation-messages", + "ReferenceInterfaceNotSubSet", + topContract.getName()); + } else { + Monitor.error(monitor, + this, + "assembly-validation-messages", + "ServiceInterfaceNotSubSet", + topContract.getName()); + } + } + } + } + + /** + * OASIS RULE: Bindings from higher in the hierarchy take precedence + * + * @param componentService the top service + * @param componentTypeService the bottom service + */ + private void calculateBindings(Service componentService, Service componentTypeService) { + // forward bindings + if (componentService.getBindings().isEmpty()) { + componentService.getBindings().addAll(componentTypeService.getBindings()); + } + + if (componentService.getBindings().isEmpty()) { + createSCABinding(componentService, null); + } + + // callback bindings + if (componentService.getCallback() == null) { + componentService.setCallback(componentTypeService.getCallback()); + if (componentService.getCallback() == null) { + // Create an empty callback to avoid null check + componentService.setCallback(assemblyFactory.createCallback()); + } + } else if (componentService.getCallback().getBindings().isEmpty() && componentTypeService.getCallback() != null) { + componentService.getCallback().getBindings().addAll(componentTypeService.getCallback().getBindings()); + } + + } + +} diff --git a/java/sca/modules/builder/src/main/java/org/apache/tuscany/sca/builder/impl/ComponentReferenceBindingBuilderImpl.java b/java/sca/modules/builder/src/main/java/org/apache/tuscany/sca/builder/impl/ComponentReferenceBindingBuilderImpl.java new file mode 100644 index 0000000000..f2b5f341e1 --- /dev/null +++ b/java/sca/modules/builder/src/main/java/org/apache/tuscany/sca/builder/impl/ComponentReferenceBindingBuilderImpl.java @@ -0,0 +1,82 @@ +/* + * 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 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.Composite; +import org.apache.tuscany.sca.assembly.Implementation; +import org.apache.tuscany.sca.assembly.builder.BindingBuilder; +import org.apache.tuscany.sca.assembly.builder.BuilderExtensionPoint; +import org.apache.tuscany.sca.assembly.builder.CompositeBuilder; +import org.apache.tuscany.sca.assembly.builder.CompositeBuilderException; +import org.apache.tuscany.sca.core.ExtensionPointRegistry; +import org.apache.tuscany.sca.definitions.Definitions; +import org.apache.tuscany.sca.monitor.Monitor; + +/** + * A composite builder that performs any additional building steps that + * component reference bindings may need. Used for WSDL generation. + * + * @version $Rev$ $Date$ + */ +public class ComponentReferenceBindingBuilderImpl implements CompositeBuilder { + + private BuilderExtensionPoint builders; + + public ComponentReferenceBindingBuilderImpl(ExtensionPointRegistry registry) { + this.builders = registry.getExtensionPoint(BuilderExtensionPoint.class); + } + + public Composite build(Composite composite, Definitions definitions, Monitor monitor) + throws CompositeBuilderException { + buildReferenceBindings(composite, monitor); + return composite; + } + + public String getID() { + return "org.apache.tuscany.sca.assembly.builder.ComponentReferenceBindingBuilder"; + } + + private void buildReferenceBindings(Composite composite, Monitor monitor) { + + // find all the component reference bindings (starting at top level) + for (Component component : composite.getComponents()) { + for (ComponentReference componentReference : component.getReferences()) { + for (Binding binding : componentReference.getBindings()) { + BindingBuilder builder = builders.getBindingBuilder(binding.getClass()); + if (builder != null) { + builder.build(component, componentReference, binding, monitor); + } + } + } + } + + // build bindings recursively + for (Component component : composite.getComponents()) { + Implementation implementation = component.getImplementation(); + if (implementation instanceof Composite) { + buildReferenceBindings((Composite)implementation, monitor); + } + } + } + +} diff --git a/java/sca/modules/builder/src/main/java/org/apache/tuscany/sca/builder/impl/ComponentReferencePromotionBuilderImpl.java b/java/sca/modules/builder/src/main/java/org/apache/tuscany/sca/builder/impl/ComponentReferencePromotionBuilderImpl.java new file mode 100644 index 0000000000..7e7a96b016 --- /dev/null +++ b/java/sca/modules/builder/src/main/java/org/apache/tuscany/sca/builder/impl/ComponentReferencePromotionBuilderImpl.java @@ -0,0 +1,173 @@ +/* + * 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.List; + +import org.apache.tuscany.sca.assembly.AssemblyFactory; +import org.apache.tuscany.sca.assembly.Component; +import org.apache.tuscany.sca.assembly.ComponentReference; +import org.apache.tuscany.sca.assembly.Composite; +import org.apache.tuscany.sca.assembly.CompositeReference; +import org.apache.tuscany.sca.assembly.Implementation; +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.core.ExtensionPointRegistry; +import org.apache.tuscany.sca.core.FactoryExtensionPoint; +import org.apache.tuscany.sca.definitions.Definitions; +import org.apache.tuscany.sca.monitor.Monitor; + +/** + * A composite builder that handles the creation of promoted composite services. + * + * @version $Rev$ $Date$ + */ +public class ComponentReferencePromotionBuilderImpl implements CompositeBuilder { + private AssemblyFactory assemblyFactory; + + public ComponentReferencePromotionBuilderImpl(ExtensionPointRegistry registry) { + FactoryExtensionPoint factories = registry.getExtensionPoint(FactoryExtensionPoint.class); + this.assemblyFactory = factories.getFactory(AssemblyFactory.class); + } + + public Composite build(Composite composite, Definitions definitions, Monitor monitor) + throws CompositeBuilderException { + configureNestedCompositeReferences(composite, monitor); + return composite; + } + + public String getID() { + return "org.apache.tuscany.sca.assembly.builder.ComponentReferencePromotionBuilder"; + } + + /** + * Push down reference configuration into nested composites. + * + * @param composite + * @param problems + */ + private void configureNestedCompositeReferences(Composite composite, Monitor monitor) { + + // Process nested composites recursively + for (Component component : composite.getComponents()) { + Implementation implementation = component.getImplementation(); + if (implementation instanceof Composite) { + configureNestedCompositeReferences((Composite)implementation, monitor); + } + } + + // Process component references declared on components in this composite + for (Component component : composite.getComponents()) { + Implementation implementation = component.getImplementation(); + if (implementation instanceof Composite) { + for (ComponentReference componentReference : component.getReferences()) { + Reference implReference = componentReference.getReference(); + if (implReference != null && implReference instanceof CompositeReference) { + + // If the component reference is wired, it is a promotion override + if (!componentReference.getEndpointReferences().isEmpty()) { + componentReference.setPromotionOverride(true); + } + + // If the component reference is a promotion override, override the + // configuration of the promoted reference + if (componentReference.isPromotionOverride()) { + CompositeReference compositeReference = (CompositeReference)implReference; + List<ComponentReference> promotedReferences = + ReferenceConfigurationUtil.getPromotedComponentReferences(compositeReference); + for (ComponentReference promotedReference : promotedReferences) { + ReferenceConfigurationUtil.reconcileReferenceBindings(componentReference, + promotedReference, + assemblyFactory, + monitor); + if (componentReference.getInterfaceContract() != null && // can be null in unit tests + componentReference.getInterfaceContract().getCallbackInterface() != null) { + SCABinding scaCallbackBinding = + promotedReference.getCallbackBinding(SCABinding.class); + if (promotedReference.getCallback() != null) { + promotedReference.getCallback().getBindings().clear(); + } else { + promotedReference.setCallback(assemblyFactory.createCallback()); + } + if (scaCallbackBinding != null) { + promotedReference.getCallback().getBindings().add(scaCallbackBinding); + } + if (componentReference.getCallback() != null) { + promotedReference.getCallback().getBindings().addAll(componentReference + .getCallback().getBindings()); + } + } + /* TODO - let endpoint references worry about target service + // Wire the promoted reference to the actual non-composite component services + if (promotedReference.getMultiplicity() == Multiplicity.ONE_ONE) { + // promotedReference.getTargets().clear(); + } + for (ComponentService target : componentReference.getTargets()) { + if (target.getService() instanceof CompositeService) { + + // Wire to the actual component service + // promoted by a composite service + CompositeService compositeService = (CompositeService)target.getService(); + // Find the promoted component service + ComponentService componentService = + ServiceConfigurationUtil.getPromotedComponentService(compositeService); + if (componentService != null) { + promotedReference.getTargets().add(componentService); + } + } else { + + // Wire to a non-composite target service + promotedReference.getTargets().add(target); + } + } + */ + } + } + } + } + } else { + /* TODO - let endpoint references worry about target servicep + for (ComponentReference componentReference : component.getReferences()) { + + // Wire the component reference to the actual + // non-composite component services + List<ComponentService> targets = componentReference.getTargets(); + for (int i = 0, n = targets.size(); i < n; i++) { + ComponentService target = targets.get(i); + if (target.getService() instanceof CompositeService) { + + // Wire to the actual component service + // promoted by a composite service + CompositeService compositeService = (CompositeService)target.getService(); + ComponentService componentService = compositeService.getPromotedService(); + if (componentService != null) { + targets.set(i, componentService); + } + } + } + } + */ + } + } + } + +} diff --git a/java/sca/modules/builder/src/main/java/org/apache/tuscany/sca/builder/impl/ComponentServiceBindingBuilderImpl.java b/java/sca/modules/builder/src/main/java/org/apache/tuscany/sca/builder/impl/ComponentServiceBindingBuilderImpl.java new file mode 100644 index 0000000000..c2a4079598 --- /dev/null +++ b/java/sca/modules/builder/src/main/java/org/apache/tuscany/sca/builder/impl/ComponentServiceBindingBuilderImpl.java @@ -0,0 +1,81 @@ +/* + * 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 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.Composite; +import org.apache.tuscany.sca.assembly.Implementation; +import org.apache.tuscany.sca.assembly.builder.BindingBuilder; +import org.apache.tuscany.sca.assembly.builder.BuilderExtensionPoint; +import org.apache.tuscany.sca.assembly.builder.CompositeBuilder; +import org.apache.tuscany.sca.assembly.builder.CompositeBuilderException; +import org.apache.tuscany.sca.core.ExtensionPointRegistry; +import org.apache.tuscany.sca.definitions.Definitions; +import org.apache.tuscany.sca.monitor.Monitor; + +/** + * A composite builder that performs any additional building steps that + * component service bindings may need. Used for WSDL generation. + * + * @version $Rev$ $Date$ + */ +public class ComponentServiceBindingBuilderImpl implements CompositeBuilder { + private BuilderExtensionPoint builders; + + public ComponentServiceBindingBuilderImpl(ExtensionPointRegistry registry) { + this.builders = registry.getExtensionPoint(BuilderExtensionPoint.class); + } + + public String getID() { + return "org.apache.tuscany.sca.assembly.builder.ComponentServiceBindingBuilder"; + } + + public Composite build(Composite composite, Definitions definitions, Monitor monitor) + throws CompositeBuilderException { + buildServiceBindings(composite, monitor); + return composite; + } + + private void buildServiceBindings(Composite composite, Monitor monitor) { + + // build bindings recursively + for (Component component : composite.getComponents()) { + Implementation implementation = component.getImplementation(); + if (implementation instanceof Composite) { + buildServiceBindings((Composite)implementation, monitor); + } + } + + // find all the component service bindings + for (Component component : composite.getComponents()) { + for (ComponentService componentService : component.getServices()) { + for (Binding binding : componentService.getBindings()) { + BindingBuilder builder = builders.getBindingBuilder(binding.getClass()); + if (builder != null) { + builder.build(component, componentService, binding, monitor); + } + } + } + } + } + +} diff --git a/java/sca/modules/builder/src/main/java/org/apache/tuscany/sca/builder/impl/ComponentServicePromotionBuilderImpl.java b/java/sca/modules/builder/src/main/java/org/apache/tuscany/sca/builder/impl/ComponentServicePromotionBuilderImpl.java new file mode 100644 index 0000000000..19ae78551a --- /dev/null +++ b/java/sca/modules/builder/src/main/java/org/apache/tuscany/sca/builder/impl/ComponentServicePromotionBuilderImpl.java @@ -0,0 +1,110 @@ +/* + * 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 org.apache.tuscany.sca.assembly.AssemblyFactory; +import org.apache.tuscany.sca.assembly.Component; +import org.apache.tuscany.sca.assembly.ComponentService; +import org.apache.tuscany.sca.assembly.Composite; +import org.apache.tuscany.sca.assembly.CompositeService; +import org.apache.tuscany.sca.assembly.Implementation; +import org.apache.tuscany.sca.assembly.Service; +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.monitor.Monitor; + +/** + * A composite builder that handles the creation of promoted services. + * + * @version $Rev$ $Date$ + */ +public class ComponentServicePromotionBuilderImpl implements CompositeBuilder { + private AssemblyFactory assemblyFactory; + + public ComponentServicePromotionBuilderImpl(AssemblyFactory assemblyFactory) { + this.assemblyFactory = assemblyFactory; + } + + public String getID() { + return "org.apache.tuscany.sca.assembly.builder.ComponentServicePromotionBuilder"; + } + + public Composite build(Composite composite, Definitions definitions, Monitor monitor) + throws CompositeBuilderException { + + // Process nested composites recursively + configureNestedCompositeServices(composite); + return composite; + } + + private void configureNestedCompositeServices(Composite composite) { + + // Process nested composites recursively + for (Component component : composite.getComponents()) { + Implementation implementation = component.getImplementation(); + if (implementation instanceof Composite) { + + // First process nested composites + configureNestedCompositeServices((Composite)implementation); + + // Process the component services declared on components in this composite + for (ComponentService componentService : component.getServices()) { + Service implService = componentService.getService(); + if (implService != null && implService instanceof CompositeService) { + CompositeService compositeService = (CompositeService)implService; + + // Get the innermost promoted service + ComponentService promotedService = + ServiceConfigurationUtil.getPromotedComponentService(compositeService); + if (promotedService != null) { + Component promotedComponent = + ServiceConfigurationUtil.getPromotedComponent(compositeService); + + // Create a new component service to represent this + // component service on the promoted component + ComponentService newComponentService = assemblyFactory.createComponentService(); + newComponentService.setName("$promoted$" + component.getName() + + "$slash$" + + componentService.getName()); + promotedComponent.getServices().add(newComponentService); + newComponentService.setService(promotedService.getService()); + newComponentService.getBindings().addAll(componentService.getBindings()); + newComponentService.setInterfaceContract(componentService.getInterfaceContract()); + + if (componentService.getInterfaceContract() != null && componentService + .getInterfaceContract().getCallbackInterface() != null) { + newComponentService.setCallback(assemblyFactory.createCallback()); + newComponentService.getCallback().getBindings().addAll(componentService.getCallback() + .getBindings()); + } + + // Change the composite service to now promote the + // newly created component service directly + compositeService.setPromotedComponent(promotedComponent); + compositeService.setPromotedService(newComponentService); + } + } + } + } + } + } + +} diff --git a/java/sca/modules/builder/src/main/java/org/apache/tuscany/sca/builder/impl/CompositeCloneBuilderImpl.java b/java/sca/modules/builder/src/main/java/org/apache/tuscany/sca/builder/impl/CompositeCloneBuilderImpl.java new file mode 100644 index 0000000000..73626243e5 --- /dev/null +++ b/java/sca/modules/builder/src/main/java/org/apache/tuscany/sca/builder/impl/CompositeCloneBuilderImpl.java @@ -0,0 +1,100 @@ +/* + * 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.ArrayList; +import java.util.List; + +import org.apache.tuscany.sca.assembly.Component; +import org.apache.tuscany.sca.assembly.Composite; +import org.apache.tuscany.sca.assembly.Implementation; +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.monitor.Monitor; + +/** + * A composite builder that clones nested composites. + * + * @version $Rev$ $Date$ + */ +public class CompositeCloneBuilderImpl implements CompositeBuilder { + + public CompositeCloneBuilderImpl() { + } + + public Composite build(Composite composite, Definitions definitions, Monitor monitor) + throws CompositeBuilderException { + + if (Composite.DOMAIN_COMPOSITE.equals(composite.getName())) { + // Try to avoid clone for top-level composites that are added to the domain composite + for (Composite included : composite.getIncludes()) { + cloneIncludes(included); + } + } else { + // Clone the includes + cloneIncludes(composite); + } + + cloneCompositeImplementations(composite); + return composite; + } + + private void cloneIncludes(Composite composite) { + List<Composite> includes = new ArrayList<Composite>(); + for (Composite included : composite.getIncludes()) { + try { + includes.add((Composite)included.clone()); + } catch (CloneNotSupportedException e) { + throw new UnsupportedOperationException(e); + } + } + composite.getIncludes().clear(); + composite.getIncludes().addAll(includes); + } + + public String getID() { + return "org.apache.tuscany.sca.assembly.builder.CompositeCloneBuilder"; + } + + /** + * Clone composite component implementations + * + * @param composite + * @param problems + */ + private void cloneCompositeImplementations(Composite composite) { + for (Component component : composite.getComponents()) { + Implementation implementation = component.getImplementation(); + if (implementation instanceof Composite) { + + Composite compositeImplementation = (Composite)implementation; + try { + // Please note the clone method is recursive + Composite clone = (Composite)compositeImplementation.clone(); + component.setImplementation(clone); + } catch (CloneNotSupportedException e) { + throw new UnsupportedOperationException(e); + } + } + } + } + +} diff --git a/java/sca/modules/builder/src/main/java/org/apache/tuscany/sca/builder/impl/CompositeComponentTypeBuilderImpl.java b/java/sca/modules/builder/src/main/java/org/apache/tuscany/sca/builder/impl/CompositeComponentTypeBuilderImpl.java new file mode 100644 index 0000000000..69428285ce --- /dev/null +++ b/java/sca/modules/builder/src/main/java/org/apache/tuscany/sca/builder/impl/CompositeComponentTypeBuilderImpl.java @@ -0,0 +1,482 @@ +/* + * 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.Implementation; +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.BuilderExtensionPoint; +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.InterfaceContract; +import org.apache.tuscany.sca.interfacedef.InterfaceContractMapper; +import org.apache.tuscany.sca.monitor.Monitor; +import org.apache.tuscany.sca.monitor.MonitorFactory; +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/200903"; + 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 Monitor monitor; + private AssemblyFactory assemblyFactory; + private SCABindingFactory scaBindingFactory; + private InterfaceContractMapper interfaceContractMapper; + private BuilderExtensionPoint builders; + + public CompositeComponentTypeBuilderImpl(ExtensionPointRegistry registry) { + UtilityExtensionPoint utilities = registry.getExtensionPoint(UtilityExtensionPoint.class); + MonitorFactory monitorFactory = utilities.getUtility(MonitorFactory.class); + monitor = monitorFactory.createMonitor(); + + 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); + } + + public void setComponentBuilder(ComponentBuilderImpl componentBuilder) { + this.componentBuilder = componentBuilder; + } + + /** + * Calculate the component type for the provided implementation + * + * @param implementation + * @return component type + */ + public void createComponentType(Implementation implementation) { + if (!(implementation instanceof Composite)) { + // component type will have been calculated at resolve time + return; + } + + // create the composite component type as this was not + // calculated at resolve time + Composite composite = (Composite)implementation; + + // 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 (composite.getComponent(component.getName()) == null) { + Monitor.error(monitor, this, "assembly-validation-messages", "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(composite, component); + } + + // 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<String, Component> components = new HashMap<String, Component>(); + Map<String, ComponentService> componentServices = new HashMap<String, ComponentService>(); + Map<String, ComponentReference> componentReferences = new HashMap<String, ComponentReference>(); + indexComponentsServicesAndReferences(composite, components, componentServices, componentReferences); + + // services + calculateServices(composite, components, componentServices); + + // references + calculateReferences(composite, components, componentReferences); + + // properties + // Properties on the composite component are unaffected by properties + // on child components. Instead child component properties might take their + // values from component properties. Hence there is nothing to do here. + //calculateProperties(composite, components); + + } + + /** + * Index components, services and references inside a composite. + * + * @param composite + * @param components + * @param componentServices + * @param componentReferences + */ + private void indexComponentsServicesAndReferences(Composite composite, + Map<String, Component> components, + Map<String, ComponentService> componentServices, + Map<String, ComponentReference> 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<String, Component> components, + Map<String, ComponentService> componentServices) { + + // Connect this component type's services to the + // services from child components which it promotes + connectPromotedServices(componentType, components, componentServices); + + // 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 + calculatePromotedInterfaceContract(compositeService, promotedComponentService); + + // promote bindings + calculatePromotedBindings(compositeService, promotedComponentService); + + // promote intents - done later in CompositePolicyBuilder - discuss with RF + // calculatePromotedIntents(compositeService, promotedComponentService); + + // promote policy sets - done later in CompositePolicyBuilder - discuss with RF + // calculatePromotedPolicySets(compositeService, promotedComponentService); + } + } + + /** + * Connect the references in the component type to the component references that + * they promote + * + * @param componentType + * @param component + */ + private void calculateReferences(ComponentType componentType, + Map<String, Component> components, + Map<String, ComponentReference> componentReferences) { + + // Connect this component type's references to the + // references from child components which it promotes + connectPromotedReferences(componentType, components, componentReferences); + + // 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<ComponentReference> promotedReferences = compositeReference.getPromotedReferences(); + + for (ComponentReference promotedComponentReference : promotedReferences) { + + // promote interface contracts + calculatePromotedInterfaceContract(compositeReference, promotedComponentReference); + + // 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); + + // promote intents - done later in CompositePolicyBuilder - discuss with RF + // calculatePromotedIntents(compositeService, promotedComponentService); + + // promote policy sets - done later in CompositePolicyBuilder - discuss with RF + // calculatePromotedPolicySets(compositeService, promotedComponentService); + } + } + } + + /** + * Connect the services in the component type to the component services that + * they promote + * + * @param componentType + * @param component + */ + private void connectPromotedServices(ComponentType componentType, + Map<String, Component> components, + Map<String, ComponentService> componentServices) { + + 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, + "assembly-validation-messages", + "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<String, Component> components, + Map<String, ComponentReference> componentReferences) { + + // Connect composite (component type) references to the component references that they promote + for (Reference reference : componentType.getReferences()) { + CompositeReference compositeReference = (CompositeReference)reference; + List<ComponentReference> 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, + "assembly-validation-messages", + "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(); + + 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 + */ + + /** + * OASIS RULE: Interface contract from higher in the implementation hierarchy takes precedence + * + * @param topContract the top contract + * @param bottomContract the bottom contract + */ + private void calculatePromotedInterfaceContract(Contract topContract, Contract bottomContract) { + // 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 = interfaceContractMapper.isCompatible(topInterfaceContract, bottomInterfaceContract); + if (!isCompatible) { + if (topContract instanceof Reference) { + Monitor.error(monitor, + this, + "assembly-validation-messages", + "ReferenceInterfaceNotSubSet", + topContract.getName()); + } else { + Monitor.error(monitor, + this, + "assembly-validation-messages", + "ServiceInterfaceNotSubSet", + topContract.getName()); + } + } + } + } + + /** + * OASIS RULE: 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 + } + } + } + } + +} //end class diff --git a/java/sca/modules/builder/src/main/java/org/apache/tuscany/sca/builder/impl/CompositeIncludeBuilderImpl.java b/java/sca/modules/builder/src/main/java/org/apache/tuscany/sca/builder/impl/CompositeIncludeBuilderImpl.java new file mode 100644 index 0000000000..cd197f625b --- /dev/null +++ b/java/sca/modules/builder/src/main/java/org/apache/tuscany/sca/builder/impl/CompositeIncludeBuilderImpl.java @@ -0,0 +1,125 @@ +/* + * 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 org.apache.tuscany.sca.assembly.Component; +import org.apache.tuscany.sca.assembly.Composite; +import org.apache.tuscany.sca.assembly.Implementation; +import org.apache.tuscany.sca.assembly.Reference; +import org.apache.tuscany.sca.assembly.Service; +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.monitor.Monitor; + +/** + * Implementation of a CompositeBuilder. + * + * @version $Rev$ $Date$ + */ +public class CompositeIncludeBuilderImpl implements CompositeBuilder { + + public CompositeIncludeBuilderImpl() { + } + + public String getID() { + return "org.apache.tuscany.sca.assembly.builder.CompositeIncludeBuilder"; + } + + public Composite build(Composite composite, Definitions definitions, Monitor monitor) + throws CompositeBuilderException { + return processIncludes(composite, monitor); + } + + /** + * Merge the elements from the included composites into the including composite + * @param composite + * @param monitor + * @return + */ + private Composite processIncludes(Composite composite, Monitor monitor) { + monitor.pushContext("Composite: " + composite.getName().toString()); + + try { + // process any composites referenced through implementation.composite + for (Component component : composite.getComponents()) { + + // recurse for composite implementations + Implementation implementation = component.getImplementation(); + if (implementation instanceof Composite) { + processIncludes((Composite)implementation, monitor); + } + } + + // get the components etc. from any included composites + for (Composite included : composite.getIncludes()) { + if (included.isLocal() && !composite.isLocal()) { + // ASM60041 + Monitor.error(monitor, this, "assembly-validation-messages", "IllegalCompositeIncusion", composite + .getName().toString(), included.getName().toString()); + return null; + } + + // The included has been cloned during composite.clone() + Composite merged = processIncludes(included, monitor); + if (merged != null) { + for (Component component : merged.getComponents()) { + // apply the autowire flag on this composite to any inline + // components - Assembly 5.6 point 4 + if (component.getAutowire() == null && merged.getAutowire() == Boolean.TRUE) { + component.setAutowire(Boolean.TRUE); + } + // Merge the intents and policySets from the included composite into + // component/service/reference elements under the composite + component.getRequiredIntents().addAll(merged.getRequiredIntents()); + component.getPolicySets().addAll(merged.getPolicySets()); + } + + for (Service service : merged.getServices()) { + service.getRequiredIntents().addAll(merged.getRequiredIntents()); + service.getPolicySets().addAll(merged.getPolicySets()); + } + + for (Reference reference : merged.getReferences()) { + reference.getRequiredIntents().addAll(merged.getRequiredIntents()); + reference.getPolicySets().addAll(merged.getPolicySets()); + } + composite.getComponents().addAll(merged.getComponents()); + composite.getServices().addAll(merged.getServices()); + composite.getReferences().addAll(merged.getReferences()); + composite.getProperties().addAll(merged.getProperties()); + composite.getWires().addAll(merged.getWires()); + // FIXME: What should we do for the extensions + /* + clone.getExtensions().addAll(fusedComposite.getExtensions()); + clone.getAttributeExtensions().addAll(fusedComposite.getAttributeExtensions()); + */ + } + } + + composite.getIncludes().clear(); + + // return the fused composite we have built up so far + return composite; + } finally { + monitor.popContext(); + } + } +} diff --git a/java/sca/modules/builder/src/main/java/org/apache/tuscany/sca/builder/impl/CompositePolicyBuilderImpl.java b/java/sca/modules/builder/src/main/java/org/apache/tuscany/sca/builder/impl/CompositePolicyBuilderImpl.java new file mode 100644 index 0000000000..5f839f4505 --- /dev/null +++ b/java/sca/modules/builder/src/main/java/org/apache/tuscany/sca/builder/impl/CompositePolicyBuilderImpl.java @@ -0,0 +1,402 @@ +/* + * 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.HashSet; +import java.util.Set; + +import org.apache.tuscany.sca.assembly.Binding; +import org.apache.tuscany.sca.assembly.Component; +import org.apache.tuscany.sca.assembly.ComponentReference; +import org.apache.tuscany.sca.assembly.ComponentService; +import org.apache.tuscany.sca.assembly.Composite; +import org.apache.tuscany.sca.assembly.CompositeReference; +import org.apache.tuscany.sca.assembly.CompositeService; +import org.apache.tuscany.sca.assembly.Endpoint; +import org.apache.tuscany.sca.assembly.EndpointReference; +import org.apache.tuscany.sca.assembly.Implementation; +import org.apache.tuscany.sca.assembly.Reference; +import org.apache.tuscany.sca.assembly.Service; +import org.apache.tuscany.sca.assembly.builder.CompositeBuilder; +import org.apache.tuscany.sca.assembly.builder.CompositeBuilderException; +import org.apache.tuscany.sca.core.ExtensionPointRegistry; +import org.apache.tuscany.sca.definitions.Definitions; +import org.apache.tuscany.sca.monitor.Monitor; +import org.apache.tuscany.sca.policy.Intent; +import org.apache.tuscany.sca.policy.IntentMap; +import org.apache.tuscany.sca.policy.PolicySet; +import org.apache.tuscany.sca.policy.PolicySubject; +import org.apache.tuscany.sca.policy.Qualifier; + +/** + * A composite builder that computes policy sets based on attached intents and policy sets. + * Useful if you want to build the model without making any runtime decisions such as + * reference/services matching + * + * @version $Rev$ $Date$ + */ +public class CompositePolicyBuilderImpl extends BaseBuilderImpl implements CompositeBuilder { + public CompositePolicyBuilderImpl(ExtensionPointRegistry registry) { + super(registry); + } + + public String getID() { + return "org.apache.tuscany.sca.assembly.builder.CompositePolicyBuilder"; + } + + public Composite build(Composite composite, Definitions definitions, Monitor monitor) + throws CompositeBuilderException { + computePolicies(composite, definitions, monitor); + return composite; + } + + /** + * Inherit the intents and policySets from the list of models + * @param intents + * @param policySets + * @param models + */ + private void inherit(PolicySubject policySubject, Object... models) { + for (Object model : models) { + if (model instanceof PolicySubject) { + PolicySubject subject = (PolicySubject)model; + policySubject.getRequiredIntents().addAll(subject.getRequiredIntents()); + policySubject.getPolicySets().addAll(subject.getPolicySets()); + } + } + } + + /** + * Check if two policy subjects requires multually exclusive intents + * @param subject1 + * @param subject2 + * @param monitor + * @return + */ + private boolean checkMutualExclusion(PolicySubject subject1, PolicySubject subject2, Monitor monitor) { + if (subject1 == subject2 || subject1 == null || subject2 == null) { + return false; + } + for (Intent i1 : subject1.getRequiredIntents()) { + for (Intent i2 : subject1.getRequiredIntents()) { + if (i1.getExcludedIntents().contains(i2) || i2.getExcludedIntents().contains(i1)) { + error(monitor, "MutuallyExclusiveIntents", new Object[] {subject1, subject2}, i1, i2); + return true; + } + } + } + return false; + } + + /** + * Inherit the policySets and intents from the implementation hierarchy + * @param subject + * @param composite + * @param component + * @param service + */ + private void inheritFromService(PolicySubject subject, Composite composite, Component component, Service service) { + if (service == null) { + return; + } + if (service instanceof ComponentService) { + // component!=null + if (component.getImplementation() instanceof Composite) { + composite = (Composite)component.getImplementation(); + } + inheritFromService(subject, composite, component, ((ComponentService)service).getService()); + // Component service also inherits the intents/policySets from composite/component + inherit(subject, composite, component); + } else if (service instanceof CompositeService) { + // composite!=null, component is not used + CompositeService compositeService = (CompositeService)service; + // Handle the promoted component service + inheritFromService(subject, composite, compositeService.getPromotedComponent(), compositeService + .getPromotedService()); + } + // For atomic service, the composite is not used + inherit(subject, component.getImplementation(), service); + } + + /** + * Inherit the policySets and intents from the implementation hierarchy + * @param subject + * @param composite + * @param component + * @param reference + */ + private void inheritFromReference(PolicySubject subject, + Composite composite, + Component component, + Reference reference) { + if (reference == null) { + return; + } + if (reference instanceof ComponentReference) { + // component!=null + if (component.getImplementation() instanceof Composite) { + composite = (Composite)component.getImplementation(); + } + inheritFromReference(subject, composite, component, ((ComponentReference)reference).getReference()); + } else if (reference instanceof CompositeReference) { + CompositeReference compositeReference = (CompositeReference)reference; + for (int i = 0, n = compositeReference.getPromotedReferences().size(); i < n; i++) { + inheritFromReference(subject, + composite, + compositeReference.getPromotedComponents().get(i), + compositeReference.getPromotedReferences().get(i)); + } + } + // Inherit from the componentType/reference + inherit(subject, component.getImplementation(), reference); + } + + /** + * Check if two names are equal + * @param name1 + * @param name2 + * @return + */ + private boolean isEqual(String name1, String name2) { + if (name1 == name2) { + return true; + } + if (name1 != null) { + return name1.equals(name2); + } else { + return name2.equals(name1); + } + } + + private Intent resolve(Definitions definitions, Intent proxy) { + for (Intent i : definitions.getIntents()) { + if (i.equals(proxy)) { + return i; + } + for (Intent qi : i.getQualifiedIntents()) { + if (qi.equals(proxy)) { + return qi; + } + } + } + return null; + } + + private void resolveAndNormalize(PolicySubject subject, Definitions definitions, Monitor monitor) { + + Set<Intent> intents = new HashSet<Intent>(); + if (definitions != null) { + for (Intent i : subject.getRequiredIntents()) { + Intent resolved = resolve(definitions, i); + if (resolved != null) { + intents.add(resolved); + } else { + warning(monitor, "IntentNotFound", subject, i); + // Intent cannot be resolved + } + } + } + + // Replace profile intents with their required intents + while (!intents.isEmpty()) { + boolean profileIntentsFound = false; + Set<Intent> copy = new HashSet<Intent>(intents); + for (Intent i : copy) { + if (!i.getRequiredIntents().isEmpty()) { + intents.remove(i); + intents.addAll(i.getRequiredIntents()); + profileIntentsFound = true; + } + } + if (!profileIntentsFound) { + // No more profileIntents + break; + } + } + + // Remove the intents whose @contraints do not include the current element + // Replace unqualified intents if there is a qualified intent in the list + Set<Intent> copy = new HashSet<Intent>(intents); + for (Intent i : copy) { + if (i.getQualifiableIntent() != null) { + intents.remove(i.getQualifiableIntent()); + } + } + + // Replace qualifiable intents with the default qualified intent + copy = new HashSet<Intent>(intents); + for (Intent i : copy) { + if (i.getDefaultQualifiedIntent() != null) { + intents.remove(i); + intents.add(i.getDefaultQualifiedIntent()); + } + } + + subject.getRequiredIntents().clear(); + subject.getRequiredIntents().addAll(intents); + + Set<PolicySet> policySets = new HashSet<PolicySet>(); + if (definitions != null) { + for (PolicySet policySet : subject.getPolicySets()) { + int index = definitions.getPolicySets().indexOf(policySet); + if (index != -1) { + policySets.add(definitions.getPolicySets().get(index)); + } else { + // PolicySet cannot be resolved + } + } + } + + for (Intent intent : subject.getRequiredIntents()) { + loop: for (PolicySet ps : definitions.getPolicySets()) { + // FIXME: We will have to check the policy references and intentMap too + // as well as the appliesTo + if (ps.getProvidedIntents().contains(intent)) { + policySets.add(ps); + break; + } + for (IntentMap map : ps.getIntentMaps()) { + for (Qualifier q : map.getQualifiers()) { + if (intent.equals(q.getIntent())) { + policySets.add(ps); + break loop; + } + } + } + } + } + + subject.getPolicySets().clear(); + subject.getPolicySets().addAll(policySets); + + } + + protected void computePolicies(Composite composite, Definitions definitions, Monitor monitor) { + + // compute policies recursively + for (Component component : composite.getComponents()) { + Implementation implementation = component.getImplementation(); + if (implementation instanceof Composite) { + computePolicies((Composite)implementation, definitions, monitor); + } + } + + for (Component component : composite.getComponents()) { + checkMutualExclusion(component, component.getImplementation(), monitor); + + for (ComponentService componentService : component.getServices()) { + checkMutualExclusion(componentService, componentService.getService(), monitor); + + if (componentService.getInterfaceContract() != null && componentService.getService() != null) { + checkMutualExclusion(componentService.getInterfaceContract().getInterface(), componentService + .getService().getInterfaceContract().getInterface(), monitor); + checkMutualExclusion(componentService.getInterfaceContract().getCallbackInterface(), + componentService.getService().getInterfaceContract().getCallbackInterface(), + monitor); + } + + for (Endpoint ep : componentService.getEndpoints()) { + // Inherit from the componentType.service.interface + if (componentService.getService() != null && componentService.getService().getInterfaceContract() != null) { + inherit(ep, componentService.getService().getInterfaceContract().getInterface()); + } + if (componentService.getInterfaceContract() != null) { + // Inherit from the component.service.interface + inherit(ep, componentService.getInterfaceContract().getInterface()); + } + // Inherit from the componentType/service + inheritFromService(ep, composite, component, componentService.getService()); + // Find the corresponding binding in the componentType and inherit the intents/policySets + if (componentService.getService() != null) { + for (Binding binding : componentService.getService().getBindings()) { + if (isEqual(ep.getBinding().getName(), binding.getName()) && (binding instanceof PolicySubject)) { + checkMutualExclusion((PolicySubject)ep.getBinding(), (PolicySubject)binding, monitor); + // Inherit from componentType.service.binding + inherit(ep, binding); + break; + } + } + } + // Inherit from composite/component/service + inheritFromService(ep, composite, ep.getComponent(), ep.getService()); + // Inherit from binding + inherit(ep, ep.getBinding()); + + // Replace profile intents with their required intents + // Remove the intents whose @contraints do not include the current element + // Replace unqualified intents if there is a qualified intent in the list + // Replace qualifiable intents with the default qualied intent + resolveAndNormalize(ep, definitions, monitor); + } + } + + for (ComponentReference componentReference : component.getReferences()) { + checkMutualExclusion(componentReference, componentReference.getReference(), monitor); + + if (componentReference.getInterfaceContract() != null && componentReference.getReference() != null) { + checkMutualExclusion(componentReference.getInterfaceContract().getInterface(), componentReference + .getReference().getInterfaceContract().getInterface(), monitor); + checkMutualExclusion(componentReference.getInterfaceContract().getCallbackInterface(), + componentReference.getReference().getInterfaceContract() + .getCallbackInterface(), + monitor); + } + + for (EndpointReference epr : componentReference.getEndpointReferences()) { + // Inherit from the componentType.reference.interface + if (componentReference.getReference() != null && componentReference.getReference() + .getInterfaceContract() != null) { + inherit(epr, componentReference.getReference().getInterfaceContract().getInterface()); + } + // Inherit from the component.reference.interface + if (componentReference.getInterfaceContract() != null) { + inherit(epr, componentReference.getInterfaceContract().getInterface()); + } + // Inherit from the componentType/reference + inheritFromReference(epr, composite, component, componentReference.getReference()); + // Find the corresponding binding in the componentType and inherit the intents/policySets + if (componentReference.getReference() != null) { + for (Binding binding : componentReference.getReference().getBindings()) { + if (epr.getBinding() != null && isEqual(epr.getBinding().getName(), binding.getName()) + && (binding instanceof PolicySubject)) { + checkMutualExclusion((PolicySubject)epr.getBinding(), (PolicySubject)binding, monitor); + // Inherit from componentType.reference.binding + inherit(epr, binding); + break; + } + } + } + // Inherit from composite/component/reference/binding + inheritFromReference(epr, composite, epr.getComponent(), epr.getReference()); + inherit(epr, epr.getBinding()); + + // Replace profile intents with their required intents + // Remove the intents whose @contraints do not include the current element + // Replace unqualified intents if there is a qualified intent in the list + // Replace qualifiable intents with the default qualied intent + resolveAndNormalize(epr, definitions, monitor); + } + } + + Implementation implementation = component.getImplementation(); + // How to deal with implementation level policySets/intents + } + } +} diff --git a/java/sca/modules/builder/src/main/java/org/apache/tuscany/sca/builder/impl/EndpointBuilderImpl.java b/java/sca/modules/builder/src/main/java/org/apache/tuscany/sca/builder/impl/EndpointBuilderImpl.java new file mode 100644 index 0000000000..fa67818408 --- /dev/null +++ b/java/sca/modules/builder/src/main/java/org/apache/tuscany/sca/builder/impl/EndpointBuilderImpl.java @@ -0,0 +1,101 @@ +/* + * 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 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.ComponentService; +import org.apache.tuscany.sca.assembly.Composite; +import org.apache.tuscany.sca.assembly.Endpoint; +import org.apache.tuscany.sca.assembly.Implementation; +import org.apache.tuscany.sca.assembly.builder.CompositeBuilderException; +import org.apache.tuscany.sca.core.ExtensionPointRegistry; +import org.apache.tuscany.sca.core.FactoryExtensionPoint; +import org.apache.tuscany.sca.definitions.Definitions; +import org.apache.tuscany.sca.monitor.Monitor; + +/** + * creates endpoint models for component services. + */ +public class EndpointBuilderImpl { + private AssemblyFactory assemblyFactory; + + public EndpointBuilderImpl(ExtensionPointRegistry registry) { + FactoryExtensionPoint modelFactories = registry.getExtensionPoint(FactoryExtensionPoint.class); + this.assemblyFactory = modelFactories.getFactory(AssemblyFactory.class); + } + + /** + * Create endpoint models for all component services. + * + * @param composite - the top-level composite to build the models for + * @param definitions + * @param monitor - a Monitor for logging errors + */ + public Composite build(Composite composite, Definitions definitions, Monitor monitor) + throws CompositeBuilderException { + + processComponentServices(composite); + return composite; + + } // end method build + + private void processComponentServices(Composite composite) { + + for (Component component : composite.getComponents()) { + + // recurse for composite implementations + Implementation implementation = component.getImplementation(); + if (implementation instanceof Composite) { + processComponentServices((Composite)implementation); + } + + // create an endpoint for each component service binding + for (ComponentService service : component.getServices()) { + + /* change to finding the promoted component and service + * when the wire is created as storing them here leads to + * the wrong URI being calculated + Component endpointComponent = component; + ComponentService endpointService = service; + + // TODO - EPR - We maintain all endpoints at the right level now + // but endpoints for promoting services must point down + // to the services they promote. + if (service.getService() instanceof CompositeService) { + CompositeService compositeService = (CompositeService)service.getService(); + endpointService = ServiceConfigurationUtil.getPromotedComponentService(compositeService); + endpointComponent = ServiceConfigurationUtil.getPromotedComponent(compositeService); + } // end if + */ + + for (Binding binding : service.getBindings()) { + Endpoint endpoint = assemblyFactory.createEndpoint(); + endpoint.setComponent(component); + endpoint.setService(service); + endpoint.setBinding(binding); + endpoint.setUnresolved(false); + service.getEndpoints().add(endpoint); + } // end for + } + } + } +} diff --git a/java/sca/modules/builder/src/main/java/org/apache/tuscany/sca/builder/impl/EndpointReferenceBuilderImpl.java b/java/sca/modules/builder/src/main/java/org/apache/tuscany/sca/builder/impl/EndpointReferenceBuilderImpl.java new file mode 100644 index 0000000000..06320316e5 --- /dev/null +++ b/java/sca/modules/builder/src/main/java/org/apache/tuscany/sca/builder/impl/EndpointReferenceBuilderImpl.java @@ -0,0 +1,840 @@ +/* + * 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 org.apache.tuscany.sca.assembly.AssemblyFactory; +import org.apache.tuscany.sca.assembly.Binding; +import org.apache.tuscany.sca.assembly.Component; +import org.apache.tuscany.sca.assembly.ComponentReference; +import org.apache.tuscany.sca.assembly.ComponentService; +import org.apache.tuscany.sca.assembly.Composite; +import org.apache.tuscany.sca.assembly.CompositeReference; +import org.apache.tuscany.sca.assembly.Endpoint; +import org.apache.tuscany.sca.assembly.EndpointReference; +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.Wire; +import org.apache.tuscany.sca.assembly.builder.CompositeBuilderException; +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.InterfaceContractMapper; +import org.apache.tuscany.sca.monitor.Monitor; +import org.apache.tuscany.sca.monitor.MonitorFactory; + +/** + * Creates endpoint reference models. + */ +public class EndpointReferenceBuilderImpl { + + private Monitor monitor; + private AssemblyFactory assemblyFactory; + private InterfaceContractMapper interfaceContractMapper; + + public EndpointReferenceBuilderImpl(ExtensionPointRegistry registry) { + UtilityExtensionPoint utilities = registry.getExtensionPoint(UtilityExtensionPoint.class); + MonitorFactory monitorFactory = utilities.getUtility(MonitorFactory.class); + monitor = monitorFactory.createMonitor(); + interfaceContractMapper = utilities.getUtility(InterfaceContractMapper.class); + + FactoryExtensionPoint modelFactories = registry.getExtensionPoint(FactoryExtensionPoint.class); + assemblyFactory = modelFactories.getFactory(AssemblyFactory.class); + } + + /** + * Create endpoint references for all component references. + * + * @param composite + */ + public Composite build(Composite composite, Definitions definitions, Monitor monitor) + throws CompositeBuilderException { + this.monitor = monitor; + + // process component services + processComponentReferences(composite); + return composite; + } + + private void processComponentReferences(Composite composite) { + + monitor.pushContext("Composite: " + composite.getName().toString()); + try { + // Index components, services and references + Map<String, Component> components = new HashMap<String, Component>(); + Map<String, ComponentService> componentServices = new HashMap<String, ComponentService>(); + Map<String, ComponentReference> componentReferences = new HashMap<String, ComponentReference>(); + indexComponentsServicesAndReferences(composite, components, componentServices, componentReferences); + + // Connect component references as described in wires + connectWires(composite, componentServices, componentReferences, monitor); + + // create endpoint references for each component's references + for (Component component : composite.getComponents()) { + monitor.pushContext("Component: " + component.getName()); + + try { + + // recurse for composite implementations + Implementation implementation = component.getImplementation(); + if (implementation instanceof Composite) { + processComponentReferences((Composite)implementation); + } + + // create endpoint references to represent the component reference + for (ComponentReference reference : component.getReferences()) { + createReferenceEndpointReferences(composite, + component, + reference, + components, + componentServices); + + // fix up links between endpoints and endpoint references that represent callbacks + for (ComponentService service : component.getServices()) { + if ((service.getInterfaceContract() != null) && (service.getInterfaceContract() + .getCallbackInterface() != null)) { + if (reference.getName().equals(service.getName())) { + for (Endpoint endpoint : service.getEndpoints()) { + endpoint.getCallbackEndpointReferences().addAll(reference + .getEndpointReferences()); + } + break; + } // end if + } // end if + } // end for + } // end for + + // Validate that references are wired or promoted, according + // to their multiplicity + validateReferenceMultiplicity(composite, component); + + } finally { + monitor.popContext(); + } + } // end for + + } finally { + monitor.popContext(); + } + + } // end method processCompoenntReferences + + protected void indexComponentsServicesAndReferences(Composite composite, + Map<String, Component> components, + Map<String, ComponentService> componentServices, + Map<String, ComponentReference> 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); + + // TODO - EPR - $promoted$ no longer used but it doesn't do any + // harm here + boolean promotedService = false; + if (componentService.getName() != null && componentService.getName().indexOf("$promoted$") > -1) { + promotedService = true; + } + + // count how many non-callback, non-promoted services there are + // if there is only one the component name also acts as the + // service name + if ((!componentService.isForCallback()) && (!promotedService)) { + + // 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); + } + } + } + + /** + * Resolve wires and connect the sources to their targets + * + * @param composite + * @param componentServices + * @param componentReferences + * @param problems + */ + private void connectWires(Composite composite, + Map<String, ComponentService> componentServices, + Map<String, ComponentReference> componentReferences, + Monitor monitor) { + + // For each wire, resolve the source reference, the target service, and + // add it to the list of targets of the reference + List<Wire> wires = composite.getWires(); + for (int i = 0, n = wires.size(); i < n; i++) { + Wire wire = wires.get(i); + + ComponentReference resolvedReference; + ComponentService resolvedService; + + // Resolve the source reference + ComponentReference source = wire.getSource(); + if (source != null && source.isUnresolved()) { + resolvedReference = componentReferences.get(source.getName()); + if (resolvedReference != null) { + wire.setSource(resolvedReference); + } else { + Monitor.warning(monitor, this, "assembly-validation-messages", "WireSourceNotFound", source + .getName()); + } + } else { + resolvedReference = wire.getSource(); + } + + // Resolve the target service + ComponentService target = wire.getTarget(); + if (target != null && target.isUnresolved()) { + resolvedService = componentServices.get(target.getName()); + if (resolvedService != null) { + wire.setTarget(target); + } else { + Monitor.warning(monitor, this, "assembly-validation-messages", "WireTargetNotFound", target + .getName()); + } + } else { + resolvedService = wire.getTarget(); + } + + // Add the target service to the list of targets of the + // reference + if (resolvedReference != null && resolvedService != null) { + // Check that the target component service provides + // a superset of + // the component reference interface + if (resolvedReference.getInterfaceContract() == null || interfaceContractMapper + .isCompatible(resolvedReference.getInterfaceContract(), resolvedService.getInterfaceContract())) { + + //resolvedReference.getTargets().add(resolvedService); + if (wire.isReplace()) { + resolvedReference.getTargets().clear(); + } + resolvedReference.getTargets().add(wire.getTarget()); + } else { + Monitor.warning(monitor, this, "assembly-validation-messages", "WireIncompatibleInterface", source + .getName(), target.getName()); + } + } + } + + // Clear the list of wires + composite.getWires().clear(); + } + + private void createReferenceEndpointReferences(Composite composite, + Component component, + ComponentReference reference, + Map<String, Component> components, + Map<String, ComponentService> componentServices) { + + monitor.pushContext("Reference: " + reference.getName()); + + // Get reference targets + List<ComponentService> refTargets = getReferenceTargets(reference); + 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()) { + + // Tuscany specific selection of the first autowire reference + // when there are more than one (ASM_60025) + if ((multiplicity == Multiplicity.ZERO_ONE || multiplicity == Multiplicity.ONE_ONE) && (reference + .getEndpointReferences().size() != 0)) { + break; + } + + // Prevent autowire connecting to self + if (targetComponent == component) + continue; + + for (ComponentService targetComponentService : targetComponent.getServices()) { + if (reference.getInterfaceContract() == null || interfaceContractMapper.isCompatible(reference + .getInterfaceContract(), targetComponentService.getInterfaceContract())) { + + EndpointReference endpointRef = createEndpointRef(component, reference, false); + endpointRef.setTargetEndpoint(createEndpoint(targetComponent, targetComponentService, true)); + endpointRef.setStatus(EndpointReference.WIRED_TARGET_FOUND_READY_FOR_MATCHING); + reference.getEndpointReferences().add(endpointRef); + + // 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 + + if (multiplicity == Multiplicity.ONE_N || multiplicity == Multiplicity.ONE_ONE) { + if (reference.getEndpointReferences().size() == 0) { + Monitor.error(monitor, + this, + "assembly-validation-messages", + "NoComponentReferenceTarget", + reference.getName()); + } + } + + setSingleAutoWireTarget(reference); + + } 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 + if (bindingsIdentifyTargets(reference)) { + Monitor.error(monitor, + this, + "assembly-validation-messages", + "ReferenceEndPointMixWithTarget", + composite.getName().toString(), + component.getName(), + reference.getName()); + } + + // Resolve targets specified on the component reference + for (ComponentService target : refTargets) { + + String targetName = getComponentServiceName(target.getName()); + String bindingName = getBindingName(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 || interfaceContractMapper.isCompatible(reference + .getInterfaceContract(), targetComponentService.getInterfaceContract())) { + + if (bindingName != null) { + // the user has selected a binding as part of the target name + Binding targetBinding = null; + + for (Binding tmp : targetComponentService.getBindings()) { + if (tmp.getName().equals(bindingName)) { + targetBinding = tmp; + continue; + } + } + + if (targetBinding != null) { + EndpointReference endpointRef = createEndpointRef(component, reference, false); + endpointRef.setTargetEndpoint(createEndpoint(targetComponent, + targetComponentService, + targetBinding, + true)); + endpointRef.setStatus(EndpointReference.WIRED_TARGET_NOT_FOUND); + // relying on the registry here to resolve the real endpoint + reference.getEndpointReferences().add(endpointRef); + + } else { + EndpointReference endpointRef = createEndpointRef(component, reference, true); + endpointRef.setTargetEndpoint(createEndpoint(component, targetName)); + endpointRef.setRemote(true); + endpointRef.setStatus(EndpointReference.WIRED_TARGET_NOT_FOUND); + reference.getEndpointReferences().add(endpointRef); + Monitor.warning(monitor, + this, + "assembly-validation-messages", + "ComponentReferenceTargetNotFound", + composite.getName().toString(), + targetName); + } + + } else { + // the user hasn't selected a binding as part of the target name + + EndpointReference endpointRef = createEndpointRef(component, reference, false); + endpointRef + .setTargetEndpoint(createEndpoint(targetComponent, targetComponentService, true)); + endpointRef.setStatus(EndpointReference.WIRED_TARGET_FOUND_READY_FOR_MATCHING); + reference.getEndpointReferences().add(endpointRef); + } + } else { + Monitor.error(monitor, + this, + "assembly-validation-messages", + "ReferenceIncompatibleInterface", + composite.getName().toString(), + component.getName() + "." + reference.getName(), + targetName); + } + } else { + // add an unresolved endpoint reference with an unresolved endpoint to go with it + EndpointReference endpointRef = createEndpointRef(component, reference, true); + endpointRef.setTargetEndpoint(createEndpoint(component, targetName)); + endpointRef.setRemote(true); + endpointRef.setStatus(EndpointReference.WIRED_TARGET_NOT_FOUND); + reference.getEndpointReferences().add(endpointRef); + Monitor.warning(monitor, + this, + "assembly-validation-messages", + "ComponentReferenceTargetNotFound", + composite.getName().toString(), + targetName); + } // end if + } // end for + } // end if + + // if no endpoints have found so far the bindings hold the targets. + if (reference.getEndpointReferences().isEmpty()) { + 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.isForCallback() && (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 + EndpointReference endpointRef = createEndpointRef(component, reference, binding, null, false); + if (binding instanceof SCABinding) { + // Assume that the system needs to resolve this binding later as + // it's the SCA binding + endpointRef.setTargetEndpoint(createEndpoint(true)); + endpointRef.setStatus(EndpointReference.NOT_CONFIGURED); + } else { + // The user has configured a binding so assume they know what + // they are doing and mark in as already resolved. + endpointRef.setTargetEndpoint(createEndpoint(false)); + endpointRef.setStatus(EndpointReference.RESOLVED_BINDING); + } + endpointRef.setRemote(true); + reference.getEndpointReferences().add(endpointRef); + 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); + } + + String targetName = getComponentServiceName(uri); + String bindingName = getBindingName(uri); + + // Resolve the target component and service + ComponentService targetComponentService = componentServices.get(targetName); + Component targetComponent = getComponentFromTargetName(components, targetName); + + // 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 || interfaceContractMapper.isCompatible(reference + .getInterfaceContract(), targetComponentService.getInterfaceContract())) { + if (bindingName != null) { + // the user has selected a binding as part of the target name + Binding targetBinding = null; + + for (Binding tmp : targetComponentService.getBindings()) { + if (tmp.getName().equals(bindingName)) { + targetBinding = tmp; + continue; + } + } + + if (targetBinding != null) { + EndpointReference endpointRef = createEndpointRef(component, reference, false); + endpointRef.setTargetEndpoint(createEndpoint(targetComponent, + targetComponentService, + targetBinding, + true)); + endpointRef.setStatus(EndpointReference.WIRED_TARGET_NOT_FOUND); + // relying on the registry here to resolve the real endpoint + reference.getEndpointReferences().add(endpointRef); + + } else { + EndpointReference endpointRef = createEndpointRef(component, reference, true); + endpointRef.setTargetEndpoint(createEndpoint(component, targetName)); + endpointRef.setRemote(true); + endpointRef.setStatus(EndpointReference.WIRED_TARGET_NOT_FOUND); + reference.getEndpointReferences().add(endpointRef); + Monitor.warning(monitor, + this, + "assembly-validation-messages", + "ComponentReferenceTargetNotFound", + composite.getName().toString(), + targetName); + } + + } else { + // create endpoint reference with dummy endpoint which will be replaced when policies + // are matched and bindings are configured later + EndpointReference endpointRef = + createEndpointRef(component, reference, binding, null, false); + endpointRef + .setTargetEndpoint(createEndpoint(targetComponent, targetComponentService, true)); + endpointRef.setStatus(EndpointReference.WIRED_TARGET_FOUND_READY_FOR_MATCHING); + reference.getEndpointReferences().add(endpointRef); + } + } else { + Monitor.warning(monitor, + this, + "assembly-validation-messages", + "ReferenceIncompatibleInterface", + composite.getName().toString(), + reference.getName(), + uri); + } + } else { + // create endpoint reference for manually configured bindings with resolved endpoint + // to signify that this reference is pointing at some unwired endpoint. The endpoint + // is given the configured binding as a representation of the endpoint configuration. + EndpointReference endpointRef = createEndpointRef(component, reference, binding, null, false); + Endpoint endpoint = createEndpoint(false); + endpoint.setBinding(binding); + endpointRef.setTargetEndpoint(endpoint); + endpointRef.setRemote(true); + endpointRef.setStatus(EndpointReference.RESOLVED_BINDING); + reference.getEndpointReferences().add(endpointRef); + } // end if + } + } + + monitor.popContext(); + + } // end method + + private void validateReferenceMultiplicity(Composite composite, Component component) { + for (ComponentReference componentReference : component.getReferences()) { + if (!ReferenceConfigurationUtil.validateMultiplicityAndTargets(componentReference.getMultiplicity(), + componentReference.getEndpointReferences())) { + if (componentReference.getEndpointReferences().isEmpty()) { + + // No error if the reference is promoted out of the current composite + boolean promoted = false; + for (Reference reference : composite.getReferences()) { + CompositeReference compositeReference = (CompositeReference)reference; + if (compositeReference.getPromotedReferences().contains(componentReference)) { + promoted = true; + break; + } + } + if (!promoted && !componentReference.isForCallback() && !componentReference.isWiredByImpl()) { + Monitor.error(monitor, + this, + "assembly-validation-messages", + "ReferenceWithoutTargets", + composite.getName().toString(), + componentReference.getName()); + } + } else { + // no error if reference is autowire and more targets + // than multiplicity have been found + if (componentReference.getAutowire() == Boolean.TRUE) { + break; + } + + Monitor.error(monitor, + this, + "assembly-validation-messages", + "TooManyReferenceTargets", + componentReference.getName()); + } + } + } + + } + + /** + * 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 + */ + private boolean bindingsIdentifyTargets(ComponentReference reference) { + for (Binding binding : reference.getBindings()) { + // <binding.sca without a URI does not identify a target + if ((binding instanceof SCABinding) && (binding.getURI() == null)) + continue; + // any other binding implies a target + // TODO Processing for other binding types + return true; + } // end for + return false; + } // end bindingsIdentifyTargets + + /** + * Helper method which obtains a list of targets for a reference + * @param reference - Component reference + * @return - the list of targets, which will be empty if there are no targets + */ + private List<ComponentService> getReferenceTargets(ComponentReference reference) { + List<ComponentService> theTargets = reference.getTargets(); + if (theTargets.isEmpty()) { + // Component reference list of targets is empty, try the implementation reference + if (reference.getReference() != null) { + theTargets = reference.getReference().getTargets(); + } // end if + } // end if + return theTargets; + } // end method getReferenceTargets + + /** + * Target names can take the form + * component/service/binding + * This extracts the component/service part + * + * @param targetName + * @return String the component/service name + */ + private String getComponentServiceName(String targetName) { + String[] parts = targetName.split("/"); + + if (parts.length > 1) { + return parts[0] + "/" + parts[1]; + } else { + return parts[0]; + } + } + + /** + * Target names can take the form + * component/service/binding + * This extracts the binding part and returns + * it. If there is no binding part it returns null + * + * @param targetName + * @return String the binding name or null if there is no binding name + */ + private String getBindingName(String targetName) { + String[] parts = targetName.split("/"); + + if (parts.length == 3) { + return parts[2]; + } else { + return null; + } + } + + /** + * Helper method that finds the Component given a target name + * @param components + * @param targetName + * @return the component + */ + private Component getComponentFromTargetName(Map<String, Component> components, String targetName) { + Component theComponent; + int s = targetName.indexOf('/'); + if (s == -1) { + theComponent = components.get(targetName); + } else { + theComponent = components.get(targetName.substring(0, s)); + } + return theComponent; + } // end method getComponentFromTargetName + + /** + * Helper method to create an Endpoint Reference + * @param component + * @param reference + * @param binding + * @param endpoint + * @param unresolved + * @return the endpoint reference + */ + private EndpointReference createEndpointRef(Component component, + ComponentReference reference, + Binding binding, + Endpoint endpoint, + boolean unresolved) { + EndpointReference endpointRef = createEndpointRef(component, reference, unresolved); + endpointRef.setBinding(binding); + endpointRef.setTargetEndpoint(endpoint); + return endpointRef; + } // end method + + /** + * Helper method to create an Endpoint Reference + * @param component + * @param reference + * @param unresolved + * @return the endpoint reference + */ + private EndpointReference createEndpointRef(Component component, ComponentReference reference, boolean unresolved) { + EndpointReference endpointRef = assemblyFactory.createEndpointReference(); + endpointRef.setComponent(component); + endpointRef.setReference(reference); + endpointRef.setUnresolved(unresolved); + return endpointRef; + } // end method createEndpointRef + + /** + * Helper method to create an endpoint + * @param component + * @param service + * @param unresolved + * @return the endpoint + */ + private Endpoint createEndpoint(Component component, ComponentService service, boolean unresolved) { + Endpoint endpoint = createEndpoint(unresolved); + endpoint.setComponent(component); + endpoint.setService(service); + endpoint.setUnresolved(unresolved); + return endpoint; + } // end method createEndpoint + + /** + * Helper method to create an endpoint + * @param component + * @param service + * @param binding + * @param unresolved + * @return the endpoint + */ + private Endpoint createEndpoint(Component component, ComponentService service, Binding binding, boolean unresolved) { + Endpoint endpoint = createEndpoint(unresolved); + endpoint.setComponent(component); + endpoint.setService(service); + endpoint.setBinding(binding); + endpoint.setUnresolved(unresolved); + return endpoint; + } // end method createEndpoint + + /** + * Helper method to create an Endpoint + * @param unresolved + * @return the endpoint + */ + private Endpoint createEndpoint(boolean unresolved) { + Endpoint endpoint = assemblyFactory.createEndpoint(); + endpoint.setUnresolved(unresolved); + return endpoint; + } // end method createEndpoint + + /** + * Helper method to create an Endpoint + * + * @param component The component that owns the reference + * @param targetName It can be one of the following formats + * <ul> + * <li>componentName + * <li>componentName/serviceName + * <li>componentName/serviceName/bindingName + * </ul> + * @return the endpoint + */ + private Endpoint createEndpoint(Component component, String targetName) { + String[] parts = targetName.split("/"); + if (parts.length < 1 || parts.length > 3) { + throw new IllegalArgumentException("Invalid target URI: " + targetName); + } + + // Find the parent uri + String uri = component.getURI(); + int index = uri.lastIndexOf('/'); + if (index == -1) { + uri = ""; + } else { + uri = uri.substring(0, index); + } + + if (parts.length >= 1) { + // Append the target component name + if (uri.length() == 0) { + uri = parts[0]; + } else { + uri = uri + "/" + parts[0]; + } + } + if (parts.length == 3) { + // <componentURI>#service-binding(serviceName/bindingName) + uri = uri + "#service-binding(" + parts[1] + "/" + parts[2] + ")"; + } else if (parts.length == 2) { + // <componentURI>#service(serviceName) + uri = uri + "#service(" + parts[1] + ")"; + } + + Endpoint endpoint = assemblyFactory.createEndpoint(); + endpoint.setUnresolved(true); + endpoint.setURI(uri); + return endpoint; + } // end method createEndpoint + + /** + * ASM_5021: where a <reference/> of a <component/> has @autowire=true + * and where the <reference/> has a <binding/> child element which + * declares a single target service, the reference is wired only to + * the single service identified by the <wire/> element + */ + private void setSingleAutoWireTarget(ComponentReference reference) { + if (reference.getEndpointReferences().size() > 1 && reference.getBindings() != null + && reference.getBindings().size() == 1) { + String uri = reference.getBindings().get(0).getURI(); + if (uri != null) { + if (uri.indexOf('/') > -1) { + // TODO: must be a way to avoid this fiddling + int i = uri.indexOf('/'); + String c = uri.substring(0, i); + String s = uri.substring(i + 1); + uri = c + "#service(" + s + ")"; + } + for (EndpointReference er : reference.getEndpointReferences()) { + if (er.getTargetEndpoint() != null && uri.equals(er.getTargetEndpoint().getURI())) { + reference.getEndpointReferences().clear(); + reference.getEndpointReferences().add(er); + return; + } + } + } + } + } + +} // end class diff --git a/java/sca/modules/builder/src/main/java/org/apache/tuscany/sca/builder/impl/ModelBuilderImpl.java b/java/sca/modules/builder/src/main/java/org/apache/tuscany/sca/builder/impl/ModelBuilderImpl.java new file mode 100644 index 0000000000..43e5d76e9e --- /dev/null +++ b/java/sca/modules/builder/src/main/java/org/apache/tuscany/sca/builder/impl/ModelBuilderImpl.java @@ -0,0 +1,130 @@ +/* + * 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.List; +import java.util.Map; + +import javax.xml.namespace.QName; + +import org.apache.tuscany.sca.assembly.Composite; +import org.apache.tuscany.sca.assembly.builder.CompositeBuilder; +import org.apache.tuscany.sca.assembly.builder.CompositeBuilderException; +import org.apache.tuscany.sca.assembly.builder.DeployedCompositeBuilder; +import org.apache.tuscany.sca.core.ExtensionPointRegistry; +import org.apache.tuscany.sca.definitions.Definitions; +import org.apache.tuscany.sca.monitor.Monitor; + +public class ModelBuilderImpl implements CompositeBuilder, DeployedCompositeBuilder { + private CompositeBuilder compositeIncludeBuilder; + private CompositeBuilder compositeCloneBuilder; + private CompositeComponentTypeBuilderImpl compositeComponentTypeBuilder; + private ComponentBuilderImpl componentBuilder; + + private BindingURIBuilderImpl bindingURIBuilder; + private ComponentServiceBindingBuilderImpl componentServiceBindingBuilder; + private ComponentReferenceBindingBuilderImpl componentReferenceBindingBuilder; + private EndpointBuilderImpl endpointBuilder; + private EndpointReferenceBuilderImpl endpointReferenceBuilder; + private ComponentReferencePromotionBuilderImpl componentReferencePromotionBuilder; + private CompositePolicyBuilderImpl compositePolicyBuilder; + + /** + * Constructs a new composite builder. + * + * @param registry the extension point registry + */ + public ModelBuilderImpl(ExtensionPointRegistry registry) { + + compositeIncludeBuilder = new CompositeIncludeBuilderImpl(); + compositeCloneBuilder = new CompositeCloneBuilderImpl(); + + compositeComponentTypeBuilder = new CompositeComponentTypeBuilderImpl(registry); + componentBuilder = new ComponentBuilderImpl(registry); + + compositeComponentTypeBuilder.setComponentBuilder(componentBuilder); + componentBuilder.setComponentTypeBuilder(compositeComponentTypeBuilder); + + bindingURIBuilder = new BindingURIBuilderImpl(registry); + componentServiceBindingBuilder = new ComponentServiceBindingBuilderImpl(registry); + componentReferenceBindingBuilder = new ComponentReferenceBindingBuilderImpl(registry); + endpointBuilder = new EndpointBuilderImpl(registry); + endpointReferenceBuilder = new EndpointReferenceBuilderImpl(registry); + componentReferencePromotionBuilder = new ComponentReferencePromotionBuilderImpl(registry); + compositePolicyBuilder = new CompositePolicyBuilderImpl(registry); + + } + + public String getID() { + return "org.apache.tuscany.sca.assembly.builder.CompositeBuilder"; + } + + public Composite build(Composite composite, Definitions definitions, Monitor monitor) + throws CompositeBuilderException { + return build(composite, definitions, null, monitor); + } + + public Composite build(Composite composite, + Definitions definitions, + Map<QName, List<String>> bindingBaseURIs, + Monitor monitor) throws CompositeBuilderException { + + try { + // Clone the composites that are included or referenced in implementation.composite + composite = compositeCloneBuilder.build(composite, definitions, monitor); + + // Collect and fuse includes. Copy all of the components + // out of the included composite into the including composite + // and discards the included composite + composite = compositeIncludeBuilder.build(composite, definitions, monitor); + + // need to apply policy external attachment + + + // Process the implementation hierarchy by calculating the component type + // for the top level implementation (composite). This has the effect of + // recursively calculating component types and configuring the + // components that depend on them + compositeComponentTypeBuilder.createComponentType(composite); + + // create the runtime model by updating the static model we have just + // created. This involves things like creating + // component URIs + // binding URIs + // binding specific build processing + // callback references - currently done in static pass + // callback services - currently done in static pass + // Endpoints + // Endoint References + // Policies + // TODO - called here at the moment but we could have a separate build phase + // to call these. Also we need to re-org these builders + bindingURIBuilder.configureBindingURIsAndNames(composite, definitions, monitor); + composite = componentServiceBindingBuilder.build(composite, definitions, monitor); // binding specific build + composite = componentReferenceBindingBuilder.build(composite, definitions, monitor); // binding specific build + endpointBuilder.build(composite, definitions, monitor); + endpointReferenceBuilder.build(composite, definitions, monitor); + composite = componentReferencePromotionBuilder.build(composite, definitions, monitor); // move into the static build? + composite = compositePolicyBuilder.build(composite, definitions, monitor); // the rest of the policy processing? + return composite; + } catch (Exception e) { + throw new CompositeBuilderException("Exception while building model " + composite.getName(), e); + } + } +} diff --git a/java/sca/modules/builder/src/main/java/org/apache/tuscany/sca/policy/builder/impl/PolicyAttachmentBuilderImpl.java b/java/sca/modules/builder/src/main/java/org/apache/tuscany/sca/builder/impl/PolicyAttachmentBuilderImpl.java index 98d93d8186..19dff30051 100644 --- a/java/sca/modules/builder/src/main/java/org/apache/tuscany/sca/policy/builder/impl/PolicyAttachmentBuilderImpl.java +++ b/java/sca/modules/builder/src/main/java/org/apache/tuscany/sca/builder/impl/PolicyAttachmentBuilderImpl.java @@ -17,7 +17,7 @@ * under the License. */ -package org.apache.tuscany.sca.policy.builder.impl; +package org.apache.tuscany.sca.builder.impl; import static javax.xml.XMLConstants.DEFAULT_NS_PREFIX; import static javax.xml.XMLConstants.XMLNS_ATTRIBUTE; diff --git a/java/sca/modules/builder/src/main/java/org/apache/tuscany/sca/builder/impl/ReferenceConfigurationUtil.java b/java/sca/modules/builder/src/main/java/org/apache/tuscany/sca/builder/impl/ReferenceConfigurationUtil.java new file mode 100644 index 0000000000..cf25440528 --- /dev/null +++ b/java/sca/modules/builder/src/main/java/org/apache/tuscany/sca/builder/impl/ReferenceConfigurationUtil.java @@ -0,0 +1,215 @@ +/* + * 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.ArrayList; +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +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.EndpointReference; +import org.apache.tuscany.sca.assembly.Multiplicity; +import org.apache.tuscany.sca.assembly.OptimizableBinding; +import org.apache.tuscany.sca.assembly.Reference; +import org.apache.tuscany.sca.monitor.Monitor; +import org.apache.tuscany.sca.monitor.Problem; +import org.apache.tuscany.sca.monitor.Problem.Severity; + +/** + * This class encapsulates utility methods to deal with reference definitions + * + * @version $Rev$ $Date$ + */ +abstract class ReferenceConfigurationUtil { + + /** + * Report a warning. + * + * @param problems + * @param message + * @param model + */ + private static void warning(Monitor monitor, String message, Object model, String... messageParameters) { + if (monitor != null) { + Problem problem = + monitor.createProblem(ReferenceConfigurationUtil.class.getName(), + "assembly-validation-messages", + Severity.WARNING, + model, + message, + (Object[])messageParameters); + monitor.problem(problem); + } + } + + static boolean isValidMultiplicityOverride(Multiplicity definedMul, Multiplicity overridenMul) { + if (definedMul != overridenMul) { + switch (definedMul) { + case ZERO_N: + return overridenMul == Multiplicity.ZERO_ONE || overridenMul == Multiplicity.ONE_ONE + || overridenMul == Multiplicity.ONE_N; + case ONE_N: + return overridenMul == Multiplicity.ONE_ONE; + case ZERO_ONE: + return overridenMul == Multiplicity.ONE_ONE; + default: + return false; + } + } else { + return true; + } + } + + static boolean validateMultiplicityAndTargets(Multiplicity multiplicity, List<EndpointReference> endpointReferences) { + + // In some tests multiplicity is not set + if (multiplicity == null) { + return true; + } + + // Count targets + int count = endpointReferences.size(); + + switch (multiplicity) { + case ZERO_N: + break; + case ZERO_ONE: + if (count > 1) { + return false; + } + break; + case ONE_ONE: + if (count != 1) { + return false; + } + break; + case ONE_N: + if (count < 1) { + return false; + } + break; + } + return true; + } + + /** + * Follow a reference promotion chain down to the innermost (non composite) + * component references. + * + * @param compositeReference + * @return + */ + static List<ComponentReference> getPromotedComponentReferences(CompositeReference compositeReference) { + List<ComponentReference> componentReferences = new ArrayList<ComponentReference>(); + collectPromotedComponentReferences(compositeReference, componentReferences); + return componentReferences; + } + + /** + * Follow a reference promotion chain down to the innermost (non composite) + * component references. + * + * @param compositeReference + * @param componentReferences + * @return + */ + private static void collectPromotedComponentReferences(CompositeReference compositeReference, + List<ComponentReference> componentReferences) { + for (ComponentReference componentReference : compositeReference.getPromotedReferences()) { + Reference reference = componentReference.getReference(); + if (reference instanceof CompositeReference) { + + // Continue to follow the reference promotion chain + collectPromotedComponentReferences((CompositeReference)reference, componentReferences); + + } else if (reference != null) { + + // Found a non-composite reference + componentReferences.add(componentReference); + } + } + } + + /** + * Override the bindings for a promoted reference from an outer component reference + * + * @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 (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 (EndpointReference epRef : reference.getEndpointReferences()) { + EndpointReference epRefClone = copyHigherReference(epRef, promotedReference); + promotedReference.getEndpointReferences().add(epRefClone); + } // end for + } // end if + + Set<Binding> callbackBindings = new HashSet<Binding>(); + if (promotedReference.getCallback() != null) { + callbackBindings.addAll(promotedReference.getCallback().getBindings()); + } + if (reference.getCallback() != null) { + callbackBindings.addAll(reference.getCallback().getBindings()); + } + promotedReference.setCallback(assemblyFactory.createCallback()); + 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 EndpointReference copyHigherReference(EndpointReference epRef, ComponentReference promotedReference) { + EndpointReference epRefClone = null; + try { + epRefClone = (EndpointReference)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/builder/src/main/java/org/apache/tuscany/sca/builder/impl/ServiceConfigurationUtil.java b/java/sca/modules/builder/src/main/java/org/apache/tuscany/sca/builder/impl/ServiceConfigurationUtil.java new file mode 100644 index 0000000000..ef03344131 --- /dev/null +++ b/java/sca/modules/builder/src/main/java/org/apache/tuscany/sca/builder/impl/ServiceConfigurationUtil.java @@ -0,0 +1,88 @@ +/* + * 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 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.Service; + +/** + * This class encapsulates utility methods to deal with service definitions. + * + * @version $Rev$ $Date$ + */ +abstract class ServiceConfigurationUtil { + + /** + * Follow a service promotion chain down to the inner most (non composite) + * component service. + * + * @param topCompositeService + * @return + */ + static ComponentService getPromotedComponentService(CompositeService compositeService) { + ComponentService componentService = compositeService.getPromotedService(); + if (componentService != null) { + Service service = componentService.getService(); + if (componentService.getName() != null && service instanceof CompositeService) { + + // Continue to follow the service promotion chain + return getPromotedComponentService((CompositeService)service); + + } else { + + // Found a non-composite service + return componentService; + } + } else { + + // No promoted service + return null; + } + } + + /** + * Follow a service promotion chain down to the innermost (non-composite) component. + * + * @param compositeService + * @return + */ + static Component getPromotedComponent(CompositeService compositeService) { + ComponentService componentService = compositeService.getPromotedService(); + if (componentService != null) { + Service service = componentService.getService(); + if (componentService.getName() != null && service instanceof CompositeService) { + + // Continue to follow the service promotion chain + return getPromotedComponent((CompositeService)service); + + } else { + + // Found a non-composite service + return compositeService.getPromotedComponent(); + } + } else { + + // No promoted service + return null; + } + } + +} diff --git a/java/sca/modules/builder/src/main/java/org/apache/tuscany/sca/builder/impl/StructuralURIBuilderImpl.java b/java/sca/modules/builder/src/main/java/org/apache/tuscany/sca/builder/impl/StructuralURIBuilderImpl.java new file mode 100644 index 0000000000..04f7759493 --- /dev/null +++ b/java/sca/modules/builder/src/main/java/org/apache/tuscany/sca/builder/impl/StructuralURIBuilderImpl.java @@ -0,0 +1,562 @@ +/* + * 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.net.URI; +import java.net.URISyntaxException; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import javax.xml.namespace.QName; + +import org.apache.tuscany.sca.assembly.Binding; +import org.apache.tuscany.sca.assembly.Component; +import org.apache.tuscany.sca.assembly.ComponentReference; +import org.apache.tuscany.sca.assembly.ComponentService; +import org.apache.tuscany.sca.assembly.Composite; +import org.apache.tuscany.sca.assembly.Contract; +import org.apache.tuscany.sca.assembly.Implementation; +import org.apache.tuscany.sca.assembly.Reference; +import org.apache.tuscany.sca.assembly.Service; +import org.apache.tuscany.sca.assembly.builder.CompositeBuilder; +import org.apache.tuscany.sca.assembly.builder.CompositeBuilderException; +import org.apache.tuscany.sca.assembly.builder.DeployedCompositeBuilder; +import org.apache.tuscany.sca.core.ExtensionPointRegistry; +import org.apache.tuscany.sca.definitions.Definitions; +import org.apache.tuscany.sca.monitor.Monitor; + +/** + * Configuration of binding URIs. + * + * @version $Rev$ $Date$ + */ +public class StructuralURIBuilderImpl implements CompositeBuilder, DeployedCompositeBuilder { + + public StructuralURIBuilderImpl(ExtensionPointRegistry registry) { + } + + /** + * Called by CompositeBindingURIBuilderImpl + * + * @param composite the composite to be configured + */ + protected void configureBindingURIsAndNames(Composite composite, Definitions definitions, Monitor monitor) + throws CompositeBuilderException { + configureBindingURIs(composite, null, definitions, null, monitor); + configureBindingNames(composite, monitor); + } + + /** + * Fully resolve the binding URIs based on available information. This includes information + * from the ".composite" files, from resources associated with the binding, e.g. WSDL files, + * from any associated policies and from the default information for each binding type. + * + * @param composite the composite to be configured + * @param bindingBaseURIs list of default binding configurations + */ + private void configureBindingURIs(Composite composite, + Definitions definitions, + Map<QName, List<String>> bindingBaseURIs, + Monitor monitor) throws CompositeBuilderException { + configureBindingURIs(composite, null, definitions, bindingBaseURIs, monitor); + } + + /** + * Fully resolve the binding URIs based on available information. This includes information + * from the ".composite" files, from resources associated with the binding, e.g. WSDL files, + * from any associated policies and from the default information for each binding type. + * + * NOTE: This method repeats some of the processing performed by the configureComponents() + * method above. The duplication is needed because NodeConfigurationServiceImpl + * calls this method without previously calling configureComponents(). In the + * normal builder sequence used by CompositeBuilderImpl, both of these methods + * are called. + * + * TODO: Share the URL calculation algorithm with the configureComponents() method above + * although keeping the configureComponents() methods signature as is because when + * a composite is actually build in a node the node default information is currently + * available + * + * @param composite the composite to be configured + * @param uri the path to the composite provided through any nested composite component implementations + * @param defaultBindings list of default binding configurations + */ + private void configureBindingURIs(Composite composite, + String parentComponentURI, + Definitions definitions, + Map<QName, List<String>> defaultBindings, + Monitor monitor) throws CompositeBuilderException { + + monitor.pushContext("Composite: " + composite.getName().toString()); + try { + // Process nested composites recursively + for (Component component : composite.getComponents()) { + + // Initialize component URI + String componentURI; + if (parentComponentURI == null) { + componentURI = component.getName(); + } else { + componentURI = parentComponentURI + '/' + component.getName(); + } + component.setURI(componentURI); + + Implementation implementation = component.getImplementation(); + if (implementation instanceof Composite) { + // Process nested composite + configureBindingURIs((Composite)implementation, componentURI, definitions, defaultBindings, monitor); + } + } + + // Initialize composite service binding URIs + List<Service> compositeServices = composite.getServices(); + for (Service service : compositeServices) { + + constructBindingNames(service, monitor); + + // Initialize binding names and URIs + for (Binding binding : service.getBindings()) { + constructBindingURI(parentComponentURI, composite, service, binding, defaultBindings, monitor); + } + } + + // Initialize component service binding URIs + for (Component component : composite.getComponents()) { + + monitor.pushContext("Component: " + component.getName()); + + try { + + for (ComponentService service : component.getServices()) { + + constructBindingNames(service, monitor); + + // Initialize binding names and URIs + for (Binding binding : service.getBindings()) { + constructBindingURI(component.getURI(), service, binding, defaultBindings, monitor); + } + } + } finally { + monitor.popContext(); + } + } + } finally { + monitor.popContext(); + } + } + + /** + * Add default names for callback bindings and reference bindings. Needs to be + * separate from configureBindingURIs() because configureBindingURIs() is called + * by NodeConfigurationServiceImpl as well as by CompositeBuilderImpl. + */ + private void configureBindingNames(Composite composite, Monitor monitor) { + + // Process nested composites recursively + for (Component component : composite.getComponents()) { + + Implementation implementation = component.getImplementation(); + if (implementation instanceof Composite) { + + // Process nested composite + configureBindingNames((Composite)implementation, monitor); + } + } + + // Initialize composite service callback binding names + for (Service service : composite.getServices()) { + constructBindingNames(service, monitor); + } + + // Initialize composite reference binding names + for (Reference reference : composite.getReferences()) { + constructBindingNames(reference, monitor); + } + + // Initialize component service and reference binding names + for (Component component : composite.getComponents()) { + + // Initialize component service callback binding names + for (ComponentService service : component.getServices()) { + constructBindingNames(service, monitor); + } + + // Initialize component reference binding names + for (ComponentReference reference : component.getReferences()) { + // Initialize binding names + constructBindingNames(reference, monitor); + } + } + } + + /** + * If a binding name is not provided by the user, construct it based on the service + * or reference name + * + * @param contract the service or reference + */ + private void constructBindingNames(Contract contract, Monitor monitor) { + List<Binding> bindings = contract.getBindings(); + Map<String, Binding> bindingMap = new HashMap<String, Binding>(); + for (Binding binding : bindings) { + // set the default binding name if one is required + // if there is no name on the binding then set it to the service or reference name + if (binding.getName() == null) { + binding.setName(contract.getName()); + } + Binding existed = bindingMap.put(binding.getName(), binding); + // Check that multiple bindings do not have the same name + if (existed != null && existed != binding) { + if (contract instanceof Service) { + Monitor.error(monitor, this, "assembly-validation-messages", "MultipleBindingsForService", contract + .getName(), binding.getName()); + } else { + Monitor.error(monitor, + this, + "assembly-validation-messages", + "MultipleBindingsForReference", + contract.getName(), + binding.getName()); + } + } + } + + if (contract.getCallback() != null) { + bindings = contract.getCallback().getBindings(); + bindingMap.clear(); + for (Binding binding : bindings) { + // set the default binding name if one is required + // if there is no name on the binding then set it to the service or reference name + if (binding.getName() == null) { + binding.setName(contract.getName()); + } + Binding existed = bindingMap.put(binding.getName(), binding); + // Check that multiple bindings do not have the same name + if (existed != null && existed != binding) { + if (contract instanceof Service) { + Monitor.error(monitor, + this, + "assembly-validation-messages", + "MultipleBindingsForServiceCallback", + contract.getName(), + binding.getName()); + } else { + Monitor.error(monitor, + this, + "assembly-validation-messages", + "MultipleBindingsForReferenceCallback", + contract.getName(), + binding.getName()); + } + } + } + } + } + + /** + * URI construction for composite bindings based on Assembly Specification section 1.7.2, This method + * assumes that the component URI part of the binding URI is formed from the part to the + * composite in question and just calls the generic constructBindingURI method with this + * information + * + * @param parentComponentURI + * @param composite + * @param service + * @param binding + * @param defaultBindings + */ + private void constructBindingURI(String parentComponentURI, + Composite composite, + Service service, + Binding binding, + Map<QName, List<String>> defaultBindings, + Monitor monitor) throws CompositeBuilderException { + // This is a composite service so there is no component to provide a component URI + // The path to this composite (through nested composites) is used. + constructBindingURI(parentComponentURI, service, binding, defaultBindings, monitor); + } + + /** + * Generic URI construction for bindings based on Assembly Specification section 1.7.2 + * + * @param componentURIString the string version of the URI part that comes from the component name + * @param service the service in question + * @param binding the binding for which the URI is being constructed + * @param includeBindingName when set true the serviceBindingURI part should be used + * @param defaultBindings the list of default binding configurations + * @throws CompositeBuilderException + */ + private void constructBindingURI(String componentURIString, + Service service, + Binding binding, + Map<QName, List<String>> defaultBindings, + Monitor monitor) throws CompositeBuilderException { + + try { + + boolean includeBindingName = !service.getName().equals(binding.getName()); + + // calculate the service binding URI + URI bindingURI; + if (binding.getURI() != null) { + bindingURI = new URI(binding.getURI()); + + // if the user has provided an absolute binding URI then use it + if (bindingURI.isAbsolute()) { + return; + } + } else { + bindingURI = null; + } + + String serviceName = service.getName(); + // Get the service binding name + String bindingName; + if (binding.getName() != null) { + bindingName = binding.getName(); + } else { + bindingName = serviceName; + } + + // calculate the component URI + URI componentURI; + if (componentURIString != null) { + componentURI = new URI(addSlashToPath(componentURIString)); + } else { + componentURI = null; + } + + // if the user has provided an absolute component URI then use it + if (componentURI != null && componentURI.isAbsolute()) { + binding.setURI(constructBindingURI(null, + componentURI, + bindingURI, + serviceName, + includeBindingName, + bindingName)); + return; + } + + // calculate the base URI + URI baseURI = null; + if (defaultBindings != null) { + List<String> uris = defaultBindings.get(binding.getType()); + if (uris != null && uris.size() > 0) { + baseURI = new URI(addSlashToPath(uris.get(0))); + } + } + + binding.setURI(constructBindingURI(baseURI, + componentURI, + bindingURI, + serviceName, + includeBindingName, + bindingName)); + } catch (URISyntaxException ex) { + Monitor.error(monitor, + this, + "assembly-validation-messages", + "URLSyntaxException", + componentURIString, + service.getName(), + binding.getName()); + } + } + + /** + * Use to ensure that URI paths end in "/" as here we want to maintain the + * last path element of an base URI when other URI are resolved against it. This is + * not the default behaviour of URI resolution as defined in RFC 2369 + * + * @param path the path string to which the "/" is to be added + * @return the resulting path with a "/" added if it not already there + */ + private static String addSlashToPath(String path) { + if (path.endsWith("/") || path.endsWith("#")) { + return path; + } else { + return path + "/"; + } + } + + /** + * Concatenate binding URI parts together based on Assembly Specification section 1.7.2 + * + * @param baseURI the base of the binding URI + * @param componentURI the middle part of the binding URI derived from the component name + * @param bindingURI the end part of the binding URI + * @param includeBindingName when set true the binding name part should be used + * @param bindingName the binding name + * @return the resulting URI as a string + */ + private static String constructBindingURI(URI baseURI, + URI componentURI, + URI bindingURI, + String serviceName, + boolean includeBindingName, + String bindingName) { + String name = includeBindingName ? serviceName + "/" + bindingName : serviceName; + String uriString; + + if (baseURI == null) { + if (componentURI == null) { + if (bindingURI != null) { + uriString = name + "/" + bindingURI.toString(); + } else { + uriString = name; + } + } else { + if (bindingURI != null) { + if (bindingURI.toString().startsWith("/")) { + uriString = componentURI.resolve(bindingURI).toString(); + } else { + uriString = componentURI.resolve(name + "/" + bindingURI).toString(); + } + } else { + uriString = componentURI.resolve(name).toString(); + } + } + } else { + if (componentURI == null) { + if (bindingURI != null) { + uriString = basedURI(baseURI, bindingURI).toString(); + } else { + uriString = basedURI(baseURI, URI.create(name)).toString(); + } + } else { + if (bindingURI != null) { + uriString = basedURI(baseURI, componentURI.resolve(bindingURI)).toString(); + } else { + uriString = basedURI(baseURI, componentURI.resolve(name)).toString(); + } + } + } + + // tidy up by removing any trailing "/" + if (uriString.endsWith("/")) { + uriString = uriString.substring(0, uriString.length() - 1); + } + + URI uri = URI.create(uriString); + if (!uri.isAbsolute()) { + uri = URI.create("/").resolve(uri); + } + return uri.toString(); + } + + /** + * Combine a URI with a base URI. + * + * @param baseURI + * @param uri + * @return + */ + private static URI basedURI(URI baseURI, URI uri) { + if (uri.getScheme() != null) { + return uri; + } + String str = uri.toString(); + if (str.startsWith("/")) { + str = str.substring(1); + } + return URI.create(baseURI.toString() + str).normalize(); + } + + public Composite build(Composite composite, Definitions definitions, Monitor monitor) + throws CompositeBuilderException { + configureStructuralURIs(composite, null, definitions, null, monitor); + return composite; + } + + public String getID() { + return "org.apache.tuscany.sca.assembly.builder.StructualURIBuilder"; + } + + public Composite build(Composite composite, + Definitions definitions, + Map<QName, List<String>> bindingBaseURIs, + Monitor monitor) throws CompositeBuilderException { + configureBindingURIs(composite, definitions, bindingBaseURIs, monitor); + return composite; + } + + private void configureStructuralURIs(Composite composite, + String parentComponentURI, + Definitions definitions, + Map<QName, List<String>> defaultBindings, + Monitor monitor) throws CompositeBuilderException { + + monitor.pushContext("Composite: " + composite.getName().toString()); + try { + for (Service service : composite.getServices()) { + constructBindingNames(service, monitor); + } + + for (Reference reference : composite.getReferences()) { + constructBindingNames(reference, monitor); + } + + // Process nested composites recursively + for (Component component : composite.getComponents()) { + + // Initialize component URI + String componentURI; + if (parentComponentURI == null) { + componentURI = component.getName(); + } else { + componentURI = parentComponentURI + '/' + component.getName(); + } + component.setURI(componentURI); + + monitor.pushContext("Component: " + component.getName()); + try { + for (ComponentService service : component.getServices()) { + constructBindingNames(service, monitor); + + // Initialize binding names and URIs + for (Binding binding : service.getBindings()) { + constructBindingURI(componentURI, service, binding, defaultBindings, monitor); + } + } + for (ComponentReference service : component.getReferences()) { + constructBindingNames(service, monitor); + } + } finally { + monitor.popContext(); + } + + Implementation implementation = component.getImplementation(); + if (implementation instanceof Composite) { + // Process nested composite + configureStructuralURIs((Composite)implementation, + componentURI, + definitions, + defaultBindings, + monitor); + } + } + + } finally { + monitor.popContext(); + } + } + +} diff --git a/java/sca/modules/builder/src/test/java/org/apache/tuscany/sca/policy/builder/impl/MockPolicy.java b/java/sca/modules/builder/src/test/java/org/apache/tuscany/sca/builder/impl/MockPolicy.java index c3c293cdf8..dac50ec227 100644 --- a/java/sca/modules/builder/src/test/java/org/apache/tuscany/sca/policy/builder/impl/MockPolicy.java +++ b/java/sca/modules/builder/src/test/java/org/apache/tuscany/sca/builder/impl/MockPolicy.java @@ -17,7 +17,7 @@ * under the License. */ -package org.apache.tuscany.sca.policy.builder.impl; +package org.apache.tuscany.sca.builder.impl; import javax.xml.namespace.QName; diff --git a/java/sca/modules/builder/src/test/java/org/apache/tuscany/sca/policy/builder/impl/PolicyAttachmentTestCase.java b/java/sca/modules/builder/src/test/java/org/apache/tuscany/sca/builder/impl/PolicyAttachmentTestCase.java index 2987dd7b5e..075dac51a1 100644 --- a/java/sca/modules/builder/src/test/java/org/apache/tuscany/sca/policy/builder/impl/PolicyAttachmentTestCase.java +++ b/java/sca/modules/builder/src/test/java/org/apache/tuscany/sca/builder/impl/PolicyAttachmentTestCase.java @@ -17,7 +17,7 @@ * under the License. */ -package org.apache.tuscany.sca.policy.builder.impl; +package org.apache.tuscany.sca.builder.impl; import java.io.IOException; import java.io.InputStream; @@ -35,6 +35,7 @@ import org.apache.tuscany.sca.assembly.builder.BuilderExtensionPoint; import org.apache.tuscany.sca.assembly.builder.CompositeBuilder; import org.apache.tuscany.sca.builder.impl.CompositeCloneBuilderImpl; import org.apache.tuscany.sca.builder.impl.CompositeIncludeBuilderImpl; +import org.apache.tuscany.sca.builder.impl.PolicyAttachmentBuilderImpl; import org.apache.tuscany.sca.builder.impl.StructuralURIBuilderImpl; import org.apache.tuscany.sca.contribution.processor.ContributionReadException; import org.apache.tuscany.sca.contribution.processor.ExtensibleStAXArtifactProcessor; diff --git a/java/sca/modules/builder/src/test/java/org/apache/tuscany/sca/policy/builder/impl/TestPolicyProcessor.java b/java/sca/modules/builder/src/test/java/org/apache/tuscany/sca/builder/impl/TestPolicyProcessor.java index 8a39e70f6b..975adf3543 100644 --- a/java/sca/modules/builder/src/test/java/org/apache/tuscany/sca/policy/builder/impl/TestPolicyProcessor.java +++ b/java/sca/modules/builder/src/test/java/org/apache/tuscany/sca/builder/impl/TestPolicyProcessor.java @@ -16,7 +16,7 @@ * specific language governing permissions and limitations * under the License. */ -package org.apache.tuscany.sca.policy.builder.impl; +package org.apache.tuscany.sca.builder.impl; import javax.xml.namespace.QName; import javax.xml.stream.XMLStreamException; |