diff options
Diffstat (limited to '')
-rw-r--r-- | java/sca/modules/assembly/src/main/java/org/apache/tuscany/sca/assembly/builder/impl/BindingURIBuilderImpl.java | 518 | ||||
-rw-r--r-- | java/sca/modules/assembly/src/main/java/org/apache/tuscany/sca/assembly/builder/impl/ComponentBuilderImpl.java | 663 | ||||
-rw-r--r-- | java/sca/modules/assembly/src/main/java/org/apache/tuscany/sca/assembly/builder/impl/CompositeComponentTypeBuilderImpl.java (renamed from java/sca/modules/assembly/src/main/java/org/apache/tuscany/sca/assembly/builder/impl/ComponentTypeBuilderImpl.java) | 87 | ||||
-rw-r--r-- | java/sca/modules/assembly/src/main/java/org/apache/tuscany/sca/assembly/builder/impl/EndpointBuilderImpl.java | 108 | ||||
-rw-r--r-- | java/sca/modules/assembly/src/main/java/org/apache/tuscany/sca/assembly/builder/impl/EndpointReferenceBuilderImpl.java | 731 | ||||
-rw-r--r-- | java/sca/modules/assembly/src/main/java/org/apache/tuscany/sca/assembly/builder/impl/ModelBuilderImpl.java | 156 |
6 files changed, 2025 insertions, 238 deletions
diff --git a/java/sca/modules/assembly/src/main/java/org/apache/tuscany/sca/assembly/builder/impl/BindingURIBuilderImpl.java b/java/sca/modules/assembly/src/main/java/org/apache/tuscany/sca/assembly/builder/impl/BindingURIBuilderImpl.java new file mode 100644 index 0000000000..cb4c549b7d --- /dev/null +++ b/java/sca/modules/assembly/src/main/java/org/apache/tuscany/sca/assembly/builder/impl/BindingURIBuilderImpl.java @@ -0,0 +1,518 @@ +/* + * 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.assembly.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.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.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.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/assembly/src/main/java/org/apache/tuscany/sca/assembly/builder/impl/ComponentBuilderImpl.java b/java/sca/modules/assembly/src/main/java/org/apache/tuscany/sca/assembly/builder/impl/ComponentBuilderImpl.java index 54475253a2..09e9d95724 100644 --- a/java/sca/modules/assembly/src/main/java/org/apache/tuscany/sca/assembly/builder/impl/ComponentBuilderImpl.java +++ b/java/sca/modules/assembly/src/main/java/org/apache/tuscany/sca/assembly/builder/impl/ComponentBuilderImpl.java @@ -18,24 +18,46 @@ */ package org.apache.tuscany.sca.assembly.builder.impl; +import static org.apache.tuscany.sca.assembly.Base.SCA11_NS; + +import java.io.InputStream; +import java.net.URI; +import java.net.URL; +import java.net.URLConnection; +import java.util.List; +import java.util.Map; import java.util.logging.Logger; 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.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.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.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.CompositeBuilderException; import org.apache.tuscany.sca.assembly.builder.ImplementationBuilder; import org.apache.tuscany.sca.core.ExtensionPointRegistry; import org.apache.tuscany.sca.core.FactoryExtensionPoint; @@ -47,6 +69,10 @@ 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$ @@ -58,12 +84,15 @@ public class ComponentBuilderImpl { protected static final String BINDING_SCA = "binding.sca"; protected static final QName BINDING_SCA_QNAME = new QName(SCA11_NS, BINDING_SCA); - private ComponentTypeBuilderImpl componentTypeBuilder; + 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); @@ -73,25 +102,32 @@ public class ComponentBuilderImpl { 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(ComponentTypeBuilderImpl componentTypeBuilder){ + public void setComponentTypeBuilder(CompositeComponentTypeBuilderImpl componentTypeBuilder){ this.componentTypeBuilder = componentTypeBuilder; } /** * Configure the component based on its component type using OASIS rules * - * @param component + * @Param parentComposite the composite that contains the component being configured. Required for property processing + * @param component the component to be configured */ - public void configureComponentFromComponentType(Component component){ + public void configureComponentFromComponentType(Composite parentComposite, + Component component){ - // do any required pre-processing on the implementation - // what does this do? + // 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()); @@ -100,19 +136,22 @@ public class ComponentBuilderImpl { } } + // 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); - - // services + + // configure services based on the calculated component type configureServices(component); - // references + // configure services based on the calculated component type configureReferences(component); - - // properties - //configureProperties(component); - } /** @@ -194,21 +233,26 @@ public class ComponentBuilderImpl { // configuration based on OASIS rules for (ComponentReference componentReference : component.getReferences()) { Reference componentTypeReference = componentReference.getReference(); + + // reference multiplicity + reconcileReferenceMultiplicity(component, + componentReference, + componentTypeReference); // interface contracts calculateInterfaceContract(componentReference, componentTypeReference); // bindings - // We don've to do anything with reference bindings. You've either + // 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); + createCallbackService(component, + componentReference); // intents - done later in CompositePolicyBuilder - discuss with RF @@ -218,9 +262,53 @@ public class ComponentBuilderImpl { // 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){ @@ -262,7 +350,32 @@ public class ComponentBuilderImpl { } } } - } + } + + 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){ @@ -308,76 +421,289 @@ public class ComponentBuilderImpl { 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()); + } + } + } + /** - * OASIS RULE: Interface contract from higher in the implementation hierarchy takes precedence + * If the property has a source attribute use this to retrieve the value from a + * property in the parent composite + * - * @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) { + * @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", - "ReferenceInterfaceNotSubSet", - topContract.getName()); - } else { + 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", - "ServiceInterfaceNotSubSet", - topContract.getName()); + 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()); } } - } + } /** - * OASIS RULE: Bindings from higher in the hierarchy take precedence + * If the property has a file attribute use this to retrieve the value from a + * local file + * - * @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()); - } + * @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(); - 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()); + 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()); } - } else if (componentService.getCallback().getBindings().isEmpty() && componentTypeService.getCallback() != null) { - componentService.getCallback().getBindings().addAll(componentTypeService.getCallback().getBindings()); } } /** + * 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 @@ -453,9 +779,84 @@ public class ComponentBuilderImpl { callbackReference.getBindings().addAll(service.getBindings()); } // end if } // end if - service.setCallbackReference(callbackReference); + 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); + + // set bindings of the callback service + if (reference.getCallback() != null) { + if (componentService.getBindings().isEmpty()) { + componentService.getBindings().addAll(reference.getCallback().getBindings()); + } + } + + reference.setCallbackService(componentService); + } + } /** * Create a default SCA binding in the case that no binding @@ -478,6 +879,122 @@ public class ComponentBuilderImpl { 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/assembly/src/main/java/org/apache/tuscany/sca/assembly/builder/impl/ComponentTypeBuilderImpl.java b/java/sca/modules/assembly/src/main/java/org/apache/tuscany/sca/assembly/builder/impl/CompositeComponentTypeBuilderImpl.java index 68db5bdb72..4d0f37d36d 100644 --- a/java/sca/modules/assembly/src/main/java/org/apache/tuscany/sca/assembly/builder/impl/ComponentTypeBuilderImpl.java +++ b/java/sca/modules/assembly/src/main/java/org/apache/tuscany/sca/assembly/builder/impl/CompositeComponentTypeBuilderImpl.java @@ -28,6 +28,7 @@ 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.ComponentProperty; import org.apache.tuscany.sca.assembly.ComponentReference; import org.apache.tuscany.sca.assembly.ComponentService; import org.apache.tuscany.sca.assembly.ComponentType; @@ -36,11 +37,13 @@ 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.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.CompositeBuilderException; import org.apache.tuscany.sca.core.ExtensionPointRegistry; import org.apache.tuscany.sca.core.FactoryExtensionPoint; import org.apache.tuscany.sca.core.UtilityExtensionPoint; @@ -51,15 +54,16 @@ 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; /** * @version $Rev$ $Date$ */ -// TODO - really implementation.composite component type builder +// TODO - really implementation.composite component type builder - CompositeComponentTypeBuilder? -public class ComponentTypeBuilderImpl { - private static final Logger logger = Logger.getLogger(ComponentTypeBuilderImpl.class.getName()); +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"; @@ -73,7 +77,7 @@ public class ComponentTypeBuilderImpl { private BuilderExtensionPoint builders; - public ComponentTypeBuilderImpl(ExtensionPointRegistry registry) { + public CompositeComponentTypeBuilderImpl(ExtensionPointRegistry registry){ UtilityExtensionPoint utilities = registry.getExtensionPoint(UtilityExtensionPoint.class); MonitorFactory monitorFactory = utilities.getUtility(MonitorFactory.class); monitor = monitorFactory.createMonitor(); @@ -120,14 +124,17 @@ public class ComponentTypeBuilderImpl { 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 - // TODO - Is this the right place to do this structural inheritance if (component.getAutowire() == null) { component.setAutowire(composite.getAutowire()); } // configure the component from its component type - componentBuilder.configureComponentFromComponentType(component); + componentBuilder.configureComponentFromComponentType(composite, component); } // create the composite component type based on the promoted artifacts @@ -147,10 +154,11 @@ public class ComponentTypeBuilderImpl { calculateReferences(composite, components, componentReferences); // properties - //calculateProperties(composite); + // 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); - // autowire - //calculateAutowire(composite); } @@ -163,9 +171,9 @@ public class ComponentTypeBuilderImpl { * @param componentReferences */ private void indexComponentsServicesAndReferences(Composite composite, - Map<String, Component> components, - Map<String, ComponentService> componentServices, - Map<String, ComponentReference> componentReferences) { + Map<String, Component> components, + Map<String, ComponentService> componentServices, + Map<String, ComponentReference> componentReferences) { for (Component component : composite.getComponents()) { @@ -284,7 +292,7 @@ public class ComponentTypeBuilderImpl { // calculatePromotedPolicySets(compositeService, promotedComponentService); } } - } + } /** * Connect the services in the component type to the component services that @@ -384,6 +392,34 @@ public class ComponentTypeBuilderImpl { } /** + * 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 @@ -459,30 +495,7 @@ public class ComponentTypeBuilderImpl { } } } - } - - /** - * 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); - } + } } //end class diff --git a/java/sca/modules/assembly/src/main/java/org/apache/tuscany/sca/assembly/builder/impl/EndpointBuilderImpl.java b/java/sca/modules/assembly/src/main/java/org/apache/tuscany/sca/assembly/builder/impl/EndpointBuilderImpl.java new file mode 100644 index 0000000000..c749782b90 --- /dev/null +++ b/java/sca/modules/assembly/src/main/java/org/apache/tuscany/sca/assembly/builder/impl/EndpointBuilderImpl.java @@ -0,0 +1,108 @@ +/* + * 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.assembly.builder.impl; + +import java.util.List; +import java.util.Vector; + +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.CompositeService; +import org.apache.tuscany.sca.assembly.Endpoint; +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.core.ExtensionPointRegistry; +import org.apache.tuscany.sca.core.FactoryExtensionPoint; +import org.apache.tuscany.sca.definitions.Definitions; +import org.apache.tuscany.sca.interfacedef.InterfaceContract; +import org.apache.tuscany.sca.monitor.Monitor; +import org.apache.tuscany.sca.policy.Intent; +import org.apache.tuscany.sca.policy.PolicySet; + +/** + * 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 void build(Composite composite, Definitions definitions, Monitor monitor) throws CompositeBuilderException { + + processComponentServices(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/assembly/src/main/java/org/apache/tuscany/sca/assembly/builder/impl/EndpointReferenceBuilderImpl.java b/java/sca/modules/assembly/src/main/java/org/apache/tuscany/sca/assembly/builder/impl/EndpointReferenceBuilderImpl.java new file mode 100644 index 0000000000..fe800200ca --- /dev/null +++ b/java/sca/modules/assembly/src/main/java/org/apache/tuscany/sca/assembly/builder/impl/EndpointReferenceBuilderImpl.java @@ -0,0 +1,731 @@ +/* + * 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.assembly.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.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 void build(Composite composite, Definitions definitions, Monitor monitor) throws CompositeBuilderException { + this.monitor = monitor; + + // process component services + processComponentReferences(composite); + } + + private void processComponentReferences(Composite composite) { + + monitor.pushContext("Composite: " + composite.getName().toString()); + try { + // index all of the components in the composite + Map<String, Component> components = new HashMap<String, Component>(); + indexComponents(composite, components); + + // index all of the services in the composite + Map<String, ComponentService> componentServices = new HashMap<String, ComponentService>(); + indexServices(composite, componentServices); + + // 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 + + private void indexComponents(Composite composite, Map<String, Component> components) { + for (Component component : composite.getComponents()) { + // Index components by name + components.put(component.getName(), component); + } + } + + 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); + } + } + } + + 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/assembly/src/main/java/org/apache/tuscany/sca/assembly/builder/impl/ModelBuilderImpl.java b/java/sca/modules/assembly/src/main/java/org/apache/tuscany/sca/assembly/builder/impl/ModelBuilderImpl.java index 2376e414ff..ccca010775 100644 --- a/java/sca/modules/assembly/src/main/java/org/apache/tuscany/sca/assembly/builder/impl/ModelBuilderImpl.java +++ b/java/sca/modules/assembly/src/main/java/org/apache/tuscany/sca/assembly/builder/impl/ModelBuilderImpl.java @@ -40,78 +40,34 @@ public class ModelBuilderImpl implements CompositeBuilder, DeployedCompositeBuil private static final Logger logger = Logger.getLogger(ModelBuilderImpl.class.getName()); private CompositeBuilder compositeIncludeBuilder; private CompositeBuilder compositeCloneBuilder; - private ComponentTypeBuilderImpl componentTypeBuilder; + private CompositeComponentTypeBuilderImpl compositeComponentTypeBuilder; private ComponentBuilderImpl componentBuilder; - -/* - private CompositeBuilder componentConfigurationBuilder; - private CompositeBuilder compositePromotionBuilder; - private CompositeBuilder componentReferenceWireBuilder; - private CompositeBuilder componentReferencePromotionBuilder; - private CompositeBuilder compositeServiceConfigurationBuilder; - private CompositeBuilder compositeReferenceConfigurationBuilder; - private CompositeBuilder compositeBindingURIBuilder; - private CompositeBuilder compositePolicyBuilder; - private CompositeBuilder componentServiceBindingBuilder; - private CompositeBuilder componentReferenceBindingBuilder; - private CompositeBuilder componentReferenceEndpointReferenceBuilder; - private CompositeBuilder componentServiceEndpointBuilder; -*/ - - - + private BindingURIBuilderImpl bindingURIBuilder; + private EndpointBuilderImpl endpointBuilder; + private EndpointReferenceBuilderImpl endpointReferenceBuilder; + private CompositePolicyBuilderImpl compositePolicyBuilder; + /** * Constructs a new composite builder. * - * @param assemblyFactory - * @param scaBindingFactory - * @param endpointFactory - * @param intentAttachPointTypeFactory - * @param interfaceContractMapper - * @param policyDefinitions - * @param monitor + * @param registry the extension point registry */ public ModelBuilderImpl(ExtensionPointRegistry registry) { - FactoryExtensionPoint modelFactories = registry.getExtensionPoint(FactoryExtensionPoint.class); - AssemblyFactory assemblyFactory = modelFactories.getFactory(AssemblyFactory.class); - - UtilityExtensionPoint utilities = registry.getExtensionPoint(UtilityExtensionPoint.class); - MonitorFactory monitorFactory = utilities.getUtility(MonitorFactory.class); - Monitor monitor = monitorFactory.createMonitor(); - compositeIncludeBuilder = new CompositeIncludeBuilderImpl(); compositeCloneBuilder = new CompositeCloneBuilderImpl(); - componentTypeBuilder = new ComponentTypeBuilderImpl(registry); + compositeComponentTypeBuilder = new CompositeComponentTypeBuilderImpl(registry); componentBuilder = new ComponentBuilderImpl(registry); - componentTypeBuilder.setComponentBuilder(componentBuilder); - componentBuilder.setComponentTypeBuilder(componentTypeBuilder); + compositeComponentTypeBuilder.setComponentBuilder(componentBuilder); + componentBuilder.setComponentTypeBuilder(compositeComponentTypeBuilder); - -/* - compositePromotionBuilder = new CompositePromotionBuilderImpl(assemblyFactory, interfaceContractMapper); - componentConfigurationBuilder = - new ComponentConfigurationBuilderImpl(assemblyFactory, scaBindingFactory, documentBuilderFactory, - transformerFactory, interfaceContractMapper); - componentReferenceWireBuilder = new ComponentReferenceWireBuilderImpl(assemblyFactory, interfaceContractMapper); - componentReferencePromotionBuilder = new ComponentReferencePromotionBuilderImpl(assemblyFactory); - - compositeServiceConfigurationBuilder = new CompositeServiceConfigurationBuilderImpl(assemblyFactory); - compositeReferenceConfigurationBuilder = new CompositeReferenceConfigurationBuilderImpl(assemblyFactory); - compositeBindingURIBuilder = - new CompositeBindingURIBuilderImpl(assemblyFactory, scaBindingFactory, documentBuilderFactory, - transformerFactory, interfaceContractMapper); - - compositePolicyBuilder = new CompositePolicyBuilderImpl(assemblyFactory, interfaceContractMapper); - componentServiceBindingBuilder = new ComponentServiceBindingBuilderImpl(); - componentReferenceBindingBuilder = new ComponentReferenceBindingBuilderImpl(); + bindingURIBuilder = new BindingURIBuilderImpl(registry); + endpointBuilder = new EndpointBuilderImpl(registry); + endpointReferenceBuilder = new EndpointReferenceBuilderImpl(registry); + compositePolicyBuilder = new CompositePolicyBuilderImpl(registry); - componentReferenceEndpointReferenceBuilder = - new ComponentReferenceEndpointReferenceBuilderImpl(assemblyFactory, interfaceContractMapper); - componentServiceEndpointBuilder = new ComponentServiceEndpointBuilderImpl(assemblyFactory); -*/ } public String getID() { @@ -142,83 +98,27 @@ public class ModelBuilderImpl implements CompositeBuilder, DeployedCompositeBuil // for the top level implementation (composite). This has the effect of // recursively calculating component types and configuring the // components that depend on them - componentTypeBuilder.createComponentType(composite); - + 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 - // callback references - // callback services + // callback references - currently done in static pass + // callback services - currently done in static pass // Endpoints // Endoint References - // runtimeBuilder.build(composite); - - // Compute the policies across the model hierarchy - //compositePolicyBuilder.build(composite, definitions, monitor); - - - -/* - // Configure all components. Created any derived model elements that - // are required. Specifically - // Component name - // autowire flags - // callback references - // callback services - // default bindings - componentConfigurationBuilder.build(composite, definitions, monitor); - - // Connect composite services/references to promoted services/references - // so that subsequent processing can navigate down the hierarchy - compositePromotionBuilder.build(composite, definitions, monitor); - - // calculate the component type for the composite that was passed in - // this involves - - - // Configure composite services by copying bindings up the promotion - // hierarchy overwriting automatic bindings with those added manually - compositeServiceConfigurationBuilder.build(composite, definitions, monitor); - - // Configure composite references by copying bindings down promotion - // hierarchy overwriting automatic bindings with those added manually - compositeReferenceConfigurationBuilder.build(composite, definitions, monitor); - - // Configure service binding URIs and names. Creates an SCA defined URI based - // on the scheme base URI, the component name and the binding name - ((CompositeBuilderTmp)compositeBindingURIBuilder).build(composite, definitions, bindingBaseURIs, monitor); - - // Perform and service binding related build activities. The binding - // will provide the builder. - componentServiceBindingBuilder.build(composite, definitions, monitor); - - // create endpoints on component services. - componentServiceEndpointBuilder.build(composite, definitions, monitor); - - // Apply any wires in the composite to create new component reference targets - componentReferenceWireBuilder.build(composite, definitions, monitor); - - // create reference endpoint reference models - componentReferenceEndpointReferenceBuilder.build(composite, definitions, monitor); - - // Push down configuration from promoted references to the - // references they promote - componentReferencePromotionBuilder.build(composite, definitions, monitor); - - - // Perform and reference binding related build activities. The binding - // will provide the builder. - componentReferenceBindingBuilder.build(composite, definitions, monitor); - - // Compute the policies across the model hierarchy + // Policies + // TODO - called here at the moment but we could have a separate build phase + // to call these. Also we could re-org the builders themselves + bindingURIBuilder.configureBindingURIsAndNames(composite, definitions, monitor); + endpointBuilder.build(composite, definitions, monitor); + endpointReferenceBuilder.build(composite, definitions, monitor); compositePolicyBuilder.build(composite, definitions, monitor); -*/ + } catch (Exception e) { throw new CompositeBuilderException("Exception while building model " + composite.getName(), e); - } // end try - - } // end method build - -} //end class + } + } +} |