diff options
author | slaws <slaws@13f79535-47bb-0310-9956-ffa450edef68> | 2009-09-21 13:11:55 +0000 |
---|---|---|
committer | slaws <slaws@13f79535-47bb-0310-9956-ffa450edef68> | 2009-09-21 13:11:55 +0000 |
commit | 88b0cf8ce9692ba063c21ee60c7afb36209238ba (patch) | |
tree | ab36ed77148fca9929b29e08b2859922294e01c5 /java | |
parent | b2bbe18e4ddcd35f6a9bffcd71183a34028425fc (diff) |
More static build changes and some simplified runtime builders (endpoint, endpoint reference and binding uri). The runtime side of things will likely need reorganizing. Am putting them there in their current form so I can run the static builders.
git-svn-id: http://svn.us.apache.org/repos/asf/tuscany@817238 13f79535-47bb-0310-9956-ffa450edef68
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 + } + } +} |