diff options
Diffstat (limited to 'sca-java-2.x/tags/2.0-M5.1-RC1/modules/builder/src/main')
21 files changed, 6950 insertions, 0 deletions
diff --git a/sca-java-2.x/tags/2.0-M5.1-RC1/modules/builder/src/main/java/org/apache/tuscany/sca/builder/impl/BindingURIBuilderImpl.java b/sca-java-2.x/tags/2.0-M5.1-RC1/modules/builder/src/main/java/org/apache/tuscany/sca/builder/impl/BindingURIBuilderImpl.java new file mode 100644 index 0000000000..4c5bca204b --- /dev/null +++ b/sca-java-2.x/tags/2.0-M5.1-RC1/modules/builder/src/main/java/org/apache/tuscany/sca/builder/impl/BindingURIBuilderImpl.java @@ -0,0 +1,355 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.apache.tuscany.sca.builder.impl; + +import java.net.URI; +import java.net.URISyntaxException; +import java.util.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.ComponentService; +import org.apache.tuscany.sca.assembly.Composite; +import org.apache.tuscany.sca.assembly.Implementation; +import org.apache.tuscany.sca.assembly.SCABinding; +import org.apache.tuscany.sca.assembly.Service; +import org.apache.tuscany.sca.assembly.builder.BuilderContext; +import org.apache.tuscany.sca.assembly.builder.CompositeBuilder; +import org.apache.tuscany.sca.assembly.builder.CompositeBuilderException; +import org.apache.tuscany.sca.assembly.builder.Messages; +import org.apache.tuscany.sca.core.ExtensionPointRegistry; +import org.apache.tuscany.sca.definitions.Definitions; +import org.apache.tuscany.sca.monitor.Monitor; + +/** + * Configuration of binding URIs. + * + * @version $Rev$ $Date$ + */ +public class BindingURIBuilderImpl implements CompositeBuilder { + + public BindingURIBuilderImpl(ExtensionPointRegistry registry) { + } + + /** + * Called by CompositeBindingURIBuilderImpl + * + * @param composite the composite to be configured + */ + public Composite build(Composite composite, BuilderContext context) + throws CompositeBuilderException { + configureBindingURIs(composite, null, context.getDefinitions(), context.getBindingBaseURIs(), context.getMonitor()); + return composite; + } + + + /** + * 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()) { + Implementation implementation = component.getImplementation(); + if (implementation instanceof Composite) { + // Process nested composite + configureBindingURIs((Composite)implementation, component.getURI(), definitions, defaultBindings, monitor); + } + } + + // Initialize composite service binding URIs + List<Service> compositeServices = composite.getServices(); + for (Service service : compositeServices) { + + // 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()) { + + // Initialize binding names and URIs + for (Binding binding : service.getBindings()) { + constructBindingURI(component, service, binding, defaultBindings, monitor); + } + } + } finally { + monitor.popContext(); + } + } + } finally { + monitor.popContext(); + } + } + + /** + * 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 = binding.getURI() == null ? null : new URI(binding.getURI()); + if (binding instanceof SCABinding) { + // Per assembly spec, the @uri for service side binding.sca should be ignored + bindingURI = null; + } + + // if the user has provided an absolute binding URI then use it + if (bindingURI != null && bindingURI.isAbsolute()) { + return; + } + + 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 = null; + if (componentURIString != null) { + componentURI = new URI(addSlashToPath(componentURIString)); + } + + // calculate the base URI + URI baseURI = null; + if (!(binding instanceof SCABinding)) { + 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, + Messages.ASSEMBLY_VALIDATION, + "URLSyntaxException", + componentURIString, + service.getName(), + binding.getName()); + } + } + + /** + * Use to ensure that URI paths end in "/" as here we want to maintain the + * last path element of an base URI when other URI are resolved against it. This is + * not the default behaviour of URI resolution as defined in RFC 2369 + * + * @param path the path string to which the "/" is to be added + * @return the resulting path with a "/" added if it not already there + */ + private static String addSlashToPath(String path) { + if (path.endsWith("/") || path.endsWith("#")) { + return path; + } else { + return path + "/"; + } + } + + /** + * Concatenate binding URI parts together based on Assembly Specification section 1.7.2 + * + * @param baseURI the base of the binding URI + * @param componentURI the middle part of the binding URI derived from the component name + * @param bindingURI the end part of the binding URI + * @param includeBindingName when set true the binding name part should be used + * @param bindingName the binding name + * @return the resulting URI as a string + */ + private static String constructBindingURI(URI baseURI, + URI componentURI, + URI bindingURI, + String serviceName, + boolean includeBindingName, + String bindingName) { + String name = includeBindingName ? serviceName + "/" + bindingName : serviceName; + String uriString; + + if (baseURI == null) { + if (componentURI == null) { + if (bindingURI != null) { + uriString = name + "/" + bindingURI.toString(); + } else { + uriString = name; + } + } else { + if (bindingURI != null) { + if (bindingURI.toString().startsWith("/")) { + uriString = componentURI.resolve(bindingURI).toString(); + } else { + uriString = componentURI.resolve(name + "/" + bindingURI).toString(); + } + } else { + uriString = componentURI.resolve(name).toString(); + } + } + } else { + if (componentURI == null) { + if (bindingURI != null) { + uriString = basedURI(baseURI, bindingURI).toString(); + } else { + uriString = basedURI(baseURI, URI.create(name)).toString(); + } + } else { + if (bindingURI != null) { + uriString = basedURI(baseURI, componentURI.resolve(bindingURI)).toString(); + } else { + uriString = basedURI(baseURI, componentURI.resolve(name)).toString(); + } + } + } + + // tidy up by removing any trailing "/" + if (uriString.endsWith("/")) { + uriString = uriString.substring(0, uriString.length() - 1); + } + + URI uri = URI.create(uriString); + if (!uri.isAbsolute()) { + uri = URI.create("/").resolve(uri); + } + return uri.toString(); + } + + /** + * Combine a URI with a base URI. + * + * @param baseURI + * @param uri + * @return + */ + private static URI basedURI(URI baseURI, URI uri) { + if (uri.getScheme() != null) { + return uri; + } + String str = uri.toString(); + if (str.startsWith("/")) { + str = str.substring(1); + } + return URI.create(baseURI.toString() + str).normalize(); + } + + public String getID() { + return "org.apache.tuscany.sca.assembly.builder.BindingURIBuilder"; + } + +} diff --git a/sca-java-2.x/tags/2.0-M5.1-RC1/modules/builder/src/main/java/org/apache/tuscany/sca/builder/impl/ComponentBuilderImpl.java b/sca-java-2.x/tags/2.0-M5.1-RC1/modules/builder/src/main/java/org/apache/tuscany/sca/builder/impl/ComponentBuilderImpl.java new file mode 100644 index 0000000000..45020676ee --- /dev/null +++ b/sca-java-2.x/tags/2.0-M5.1-RC1/modules/builder/src/main/java/org/apache/tuscany/sca/builder/impl/ComponentBuilderImpl.java @@ -0,0 +1,1395 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.tuscany.sca.builder.impl; + +import java.io.InputStream; +import java.io.StringReader; +import java.net.URI; +import java.net.URL; +import java.net.URLConnection; + +import javax.xml.XMLConstants; +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.dom.DOMSource; +import javax.xml.transform.sax.SAXSource; +import javax.xml.transform.stream.StreamSource; +import javax.xml.validation.Schema; +import javax.xml.validation.SchemaFactory; +import javax.xml.validation.Validator; +import javax.xml.xpath.XPathConstants; +import javax.xml.xpath.XPathExpression; +import javax.xml.xpath.XPathExpressionException; + +import org.apache.tuscany.sca.assembly.AssemblyFactory; +import org.apache.tuscany.sca.assembly.Binding; +import org.apache.tuscany.sca.assembly.Component; +import org.apache.tuscany.sca.assembly.ComponentProperty; +import org.apache.tuscany.sca.assembly.ComponentReference; +import org.apache.tuscany.sca.assembly.ComponentService; +import org.apache.tuscany.sca.assembly.Composite; +import org.apache.tuscany.sca.assembly.CompositeReference; +import org.apache.tuscany.sca.assembly.CompositeService; +import org.apache.tuscany.sca.assembly.Contract; +import org.apache.tuscany.sca.assembly.Implementation; +import org.apache.tuscany.sca.assembly.Multiplicity; +import org.apache.tuscany.sca.assembly.Property; +import org.apache.tuscany.sca.assembly.Reference; +import org.apache.tuscany.sca.assembly.SCABinding; +import org.apache.tuscany.sca.assembly.SCABindingFactory; +import org.apache.tuscany.sca.assembly.Service; +import org.apache.tuscany.sca.assembly.builder.BuilderContext; +import org.apache.tuscany.sca.assembly.builder.BuilderExtensionPoint; +import org.apache.tuscany.sca.assembly.builder.ImplementationBuilder; +import org.apache.tuscany.sca.assembly.builder.Messages; +import org.apache.tuscany.sca.assembly.xsd.Constants; +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.databinding.Mediator; +import org.apache.tuscany.sca.databinding.impl.MediatorImpl; +import org.apache.tuscany.sca.databinding.jaxb.JAXBDataBinding; +import org.apache.tuscany.sca.databinding.xml.DOMDataBinding; +import org.apache.tuscany.sca.definitions.Definitions; +import org.apache.tuscany.sca.interfacedef.Compatibility; +import org.apache.tuscany.sca.interfacedef.DataType; +import org.apache.tuscany.sca.interfacedef.IncompatibleInterfaceContractException; +import org.apache.tuscany.sca.interfacedef.InterfaceContract; +import org.apache.tuscany.sca.interfacedef.InterfaceContractMapper; +import org.apache.tuscany.sca.interfacedef.impl.DataTypeImpl; +import org.apache.tuscany.sca.interfacedef.util.XMLType; +import org.apache.tuscany.sca.monitor.Monitor; +import org.apache.tuscany.sca.policy.ExtensionType; +import org.apache.tuscany.sca.policy.PolicySubject; +import org.apache.tuscany.sca.xsd.XSDefinition; +import org.apache.ws.commons.schema.XmlSchema; +import org.w3c.dom.Document; +import org.w3c.dom.Element; +import org.w3c.dom.Node; +import org.w3c.dom.NodeList; +import org.xml.sax.InputSource; + +/** + * @version $Rev$ $Date$ + */ +public class ComponentBuilderImpl { + protected static final String SCA11_NS = "http://docs.oasis-open.org/ns/opencsa/sca/200912"; + protected static final String BINDING_SCA = "binding.sca"; + protected static final QName BINDING_SCA_QNAME = new QName(SCA11_NS, BINDING_SCA); + + private CompositeComponentTypeBuilderImpl componentTypeBuilder; + protected ComponentPolicyBuilderImpl policyBuilder; + private AssemblyFactory assemblyFactory; + private SCABindingFactory scaBindingFactory; + private DocumentBuilderFactory documentBuilderFactory; + protected TransformerFactory transformerFactory; + private InterfaceContractMapper interfaceContractMapper; + private BuilderExtensionPoint builders; + private Mediator mediator; + + public ComponentBuilderImpl(ExtensionPointRegistry registry) { + UtilityExtensionPoint utilities = registry.getExtensionPoint(UtilityExtensionPoint.class); + + 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); + policyBuilder = new ComponentPolicyBuilderImpl(registry); + builders = registry.getExtensionPoint(BuilderExtensionPoint.class); + mediator = new MediatorImpl(registry); + } + + public void setComponentTypeBuilder(CompositeComponentTypeBuilderImpl componentTypeBuilder) { + this.componentTypeBuilder = componentTypeBuilder; + } + + /** + * Configure the component based on its component type using OASIS rules + * + * @Param outerCompoment the component that uses the parentComposite as its implementation + * @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 outerComponent, Composite parentComposite, Component component, BuilderContext context) { + + Monitor monitor = context.getMonitor(); + monitor.pushContext("Component: " + component.getName().toString()); + + try { + // 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 + + // check that the implementation is present + if (!isComponentImplementationPresent(component, monitor)){ + return; + } + + // carry out any implementation specific builder processing + Implementation impl = component.getImplementation(); + if (impl != null) { + ImplementationBuilder builder = builders.getImplementationBuilder(impl.getType()); + if (builder != null) { + builder.build(component, impl, context); + } + } + + // 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(outerComponent, parentComposite, component, monitor); + + // create the component type for this component + // taking any nested composites into account + createComponentType(component, context); + + // configure services based on the calculated component type + configureServices(component, context); + + // configure services based on the calculated component type + configureReferences(component, context); + + // NOTE: configureServices/configureReferences may add callback references and services + policyBuilder.configure(component, context); + + } finally { + monitor.popContext(); + } + } + + /** + * Checks that a component implementation is present and resolved + * before doing anything else + * + * @param component + * @return true if the implementation is present and resolved + */ + private boolean isComponentImplementationPresent(Component component, Monitor monitor){ + Implementation implementation = component.getImplementation(); + if (implementation == null) { + // A component must have an implementation + Monitor.error(monitor, + this, + Messages.ASSEMBLY_VALIDATION, + "NoComponentImplementation", + component.getName()); + return false; + } else if (implementation.isUnresolved()) { + // The implementation must be fully resolved + Monitor.error(monitor, + this, + Messages.ASSEMBLY_VALIDATION, + "UnresolvedComponentImplementation", + component, + component.getName(), + implementation.getURI()); + return false; + } + + return true; + } + + /** + * Use the component type builder to build the component type for + * this component. + * + * @param component + */ + private void createComponentType(Component component, BuilderContext context) { + Implementation implementation = component.getImplementation(); + if (implementation instanceof Composite) { + componentTypeBuilder.createComponentType(component, (Composite)implementation, context); + } + } + + /** + * Configure this component's services based on the services in its + * component type and the configuration from the composite file + * + * @param component + */ + private void configureServices(Component component, BuilderContext context) { + Monitor monitor = context.getMonitor(); + + // If the component type has services that are not described in this + // component then create services for this component + addServicesFromComponentType(component, monitor); + + // Connect this component's services to the + // services from its component type + connectServicesToComponentType(component, monitor); + + // look at each component service in turn and calculate its + // configuration based on OASIS rules + for (ComponentService componentService : component.getServices()) { + + Service componentTypeService = componentService.getService(); + + if (componentTypeService == null) { + // raise error? + // can be null in some of the assembly-xml unit tests + continue; + } + + // interface contracts + calculateServiceInterfaceContract(component, componentService, componentTypeService, monitor); + + // bindings + calculateBindings(component, componentService, componentTypeService, monitor); + + // add callback reference model objects + createCallbackReference(component, componentService); + } + } + + /** + * Configure this component's references based on the references in its + * component type and the configuration from the composite file + * + * @param component + */ + private void configureReferences(Component component, BuilderContext context) { + Monitor monitor = context.getMonitor(); + + // If the component type has references that are not described in this + // component then create references for this component + addReferencesFromComponentType(component, monitor); + + // Connect this component's references to the + // references from its component type + connectReferencesToComponentType(component, monitor); + + // look at each component reference in turn and calculate its + // configuration based on OASIS rules + for (ComponentReference componentReference : component.getReferences()) { + Reference componentTypeReference = componentReference.getReference(); + + if (componentTypeReference == null) { + // raise error? + // can be null in some of the assembly-xml unit tests + continue; + } + + // reference multiplicity + reconcileReferenceMultiplicity(component, componentReference, componentTypeReference, monitor); + + // interface contracts + calculateReferenceInterfaceContract(component, componentReference, componentTypeReference, monitor); + + // bindings + calculateBindings(componentReference, componentTypeReference); + + // add callback service model objects + createCallbackService(component, componentReference); + + // Propagate autowire setting from the component down the structural + // hierarchy + if (componentReference.getAutowire() == null) { + componentReference.setAutowire(component.getAutowire()); + } + } + } + + /** + * 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(Component outerComponent, Composite parentComposite, Component component, Monitor monitor) { + // If the component type has properties that are not described in this + // component then create properties for this component + addPropertiesFromComponentType(component, monitor); + + // Connect this component's properties to the + // properties from its component type + connectPropertiesToComponentType(component, monitor); + + // Reconcile component properties and their component type properties + for (ComponentProperty componentProperty : component.getProperties()) { + reconcileComponentPropertyWithComponentType(component, componentProperty, monitor); + + // configure the property value based on the @source attribute + // At the moment this is done in the parent composite component + // type calculation + processPropertySourceAttribute(outerComponent, parentComposite, component, componentProperty, monitor); + + // configure the property value based on the @file attribute + processPropertyFileAttribute(component, componentProperty, monitor); + + // Check that a value is supplied + if (componentProperty.isMustSupply() && !isPropertyValueSet(componentProperty)) { + Monitor.error(monitor, + this, + Messages.ASSEMBLY_VALIDATION, + "PropertyMustSupplyNull", + component.getName(), + componentProperty.getName()); + } + + // check that not too many values are supplied + if (!componentProperty.isMany() && isPropertyManyValued(componentProperty)){ + Monitor.error(monitor, + this, + Messages.ASSEMBLY_VALIDATION, + "PropertyHasManyValues", + component.getName(), + componentProperty.getName()); + } + + // check the property type + checkComponentPropertyType(component, componentProperty, monitor); + + } + } + + private void addServicesFromComponentType(Component component, Monitor monitor) { + + // Create a component service for each service + if (component.getImplementation() != null) { + for (Service service : component.getImplementation().getServices()) { + // check for duplicate service names in implementation + if (service != component.getImplementation().getService(service.getName())){ + Monitor.error(monitor, + this, + Messages.ASSEMBLY_VALIDATION, + "DuplicateImplementationServiceName", + component.getName(), + service.getName()); + } + + ComponentService componentService = (ComponentService)component.getService(service.getName()); + + // if the component doesn't have a service with the same name as the + // component type service then create one + if (componentService == null) { + componentService = assemblyFactory.createComponentService(); + componentService.setForCallback(service.isForCallback()); + String name = service.getName(); + componentService.setName(name); + component.getServices().add(componentService); + } + } + } + } + + private void addReferencesFromComponentType(Component component, Monitor monitor) { + + // Create a component reference for each reference + if (component.getImplementation() != null) { + for (Reference reference : component.getImplementation().getReferences()) { + // check for duplicate reference names in implementation + if (reference != component.getImplementation().getReference(reference.getName())){ + Monitor.error(monitor, + this, + Messages.ASSEMBLY_VALIDATION, + "DuplicateImplementationReferenceName", + component.getName(), + reference.getName()); + } + + ComponentReference componentReference = (ComponentReference)component.getReference(reference.getName()); + + // if the component doesn't have a reference with the same name as the + // component type reference then create one + if (componentReference == null) { + componentReference = assemblyFactory.createComponentReference(); + componentReference.setForCallback(reference.isForCallback()); + componentReference.setName(reference.getName()); + componentReference.setReference(reference); + component.getReferences().add(componentReference); + } + } + } + } + + private void addPropertiesFromComponentType(Component component, Monitor monitor) { + + // Create component property for each property + if (component.getImplementation() != null) { + for (Property property : component.getImplementation().getProperties()) { + // check for duplicate property names in implementation + if (property != component.getImplementation().getProperty(property.getName())){ + Monitor.error(monitor, + this, + Messages.ASSEMBLY_VALIDATION, + "DuplicateImplementationPropertyName", + component.getName(), + property.getName()); + } + 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, Monitor monitor) { + + // Connect each component service to the corresponding component type service + for (ComponentService componentService : component.getServices()) { + // check for duplicate service names in component + if (componentService != component.getService(componentService.getName())){ + Monitor.error(monitor, + this, + Messages.ASSEMBLY_VALIDATION, + "DuplicateComponentServiceName", + component.getName(), + componentService.getName()); + } + + if (componentService.getService() != null || componentService.isForCallback()) { + continue; + } + + if (component.getImplementation() == null) { + // is null in some of our basic unit tests + continue; + } + + Service service = component.getImplementation().getService(componentService.getName()); + + if (service != null) { + componentService.setService(service); + } else { + Monitor.error(monitor, + this, + Messages.ASSEMBLY_VALIDATION, + "ServiceNotFoundForComponentService", + component.getName(), + componentService.getName()); + } + } + } + + private void connectReferencesToComponentType(Component component, Monitor monitor) { + + // Connect each component reference to the corresponding component type reference + for (ComponentReference componentReference : component.getReferences()) { + // check for duplicate reference names in component + if (componentReference != component.getReference(componentReference.getName())){ + Monitor.error(monitor, + this, + Messages.ASSEMBLY_VALIDATION, + "DuplicateComponentReferenceName", + component.getName(), + componentReference.getName()); + } + + if (componentReference.getReference() != null || componentReference.isForCallback()) { + continue; + } + + if (component.getImplementation() == null) { + // is null in some of our basic unit tests + continue; + } + + Reference reference = component.getImplementation().getReference(componentReference.getName()); + + if (reference != null) { + componentReference.setReference(reference); + } else { + Monitor.error(monitor, + this, + Messages.ASSEMBLY_VALIDATION, + "ReferenceNotFoundForComponentReference", + component.getName(), + componentReference.getName()); + } + } + } + + private void connectPropertiesToComponentType(Component component, Monitor monitor) { + // Connect each component property to the corresponding component type property + for (ComponentProperty componentProperty : component.getProperties()) { + // check for duplicate property names in component + if (componentProperty != component.getProperty(componentProperty.getName())){ + Monitor.error(monitor, + this, + Messages.ASSEMBLY_VALIDATION, + "DuplicateComponentPropertyName", + component.getName(), + componentProperty.getName()); + } + + Property property = component.getImplementation().getProperty(componentProperty.getName()); + + if (property != null) { + componentProperty.setProperty(property); + } else { + Monitor.error(monitor, + this, + Messages.ASSEMBLY_VALIDATION, + "PropertyNotFound", + component.getName(), + componentProperty.getName()); + } + } + } + + private void reconcileReferenceMultiplicity(Component component, + Reference componentReference, + Reference componentTypeReference, + Monitor monitor) { + if (componentReference.getMultiplicity() != null) { + if (!isValidMultiplicityOverride(componentTypeReference.getMultiplicity(), componentReference + .getMultiplicity())) { + Monitor.error(monitor, + this, + Messages.ASSEMBLY_VALIDATION, + "ReferenceIncompatibleMultiplicity", + component.getName(), + componentReference.getName()); + } + } else { + componentReference.setMultiplicity(componentTypeReference.getMultiplicity()); + } + } + + private void reconcileComponentPropertyWithComponentType(Component component, ComponentProperty componentProperty, Monitor monitor) { + 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, + Messages.ASSEMBLY_VALIDATION, + "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 component property does not override the + // many attribute + if (!componentTypeProperty.isMany() && componentProperty.isMany()) { + Monitor.error(monitor, + this, + Messages.ASSEMBLY_VALIDATION, + "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, + Messages.ASSEMBLY_VALIDATION, + "NoTypeForComponentProperty", + component.getName(), + componentProperty.getName()); + } + + // check that the types specified in the component type and component property match + if ( componentProperty.getXSDElement() != null && + !componentProperty.getXSDElement().equals(componentTypeProperty.getXSDElement())){ + Monitor.error(monitor, + this, + Messages.ASSEMBLY_VALIDATION, + "PropertXSDElementsDontMatch", + component.getName(), + componentProperty.getName(), + componentProperty.getXSDElement(), + componentTypeProperty.getXSDElement()); + } + + if ( componentProperty.getXSDType() != null && + !componentProperty.getXSDType().equals(componentTypeProperty.getXSDType())){ + Monitor.error(monitor, + this, + Messages.ASSEMBLY_VALIDATION, + "PropertXSDTypesDontMatch", + component.getName(), + componentProperty.getName(), + componentProperty.getXSDType(), + componentTypeProperty.getXSDType()); + } + } + } + + /** + * checks that the component property value is correctly typed when compared with + * the type specified in the composite file property + * + * TODO - Don't yet handle multiplicity + * Need to check composite properties also + * + * @param component + * @param componentProperty + * @param monitor + */ + private void checkComponentPropertyType(Component component, ComponentProperty componentProperty, Monitor monitor) { + + QName propertyXSDType = componentProperty.getXSDType(); + QName propertyElementType = componentProperty.getXSDElement(); + + if (propertyXSDType != null){ + if (propertyXSDType.getNamespaceURI().equals("http://www.w3.org/2001/XMLSchema")) { + // The property has a simple schema type so we can use the + // data binding framework to see if the XML value can be transformed + // into a simple Java value + Document doc = (Document)componentProperty.getValue(); + Node source = (doc == null) ? null : doc.getDocumentElement().getFirstChild(); + DataType<XMLType> sourceDataType = new DataTypeImpl<XMLType>(DOMDataBinding.NAME, + Node.class, + new XMLType(null, componentProperty.getXSDType())); + DataType<XMLType> targetDataType = new DataTypeImpl<XMLType>(JAXBDataBinding.NAME, + Object.class, + new XMLType(null, componentProperty.getXSDType())); + try { + mediator.mediate(source, sourceDataType, targetDataType, null); + } catch (Exception ex){ + Monitor.error(monitor, + this, + Messages.ASSEMBLY_VALIDATION, + "PropertyValueDoesNotMatchSimpleType", + componentProperty.getName(), + component.getName(), + componentProperty.getXSDType().toString()); + } + } else { + // The property has a complex schema type so we fluff up a schema + // and use that to validate the property value + XSDefinition xsdDefinition = (XSDefinition)componentProperty.getXSDDefinition(); + + if (xsdDefinition != null) { + try { + // create schema factory for XML schema + SchemaFactory factory = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI); + + Document schemaDom = xsdDefinition.getSchema().getSchemaDocument(); + + String valueSchema = null; + Schema schema = null; + + if (componentProperty.getXSDType().getNamespaceURI().equals(Constants.SCA11_NS)){ + // include the referenced schema as it's already in the OASIS namespace + valueSchema = "<?xml version=\"1.0\" encoding=\"UTF-8\"?> " + + "<schema xmlns=\"http://www.w3.org/2001/XMLSchema\" "+ + "xmlns:sca=\"http://docs.oasis-open.org/ns/opencsa/sca/200912\" "+ + "xmlns:__tmp=\"" + componentProperty.getXSDType().getNamespaceURI() + "\" "+ + "targetNamespace=\"http://docs.oasis-open.org/ns/opencsa/sca/200912\" " + + "elementFormDefault=\"qualified\">" + + "<include schemaLocation=\"" + xsdDefinition.getLocation() + "\"/>" + +// "<element name=\"value\" type=\"" + "__tmp:" + componentProperty.getXSDType().getLocalPart() + "\"/>" + + "</schema>"; +// Source sources[] = {new StreamSource(new StringReader(valueSchema))}; + Source sources[] = {new DOMSource(schemaDom)}; + schema = factory.newSchema(sources); + + // The SCA schema already contains a "value" element so I can't create this schema + // the SCA value element is an any so return assuming that it validates. + return; + } else { + // import the referenced schema + valueSchema = "<?xml version=\"1.0\" encoding=\"UTF-8\"?> " + + "<schema xmlns=\"http://www.w3.org/2001/XMLSchema\" "+ + "xmlns:sca=\"http://docs.oasis-open.org/ns/opencsa/sca/200912\" "+ + "xmlns:__tmp=\"" + componentProperty.getXSDType().getNamespaceURI() + "\" "+ + "targetNamespace=\"http://docs.oasis-open.org/ns/opencsa/sca/200912\" " + + "elementFormDefault=\"qualified\">" + + "<import namespace=\"" + componentProperty.getXSDType().getNamespaceURI() + "\"/>" + + "<element name=\"value\" type=\"" + "__tmp:" + componentProperty.getXSDType().getLocalPart() + "\"/>" + + "</schema>"; + Source sources[] = {new DOMSource(schemaDom), new StreamSource(new StringReader(valueSchema))}; + schema = factory.newSchema(sources); + } + + // get the value child of the property element + Document property = (Document)componentProperty.getValue(); + Element value = (Element)property.getDocumentElement().getFirstChild(); + + // validate the element property/value from the DOM + Validator validator = schema.newValidator(); + validator.validate(new DOMSource(value)); + + } catch (Exception e) { + Monitor.error(monitor, + this, + Messages.ASSEMBLY_VALIDATION, + "PropertyValueDoesNotMatchComplexType", + componentProperty.getName(), + component.getName(), + componentProperty.getXSDType().toString(), + e.getMessage()); + } + } + } + } else if (propertyElementType != null) { + // TODO - TUSCANY-3530 - still need to add validation for element type + + } + } + + /** + * If the property has a source attribute use this to retrieve the value from a + * property in the parent composite + * + * @param parentCompoent the composite that contains the component + * @param component + * @param componentProperty + */ + private void processPropertySourceAttribute(Component outerComponent, + Composite parentComposite, + Component component, + ComponentProperty componentProperty, + Monitor monitor) { + 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 sourceProp = null; + if (outerComponent != null) { + sourceProp = outerComponent.getProperty(name); + } else { + sourceProp = parentComposite.getProperty(name); + } + if (sourceProp == null) { + Monitor.error(monitor, + this, + Messages.ASSEMBLY_VALIDATION, + "PropertySourceNotFound", + source, + componentProperty.getName(), + component.getName()); + } + + Document sourcePropValue = (Document)sourceProp.getValue(); + + try { + // FIXME: How to deal with namespaces? + Document node = + evaluateXPath(sourcePropValue, + componentProperty.getSourceXPathExpression(), + documentBuilderFactory); + + if (node != null) { + componentProperty.setValue(node); + } else { + Monitor.warning(monitor, + this, + Messages.ASSEMBLY_VALIDATION, + "PropertyXpathExpressionReturnedNull", + component.getName(), + componentProperty.getName(), + componentProperty.getSource()); + } + } catch (Exception ex) { + Monitor.error(monitor, + this, + Messages.ASSEMBLY_VALIDATION, + "PropertySourceXpathInvalid", + source, + componentProperty.getName(), + component.getName(), + ex); + } + } else { + Monitor.error(monitor, + this, + Messages.ASSEMBLY_VALIDATION, + "PropertySourceValueInvalid", + source, + componentProperty.getName(), + component.getName()); + } + } + } + + /** + * If the property has a file attribute use this to retrieve the value from a + * local file + + * + * @param parentCompoent the composite that contains the component + * @param component + */ + private void processPropertyFileAttribute(Component component, ComponentProperty componentProperty, Monitor monitor) { + String file = componentProperty.getFile(); + if (file != null) { + try { + URI uri = URI.create(file); + // URI resolution for relative URIs is done when the composite is resolved. + URL url = uri.toURL(); + URLConnection connection = url.openConnection(); + connection.setUseCaches(false); + InputStream is = null; + try { + is = connection.getInputStream(); + + Source streamSource = new SAXSource(new InputSource(is)); + DOMResult result = new DOMResult(); + javax.xml.transform.Transformer transformer = transformerFactory.newTransformer(); + transformer.transform(streamSource, result); + + Document document = (Document)result.getNode(); + + // TUSCANY-2377, Add a fake value element so it's consistent with + // the DOM tree loaded from inside SCDL + if (!document.getDocumentElement().getLocalName().equals("value")){ + Element root = document.createElementNS(null, "value"); + root.appendChild(document.getDocumentElement()); + + // remove all the child nodes as they will be replaced by + // the "value" node + NodeList children = document.getChildNodes(); + for (int i=0; i < children.getLength(); i++){ + document.removeChild(children.item(i)); + } + + // add the value node back in + document.appendChild(root); + } + + componentProperty.setValue(document); + } finally { + if (is != null) { + is.close(); + } + } + } catch (Exception ex) { + Monitor.error(monitor, + this, + Messages.ASSEMBLY_VALIDATION, + "PropertyFileValueInvalid", + file, + componentProperty.getName(), + component.getName(), + ex); + } + } + + } + + /** + * Evaluate an XPath expression against a Property value, returning the result as a Property value + * @param node - the document root element of a Property value + * @param expression - the XPath expression + * @param documentBuilderFactory - a DOM document builder factory + * @return - a DOM Document representing the result of the evaluation as a Property value + * @throws XPathExpressionException + * @throws ParserConfigurationException + */ + private Document evaluateXPath(Document node, + XPathExpression expression, + DocumentBuilderFactory documentBuilderFactory) throws XPathExpressionException, + ParserConfigurationException { + + // The document element is a <sca:property/> element + Node property = node.getDocumentElement(); + // The first child of the <property/> element is a <value/> element + Node value = property.getFirstChild(); + + Node result = (Node)expression.evaluate(value, XPathConstants.NODE); + if (result == null) { + return null; + } + + if (result instanceof Document) { + return (Document)result; + } else { + Document document = documentBuilderFactory.newDocumentBuilder().newDocument(); + Element newProperty = document.createElementNS(SCA11_NS, "property"); + + if (result.getNodeType() == Node.ELEMENT_NODE) { + // If the result is a <value/> element, use it directly in the result + newProperty.appendChild(document.importNode(result, true)); + } else { + // If the result is not a <value/> element, create a <value/> element to contain the result + Element newValue = document.createElementNS(SCA11_NS, "value"); + newValue.appendChild(document.importNode(result, true)); + newProperty.appendChild(newValue); + } // end if + document.appendChild(newProperty); + + return document; + } + } + + /** + * Create a callback reference for a component service + * + * @param component + * @param service + */ + private void createCallbackReference(Component component, ComponentService service) { + + // if the service has a callback interface create a reference + // to represent the callback + if (service.getInterfaceContract() != null && // can be null in unit tests + service.getInterfaceContract().getCallbackInterface() != null) { + + ComponentReference callbackReference = assemblyFactory.createComponentReference(); + callbackReference.setForCallback(true); + callbackReference.setName(service.getName()); + try { + InterfaceContract contract = (InterfaceContract)service.getInterfaceContract().clone(); + contract.setInterface(contract.getCallbackInterface()); + contract.setCallbackInterface(null); + callbackReference.setInterfaceContract(contract); + } catch (CloneNotSupportedException e) { + // will not happen + } + Service implService = service.getService(); + if (implService != null) { + + // If the implementation service is a CompositeService, ensure that the Reference that is + // created is a CompositeReference, otherwise create a Reference + Reference implReference; + if (implService instanceof CompositeService) { + CompositeReference implCompReference = assemblyFactory.createCompositeReference(); + // Set the promoted component from the promoted component of the composite service + implCompReference.getPromotedComponents().add(((CompositeService)implService) + .getPromotedComponent()); + // Set the promoted service + ComponentReference promotedReference = assemblyFactory.createComponentReference(); + String promotedRefName = + ((CompositeService)implService).getPromotedComponent().getName() + "/" + + ((CompositeService)implService).getPromotedService().getName(); + promotedReference.setName(promotedRefName); + promotedReference.setUnresolved(true); + implCompReference.getPromotedReferences().add(promotedReference); + implReference = implCompReference; + // Add the composite reference to the composite implementation artifact + Implementation implementation = component.getImplementation(); + if (implementation != null && implementation instanceof Composite) { + ((Composite)implementation).getReferences().add(implCompReference); + } + } else { + implReference = assemblyFactory.createReference(); + } + + implReference.setName(implService.getName()); + try { + InterfaceContract implContract = (InterfaceContract)implService.getInterfaceContract().clone(); + implContract.setInterface(implContract.getCallbackInterface()); + implContract.setCallbackInterface(null); + implReference.setInterfaceContract(implContract); + } catch (CloneNotSupportedException e) { + // will not happen + } + callbackReference.setReference(implReference); + } + component.getReferences().add(callbackReference); + + // Set the bindings of the callback reference + if (callbackReference.getBindings().isEmpty()) { + // If there are specific callback bindings set in the SCDL service + // callback element then use them + if (service.getCallback() != null && service.getCallback().getBindings().size() > 0) { + callbackReference.getBindings().addAll(service.getCallback().getBindings()); + } else { + // otherwise create a default binding which + // will cause the EPR for this reference to be + // marked as EndpointReference.NOT_CONFIGURED + createSCABinding(callbackReference, null); + + // TODO - should really use the forward binding here but + // awaiting OASIS decision on what's going to + // happen with callbacks + } + } + service.setCallbackReference(callbackReference); + } + } + + /** + * Create a callback service for a component reference + * + * @param component + * @param service + */ + private void createCallbackService(Component component, ComponentReference reference) { + if (reference.getInterfaceContract() != null && // can be null in unit tests + reference.getInterfaceContract().getCallbackInterface() != null) { + ComponentService componentService = assemblyFactory.createComponentService(); + componentService.setForCallback(true); + componentService.setName(reference.getName()); + try { + InterfaceContract contract = (InterfaceContract)reference.getInterfaceContract().clone(); + contract.setInterface(contract.getCallbackInterface()); + contract.setCallbackInterface(null); + componentService.setInterfaceContract(contract); + } catch (CloneNotSupportedException e) { + // will not happen + } + Reference implReference = reference.getReference(); + if (implReference != null) { + // If the implementation reference is a CompositeReference, ensure that the Service that is + // created is a CompositeService, otherwise create a Service + Service implService; + if (implReference instanceof CompositeReference) { + CompositeService implCompService = assemblyFactory.createCompositeService(); + // TODO The reality here is that the composite reference which has the callback COULD promote more than + // one component reference - and there must be a separate composite callback service for each of these component + // references + // Set the promoted component from the promoted component of the composite reference + implCompService.setPromotedComponent(((CompositeReference)implReference).getPromotedComponents() + .get(0)); + implCompService.setForCallback(true); + // Set the promoted service + ComponentService promotedService = assemblyFactory.createComponentService(); + promotedService.setName(((CompositeReference)implReference).getPromotedReferences().get(0) + .getName()); + promotedService.setUnresolved(true); + promotedService.setForCallback(true); + implCompService.setPromotedService(promotedService); + implService = implCompService; + // Add the composite service to the composite implementation artifact + Implementation implementation = component.getImplementation(); + if (implementation != null && implementation instanceof Composite) { + ((Composite)implementation).getServices().add(implCompService); + } // end if + // + } else { + implService = assemblyFactory.createService(); + } // end if + // + implService.setName(implReference.getName()); + try { + InterfaceContract implContract = (InterfaceContract)implReference.getInterfaceContract().clone(); + implContract.setInterface(implContract.getCallbackInterface()); + implContract.setCallbackInterface(null); + implService.setInterfaceContract(implContract); + } catch (CloneNotSupportedException e) { + // will not happen + } + componentService.setService(implService); + } + component.getServices().add(componentService); + + // configure bindings for the callback service + if (componentService.getBindings().isEmpty()) { + if (reference.getCallback() != null && reference.getCallback().getBindings().size() > 0) { + // set bindings of the callback service based on the information provided in + // SCDL reference callback element + componentService.getBindings().addAll(reference.getCallback().getBindings()); + } else if (reference.getBindings().size() > 0) { + // use any bindings explicitly declared on the forward reference + for (Binding binding : reference.getBindings()) { + try { + Binding clonedBinding = (Binding)binding.clone(); + // binding uri will be calculated during runtime build + clonedBinding.setURI(null); + componentService.getBindings().add(clonedBinding); + } catch (CloneNotSupportedException ex) { + + } + } + } else { + // TODO - should use the binding resolved from the service but + // waiting for OASIS to decide what to do about callbacks + // create a default binding + createSCABinding(componentService, null); + } + } + + reference.setCallbackService(componentService); + } + } + + /** + * Create a default SCA binding in the case that no binding + * is specified by the user + * + * @param contract + * @param definitions + */ + protected void createSCABinding(Contract contract, Definitions definitions) { + + SCABinding scaBinding = scaBindingFactory.createSCABinding(); + scaBinding.setName(contract.getName()); + + if (definitions != null) { + for (ExtensionType attachPointType : definitions.getBindingTypes()) { + if (attachPointType.getType().equals(BINDING_SCA_QNAME)) { + ((PolicySubject)scaBinding).setExtensionType(attachPointType); + } + } + } + + contract.getBindings().add(scaBinding); + contract.setOverridingBindings(false); + } + + /** + * 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.getDocumentElement() == null) { + return false; + } + + if (value.getDocumentElement().getChildNodes().getLength() == 0) { + return false; + } + + return true; + } + + /** + * Look to see is a property has more than one value + * + * @param property + * @return true is the property has more than one value + */ + private boolean isPropertyManyValued(Property property) { + + if (isPropertyValueSet(property)){ + Document value = (Document)property.getValue(); + if (value.getDocumentElement().getChildNodes().getLength() > 1){ + return true; + } + } + return false; + } + + 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; + } + } + + + /** + * Interface contract from higher in the implementation hierarchy takes precedence + * When it comes to checking compatibility the top level service interface is a + * subset of the promoted service interface so treat the top level interface as + * the source + * + * @param topContract the top contract + * @param bottomContract the bottom contract + */ + private void calculateServiceInterfaceContract(Component component, Service topContract, Service bottomContract, Monitor monitor) { + + // Use the interface contract from the bottom level contract if + // none is specified on the top level contract + InterfaceContract topInterfaceContract = topContract.getInterfaceContract(); + InterfaceContract bottomInterfaceContract = bottomContract.getInterfaceContract(); + + if (topInterfaceContract == null) { + topContract.setInterfaceContract(bottomInterfaceContract); + } else if (bottomInterfaceContract != null) { + // Check that the top and bottom interface contracts are compatible + boolean isCompatible = true; + String incompatibilityReason = ""; + try{ + isCompatible = interfaceContractMapper.checkCompatibility(topInterfaceContract, bottomInterfaceContract, Compatibility.SUBSET, false, false); + } catch (IncompatibleInterfaceContractException ex){ + isCompatible = false; + incompatibilityReason = ex.getMessage(); + } + if (!isCompatible) { + Monitor.error(monitor, + this, + Messages.ASSEMBLY_VALIDATION, + "ServiceIncompatibleComponentInterface", + component.getName(), + topContract.getName(), + incompatibilityReason); + } + } + } + + /** + * Interface contract from higher in the implementation hierarchy takes precedence + * When it comes to checking compatibility the top level reference interface is a + * superset of the promoted reference interface so treat the promoted + * (bottom) interface as the source + * + * @param topContract the top contract + * @param bottomContract the bottom contract + */ + private void calculateReferenceInterfaceContract(Component component, Reference topContract, Reference bottomContract, Monitor monitor) { + + // Use the interface contract from the bottom level contract if + // none is specified on the top level contract + InterfaceContract topInterfaceContract = topContract.getInterfaceContract(); + InterfaceContract bottomInterfaceContract = bottomContract.getInterfaceContract(); + + if (topInterfaceContract == null) { + topContract.setInterfaceContract(bottomInterfaceContract); + } else if (bottomInterfaceContract != null) { + // Check that the top and bottom interface contracts are compatible + boolean isCompatible = true; + String incompatibilityReason = ""; + try{ + isCompatible = interfaceContractMapper.checkCompatibility(bottomInterfaceContract, topInterfaceContract, Compatibility.SUBSET, false, false); + } catch (IncompatibleInterfaceContractException ex){ + isCompatible = false; + incompatibilityReason = ex.getMessage(); + } + if (!isCompatible) { + Monitor.error(monitor, + this, + Messages.ASSEMBLY_VALIDATION, + "ReferenceIncompatibleComponentInterface", + component.getName(), + topContract.getName(), + incompatibilityReason); + } + } + } + + /** + * Bindings from higher in the hierarchy take precedence + * + * @param componentService the top service + * @param componentTypeService the bottom service + */ + private void calculateBindings(Component component, Service componentService, Service componentTypeService, Monitor monitor) { + // 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()); + } + + // [ASM90005] validate that binding.sca has no uri set + for (Binding binding : componentService.getBindings()){ + if (binding instanceof SCABinding){ + if ((binding.getURI() != null) && + (binding.getURI().length() > 0)){ + Monitor.error(monitor, + this, + Messages.ASSEMBLY_VALIDATION, + "URIFoundOnServiceSCABinding", + binding.getName(), + component.getName(), + componentService.getName(), + binding.getURI()); + } + } + } + + } + + /** + * Bindings from higher in the hierarchy take precedence + * + * @param componentReference the top service + * @param componentTypeReference the bottom service + */ + private void calculateBindings(Reference componentReference, Reference componentTypeReference) { + // forward bindings + if (componentReference.getBindings().isEmpty()) { + componentReference.getBindings().addAll(componentTypeReference.getBindings()); + } + + // callback bindings + if (componentReference.getCallback() == null) { + componentReference.setCallback(componentTypeReference.getCallback()); + } else if (componentReference.getCallback().getBindings().isEmpty() && componentTypeReference.getCallback() != null) { + componentReference.getCallback().getBindings().addAll(componentTypeReference.getCallback().getBindings()); + } + } + +} diff --git a/sca-java-2.x/tags/2.0-M5.1-RC1/modules/builder/src/main/java/org/apache/tuscany/sca/builder/impl/ComponentPolicyBuilderImpl.java b/sca-java-2.x/tags/2.0-M5.1-RC1/modules/builder/src/main/java/org/apache/tuscany/sca/builder/impl/ComponentPolicyBuilderImpl.java new file mode 100644 index 0000000000..a5ad40df86 --- /dev/null +++ b/sca-java-2.x/tags/2.0-M5.1-RC1/modules/builder/src/main/java/org/apache/tuscany/sca/builder/impl/ComponentPolicyBuilderImpl.java @@ -0,0 +1,553 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.apache.tuscany.sca.builder.impl; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import javax.xml.namespace.QName; + +import org.apache.tuscany.sca.assembly.Binding; +import org.apache.tuscany.sca.assembly.Component; +import org.apache.tuscany.sca.assembly.ComponentReference; +import org.apache.tuscany.sca.assembly.ComponentService; +import org.apache.tuscany.sca.assembly.CompositeReference; +import org.apache.tuscany.sca.assembly.CompositeService; +import org.apache.tuscany.sca.assembly.Contract; +import org.apache.tuscany.sca.assembly.Reference; +import org.apache.tuscany.sca.assembly.Service; +import org.apache.tuscany.sca.assembly.builder.BuilderContext; +import org.apache.tuscany.sca.assembly.builder.BuilderExtensionPoint; +import org.apache.tuscany.sca.assembly.builder.Messages; +import org.apache.tuscany.sca.core.ExtensionPointRegistry; +import org.apache.tuscany.sca.definitions.Definitions; +import org.apache.tuscany.sca.monitor.Monitor; +import org.apache.tuscany.sca.policy.ExtensionType; +import org.apache.tuscany.sca.policy.Intent; +import org.apache.tuscany.sca.policy.IntentMap; +import org.apache.tuscany.sca.policy.PolicyExpression; +import org.apache.tuscany.sca.policy.PolicySet; +import org.apache.tuscany.sca.policy.PolicySubject; +import org.apache.tuscany.sca.policy.Qualifier; + +/** + * A composite builder that computes policy sets based on attached intents and policy sets. + * Useful if you want to build the model without making any runtime decisions such as + * reference/services matching + * + * @version $Rev$ $Date$ + */ +public class ComponentPolicyBuilderImpl { + + protected BuilderExtensionPoint builders; + + public ComponentPolicyBuilderImpl(ExtensionPointRegistry registry) { + this.builders = registry.getExtensionPoint(BuilderExtensionPoint.class); + } + + /** + * Report a warning. + * + * @param monitor + * @param problems + * @param message + * @param model + */ + protected void warning(Monitor monitor, String message, Object model, Object... messageParameters) { + Monitor.warning(monitor, this, Messages.BUILDER_VALIDATION_BUNDLE, message, messageParameters); + } + + /** + * Report a error. + * + * @param monitor + * @param problems + * @param message + * @param model + */ + protected void error(Monitor monitor, String message, Object model, Object... messageParameters) { + Monitor.error(monitor, this, Messages.BUILDER_VALIDATION_BUNDLE, message, messageParameters); + } + + + /** + * Inherit the intents and policySets from the list of models + * + * @param policySubject - the subject to which intents will be added + * @param intentType - choose to copy interaction or implementation intents. Null = both + * @param ignoreExclusiveIntents - when set true mutually exclusive intents won't be copied + * @param models - the subjects from which intents will be copied + */ + protected void inherit(PolicySubject policySubject, Intent.Type intentType, boolean ignoreExclusiveIntents, Object... models) { + for (Object model : models) { + if (model instanceof PolicySubject) { + PolicySubject subject = (PolicySubject)model; + + if (!ignoreExclusiveIntents) { + // The intents are merged and the exclusion check will be done after + for (Intent intent : subject.getRequiredIntents()) { + if (!policySubject.getRequiredIntents().contains(intent)){ + if (intentType != null) { + if (intent.getType().equals(intentType)){ + policySubject.getRequiredIntents().add(intent); + } + } else { + policySubject.getRequiredIntents().add(intent); + } + } + } + } else { + Set<Intent> intents = new HashSet<Intent>(); + for (Intent i1 : subject.getRequiredIntents()) { + boolean exclusive = false; + for (Intent i2 : policySubject.getRequiredIntents()) { + if (i1.getExcludedIntents().contains(i2) || i2.getExcludedIntents().contains(i1)) { + exclusive = true; + break; + } + } + if (!exclusive) { + if (!intents.contains(i1)){ + if (intentType != null) { + if (i1.getType().equals(intentType)){ + intents.add(i1); + } + } else { + intents.add(i1); + } + } + } + } + policySubject.getRequiredIntents().addAll(intents); + } + //FIXME this duplicates the intents for a implementation + //e.g <implementation.java requires="managedTransaction.local managedTransaction.local" + //becomes twice + //[{http://docs.oasis-open.org/ns/opencsa/sca/200912}managedTransaction.local, + //{http://docs.oasis-open.org/ns/opencsa/sca/200912}managedTransaction.local] + for (PolicySet policySet : subject.getPolicySets()){ + if (!policySubject.getPolicySets().contains(policySet)){ + policySubject.getPolicySets().add(policySet); + } + } + } + } + } + + protected void configure(PolicySubject subject1, PolicySubject subject2, Intent.Type intentType, BuilderContext context) { + if (subject1 != null) { + resolveAndCheck(subject1, context); + } + if (subject2 != null) { + resolveAndCheck(subject2, context); + } + inherit(subject1, intentType, false, subject2); + checkMutualExclusion(subject1, context); + } + + protected void configure(ComponentService componentService, BuilderContext context) { + Service service = componentService.getService(); + if (service != null) { + configure(componentService, service, null, context); + configureBindings(componentService, service, context); + } + } + + private void configureBindings(Contract componentContract, Contract componentTypeContract, BuilderContext context) { + if (componentTypeContract == null) { + return; + } + Map<String, Binding> componentTypeContractBindings = new HashMap<String, Binding>(); + for (Binding binding : componentTypeContract.getBindings()) { + componentTypeContractBindings.put(binding.getName(), binding); + } + for (Binding binding : componentContract.getBindings()) { + Binding componentTypeBinding = componentTypeContractBindings.get(binding.getName()); + if (binding instanceof PolicySubject && + componentTypeBinding instanceof PolicySubject) { + configure((PolicySubject)binding, (PolicySubject)componentTypeBinding, Intent.Type.interaction, context); + } + } + } + + protected void configure(ComponentReference componentReference, BuilderContext context) { + Reference reference = componentReference.getReference(); + if (reference != null) { + configure(componentReference, reference, null, context); + configureBindings(componentReference, reference, context); + } + } + + protected void configure(CompositeService compositeService, BuilderContext context) { + configure(compositeService, compositeService.getPromotedService(), null, context); + } + + protected void configure(CompositeReference compositeReference, BuilderContext context) { + for (ComponentReference reference : compositeReference.getPromotedReferences()) { + configure(compositeReference, reference, null, context); + } + } + + public void configure(Component component, BuilderContext context) { + Monitor monitor = context.getMonitor(); + + // fix up the component type by copying all implementation level + // interaction intents to *all* the component type services + for (ComponentService componentService : component.getServices()) { + monitor.pushContext("Service: " + componentService.getName()); + try { + configure(componentService, component.getImplementation(), Intent.Type.interaction, context); + removeConstrainedIntents(componentService, context); + } finally { + monitor.popContext(); + } + } + + // Inherit the intents and policySets from the componentType + for (ComponentReference componentReference : component.getReferences()) { + monitor.pushContext("Reference: " + componentReference.getName()); + try { + configure(componentReference, context); + removeConstrainedIntents(componentReference, context); + } finally { + monitor.popContext(); + } + } + + for (ComponentService componentService : component.getServices()) { + monitor.pushContext("Service: " + componentService.getName()); + try { + configure(componentService, context); + removeConstrainedIntents(componentService, context); + } finally { + monitor.popContext(); + } + } + } + + /** + * Checks if any qualifiable intents of intents in an excluded intent list match + * with a second intent. looking for the case where + * + * <intent name="intentA" excludes="intentB"/> + * <intent name="intentB" > + * <sca:qualifier name="q1" default="true"/> + * <sca:qualifier name="q2" default="true"/> + * </intent> + * + * And were + * + * requires="intentA intentB.q1" appears on an element + * + * @param excludedIntentList + * @param intent + * @return + */ + protected boolean checkQualifiedMutualExclusion(List<Intent> excludedIntentList, Intent intent){ + for (Intent excludedIntent : excludedIntentList){ + if (intent.getQualifiableIntent() != null && + excludedIntent != null && + intent.getQualifiableIntent().equals(excludedIntent)){ + return true; + } + } + return false; + } + + /** + * Check if two intents are mutually exclusive + * + * @param i1 + * @param i2 + * @param context + * @return + */ + protected boolean checkMutualExclusion(Intent i1, Intent i2, BuilderContext context){ + if ((i1 != i2) && + (i1.getExcludedIntents().contains(i2) || + i2.getExcludedIntents().contains(i1) || + checkQualifiedMutualExclusion(i1.getExcludedIntents(), i2) || + checkQualifiedMutualExclusion(i2.getExcludedIntents(), i1))) { + error(context.getMonitor(), "MutuallyExclusiveIntentsAtBuild", this, i1, i2); + return true; + } + + return false; + } + + /** + * Check if a single policy subject requires mutually exclusive intents + * @param subject1 - the policy subject to check + * @param context - context containing useful things like the monitor instance + * @return true if the policy subject contains mutually exclusive intents + */ + protected boolean checkMutualExclusion(PolicySubject subject1, BuilderContext context) { + if (subject1 == null) { + return false; + } + for (Intent i1 : subject1.getRequiredIntents()) { + for (Intent i2 : subject1.getRequiredIntents()) { + if (checkMutualExclusion(i1, i2, context)){ + return true; + } + } + } + return false; + } + + /** + * Check if two policy subjects requires mutually exclusive intents + * @param subject1 + * @param subject2 + * @param monitor + * @return + */ + protected boolean checkMutualExclusion(PolicySubject subject1, PolicySubject subject2, BuilderContext context) { + if (subject1 == subject2 || subject1 == null || subject2 == null) { + return false; + } + for (Intent i1 : subject1.getRequiredIntents()) { + for (Intent i2 : subject2.getRequiredIntents()) { + if (checkMutualExclusion(i1, i2, context)){ + return true; + } + } + } + return false; + } + + protected boolean resolveAndCheck(PolicySubject subject, BuilderContext context) { + if (subject == null) { + return false; + } + // FIXME: [rfeng] Should we resolve the intents during the "build" phase? + resolveAndNormalize(subject, context); + + checkMutualExclusion(subject, context); + + return false; + } + + /** + * Check if two names are equal + * @param name1 + * @param name2 + * @return + */ + protected boolean isEqual(String name1, String name2) { + if (name1 == name2) { + return true; + } + if (name1 != null) { + return name1.equals(name2); + } else { + return name2.equals(name1); + } + } + + protected static Intent resolve(Definitions definitions, Intent proxy) { + for (Intent i : definitions.getIntents()) { + if (i.equals(proxy)) { + return i; + } + for (Intent qi : i.getQualifiedIntents()) { + if (qi.equals(proxy)) { + return qi; + } + } + } + return null; + } + + protected void resolveAndNormalize(PolicySubject subject, BuilderContext context) { + Definitions definitions = context.getDefinitions(); + Set<Intent> intents = new HashSet<Intent>(); + if (definitions != null) { + for (Intent i : subject.getRequiredIntents()) { + Intent resolved = resolve(definitions, i); + if (resolved != null) { + intents.add(resolved); + } else { + error(context.getMonitor(), "IntentNotFoundAtBuild", subject, i); + // Intent cannot be resolved + } + } + } + + // Replace profile intents with their required intents + while (!intents.isEmpty()) { + boolean profileIntentsFound = false; + Set<Intent> copy = new HashSet<Intent>(intents); + for (Intent i : copy) { + if (!i.getRequiredIntents().isEmpty()) { + intents.remove(i); + intents.addAll(i.getRequiredIntents()); + profileIntentsFound = true; + } + } + if (!profileIntentsFound) { + // No more profileIntents + break; + } + } + + // Replace unqualified intents if there is a qualified intent in the list + Set<Intent> copy = new HashSet<Intent>(intents); + for (Intent i : copy) { + if (i.getQualifiableIntent() != null) { + intents.remove(i.getQualifiableIntent()); + } + + } + + // Replace qualifiable intents with the default qualified intent + copy = new HashSet<Intent>(intents); + for (Intent i : copy) { + if (i.getDefaultQualifiedIntent() != null) { + intents.remove(i); + intents.add(i.getDefaultQualifiedIntent()); + } + } + + subject.getRequiredIntents().clear(); + subject.getRequiredIntents().addAll(intents); + + // TUSCANY-3503 - policy sets now only applied through direct + // or external attachement + // resolve policy set names that have been specified for the + // policy subject against the real policy sets from the + // definitions files + Set<PolicySet> policySets = new HashSet<PolicySet>(); + if (definitions != null) { + for (PolicySet policySet : subject.getPolicySets()) { + int index = definitions.getPolicySets().indexOf(policySet); + if (index != -1) { + policySets.add(definitions.getPolicySets().get(index)); + } else { + // PolicySet cannot be resolved + warning(context.getMonitor(), "PolicySetNotFoundAtBuild", subject, policySet); + } + } + } + + subject.getPolicySets().clear(); + subject.getPolicySets().addAll(policySets); + } + + protected void removeConstrainedIntents(PolicySubject subject, BuilderContext context) { + List<Intent> intents = subject.getRequiredIntents(); + + // Remove the intents whose @contrains do not include the current element + ExtensionType extensionType = subject.getExtensionType(); + if(extensionType != null){ + List<Intent> copy = new ArrayList<Intent>(intents); + for (Intent i : copy) { + if (i.getConstrainedTypes().size() > 0){ + boolean constraintFound = false; + for (ExtensionType constrainedType : i.getConstrainedTypes()){ + if (constrainedType.getType().equals(extensionType.getType()) || + constrainedType.getType().equals(extensionType.getBaseType())){ + constraintFound = true; + break; + } + } + if(!constraintFound){ + intents.remove(i); + } + } + } + } + } + + protected void checkIntentsResolved(PolicySubject subject, BuilderContext context) { + // find the policy sets that satisfy the intents that are now + // attached to the policy subject. From the OASIS policy + // spec CD02 rev7: + // 1272 A policySet provides an intent if any of the statements are true: + // 1273 1. The intent is contained in the policySet @provides list. + // 1274 2. The intent is a qualified intent and the unqualified form of the intent is contained in the policySet + // 1275 @provides list. + // 1276 3. The policySet @provides list contains a qualified form of the intent (where the intent is qualifiable). + for (Intent intent : subject.getRequiredIntents()) { + boolean intentMatched = false; + + loop: for (PolicySet ps : subject.getPolicySets()) { + // FIXME: We will have to check the policy references and intentMap too + // as well as the appliesTo + if (ps.getProvidedIntents().contains(intent)) { + intentMatched = true; + break; + } + + for (Intent psProvidedIntent : ps.getProvidedIntents()){ + if (isQualifiedBy(psProvidedIntent, intent)){ + intentMatched = true; + break loop; + } + } + + for (IntentMap map : ps.getIntentMaps()) { + for (Qualifier q : map.getQualifiers()) { + if (intent.equals(q.getIntent())) { + intentMatched = true; + break loop; + } + } + } + } + + if (!intentMatched){ + // Raise a warning as we have an intent that doesn't have a matching + // policy set at this start. + // TODO - this could be because the intent is provided by and extension + // and hence there is no explicit policy set. Need and extra piece + // of processing to walk through the extension models. + warning(context.getMonitor(), "IntentNotSatisfiedAtBuild", subject, intent.getName(), subject.toString()); + } + } + } + + protected Set<QName> getPolicyNames(PolicySubject subject) { + if (subject == null) { + return Collections.emptySet(); + } + Set<QName> names = new HashSet<QName>(); + for (PolicySet ps : subject.getPolicySets()) { + for (PolicyExpression exp : ps.getPolicies()) { + names.add(exp.getName()); + } + } + return names; + } + + protected boolean isQualifiedBy(Intent qualifiableIntent, Intent qualifiedIntent){ + if (qualifiedIntent.getQualifiableIntent() == qualifiableIntent){ + return true; + } else { + return false; + } + } + +} diff --git a/sca-java-2.x/tags/2.0-M5.1-RC1/modules/builder/src/main/java/org/apache/tuscany/sca/builder/impl/ComponentReferenceBindingBuilderImpl.java b/sca-java-2.x/tags/2.0-M5.1-RC1/modules/builder/src/main/java/org/apache/tuscany/sca/builder/impl/ComponentReferenceBindingBuilderImpl.java new file mode 100644 index 0000000000..c48d868105 --- /dev/null +++ b/sca-java-2.x/tags/2.0-M5.1-RC1/modules/builder/src/main/java/org/apache/tuscany/sca/builder/impl/ComponentReferenceBindingBuilderImpl.java @@ -0,0 +1,81 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.apache.tuscany.sca.builder.impl; + +import org.apache.tuscany.sca.assembly.Binding; +import org.apache.tuscany.sca.assembly.Component; +import org.apache.tuscany.sca.assembly.ComponentReference; +import org.apache.tuscany.sca.assembly.Composite; +import org.apache.tuscany.sca.assembly.Implementation; +import org.apache.tuscany.sca.assembly.builder.BindingBuilder; +import org.apache.tuscany.sca.assembly.builder.BuilderContext; +import org.apache.tuscany.sca.assembly.builder.BuilderExtensionPoint; +import org.apache.tuscany.sca.assembly.builder.CompositeBuilder; +import org.apache.tuscany.sca.assembly.builder.CompositeBuilderException; +import org.apache.tuscany.sca.core.ExtensionPointRegistry; + +/** + * A composite builder that performs any additional building steps that + * component reference bindings may need. Used for WSDL generation. + * + * @version $Rev$ $Date$ + */ +public class ComponentReferenceBindingBuilderImpl implements CompositeBuilder { + + private BuilderExtensionPoint builders; + + public ComponentReferenceBindingBuilderImpl(ExtensionPointRegistry registry) { + this.builders = registry.getExtensionPoint(BuilderExtensionPoint.class); + } + + public Composite build(Composite composite, BuilderContext context) + throws CompositeBuilderException { + buildReferenceBindings(composite, context); + return composite; + } + + public String getID() { + return "org.apache.tuscany.sca.assembly.builder.ComponentReferenceBindingBuilder"; + } + + private void buildReferenceBindings(Composite composite, BuilderContext context) { + + // find all the component reference bindings (starting at top level) + for (Component component : composite.getComponents()) { + for (ComponentReference componentReference : component.getReferences()) { + for (Binding binding : componentReference.getBindings()) { + BindingBuilder builder = builders.getBindingBuilder(binding.getType()); + if (builder != null) { + builder.build(component, componentReference, binding, context); + } + } + } + } + + // build bindings recursively + for (Component component : composite.getComponents()) { + Implementation implementation = component.getImplementation(); + if (implementation instanceof Composite) { + buildReferenceBindings((Composite)implementation, context); + } + } + } + +} diff --git a/sca-java-2.x/tags/2.0-M5.1-RC1/modules/builder/src/main/java/org/apache/tuscany/sca/builder/impl/ComponentServiceBindingBuilderImpl.java b/sca-java-2.x/tags/2.0-M5.1-RC1/modules/builder/src/main/java/org/apache/tuscany/sca/builder/impl/ComponentServiceBindingBuilderImpl.java new file mode 100644 index 0000000000..9a74023504 --- /dev/null +++ b/sca-java-2.x/tags/2.0-M5.1-RC1/modules/builder/src/main/java/org/apache/tuscany/sca/builder/impl/ComponentServiceBindingBuilderImpl.java @@ -0,0 +1,80 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.apache.tuscany.sca.builder.impl; + +import org.apache.tuscany.sca.assembly.Binding; +import org.apache.tuscany.sca.assembly.Component; +import org.apache.tuscany.sca.assembly.ComponentService; +import org.apache.tuscany.sca.assembly.Composite; +import org.apache.tuscany.sca.assembly.Implementation; +import org.apache.tuscany.sca.assembly.builder.BindingBuilder; +import org.apache.tuscany.sca.assembly.builder.BuilderContext; +import org.apache.tuscany.sca.assembly.builder.BuilderExtensionPoint; +import org.apache.tuscany.sca.assembly.builder.CompositeBuilder; +import org.apache.tuscany.sca.assembly.builder.CompositeBuilderException; +import org.apache.tuscany.sca.core.ExtensionPointRegistry; + +/** + * A composite builder that performs any additional building steps that + * component service bindings may need. Used for WSDL generation. + * + * @version $Rev$ $Date$ + */ +public class ComponentServiceBindingBuilderImpl implements CompositeBuilder { + private BuilderExtensionPoint builders; + + public ComponentServiceBindingBuilderImpl(ExtensionPointRegistry registry) { + this.builders = registry.getExtensionPoint(BuilderExtensionPoint.class); + } + + public String getID() { + return "org.apache.tuscany.sca.assembly.builder.ComponentServiceBindingBuilder"; + } + + public Composite build(Composite composite, BuilderContext context) + throws CompositeBuilderException { + buildServiceBindings(composite, context); + return composite; + } + + private void buildServiceBindings(Composite composite, BuilderContext context) { + + // build bindings recursively + for (Component component : composite.getComponents()) { + Implementation implementation = component.getImplementation(); + if (implementation instanceof Composite) { + buildServiceBindings((Composite)implementation, context); + } + } + + // find all the component service bindings + for (Component component : composite.getComponents()) { + for (ComponentService componentService : component.getServices()) { + for (Binding binding : componentService.getBindings()) { + BindingBuilder builder = builders.getBindingBuilder(binding.getType()); + if (builder != null) { + builder.build(component, componentService, binding, context); + } + } + } + } + } + +} diff --git a/sca-java-2.x/tags/2.0-M5.1-RC1/modules/builder/src/main/java/org/apache/tuscany/sca/builder/impl/CompositeCloneBuilderImpl.java b/sca-java-2.x/tags/2.0-M5.1-RC1/modules/builder/src/main/java/org/apache/tuscany/sca/builder/impl/CompositeCloneBuilderImpl.java new file mode 100644 index 0000000000..148a3b5368 --- /dev/null +++ b/sca-java-2.x/tags/2.0-M5.1-RC1/modules/builder/src/main/java/org/apache/tuscany/sca/builder/impl/CompositeCloneBuilderImpl.java @@ -0,0 +1,100 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.apache.tuscany.sca.builder.impl; + +import java.util.ArrayList; +import java.util.List; + +import org.apache.tuscany.sca.assembly.Component; +import org.apache.tuscany.sca.assembly.Composite; +import org.apache.tuscany.sca.assembly.Implementation; +import org.apache.tuscany.sca.assembly.builder.BuilderContext; +import org.apache.tuscany.sca.assembly.builder.CompositeBuilder; +import org.apache.tuscany.sca.assembly.builder.CompositeBuilderException; + +/** + * A composite builder that clones nested composites. + * + * @version $Rev$ $Date$ + */ +public class CompositeCloneBuilderImpl implements CompositeBuilder { + + public CompositeCloneBuilderImpl() { + } + + public Composite build(Composite composite, BuilderContext context) + throws CompositeBuilderException { + + if (Composite.DOMAIN_COMPOSITE.equals(composite.getName())) { + // Try to avoid clone for top-level composites that are added to the domain composite + for (Composite included : composite.getIncludes()) { + cloneIncludes(included); + cloneCompositeImplementations(included); + } + } else { + // Clone the includes + cloneIncludes(composite); + cloneCompositeImplementations(composite); + } + + return composite; + } + + private void cloneIncludes(Composite composite) { + List<Composite> includes = new ArrayList<Composite>(); + for (Composite included : composite.getIncludes()) { + try { + includes.add((Composite)included.clone()); + } catch (CloneNotSupportedException e) { + throw new UnsupportedOperationException(e); + } + } + composite.getIncludes().clear(); + composite.getIncludes().addAll(includes); + } + + public String getID() { + return "org.apache.tuscany.sca.assembly.builder.CompositeCloneBuilder"; + } + + /** + * Clone composite component implementations + * + * @param composite + * @param problems + */ + private void cloneCompositeImplementations(Composite composite) { + for (Component component : composite.getComponents()) { + Implementation implementation = component.getImplementation(); + if (implementation instanceof Composite) { + + Composite compositeImplementation = (Composite)implementation; + try { + // Please note the clone method is recursive + Composite clone = (Composite)compositeImplementation.clone(); + component.setImplementation(clone); + } catch (CloneNotSupportedException e) { + throw new UnsupportedOperationException(e); + } + } + } + } + +} diff --git a/sca-java-2.x/tags/2.0-M5.1-RC1/modules/builder/src/main/java/org/apache/tuscany/sca/builder/impl/CompositeComponentTypeBuilderImpl.java b/sca-java-2.x/tags/2.0-M5.1-RC1/modules/builder/src/main/java/org/apache/tuscany/sca/builder/impl/CompositeComponentTypeBuilderImpl.java new file mode 100644 index 0000000000..2ea35ffb9b --- /dev/null +++ b/sca-java-2.x/tags/2.0-M5.1-RC1/modules/builder/src/main/java/org/apache/tuscany/sca/builder/impl/CompositeComponentTypeBuilderImpl.java @@ -0,0 +1,619 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.tuscany.sca.builder.impl; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.logging.Logger; + +import javax.xml.namespace.QName; + +import org.apache.tuscany.sca.assembly.AssemblyFactory; +import org.apache.tuscany.sca.assembly.Binding; +import org.apache.tuscany.sca.assembly.Component; +import org.apache.tuscany.sca.assembly.ComponentReference; +import org.apache.tuscany.sca.assembly.ComponentService; +import org.apache.tuscany.sca.assembly.ComponentType; +import org.apache.tuscany.sca.assembly.Composite; +import org.apache.tuscany.sca.assembly.CompositeReference; +import org.apache.tuscany.sca.assembly.CompositeService; +import org.apache.tuscany.sca.assembly.Contract; +import org.apache.tuscany.sca.assembly.Multiplicity; +import org.apache.tuscany.sca.assembly.Reference; +import org.apache.tuscany.sca.assembly.SCABinding; +import org.apache.tuscany.sca.assembly.SCABindingFactory; +import org.apache.tuscany.sca.assembly.Service; +import org.apache.tuscany.sca.assembly.builder.BuilderContext; +import org.apache.tuscany.sca.assembly.builder.BuilderExtensionPoint; +import org.apache.tuscany.sca.assembly.builder.Messages; +import org.apache.tuscany.sca.core.ExtensionPointRegistry; +import org.apache.tuscany.sca.core.FactoryExtensionPoint; +import org.apache.tuscany.sca.core.UtilityExtensionPoint; +import org.apache.tuscany.sca.definitions.Definitions; +import org.apache.tuscany.sca.interfacedef.Compatibility; +import org.apache.tuscany.sca.interfacedef.IncompatibleInterfaceContractException; +import org.apache.tuscany.sca.interfacedef.InterfaceContract; +import org.apache.tuscany.sca.interfacedef.InterfaceContractMapper; +import org.apache.tuscany.sca.monitor.Monitor; +import org.apache.tuscany.sca.policy.ExtensionType; +import org.apache.tuscany.sca.policy.PolicySubject; + +/** + * @version $Rev$ $Date$ + */ + +// TODO - really implementation.composite component type builder - CompositeComponentTypeBuilder? + +public class CompositeComponentTypeBuilderImpl { + private static final Logger logger = Logger.getLogger(CompositeComponentTypeBuilderImpl.class.getName()); + + protected static final String SCA11_NS = "http://docs.oasis-open.org/ns/opencsa/sca/200912"; + protected static final String BINDING_SCA = "binding.sca"; + protected static final QName BINDING_SCA_QNAME = new QName(SCA11_NS, BINDING_SCA); + + private ComponentBuilderImpl componentBuilder; + private AssemblyFactory assemblyFactory; + private SCABindingFactory scaBindingFactory; + private InterfaceContractMapper interfaceContractMapper; + private BuilderExtensionPoint builders; + + public CompositeComponentTypeBuilderImpl(ExtensionPointRegistry registry) { + UtilityExtensionPoint utilities = registry.getExtensionPoint(UtilityExtensionPoint.class); + + FactoryExtensionPoint modelFactories = registry.getExtensionPoint(FactoryExtensionPoint.class); + assemblyFactory = modelFactories.getFactory(AssemblyFactory.class); + scaBindingFactory = modelFactories.getFactory(SCABindingFactory.class); + + interfaceContractMapper = utilities.getUtility(InterfaceContractMapper.class); + builders = registry.getExtensionPoint(BuilderExtensionPoint.class); + } + + public void setComponentBuilder(ComponentBuilderImpl componentBuilder) { + this.componentBuilder = componentBuilder; + } + + /** + * Calculate the component type for the provided implementation + * + * @param implementation + * @return component type + */ + public void createComponentType(Component outerComponent, Composite composite, BuilderContext context) { + + Monitor monitor = context.getMonitor(); + monitor.pushContext("Composite: " + composite.getName().toString()); + + try { + // first make sure that each child component has been properly configured based + // on its own component type + for (Component component : composite.getComponents()) { + + // Check for duplicate component names + if (component != composite.getComponent(component.getName())) { + Monitor.error(monitor, + this, + Messages.ASSEMBLY_VALIDATION, + "DuplicateComponentName", + composite.getName().toString(), + component.getName()); + } + + // do any work we need to do before we configure the component + // Anything that needs to be pushed down the promotion + // hierarchy must be done before we configure the component + + // Push down the autowire flag from the composite to components + if (component.getAutowire() == null) { + component.setAutowire(composite.getAutowire()); + } + + // configure the component from its component type + componentBuilder.configureComponentFromComponentType(outerComponent, composite, component, context); + } + + // create the composite component type based on the promoted artifacts + // from the components that it contains + + // index all the components, services and references in the + // component type so that they are easy to find + Map<String, Component> components = new HashMap<String, Component>(); + Map<String, ComponentService> componentServices = new HashMap<String, ComponentService>(); + Map<String, ComponentReference> componentReferences = new HashMap<String, ComponentReference>(); + indexComponentsServicesAndReferences(composite, components, componentServices, componentReferences); + + // services + calculateServices(composite, components, componentServices, context); + + // references + calculateReferences(composite, components, componentReferences, context); + + // properties + // Properties on the composite component are unaffected by properties + // on child components. Instead child component properties might take their + // values from composite properties. Hence there is nothing to do here. + //calculateProperties(composite, components); + + } finally { + monitor.popContext(); + } + } + + /** + * Index components, services and references inside a composite. + * + * @param composite + * @param components + * @param componentServices + * @param componentReferences + */ + private void indexComponentsServicesAndReferences(Composite composite, + Map<String, Component> components, + Map<String, ComponentService> componentServices, + Map<String, ComponentReference> componentReferences) { + + for (Component component : composite.getComponents()) { + + // Index components by name + components.put(component.getName(), component); + + ComponentService nonCallbackService = null; + int nonCallbackServices = 0; + for (ComponentService componentService : component.getServices()) { + + // Index component services by component name / service name + String uri = component.getName() + '/' + componentService.getName(); + componentServices.put(uri, componentService); + + // count how many non-callback services there are + // if there is only one the component name also acts as the service name + if (!componentService.isForCallback()) { + + // Check how many non callback non-promoted services we have + if (nonCallbackServices == 0) { + nonCallbackService = componentService; + } + nonCallbackServices++; + } + } + + if (nonCallbackServices == 1) { + // If we have a single non callback service, index it by + // component name as well + componentServices.put(component.getName(), nonCallbackService); + } + + // Index references by component name / reference name + for (ComponentReference componentReference : component.getReferences()) { + String uri = component.getName() + '/' + componentReference.getName(); + componentReferences.put(uri, componentReference); + } + } + } + + /** + * Connect the services in the component type to the component services that + * they promote + * + * @param componentType + * @param component + */ + private void calculateServices(ComponentType componentType, + Map<String, Component> components, + Map<String, ComponentService> componentServices, + BuilderContext context) { + + Monitor monitor = context.getMonitor(); + + // Connect this component type's services to the + // services from child components which it promotes + connectPromotedServices(componentType, components, componentServices, monitor); + + // look at each component type service in turn and + // calculate its configuration based on OASIS rules + for (Service service : componentType.getServices()) { + CompositeService compositeService = (CompositeService)service; + ComponentService promotedComponentService = compositeService.getPromotedService(); + + // promote interface contracts + calculatePromotedServiceInterfaceContract(compositeService, promotedComponentService, monitor); + + // promote bindings + calculatePromotedBindings(compositeService, promotedComponentService); + + componentBuilder.policyBuilder.configure(compositeService, context); + } + } + + /** + * Connect the references in the component type to the component references that + * they promote + * + * @param componentType + * @param component + */ + private void calculateReferences(ComponentType componentType, + Map<String, Component> components, + Map<String, ComponentReference> componentReferences, + BuilderContext context) { + Monitor monitor = context.getMonitor(); + // Connect this component type's references to the + // references from child components which it promotes + connectPromotedReferences(componentType, components, componentReferences, monitor); + + // look at each component type reference in turn and + // calculate its configuration based on OASIS rules + for (Reference reference : componentType.getReferences()) { + CompositeReference compositeReference = (CompositeReference)reference; + List<ComponentReference> promotedReferences = compositeReference.getPromotedReferences(); + + for (ComponentReference promotedComponentReference : promotedReferences) { + + // promote multiplicity + reconcileReferenceMultiplicity(componentType, compositeReference, promotedComponentReference, monitor); + + // check nonOverridable + validateNonOverridable(componentType, compositeReference, promotedComponentReference, monitor); + + // promote interface contracts + calculatePromotedReferenceInterfaceContract(compositeReference, promotedComponentReference, monitor); + + // promote bindings + // Don't need to promote reference bindings as any lower level binding will + // already be targeting the correct service without need for promotion + //calculatePromotedBindings(compositeReference, promotedComponentReference); + } + + componentBuilder.policyBuilder.configure(compositeReference, context); + } + } + + /** + * Connect the services in the component type to the component services that + * they promote + * + * @param componentType + * @param component + */ + private void connectPromotedServices(ComponentType componentType, + Map<String, Component> components, + Map<String, ComponentService> componentServices, + Monitor monitor) { + + for (Service service : componentType.getServices()) { + // Connect composite (component type) services to the component services + // that they promote + CompositeService compositeService = (CompositeService)service; + ComponentService componentService = compositeService.getPromotedService(); + if (componentService != null && componentService.isUnresolved()) { + // get the name of the promoted component/service + String promotedComponentName = compositeService.getPromotedComponent().getName(); + String promotedServiceName; + if (componentService.getName() != null) { + if (compositeService.isForCallback()) { + // For callbacks the name already has the form "componentName/servicename" + promotedServiceName = componentService.getName(); + } else { + promotedServiceName = promotedComponentName + '/' + componentService.getName(); + } + } else { + promotedServiceName = promotedComponentName; + } + + // find the promoted service + ComponentService promotedService = componentServices.get(promotedServiceName); + + if (promotedService != null) { + + // Point to the resolved component + Component promotedComponent = components.get(promotedComponentName); + compositeService.setPromotedComponent(promotedComponent); + + // Point to the resolved component service + compositeService.setPromotedService(promotedService); + } else { + Monitor.error(monitor, + this, + Messages.ASSEMBLY_VALIDATION, + "PromotedServiceNotFound", + ((Composite)componentType).getName().toString(), + promotedServiceName); + } + } + } + } + + /** + * Connect the references in the component type to the component references that + * they promote + * + * @param componentType + * @param component + */ + private void connectPromotedReferences(ComponentType componentType, + Map<String, Component> components, + Map<String, ComponentReference> componentReferences, + Monitor monitor) { + + // Connect composite (component type) references to the component references that they promote + for (Reference reference : componentType.getReferences()) { + CompositeReference compositeReference = (CompositeReference)reference; + List<ComponentReference> promotedReferences = compositeReference.getPromotedReferences(); + for (int i = 0, n = promotedReferences.size(); i < n; i++) { + ComponentReference componentReference = promotedReferences.get(i); + if (componentReference.isUnresolved()) { + String componentReferenceName = componentReference.getName(); + componentReference = componentReferences.get(componentReferenceName); + if (componentReference != null) { + // Set the promoted component + Component promotedComponent = compositeReference.getPromotedComponents().get(i); + promotedComponent = components.get(promotedComponent.getName()); + compositeReference.getPromotedComponents().set(i, promotedComponent); + + componentReference.setPromoted(true); + + // Point to the resolved component reference + promotedReferences.set(i, componentReference); + } else { + Monitor.error(monitor, + this, + Messages.ASSEMBLY_VALIDATION, + "PromotedReferenceNotFound", + ((Composite)componentType).getName().toString(), + componentReferenceName); + } + } + } + } + } + + /** + * Create a default SCA binding in the case that no binding + * is specified by the user + * + * @param contract + * @param definitions + */ + protected void createSCABinding(Contract contract, Definitions definitions) { + + SCABinding scaBinding = scaBindingFactory.createSCABinding(); + scaBinding.setName(contract.getName()); + + if (definitions != null) { + for (ExtensionType attachPointType : definitions.getBindingTypes()) { + if (attachPointType.getType().equals(BINDING_SCA_QNAME)) { + ((PolicySubject)scaBinding).setExtensionType(attachPointType); + } + } + } + + contract.getBindings().add(scaBinding); + contract.setOverridingBindings(false); + } + + /** + * The following methods implement rules that the OASIS specification defined explicitly + * to control how configuration from a component type is inherited by a component + */ + + /** + * Interface contract from higher in the implementation hierarchy takes precedence. + * When it comes to checking compatibility the top level service interface is a + * subset of the promoted service interface so treat the top level interface as + * the source + * + * @param topContract the top contract + * @param bottomContract the bottom contract + */ + private void calculatePromotedServiceInterfaceContract(Service topContract, Service bottomContract, Monitor monitor) { + // Use the interface contract from the bottom level contract if + // none is specified on the top level contract + InterfaceContract topInterfaceContract = topContract.getInterfaceContract(); + InterfaceContract bottomInterfaceContract = bottomContract.getInterfaceContract(); + + if (topInterfaceContract == null) { + topContract.setInterfaceContract(bottomInterfaceContract); + } else if (bottomInterfaceContract != null) { + // Check that the top and bottom interface contracts are compatible + boolean isCompatible = true; + String incompatibilityReason = ""; + try{ + isCompatible = interfaceContractMapper.checkCompatibility(topInterfaceContract, bottomInterfaceContract, Compatibility.SUBSET, false, false); + } catch (IncompatibleInterfaceContractException ex){ + isCompatible = false; + incompatibilityReason = ex.getMessage(); + } + if (!isCompatible) { + Monitor.error(monitor, + this, + Messages.ASSEMBLY_VALIDATION, + "ServiceInterfaceNotSubSet", + topContract.getName(), + incompatibilityReason); + } + } + } + + /** + * Interface contract from higher in the implementation hierarchy takes precedence. + * When it comes to checking compatibility the top level reference interface is a + * superset of the promoted reference interface so treat the promoted + * (bottom) interface as the source + * + * @param topContract the top contract + * @param bottomContract the bottom contract + */ + private void calculatePromotedReferenceInterfaceContract(Reference topContract, Reference bottomContract, Monitor monitor) { + // Use the interface contract from the bottom level contract if + // none is specified on the top level contract + InterfaceContract topInterfaceContract = topContract.getInterfaceContract(); + InterfaceContract bottomInterfaceContract = bottomContract.getInterfaceContract(); + + if (topInterfaceContract == null) { + topContract.setInterfaceContract(bottomInterfaceContract); + } else if (bottomInterfaceContract != null) { + // Check that the top and bottom interface contracts are compatible + boolean isCompatible = true; + String incompatibilityReason = ""; + try{ + isCompatible = interfaceContractMapper.checkCompatibility(bottomInterfaceContract, topInterfaceContract, Compatibility.SUBSET, false, false); + } catch (IncompatibleInterfaceContractException ex){ + isCompatible = false; + incompatibilityReason = ex.getMessage(); + } + if (!isCompatible) { + Monitor.error(monitor, + this, + Messages.ASSEMBLY_VALIDATION, + "ReferenceInterfaceNotSubSet", + topContract.getName(), + incompatibilityReason); + } + } + } + + /** + * Bindings from higher in the implementation hierarchy take precedence + * + * @param compositeService + * @param promotedComponentService + */ + private void calculatePromotedBindings(CompositeService compositeService, ComponentService promotedComponentService) { + // forward bindings + if (compositeService.getBindings().isEmpty()) { + for (Binding binding : promotedComponentService.getBindings()) { + try { + compositeService.getBindings().add((Binding)binding.clone()); + } catch (CloneNotSupportedException ex) { + // this binding can't be used in the promoted service + } + } + } + + if (compositeService.getBindings().isEmpty()) { + createSCABinding(compositeService, null); + } + + // callback bindings + if (promotedComponentService.getCallback() != null) { + if (compositeService.getCallback() != null) { + compositeService.getCallback().getBindings().clear(); + } else { + compositeService.setCallback(assemblyFactory.createCallback()); + } + + for (Binding binding : promotedComponentService.getCallback().getBindings()) { + try { + compositeService.getCallback().getBindings().add((Binding)binding.clone()); + } catch (CloneNotSupportedException ex) { + // this binding can't be used in the promoted service + } + } + } + } + + private void reconcileReferenceMultiplicity(ComponentType componentType, + Reference compositeReference, + Reference promotedComponentReference, + Monitor monitor) { + if (compositeReference.getMultiplicity() != null) { + if (!isValidMultiplicityOverride(promotedComponentReference.getTargets().size() > 0, + promotedComponentReference.getMultiplicity(), + compositeReference.getMultiplicity())) { + Monitor.error(monitor, + this, + Messages.ASSEMBLY_VALIDATION, + "CompositeReferenceIncompatibleMultiplicity", + componentType.getURI(), + compositeReference.getName(), + promotedComponentReference.getName()); + } + } else { + compositeReference.setMultiplicity(promotedComponentReference.getMultiplicity()); + } + } + + private boolean isValidMultiplicityOverride(boolean componentRefHasTarget, + Multiplicity componentRefMul, + Multiplicity compositeRefMul) { + if ((componentRefMul != null) && + (compositeRefMul != null) && + componentRefMul != compositeRefMul) { + if (componentRefHasTarget){ + switch (componentRefMul) { + case ZERO_ONE: + return compositeRefMul == Multiplicity.ZERO_ONE || + compositeRefMul == Multiplicity.ONE_ONE; + case ONE_ONE: + return compositeRefMul == Multiplicity.ZERO_ONE || + compositeRefMul == Multiplicity.ONE_ONE; + case ZERO_N: + return true; + case ONE_N: + return true; + default: + return false; + } + } else { + switch (componentRefMul) { + case ZERO_ONE: + return compositeRefMul == Multiplicity.ONE_ONE; + case ONE_ONE: + return compositeRefMul == Multiplicity.ONE_ONE; + case ZERO_N: + return true; + case ONE_N: + return compositeRefMul == Multiplicity.ONE_ONE || + compositeRefMul == Multiplicity.ONE_N; + + default: + return false; + } + } + } else { + return true; + } + } + + /** + * ASM50042 - Checks that if a component reference with multiplicity="1..1" is marked + * as nonOveridable then there are no composite references that promote it + * + * @param componentType + * @param compositeReference + * @param promotedComponentReference + * @param monitor + */ + private void validateNonOverridable(ComponentType componentType, + Reference compositeReference, + Reference promotedComponentReference, + Monitor monitor){ + if ((promotedComponentReference.getMultiplicity() == Multiplicity.ONE_ONE) && + (((ComponentReference)promotedComponentReference)).isNonOverridable() == true) { + Monitor.error(monitor, + this, + Messages.ASSEMBLY_VALIDATION, + "CompositeReferencePromotesNonOverridableReference", + componentType.getURI(), + compositeReference.getName(), + promotedComponentReference.getName()); + } + } + +} //end class diff --git a/sca-java-2.x/tags/2.0-M5.1-RC1/modules/builder/src/main/java/org/apache/tuscany/sca/builder/impl/CompositeIncludeBuilderImpl.java b/sca-java-2.x/tags/2.0-M5.1-RC1/modules/builder/src/main/java/org/apache/tuscany/sca/builder/impl/CompositeIncludeBuilderImpl.java new file mode 100644 index 0000000000..63864e5832 --- /dev/null +++ b/sca-java-2.x/tags/2.0-M5.1-RC1/modules/builder/src/main/java/org/apache/tuscany/sca/builder/impl/CompositeIncludeBuilderImpl.java @@ -0,0 +1,126 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.apache.tuscany.sca.builder.impl; + +import org.apache.tuscany.sca.assembly.Component; +import org.apache.tuscany.sca.assembly.Composite; +import org.apache.tuscany.sca.assembly.Implementation; +import org.apache.tuscany.sca.assembly.Reference; +import org.apache.tuscany.sca.assembly.Service; +import org.apache.tuscany.sca.assembly.builder.BuilderContext; +import org.apache.tuscany.sca.assembly.builder.CompositeBuilder; +import org.apache.tuscany.sca.assembly.builder.CompositeBuilderException; +import org.apache.tuscany.sca.assembly.builder.Messages; +import org.apache.tuscany.sca.monitor.Monitor; + +/** + * Implementation of a CompositeBuilder. + * + * @version $Rev$ $Date$ + */ +public class CompositeIncludeBuilderImpl implements CompositeBuilder { + + public CompositeIncludeBuilderImpl() { + } + + public String getID() { + return "org.apache.tuscany.sca.assembly.builder.CompositeIncludeBuilder"; + } + + public Composite build(Composite composite, BuilderContext context) + throws CompositeBuilderException { + return processIncludes(composite, context.getMonitor()); + } + + /** + * Merge the elements from the included composites into the including composite + * @param composite + * @param monitor + * @return + */ + private Composite processIncludes(Composite composite, Monitor monitor) { + monitor.pushContext("Composite: " + composite.getName().toString()); + + try { + // process any composites referenced through implementation.composite + for (Component component : composite.getComponents()) { + + // recurse for composite implementations + Implementation implementation = component.getImplementation(); + if (implementation instanceof Composite) { + processIncludes((Composite)implementation, monitor); + } + } + + // get the components etc. from any included composites + for (Composite included : composite.getIncludes()) { + if (included.isLocal() && !composite.isLocal()) { + // ASM60041 + Monitor.error(monitor, this, Messages.ASSEMBLY_VALIDATION, "IllegalCompositeIncusion", composite + .getName().toString(), included.getName().toString()); + return null; + } + + // The included has been cloned during composite.clone() + Composite merged = processIncludes(included, monitor); + if (merged != null) { + for (Component component : merged.getComponents()) { + // apply the autowire flag on this composite to any inline + // components - Assembly 5.6 point 4 + if (component.getAutowire() == null && Boolean.TRUE.equals(merged.getAutowire())) { + component.setAutowire(Boolean.TRUE); + } + // Merge the intents and policySets from the included composite into + // component/service/reference elements under the composite + component.getRequiredIntents().addAll(merged.getRequiredIntents()); + component.getPolicySets().addAll(merged.getPolicySets()); + } + + for (Service service : merged.getServices()) { + service.getRequiredIntents().addAll(merged.getRequiredIntents()); + service.getPolicySets().addAll(merged.getPolicySets()); + } + + for (Reference reference : merged.getReferences()) { + reference.getRequiredIntents().addAll(merged.getRequiredIntents()); + reference.getPolicySets().addAll(merged.getPolicySets()); + } + composite.getComponents().addAll(merged.getComponents()); + composite.getServices().addAll(merged.getServices()); + composite.getReferences().addAll(merged.getReferences()); + composite.getProperties().addAll(merged.getProperties()); + composite.getWires().addAll(merged.getWires()); + // FIXME: What should we do for the extensions + /* + clone.getExtensions().addAll(fusedComposite.getExtensions()); + clone.getAttributeExtensions().addAll(fusedComposite.getAttributeExtensions()); + */ + } + } + + composite.getIncludes().clear(); + + // return the fused composite we have built up so far + return composite; + } finally { + monitor.popContext(); + } + } +} diff --git a/sca-java-2.x/tags/2.0-M5.1-RC1/modules/builder/src/main/java/org/apache/tuscany/sca/builder/impl/CompositePolicyBuilderImpl.java b/sca-java-2.x/tags/2.0-M5.1-RC1/modules/builder/src/main/java/org/apache/tuscany/sca/builder/impl/CompositePolicyBuilderImpl.java new file mode 100644 index 0000000000..ea459bf2fa --- /dev/null +++ b/sca-java-2.x/tags/2.0-M5.1-RC1/modules/builder/src/main/java/org/apache/tuscany/sca/builder/impl/CompositePolicyBuilderImpl.java @@ -0,0 +1,288 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.apache.tuscany.sca.builder.impl; + +import java.util.Set; + +import javax.xml.namespace.QName; + +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.Endpoint; +import org.apache.tuscany.sca.assembly.EndpointReference; +import org.apache.tuscany.sca.assembly.Implementation; +import org.apache.tuscany.sca.assembly.builder.BuilderContext; +import org.apache.tuscany.sca.assembly.builder.CompositeBuilder; +import org.apache.tuscany.sca.assembly.builder.CompositeBuilderException; +import org.apache.tuscany.sca.assembly.builder.PolicyBuilder; +import org.apache.tuscany.sca.core.ExtensionPointRegistry; +import org.apache.tuscany.sca.monitor.Monitor; +import org.apache.tuscany.sca.policy.Intent; + +/** + * A composite builder that computes policy sets based on attached intents and policy sets. + * Useful if you want to build the model without making any runtime decisions such as + * reference/services matching + * + * @version $Rev$ $Date$ + */ +public class CompositePolicyBuilderImpl extends ComponentPolicyBuilderImpl implements CompositeBuilder { + + private CompositeBuilder policyAppliesToBuilder = null; + + public CompositePolicyBuilderImpl(ExtensionPointRegistry registry) { + super(registry); + + policyAppliesToBuilder = new PolicyAppliesToBuilderImpl(registry); + } + + public String getID() { + return "org.apache.tuscany.sca.assembly.builder.CompositePolicyBuilder"; + } + + public Composite build(Composite composite, BuilderContext context) throws CompositeBuilderException { + computePolicies(composite, context); + checkPolicies(composite, context); + buildPolicies(composite, context); + return composite; + } + + protected void computePolicies(Composite composite, BuilderContext context) { + Monitor monitor = context.getMonitor(); + monitor.pushContext("Composite: " + composite.getName().toString()); + + try { + resolveAndCheck(composite, context); + + // compute policies recursively + for (Component component : composite.getComponents()) { + monitor.pushContext("Component: " + component.getName()); + + //resolve component level + resolveAndCheck(component, context); + + try { + Implementation implementation = component.getImplementation(); + + for (ComponentService componentService : component.getServices()) { + monitor.pushContext("Service: " + componentService.getName()); + + try { + resolveAndCheck(componentService, context); + + if (componentService.getInterfaceContract() != null) { + resolveAndCheck(componentService.getInterfaceContract().getInterface(), context); + + resolveAndCheck(componentService.getInterfaceContract().getCallbackInterface(), context); + + } + + for (Endpoint ep : componentService.getEndpoints()) { + if (componentService.getInterfaceContract() != null) { + // Inherit from the component.service.interface + inherit(ep, Intent.Type.interaction, true, componentService.getInterfaceContract().getInterface()); + } + + // Inherit from composite/component/service + inherit(ep, Intent.Type.interaction, true, composite, ep.getComponent(), ep.getService()); + + // Inherit from binding + inherit(ep, Intent.Type.interaction, true, ep.getBinding()); + + // Replace profile intents with their required intents + // Replace unqualified intents if there is a qualified intent in the list + // Replace qualifiable intents with the default qualied intent + resolveAndNormalize(ep, context); + + // Remove the intents whose @contraints do not include the current element + removeConstrainedIntents(ep, context); + + // check that all intents are resolved + checkIntentsResolved(ep, context); + + // check that the resulting endpoint has no mutually exclusive intents + checkMutualExclusion(ep, context); + } + } finally { + monitor.popContext(); + } + } + + for (ComponentReference componentReference : component.getReferences()) { + monitor.pushContext("Reference: " + componentReference.getName().toString()); + + try { + + if (componentReference.getInterfaceContract() != null) { + resolveAndCheck(componentReference.getInterfaceContract().getInterface(), context); + + resolveAndCheck(componentReference.getInterfaceContract().getCallbackInterface(), + context); + } + + for (EndpointReference epr : componentReference.getEndpointReferences()) { + + // Inherit from the component.reference.interface + if (componentReference.getInterfaceContract() != null) { + inherit(epr, Intent.Type.interaction, true, componentReference.getInterfaceContract().getInterface()); + } + + // Inherit from composite/component/reference + inherit(epr, Intent.Type.interaction, true, composite, epr.getComponent(), epr.getReference()); + + // Inherit from binding + inherit(epr, Intent.Type.interaction, true, epr.getBinding()); + + // Replace profile intents with their required intents + // Replace unqualified intents if there is a qualified intent in the list + // Replace qualifiable intents with the default qualified intent + resolveAndNormalize(epr, context); + + // Remove the intents whose @contraints do not include the current element + removeConstrainedIntents(epr, context); + + // check that all intents are resolved + checkIntentsResolved(epr, context); + + // check that the resulting endpoint reference has no mutually exclusive intents + checkMutualExclusion(epr, context); + } + } finally { + monitor.popContext(); + } + } + + if (implementation instanceof Composite) { + inherit(implementation, Intent.Type.implementation, true, component, composite); + checkIntentsResolved(implementation, context); + computePolicies((Composite)implementation, context); + } else { + resolveAndCheck(implementation, context); + if (implementation != null) { + inherit(implementation, Intent.Type.implementation, true, component, composite); + + // Remove the intents whose @contraints do not include the current element + removeConstrainedIntents(implementation, context); + + // check that all intents are resolved + checkIntentsResolved(implementation, context); + } + } + } finally { + monitor.popContext(); + } + } + } finally { + monitor.popContext(); + } + } + + /** + * This is mainly about removing policies that don't "applyTo" the element where + * they have ended up after all the attachment and inheritance processing + * + * @param composite + * @param context + */ + protected void checkPolicies(Composite composite, BuilderContext context) throws CompositeBuilderException{ + policyAppliesToBuilder.build(composite, context); + } + + protected void buildPolicies(Composite composite, BuilderContext context) { + + // build policies recursively + for (Component component : composite.getComponents()) { + Implementation implementation = component.getImplementation(); + if (implementation instanceof Composite) { + buildPolicies((Composite)implementation, context); + } + } + + for (Component component : composite.getComponents()) { + + for (ComponentService componentService : component.getServices()) { + for (Endpoint ep : componentService.getEndpoints()) { + Set<QName> policyNames = getPolicyNames(ep); + + // check that only one policy language is present in the endpoint's policy sets + if (policyNames.size() > 1){ + error(context.getMonitor(), + "MultiplePolicyLanguagesInEP", + this, + ep.toString(), + policyNames.toString()); + } else { + for (QName policyType : policyNames) { + PolicyBuilder builder = builders.getPolicyBuilder(policyType); + if (builder != null) { + builder.build(ep, context); + } + } + } + } + } + + for (ComponentReference componentReference : component.getReferences()) { + for (EndpointReference epr : componentReference.getEndpointReferences()) { + Set<QName> policyNames = getPolicyNames(epr); + + // check that only one policy language is present in the endpoint references's policy sets + if (policyNames.size() > 1){ + error(context.getMonitor(), + "MultiplePolicyLanguagesInEPR", + this, + epr.toString(), + policyNames.toString()); + } else { + for (QName policyType : policyNames) { + PolicyBuilder builder = builders.getPolicyBuilder(policyType); + if (builder != null) { + builder.build(epr, context); + } + } + } + } + } + + Implementation implementation = component.getImplementation(); + if (implementation != null) { + Set<QName> policyNames = getPolicyNames(implementation); + + // check that only one policy language is present in the implementations's policy sets + if (policyNames.size() > 1){ + error(context.getMonitor(), + "MultiplePolicyLanguagesInImplementation", + this, + component.toString(), + policyNames.toString()); + } else { + for (QName policyType : policyNames) { + PolicyBuilder builder = builders.getPolicyBuilder(policyType); + if (builder != null) { + builder.build(component, implementation, context); + } + } + } + } + } + } +} diff --git a/sca-java-2.x/tags/2.0-M5.1-RC1/modules/builder/src/main/java/org/apache/tuscany/sca/builder/impl/CompositeWireApplierImpl.java b/sca-java-2.x/tags/2.0-M5.1-RC1/modules/builder/src/main/java/org/apache/tuscany/sca/builder/impl/CompositeWireApplierImpl.java new file mode 100644 index 0000000000..3167b8cdb6 --- /dev/null +++ b/sca-java-2.x/tags/2.0-M5.1-RC1/modules/builder/src/main/java/org/apache/tuscany/sca/builder/impl/CompositeWireApplierImpl.java @@ -0,0 +1,212 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.apache.tuscany.sca.builder.impl; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import org.apache.tuscany.sca.assembly.AssemblyFactory; +import org.apache.tuscany.sca.assembly.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.Implementation; +import org.apache.tuscany.sca.assembly.Reference; +import org.apache.tuscany.sca.assembly.Service; +import org.apache.tuscany.sca.assembly.Wire; +import org.apache.tuscany.sca.assembly.builder.BuilderContext; +import org.apache.tuscany.sca.assembly.builder.CompositeBuilder; +import org.apache.tuscany.sca.assembly.builder.CompositeBuilderException; +import org.apache.tuscany.sca.assembly.builder.Messages; +import org.apache.tuscany.sca.core.ExtensionPointRegistry; +import org.apache.tuscany.sca.core.FactoryExtensionPoint; +import org.apache.tuscany.sca.core.UtilityExtensionPoint; +import org.apache.tuscany.sca.interfacedef.InterfaceContractMapper; +import org.apache.tuscany.sca.monitor.Monitor; + +/** + * Apply any <wire/> elements in the composites by creating suitable reference targets + * + * @version $Rev$ $Date$ + */ +public class CompositeWireApplierImpl implements CompositeBuilder { + + private InterfaceContractMapper interfaceContractMapper; + + + public CompositeWireApplierImpl(ExtensionPointRegistry registry) { + UtilityExtensionPoint utilities = registry.getExtensionPoint(UtilityExtensionPoint.class); + interfaceContractMapper = utilities.getUtility(InterfaceContractMapper.class); + } + + public String getID() { + return "org.apache.tuscany.sca.assembly.builder.CompositeWireApplierImpl"; + } + + public Composite build(Composite composite, BuilderContext context) + throws CompositeBuilderException { + + processComposite(composite, context); + + return composite; + } + + private void processComposite(Composite composite, BuilderContext context){ + // Index components, services and references + Map<String, Component> components = new HashMap<String, Component>(); + Map<String, ComponentService> componentServices = new HashMap<String, ComponentService>(); + Map<String, ComponentReference> componentReferences = new HashMap<String, ComponentReference>(); + indexComponentsServicesAndReferences(composite, components, componentServices, componentReferences); + + // Connect component references as described in wires + connectWires(composite, componentServices, componentReferences, context.getMonitor()); + + for (Component component : composite.getComponents()) { + // recurse for composite implementations + Implementation implementation = component.getImplementation(); + if (implementation instanceof Composite) { + processComposite((Composite)implementation, context); + } + } + } + + protected void indexComponentsServicesAndReferences(Composite composite, + Map<String, Component> components, + Map<String, ComponentService> componentServices, + Map<String, ComponentReference> componentReferences) { + + for (Component component : composite.getComponents()) { + + // Index components by name + components.put(component.getName(), component); + + ComponentService nonCallbackService = null; + int nonCallbackServices = 0; + for (ComponentService componentService : component.getServices()) { + + // Index component services by component name / service name + String uri = component.getName() + '/' + + componentService.getName(); + componentServices.put(uri, componentService); + + // count how many non-callback services there are + // if there is only one the component name also acts as the + // service name + if (!componentService.isForCallback()) { + // Check how many non callback non-promoted services we have + if (nonCallbackServices == 0) { + nonCallbackService = componentService; + } + nonCallbackServices++; + } + } + + if (nonCallbackServices == 1) { + // If we have a single non callback service, index it by + // component name as well + componentServices.put(component.getName(), nonCallbackService); + } + + // Index references by component name / reference name + for (ComponentReference componentReference : component + .getReferences()) { + String uri = component.getName() + '/' + + componentReference.getName(); + componentReferences.put(uri, componentReference); + } + } + } + + /** + * Resolve wires and connect the sources to their targets + * + * @param composite + * @param componentServices + * @param componentReferences + * @param problems + */ + private void connectWires(Composite composite, + Map<String, ComponentService> componentServices, + Map<String, ComponentReference> componentReferences, + Monitor monitor) { + + // For each wire, resolve the source reference, the target service, and + // add it to the list of targets of the reference + List<Wire> wires = composite.getWires(); + for (int i = 0, n = wires.size(); i < n; i++) { + Wire wire = wires.get(i); + + ComponentReference resolvedReference; + ComponentService resolvedService; + + // Resolve the source reference + ComponentReference source = wire.getSource(); + if (source != null && source.isUnresolved()) { + resolvedReference = componentReferences.get(source.getName()); + if (resolvedReference != null) { + wire.setSource(resolvedReference); + } else { + Monitor.warning(monitor, this, Messages.ASSEMBLY_VALIDATION, "WireSourceNotFound", source + .getName()); + } + } else { + resolvedReference = wire.getSource(); + } + + // Resolve the target service + ComponentService target = wire.getTarget(); + if (target != null && target.isUnresolved()) { + resolvedService = componentServices.get(target.getName()); + if (resolvedService != null) { + wire.setTarget(target); + } else { + Monitor.warning(monitor, this, Messages.ASSEMBLY_VALIDATION, "WireTargetNotFound", target + .getName()); + } + } else { + resolvedService = wire.getTarget(); + } + + // Add the target service to the list of targets of the + // reference + if (resolvedReference != null && resolvedService != null) { + // Check that the target component service provides + // a superset of + // the component reference interface + if (resolvedReference.getInterfaceContract() == null || interfaceContractMapper + .isCompatibleSubset(resolvedReference.getInterfaceContract(), resolvedService.getInterfaceContract())) { + + //resolvedReference.getTargets().add(resolvedService); + if (wire.isReplace()) { + resolvedReference.getTargets().clear(); + } + resolvedReference.getTargets().add(wire.getTarget()); + } else { + Monitor.warning(monitor, this, Messages.ASSEMBLY_VALIDATION, "WireIncompatibleInterface", source + .getName(), target.getName()); + } + } + } + + // Clear the list of wires + composite.getWires().clear(); + } +} diff --git a/sca-java-2.x/tags/2.0-M5.1-RC1/modules/builder/src/main/java/org/apache/tuscany/sca/builder/impl/EndpointBuilderImpl.java b/sca-java-2.x/tags/2.0-M5.1-RC1/modules/builder/src/main/java/org/apache/tuscany/sca/builder/impl/EndpointBuilderImpl.java new file mode 100644 index 0000000000..6c44d2e9e0 --- /dev/null +++ b/sca-java-2.x/tags/2.0-M5.1-RC1/modules/builder/src/main/java/org/apache/tuscany/sca/builder/impl/EndpointBuilderImpl.java @@ -0,0 +1,135 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.apache.tuscany.sca.builder.impl; + +import java.util.List; + +import org.apache.tuscany.sca.assembly.AssemblyFactory; +import org.apache.tuscany.sca.assembly.Binding; +import org.apache.tuscany.sca.assembly.Component; +import org.apache.tuscany.sca.assembly.ComponentService; +import org.apache.tuscany.sca.assembly.Composite; +import org.apache.tuscany.sca.assembly.Endpoint; +import org.apache.tuscany.sca.assembly.Implementation; +import org.apache.tuscany.sca.assembly.builder.BuilderContext; +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.interfacedef.Operation; +import org.apache.tuscany.sca.monitor.Monitor; + +/** + * creates endpoint models for component services. + */ +public class EndpointBuilderImpl implements CompositeBuilder { + private static final String BUILDER_VALIDATION_BUNDLE = "org.apache.tuscany.sca.builder.builder-validation-messages"; + + private AssemblyFactory assemblyFactory; + + public EndpointBuilderImpl(ExtensionPointRegistry registry) { + FactoryExtensionPoint modelFactories = registry.getExtensionPoint(FactoryExtensionPoint.class); + this.assemblyFactory = modelFactories.getFactory(AssemblyFactory.class); + } + + /** + * Create endpoint models for all component services. + * + * @param composite - the top-level composite to build the models for + * @param definitions + * @param monitor - a Monitor for logging errors + */ + public Composite build(Composite composite, BuilderContext context) throws CompositeBuilderException { + + processComponentServices(composite, context); + return composite; + + } + + private void processComponentServices(Composite composite, BuilderContext context) { + + Monitor monitor = context.getMonitor(); + + for (Component component : composite.getComponents()) { + + try { + monitor.pushContext("Component: " + component.getName().toString()); + + // recurse for composite implementations + Implementation implementation = component.getImplementation(); + if (implementation instanceof Composite) { + processComponentServices((Composite)implementation, context); + } + + // create an endpoint for each component service binding + for (ComponentService service : component.getServices()) { + try { + monitor.pushContext("Service: " + service.getName()); + + //verify JAX-WS async assertions as in JavaCAA section 11.1 + List<Operation> asyncOperations = null; + try { + asyncOperations = (List<Operation>) service.getInterfaceContract().getInterface().getAttributes().get("JAXWS-ASYNC-OPERATIONS"); + }catch(Exception e) { + //ignore + } + + if(asyncOperations != null) { + if( ! asyncOperations.isEmpty()) { + + //error JCA100006 + + //FIXME create a java validation message resource bundle + Monitor.error(monitor, + this, + BUILDER_VALIDATION_BUNDLE, + "JaxWSClientAsyncMethodsNotAllowed", + service, + service.getName()); + } + } + + // We maintain all endpoints at the right level now + // but endpoints for promoting services must point down + // to the services they promote. This is not actually done + // until the wire is created though in order that the + // uri is calculated correctly + 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 + } finally { + monitor.popContext(); + } + } + } finally { + monitor.popContext(); + } + } + } + + public String getID() { + return "org.apache.tuscany.sca.assembly.builder.EndpointBuilder"; + } +} diff --git a/sca-java-2.x/tags/2.0-M5.1-RC1/modules/builder/src/main/java/org/apache/tuscany/sca/builder/impl/EndpointReferenceBuilderImpl.java b/sca-java-2.x/tags/2.0-M5.1-RC1/modules/builder/src/main/java/org/apache/tuscany/sca/builder/impl/EndpointReferenceBuilderImpl.java new file mode 100644 index 0000000000..9938a054c5 --- /dev/null +++ b/sca-java-2.x/tags/2.0-M5.1-RC1/modules/builder/src/main/java/org/apache/tuscany/sca/builder/impl/EndpointReferenceBuilderImpl.java @@ -0,0 +1,836 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.apache.tuscany.sca.builder.impl; + +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import java.util.Set; +import java.util.logging.Logger; + +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.BuilderContext; +import org.apache.tuscany.sca.assembly.builder.CompositeBuilderException; +import org.apache.tuscany.sca.assembly.builder.Messages; +import org.apache.tuscany.sca.core.ExtensionPointRegistry; +import org.apache.tuscany.sca.core.FactoryExtensionPoint; +import org.apache.tuscany.sca.core.UtilityExtensionPoint; +import org.apache.tuscany.sca.interfacedef.InterfaceContractMapper; +import org.apache.tuscany.sca.monitor.Monitor; +import org.apache.tuscany.sca.policy.Intent; +import org.oasisopen.sca.ServiceRuntimeException; + +/** + * Creates endpoint reference models. + */ +public class EndpointReferenceBuilderImpl { + private final Logger logger = Logger.getLogger(EndpointReferenceBuilderImpl.class.getName()); + + private AssemblyFactory assemblyFactory; + private InterfaceContractMapper interfaceContractMapper; + + // causes dependency between builders and core + //private EndpointReferenceBinder endpointReferenceBinder; + + public EndpointReferenceBuilderImpl(ExtensionPointRegistry registry) { + UtilityExtensionPoint utilities = registry.getExtensionPoint(UtilityExtensionPoint.class); + interfaceContractMapper = utilities.getUtility(InterfaceContractMapper.class); + + FactoryExtensionPoint modelFactories = registry.getExtensionPoint(FactoryExtensionPoint.class); + assemblyFactory = modelFactories.getFactory(AssemblyFactory.class); + + // causes dependency between builders and core + //endpointReferenceBinder = registry.getExtensionPoint(EndpointReferenceBinder.class); + } + + /** + * Create endpoint references for all component references. + * + * @param composite + */ + public Composite build(Composite composite, BuilderContext context) + throws CompositeBuilderException { + + // create endpoint references for each reference + createEndpointReferences(composite, context); + + // validate component references + // left until this stage, after all endpoints have been created, + // to to catch more complex cases caused by reference promotion + validateComponentReferences(composite, context.getMonitor()); + + // TODO - move the following buld time matching code + // to somewhere else because of + // the dependency between builders and core + + // create temporary local registry for all available local endpoints + //EndpointRegistry registry = new EndpointRegistryImpl(); + + // populate the registry with all the endpoints that are present in the model + //populateLocalRegistry(composite, registry, context); + + // match all local services against the endpoint references + // we've just created + //matchEndpointReferences(composite, registry, context); + + return composite; + } + + /** + * Iterate down through the composites creating end point references for + * all component references + * + * @param composite + * @param context + */ + private void createEndpointReferences(Composite composite, BuilderContext context){ + + context.getMonitor().pushContext("Composite: " + composite.getName().toString()); + + try { + for (Component component : composite.getComponents()) { + context.getMonitor().pushContext("Component: " + component.getName()); + + try { + // recurse for composite implementations + Implementation implementation = component.getImplementation(); + if (implementation instanceof Composite) { + createEndpointReferences((Composite)implementation, context); + } + + for (ComponentReference reference : component.getReferences()) { + processComponentReference(composite, + component, + reference, + context); + + // 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 + + // push down endpoint references into the leaf component references + // in the case where this component reference promotes a reference from + // a composite implementation + pushDownEndpointReferences(composite, + component, + reference, + context.getMonitor()); + + } + + // Validate that references are wired or promoted, according + // to their multiplicity. This validates as we go and catches cases + // where a reference has been configured directly incorrectly with its + // immediate multiplicity setting. We re-run this validation again later + // to catch to more complex cases where reference promotion causes + // multiplicity errors. + validateReferenceMultiplicity(composite, component, context.getMonitor()); + + } finally { + context.getMonitor().popContext(); + } + } + } finally { + context.getMonitor().popContext(); + } + } + + /** + * Create endpoint references for a component references. Endpoint references can be + * implied by refrence targets, autowire or binding settings + * + * @param composite + * @param component + * @param reference + * @param context + */ + private void processComponentReference(Composite composite, + Component component, + ComponentReference reference, + BuilderContext context){ + + context.getMonitor().pushContext("Reference: " + reference.getName()); + + try { + // Get reference targets + List<ComponentService> refTargets = getReferenceTargets(reference); + + // This autowire processing really needs to move to the matching + // algorithm but dependency problems means it has to stay here for now + if (Boolean.TRUE.equals(reference.getAutowire()) && 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.isCompatibleSubset(reference.getInterfaceContract(), + targetComponentService.getInterfaceContract())) { + + if (intentsMatch(reference.getRequiredIntents(), targetComponentService.getRequiredIntents())) { + EndpointReference endpointRef = createEndpointRef(component, reference, false); + endpointRef.setTargetEndpoint(createEndpoint(targetComponent, targetComponentService, true)); + endpointRef.setStatus(EndpointReference.Status.WIRED_TARGET_NOT_FOUND); + 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(context.getMonitor(), + this, + Messages.ASSEMBLY_VALIDATION, + "NoComponentReferenceTarget", + reference.getName()); + } + } + + setSingleAutoWireTarget(reference); + + // as this is the autowire case we ignore any further configuration + return; + } + + // check to see if explicit reference targets have been specified + 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(context.getMonitor(), + this, + Messages.ASSEMBLY_VALIDATION, + "ReferenceEndPointMixWithTarget", + composite.getName().toString(), + component.getName(), + reference.getName()); + } + + // create endpoint references for targets + for (ComponentService target : refTargets) { + + EndpointReference endpointRef = createEndpointRef(component, reference, true); + endpointRef.setTargetEndpoint(createEndpoint(component, target.getName())); + endpointRef.setStatus(EndpointReference.Status.WIRED_TARGET_NOT_FOUND); + reference.getEndpointReferences().add(endpointRef); + + // There is a special case where the user has defined policies on a + // non-targetted, i.e. no URI, binding.sca in order to control the + // intended QoS of the wire when matching takes place. If any other + // bindings are specified then the test later on will complain about + // mixing targts with bindings + if (reference.getBindings().size() == 1){ + Binding binding = reference.getBindings().get(0); + if ((binding instanceof SCABinding) && (binding.getURI() == null)){ + endpointRef.setBinding(binding); + } + } + } + } + + // if no endpoints have been 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.Status.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.Status.RESOLVED_BINDING); + } + +// if (reference.getCallbackService() != null) { +// Endpoint callbackEndpoint = +// createEndpoint(component, reference.getCallbackService(), false); +// endpointRef.setCallbackEndpoint(callbackEndpoint); +// } + + reference.getEndpointReferences().add(endpointRef); + continue; + } // end if + + // The user has put something in the binding uri but we don't know if it's + // a real URI or a target name. We can't tell until we have access to the + // fully populated registry at run time. The "createComponent()" call here + // will do its best to parse out component/service/binding elements assuming + // that the getSCATargetParts detects that there are three "/" separated + // parts in the uri. + EndpointReference endpointRef = createEndpointRef(component, reference, binding, null, false); + Endpoint endpoint = null; + try { + getSCATargetParts(uri); + + // the target uri might be an SCA target so create an endpoint + // so that the binder can test it against the fully populated + // registry + endpoint = createEndpoint(component, uri); + endpointRef.setStatus(EndpointReference.Status.WIRED_TARGET_IN_BINDING_URI); + } catch (Exception ex) { + // the target string definitely isn't an SCA target string + // so we can assume here that the user has configured a + // resolved binding + endpoint = createEndpoint(false); + endpoint.setURI(uri); + endpoint.setBinding(binding); + endpointRef.setStatus(EndpointReference.Status.RESOLVED_BINDING); + } + + endpointRef.setTargetEndpoint(endpoint); +// if (reference.getCallbackService() != null) { +// Endpoint callbackEndpoint = +// createEndpoint(component, reference.getCallbackService(), false); +// endpointRef.setCallbackEndpoint(callbackEndpoint); +// } + reference.getEndpointReferences().add(endpointRef); + } + } + } finally { + context.getMonitor().popContext(); + } + } + + private boolean intentsMatch(List<Intent> referenceIntents, List<Intent> serviceIntents) { + Set<Intent> referenceIntentSet = new HashSet<Intent>(referenceIntents); + Set<Intent> serviceIntentSet = new HashSet<Intent>(serviceIntents); + return referenceIntentSet.equals(serviceIntentSet); + } + + /** + * The validate stage is separate from the process stage as endpoint references are + * pushed down the hierarchy. We don't know the full set of endpoint references until + * all processing is complete. Hence we can't validate as we go + * + * @param composite + * @param monitor + */ + private void validateComponentReferences(Composite composite, Monitor monitor) { + + monitor.pushContext("Composite: " + composite.getName().toString()); + try { + // 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) { + validateComponentReferences((Composite)implementation, monitor); + } + // Validate that references are wired or promoted, according + // to their multiplicity + validateReferenceMultiplicity(composite, component, monitor); + + } finally { + monitor.popContext(); + } + } + } finally { + monitor.popContext(); + } + } + + /** + * Reference targets have to be resolved in the context in which they are + * defined so they can't be pushed down the hierarchy during the static build. + * So we wait until we have calculated the endpoint references before pushing them + * down. Muliplicity errors will be caught by the multiplicity validation check that + * comes next + * + * @param composite + * @param component + * @param reference + * @param monitor + */ + private void pushDownEndpointReferences(Composite composite, + Component component, + ComponentReference componentReference, + Monitor monitor) { + Reference reference = componentReference.getReference(); + + if (reference instanceof CompositeReference) { + List<ComponentReference> leafComponentReferences = getPromotedComponentReferences((CompositeReference)reference); + + // for each leaf component reference copy in the endpoint references for this + // higher level (promoting) reference + // TODO - the elements are inserted starting at 0 here because the code allows references multiplicity + // validation constraints to be broken if the reference is autowire. At runtime the + // first one is chosen if max multiplicity is 1. We have an OSOA test that assumes that + // promoted references overwrite leaf references. This insert gives the same effect in the + // autowire case. We need to think about if there is a more correct answer. + for (ComponentReference leafRef : leafComponentReferences){ + int insertLocation = 0; + for (EndpointReference epr : componentReference.getEndpointReferences()){ + // copy the epr + EndpointReference eprCopy = copyHigherReference(epr, leafRef); + leafRef.getEndpointReferences().add(insertLocation, eprCopy); + insertLocation++; + } + } + } + + // TODO - what to do about callbacks in the reference promotion case + } + + /** + * Follow a reference promotion chain down to the innermost (non composite) + * component references. + * + * @param compositeReference + * @return + */ + private List<ComponentReference> getPromotedComponentReferences(CompositeReference compositeReference) { + List<ComponentReference> componentReferences = new ArrayList<ComponentReference>(); + collectPromotedComponentReferences(compositeReference, componentReferences); + return componentReferences; + } + + /** + * Follow a reference promotion chain down to the innermost (non composite) + * component references. + * + * @param compositeReference + * @param componentReferences + * @return + */ + private void collectPromotedComponentReferences(CompositeReference compositeReference, + List<ComponentReference> componentReferences) { + for (ComponentReference componentReference : compositeReference.getPromotedReferences()) { + Reference reference = componentReference.getReference(); + if (reference instanceof CompositeReference) { + + // Continue to follow the reference promotion chain + collectPromotedComponentReferences((CompositeReference)reference, componentReferences); + + } else if (reference != null) { + + // Found a non-composite reference + componentReferences.add(componentReference); + } + } + } + + /** + * Copy a higher level EndpointReference down to a lower level reference which it promotes + * @param epRef - the endpoint reference + * @param promotedReference - the promoted reference + * @return - a copy of the EndpointReference with data merged from the promoted reference + */ + private EndpointReference copyHigherReference(EndpointReference epRef, ComponentReference promotedReference) { + EndpointReference epRefClone = null; + try { + epRefClone = (EndpointReference)epRef.clone(); + } catch (Exception e) { + throw new ServiceRuntimeException(e); + } // end try + // Copy across details of the inner reference + //ComponentReference ref = epRefClone.getReference(); + //FIXME + epRefClone.setReference(promotedReference); + return epRefClone; + } + + /** + * For all references in a component check that multiplicity is correct + * + * @param composite + * @param component + * @param monitor + */ + private void validateReferenceMultiplicity(Composite composite, Component component, Monitor monitor) { + for (ComponentReference componentReference : component.getReferences()) { + if (!validateMultiplicity(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, + Messages.ASSEMBLY_VALIDATION, + "ReferenceWithoutTargets", + composite.getName().toString(), + componentReference.getName()); + } + } else { + // no error if reference is autowire and more targets + // than multiplicity have been found + if (Boolean.TRUE.equals(componentReference.getAutowire())) { + break; + } + + Monitor.error(monitor, + this, + Messages.ASSEMBLY_VALIDATION, + "TooManyReferenceTargets", + componentReference.getName()); + } + } + } + + } + + /** + * For a single component reference check that multiplicity is correct + * + * @param multiplicity + * @param endpointReferences + * @return + */ + private boolean validateMultiplicity(Multiplicity multiplicity, List<EndpointReference> endpointReferences) { + + // In some tests multiplicity is not set + if (multiplicity == null) { + return true; + } + + // Count targets + int count = endpointReferences.size(); + + switch (multiplicity) { + case ZERO_N: + break; + case ZERO_ONE: + if (count > 1) { + return false; + } + break; + case ONE_ONE: + if (count != 1) { + return false; + } + break; + case ONE_N: + if (count < 1) { + return false; + } + break; + } + return true; + } + + /** + * 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 + + /** + * 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); + + // [rfeng] Populate the callback endpoints + if (reference.getCallbackService() != null) { + List<Endpoint> callbackEndpoints = reference.getCallbackService().getEndpoints(); + if (!callbackEndpoints.isEmpty()) { + // [rfeng] FIXME: how to select the callback endpoints? + endpointRef.setCallbackEndpoint(callbackEndpoints.get(0)); + } + } + return endpointRef; + } // end method createEndpointRef + + /** + * 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 + + + /** + * Separates a target name into component/service/binding parts. Throws an exceptions + * if the number of parts <1 or > 3 + * @param targetName + * @return String[] the recovered target parts + */ + private String[] getSCATargetParts(String targetName){ + String[] parts = targetName.split("/"); + if (parts.length < 1 || parts.length > 3) { + throw new IllegalArgumentException("Invalid target URI: " + targetName); + } + return parts; + } + + /** + * 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 = getSCATargetParts(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 + + /** + * 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 + + /** + * 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; + } + } + } + } + } + + //========================================================================= + // methods below related to build time matching which is currently disabled +/* + private void populateLocalRegistry(Composite composite, EndpointRegistry registry, BuilderContext context){ + for (Component component : composite.getComponents()) { + // recurse for composite implementations + Implementation implementation = component.getImplementation(); + if (implementation instanceof Composite) { + populateLocalRegistry((Composite)implementation, registry, context); + } + + for (ComponentService service : component.getServices()) { + for (Endpoint endpoint : service.getEndpoints()){ + registry.addEndpoint(endpoint); + } + } + + + for (ComponentReference reference : component.getReferences()) { + for (EndpointReference epr : reference.getEndpointReferences()){ + registry.addEndpointReference(epr); + } + } + + // remove all autowire place holders so they don't cause wires to be created + // have to pass in reference as we don't have access to the registry in + // the builders + for (EndpointReference epr : registry.getEndpointReferences()){ + if (epr.getStatus() == EndpointReference.Status.AUTOWIRE_PLACEHOLDER){ + epr.getReference().getEndpointReferences().remove(epr); + } + } + } + } + + private void matchEndpointReferences(Composite composite, EndpointRegistry registry, BuilderContext context){ + + // look at all the endpoint references and try to match them to + // endpoints + for (EndpointReference endpointReference : registry.getEndpointReferences()){ + endpointReferenceBinder.bindBuildTime(registry, endpointReference); + } + } +*/ + + +}
\ No newline at end of file diff --git a/sca-java-2.x/tags/2.0-M5.1-RC1/modules/builder/src/main/java/org/apache/tuscany/sca/builder/impl/IntentValidator.java b/sca-java-2.x/tags/2.0-M5.1-RC1/modules/builder/src/main/java/org/apache/tuscany/sca/builder/impl/IntentValidator.java new file mode 100644 index 0000000000..b2f7a4ceed --- /dev/null +++ b/sca-java-2.x/tags/2.0-M5.1-RC1/modules/builder/src/main/java/org/apache/tuscany/sca/builder/impl/IntentValidator.java @@ -0,0 +1,139 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.apache.tuscany.sca.builder.impl; + +import java.util.List; + +import javax.xml.namespace.QName; + +import org.apache.tuscany.sca.assembly.Component; +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.builder.BuilderContext; +import org.apache.tuscany.sca.assembly.builder.Messages; +import org.apache.tuscany.sca.assembly.builder.PolicyBuilder; +import org.apache.tuscany.sca.core.ExtensionPointRegistry; +import org.apache.tuscany.sca.monitor.Monitor; +import org.apache.tuscany.sca.policy.Intent; +import org.apache.tuscany.sca.policy.PolicySubject; + +/** + * Intent Validator + */ +public class IntentValidator implements PolicyBuilder { + + /** + * Defaut constructor + * @param registry Extension Registry + */ + public IntentValidator(ExtensionPointRegistry registry) { + super(); + } + + public boolean build(Endpoint endpoint, BuilderContext context) { + return checkMutualExclusion(endpoint, context); + } + + public boolean build(EndpointReference endpointReference, BuilderContext context) { + boolean ok = checkMutualExclusion(endpointReference, context); + if(!ok) { + return false; + } + + Endpoint endpoint = endpointReference.getTargetEndpoint(); + if (endpoint == null) { + return true; + } + ok = checkMutualExclusion(endpointReference, endpoint, context); + List<Intent> intentList1 = endpointReference.getRequiredIntents(); + List<Intent> intentList2 = endpoint.getRequiredIntents(); + return ok; + } + + public boolean build(Component component, Implementation implementation, BuilderContext context) { + return true; + } + + public boolean build(EndpointReference endpointReference, Endpoint endpoint, BuilderContext context) { + return true; + } + + public QName getPolicyType() { + return null; + } + + public List<QName> getSupportedBindings() { + return null; + } + + /** + * Check if two policy subjects requires multually exclusive intents + * @param subject1 + * @param subject2 + * @param monitor + * @return + */ + private boolean checkMutualExclusion(PolicySubject subject1, PolicySubject subject2, BuilderContext context) { + if (subject1 == subject2 || subject1 == null || subject2 == null) { + return false; + } + for (Intent i1 : subject1.getRequiredIntents()) { + for (Intent i2 : subject2.getRequiredIntents()) { + if (i1.getExcludedIntents().contains(i2) || i2.getExcludedIntents().contains(i1)) { + Monitor.error(context.getMonitor(), + this, + Messages.ASSEMBLY_VALIDATION, + "MutuallyExclusiveIntents", + new Object[] {subject1, subject2}, + i1, + i2); + return true; + } + } + } + return false; + } + + private boolean checkMutualExclusion(PolicySubject subject, BuilderContext context) { + if (subject == null) { + return false; + } + List<Intent> intents = subject.getRequiredIntents(); + int size = intents.size(); + for (int i = 0; i < size; i++) { + for (int j = i + 1; j < size; j++) { + Intent i1 = intents.get(i); + Intent i2 = intents.get(j); + if (i1 != i2 && i1.getExcludedIntents().contains(i2) || i2.getExcludedIntents().contains(i1)) { + Monitor.error(context.getMonitor(), + this, + Messages.ASSEMBLY_VALIDATION, + "MutuallyExclusiveIntents", + subject, + i1, + i2); + return true; + } + } + } + return false; + } +} diff --git a/sca-java-2.x/tags/2.0-M5.1-RC1/modules/builder/src/main/java/org/apache/tuscany/sca/builder/impl/ModelBuilderImpl.java b/sca-java-2.x/tags/2.0-M5.1-RC1/modules/builder/src/main/java/org/apache/tuscany/sca/builder/impl/ModelBuilderImpl.java new file mode 100644 index 0000000000..89fdc09ae1 --- /dev/null +++ b/sca-java-2.x/tags/2.0-M5.1-RC1/modules/builder/src/main/java/org/apache/tuscany/sca/builder/impl/ModelBuilderImpl.java @@ -0,0 +1,189 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.tuscany.sca.builder.impl; + +import java.io.ByteArrayOutputStream; + +import javax.xml.stream.XMLOutputFactory; + +import org.apache.tuscany.sca.assembly.Component; +import org.apache.tuscany.sca.assembly.Composite; +import org.apache.tuscany.sca.assembly.builder.BuilderContext; +import org.apache.tuscany.sca.assembly.builder.CompositeBuilder; +import org.apache.tuscany.sca.assembly.builder.CompositeBuilderException; +import org.apache.tuscany.sca.contribution.processor.ProcessorContext; +import org.apache.tuscany.sca.contribution.processor.StAXArtifactProcessor; +import org.apache.tuscany.sca.contribution.processor.StAXArtifactProcessorExtensionPoint; +import org.apache.tuscany.sca.core.ExtensionPointRegistry; +import org.apache.tuscany.sca.core.FactoryExtensionPoint; + +public class ModelBuilderImpl implements CompositeBuilder { + private ExtensionPointRegistry registry; + + private CompositeBuilder compositeIncludeBuilder; + private CompositeBuilder compositeCloneBuilder; + private CompositeComponentTypeBuilderImpl compositeComponentTypeBuilder; + private ComponentBuilderImpl componentBuilder; + + private CompositeBuilder structuralURIBuilder; + private BindingURIBuilderImpl bindingURIBuilder; + private ComponentServiceBindingBuilderImpl componentServiceBindingBuilder; + private ComponentReferenceBindingBuilderImpl componentReferenceBindingBuilder; + private CompositeBuilder compositeWireApplier; + private EndpointBuilderImpl endpointBuilder; + private EndpointReferenceBuilderImpl endpointReferenceBuilder; + + private CompositeBuilder policyAttachmentBuilder; + private CompositePolicyBuilderImpl compositePolicyBuilder; + + /** + * Constructs a new composite builder. + * + * @param registry the extension point registry + */ + public ModelBuilderImpl(ExtensionPointRegistry registry) { + this.registry = registry; + + compositeIncludeBuilder = new CompositeIncludeBuilderImpl(); + compositeCloneBuilder = new CompositeCloneBuilderImpl(); + + compositeComponentTypeBuilder = new CompositeComponentTypeBuilderImpl(registry); + componentBuilder = new ComponentBuilderImpl(registry); + + compositeComponentTypeBuilder.setComponentBuilder(componentBuilder); + componentBuilder.setComponentTypeBuilder(compositeComponentTypeBuilder); + + structuralURIBuilder = new StructuralURIBuilderImpl(registry); + bindingURIBuilder = new BindingURIBuilderImpl(registry); + componentServiceBindingBuilder = new ComponentServiceBindingBuilderImpl(registry); + componentReferenceBindingBuilder = new ComponentReferenceBindingBuilderImpl(registry); + compositeWireApplier = new CompositeWireApplierImpl(registry); + endpointBuilder = new EndpointBuilderImpl(registry); + endpointReferenceBuilder = new EndpointReferenceBuilderImpl(registry); + + policyAttachmentBuilder = new PolicyAttachmentBuilderImpl(registry); + compositePolicyBuilder = new CompositePolicyBuilderImpl(registry); + } + + public String getID() { + return "org.apache.tuscany.sca.assembly.builder.CompositeBuilder"; + } + + public Composite build(Composite composite, BuilderContext context) + throws CompositeBuilderException { + try { + // Clone the composites that are included or referenced in implementation.composite + composite = compositeCloneBuilder.build(composite, context); + + // Collect and fuse includes. Copy all of the components + // out of the included composite into the including composite + // and discards the included composite + composite = compositeIncludeBuilder.build(composite, context); + + // Set up the structural URIs for components (services/references/bindings) + // TODO does this need to happen before policy attachment + composite = structuralURIBuilder.build(composite, context); + + // Apply policy external attachment. Happens before the composite type + // is created so that suitable promotion and structural processing is + // applied to the attached policies + // TODO - I don't think this is correct. The policy spec (4.12.1)implies that + // policy attachment happens independently of implementation or + // structural inheritance + composite = policyAttachmentBuilder.build(composite, context); + + // Process the implementation hierarchy by calculating the component type + // for the top level implementation (composite). This has the effect of + // recursively calculating component types and configuring the + // components that depend on them + compositeComponentTypeBuilder.createComponentType(null, composite, context); + + // Calculate the URI associated with service bindings + composite = bindingURIBuilder.build(composite, context); + + // perform any binding specific build processing + composite = componentServiceBindingBuilder.build(composite, context); // binding specific build + composite = componentReferenceBindingBuilder.build(composite, context); // binding specific build + + // calculate which reference targets are implied by the wire elements + // that can appear at the composite level + composite = compositeWireApplier.build(composite, context); + + // compute all the service endpoints + endpointBuilder.build(composite, context); + + // compute all the reference endpoint references + endpointReferenceBuilder.build(composite, context); + + // calculate intents and policy sets across the model hierarchy + // relies on the endpoints and endpoint references having been calculated + composite = compositePolicyBuilder.build(composite, context); + + // For debugging - in success cases + //System.out.println(dumpBuiltComposite(composite)); + + return composite; + } catch (Exception e) { + // For debugging - in failure cases + //System.out.println(dumpBuiltComposite(composite)); + throw new CompositeBuilderException("Exception while building model " + composite.getName(), e); + } + } + + /** + * For debugging the build process + * + * @return a tring version of the built model + */ + public String dumpBuiltComposite(Composite composite) { + + StAXArtifactProcessorExtensionPoint xmlProcessors = + registry.getExtensionPoint(StAXArtifactProcessorExtensionPoint.class); + StAXArtifactProcessor<Composite> compositeProcessor = + xmlProcessors.getProcessor(Composite.class); + + return writeComposite(composite, compositeProcessor); + } + + private String writeComposite(Composite composite, StAXArtifactProcessor<Composite> compositeProcessor){ + ByteArrayOutputStream bos = new ByteArrayOutputStream(); + XMLOutputFactory outputFactory = + registry.getExtensionPoint(FactoryExtensionPoint.class) + .getFactory(XMLOutputFactory.class); + + try { + compositeProcessor.write(composite, outputFactory.createXMLStreamWriter(bos), new ProcessorContext(registry)); + } catch(Exception ex) { + return ex.toString(); + } + + String result = bos.toString(); + + // write out and nested composites + for (Component component : composite.getComponents()) { + if (component.getImplementation() instanceof Composite) { + result += "\n<!-- XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX -->\n" + + writeComposite((Composite)component.getImplementation(), + compositeProcessor); + } + } + + return result; + } +} diff --git a/sca-java-2.x/tags/2.0-M5.1-RC1/modules/builder/src/main/java/org/apache/tuscany/sca/builder/impl/PolicyAppliesToBuilderImpl.java b/sca-java-2.x/tags/2.0-M5.1-RC1/modules/builder/src/main/java/org/apache/tuscany/sca/builder/impl/PolicyAppliesToBuilderImpl.java new file mode 100644 index 0000000000..2417940b1c --- /dev/null +++ b/sca-java-2.x/tags/2.0-M5.1-RC1/modules/builder/src/main/java/org/apache/tuscany/sca/builder/impl/PolicyAppliesToBuilderImpl.java @@ -0,0 +1,171 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.apache.tuscany.sca.builder.impl; + + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import javax.xml.xpath.XPathConstants; +import javax.xml.xpath.XPathExpression; + +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.Endpoint; +import org.apache.tuscany.sca.assembly.EndpointReference; +import org.apache.tuscany.sca.assembly.Implementation; +import org.apache.tuscany.sca.assembly.builder.BuilderContext; +import org.apache.tuscany.sca.assembly.builder.CompositeBuilderException; + +import org.apache.tuscany.sca.core.ExtensionPointRegistry; +import org.apache.tuscany.sca.policy.PolicySet; +import org.apache.tuscany.sca.policy.PolicySubject; +import org.w3c.dom.Document; +import org.w3c.dom.Node; +import org.w3c.dom.NodeList; + +/** + * A builder that checks that policy sets apply to the elements to which they are attached. + * Any that don't are removed. It first creates a DOM model for the composite so that the xpath + * expression can be evaluated. For each element that holds a policy set is calculates the + * appliesTo nodes and checks that the current element is in the set. If not the policySet is + * removed from the element + * + * @version $Rev$ $Date$ + */ +public class PolicyAppliesToBuilderImpl extends PolicyAttachmentBuilderImpl { + + public PolicyAppliesToBuilderImpl(ExtensionPointRegistry registry) { + super(registry); + } + + public String getID() { + return "org.apache.tuscany.sca.policy.builder.PolicyAppliesToBuilder"; + } + + public Composite build(Composite composite, BuilderContext context) + throws CompositeBuilderException { + try { + // create a DOM for the Domain Composite Infoset + Document document = saveAsDOM(composite); + + // create a cache of evaluated node against each policy set so we don't + // have to keep evaluating policy sets that appear in multiple places + Map<PolicySet, List<PolicySubject>> appliesToSubjects = new HashMap<PolicySet, List<PolicySubject>>(); + + // for all implementations, endpoint and endpoint references check that + // the policy sets validly apply + return checkAppliesTo(document, appliesToSubjects, composite, context); + + } catch (Exception e) { + throw new CompositeBuilderException(e); + } + } + + private Composite checkAppliesTo(Document document, Map<PolicySet, List<PolicySubject>> appliesToSubjects, Composite composite, BuilderContext context) throws Exception { + // look at policies recursively + for (Component component : composite.getComponents()) { + Implementation implementation = component.getImplementation(); + if (implementation instanceof Composite) { + checkAppliesTo(document, appliesToSubjects, (Composite)implementation, context); + } + } + + for (Component component : composite.getComponents()) { + + for (ComponentService componentService : component.getServices()) { + for (Endpoint ep : componentService.getEndpoints()) { + if (ep.getBinding() instanceof PolicySubject) { + checkAppliesToSubject(document, appliesToSubjects, composite, (PolicySubject)ep.getBinding(), ep.getPolicySets()); + } + } + } + + for (ComponentReference componentReference : component.getReferences()) { + for (EndpointReference epr : componentReference.getEndpointReferences()) { + if (epr.getBinding() instanceof PolicySubject) { + checkAppliesToSubject(document, appliesToSubjects, composite, (PolicySubject)epr.getBinding(), epr.getPolicySets()); + } + } + } + + Implementation implementation = component.getImplementation(); + if (implementation != null && + implementation instanceof PolicySubject) { + checkAppliesToSubject(document, appliesToSubjects, composite, implementation, implementation.getPolicySets()); + } + } + + return composite; + } + + /** + * Checks that all the provided policy sets apply to the provided policy subject + * + * @param document + * @param appliesToSubjects + * @param policySubject + * @param policySets + * @return + * @throws Exception + */ + private void checkAppliesToSubject(Document document, Map<PolicySet, List<PolicySubject>> appliesToSubjects, Composite composite, PolicySubject policySubject, List<PolicySet> policySets) throws Exception { + List<PolicySet> policySetsToRemove = new ArrayList<PolicySet>(); + + for (PolicySet policySet : policySets){ + List<PolicySubject> subjects = appliesToSubjects.get(policySet); + + if (subjects == null){ + XPathExpression appliesTo = policySet.getAppliesToXPathExpression(); + if (appliesTo != null) { + NodeList nodes = (NodeList)appliesTo.evaluate(document, XPathConstants.NODESET); + + if (nodes.getLength() > 0){ + subjects = new ArrayList<PolicySubject>(); + appliesToSubjects.put(policySet, subjects); + } + + for (int i = 0; i < nodes.getLength(); i++) { + Node node = nodes.item(i); + String index = getStructuralURI(node); + PolicySubject subject = lookup(composite, index); + subjects.add(subject); + } + } + } + + if (subjects != null){ + if (!subjects.contains(policySubject)){ + policySetsToRemove.add(policySet); + } + } + + // TODO - If no "appliesTo" is provided does the policy set apply to + // everything or nothing? + + } + + policySets.removeAll(policySetsToRemove); + } +} diff --git a/sca-java-2.x/tags/2.0-M5.1-RC1/modules/builder/src/main/java/org/apache/tuscany/sca/builder/impl/PolicyAttachmentBuilderImpl.java b/sca-java-2.x/tags/2.0-M5.1-RC1/modules/builder/src/main/java/org/apache/tuscany/sca/builder/impl/PolicyAttachmentBuilderImpl.java new file mode 100644 index 0000000000..e9a49c8842 --- /dev/null +++ b/sca-java-2.x/tags/2.0-M5.1-RC1/modules/builder/src/main/java/org/apache/tuscany/sca/builder/impl/PolicyAttachmentBuilderImpl.java @@ -0,0 +1,336 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.apache.tuscany.sca.builder.impl; + +import java.io.IOException; +import java.io.StringWriter; +import java.util.Set; + +import javax.xml.namespace.QName; +import javax.xml.stream.XMLStreamException; +import javax.xml.stream.XMLStreamWriter; +import javax.xml.xpath.XPathConstants; +import javax.xml.xpath.XPathExpression; + +import org.apache.tuscany.sca.assembly.Base; +import org.apache.tuscany.sca.assembly.Binding; +import org.apache.tuscany.sca.assembly.Component; +import org.apache.tuscany.sca.assembly.ComponentReference; +import org.apache.tuscany.sca.assembly.ComponentService; +import org.apache.tuscany.sca.assembly.Composite; +import org.apache.tuscany.sca.assembly.Contract; +import org.apache.tuscany.sca.assembly.Implementation; +import org.apache.tuscany.sca.assembly.builder.BuilderContext; +import org.apache.tuscany.sca.assembly.builder.CompositeBuilder; +import org.apache.tuscany.sca.assembly.builder.CompositeBuilderException; +import org.apache.tuscany.sca.common.xml.dom.DOMHelper; +import org.apache.tuscany.sca.common.xml.stax.StAXHelper; +import org.apache.tuscany.sca.contribution.processor.ContributionWriteException; +import org.apache.tuscany.sca.contribution.processor.ProcessorContext; +import org.apache.tuscany.sca.contribution.processor.StAXArtifactProcessor; +import org.apache.tuscany.sca.contribution.processor.StAXArtifactProcessorExtensionPoint; +import org.apache.tuscany.sca.core.ExtensionPointRegistry; +import org.apache.tuscany.sca.definitions.Definitions; +import org.apache.tuscany.sca.monitor.Monitor; +import org.apache.tuscany.sca.policy.PolicySet; +import org.apache.tuscany.sca.policy.PolicySubject; +import org.w3c.dom.Document; +import org.w3c.dom.Element; +import org.w3c.dom.Node; +import org.w3c.dom.NodeList; +import org.xml.sax.SAXException; + +/** + * A builder that attaches policy sets to the domain composite using the xpath defined by + * the attachTo attribute. It first creates a DOM model for the composite so that the xpath + * expression can be evaluated. For the nodes selected by the xpath, caluclate the element + * URI and add the policy set into the composite model + * + * @version $Rev$ $Date$ + */ +public class PolicyAttachmentBuilderImpl implements CompositeBuilder { + protected static final String BUILDER_VALIDATION_BUNDLE = "org.apache.tuscany.sca.builder.builder-validation-messages"; + + protected StAXHelper staxHelper; + protected DOMHelper domHelper; + protected ExtensionPointRegistry registry; + protected StAXArtifactProcessor<Composite> processor; + + public PolicyAttachmentBuilderImpl(ExtensionPointRegistry registry) { + this.registry = registry; + domHelper = DOMHelper.getInstance(registry); + staxHelper = StAXHelper.getInstance(registry); + StAXArtifactProcessorExtensionPoint processors = + registry.getExtensionPoint(StAXArtifactProcessorExtensionPoint.class); + processor = processors.getProcessor(Composite.class); + } + + public String getID() { + return "org.apache.tuscany.sca.policy.builder.PolicyAttachmentBuilder"; + } + + public Composite build(Composite composite, BuilderContext context) + throws CompositeBuilderException { + try { + Composite patched = applyXPath(composite, context.getDefinitions(), context.getMonitor()); + return patched; + } catch (Exception e) { + throw new CompositeBuilderException(e); + } + } + + /** + * Apply the attachTo XPath against the composite model + * @param composite The orginal composite + * @param definitions SCA definitions that contain the policy sets + * @param monitor The monitor + * @return A reloaded composite + * @throws Exception + */ + private Composite applyXPath(Composite composite, Definitions definitions, Monitor monitor) throws Exception { + + monitor.pushContext("Composite: " + composite.getName().toString()); + + try { + if (definitions == null || definitions.getPolicySets().isEmpty()) { + return composite; + } + // Recursively apply the xpath against the composites referenced by <implementation.composite> + for (Component component : composite.getComponents()) { + Implementation impl = component.getImplementation(); + if (impl instanceof Composite) { + Composite patched = applyXPath((Composite)impl, definitions, monitor); + if (patched != impl) { + component.setImplementation(patched); + } + } + } + Document document = null; + + for (PolicySet ps : definitions.getPolicySets()) { + // First calculate the applicable nodes + Set<Node> applicableNodes = null; + /* + XPathExpression appliesTo = ps.getAppliesToXPathExpression(); + if (appliesTo != null) { + applicableNodes = new HashSet<Node>(); + NodeList nodes = (NodeList)appliesTo.evaluate(document, XPathConstants.NODESET); + for (int i = 0; i < nodes.getLength(); i++) { + applicableNodes.add(nodes.item(i)); + } + } + */ + XPathExpression exp = ps.getAttachToXPathExpression(); + if (exp != null) { + if (document == null) { + document = saveAsDOM(composite); + } + NodeList nodes = (NodeList)exp.evaluate(document, XPathConstants.NODESET); + for (int i = 0; i < nodes.getLength(); i++) { + Node node = nodes.item(i); + + // POL_40002 - you can't attach a policy to a property node + // or one of it's children + // walk backwards up the node tree looking for an element called property + // and raise an error if we find one + Node testNode = node; + while (testNode != null){ + if ((node.getNodeType() == Node.ELEMENT_NODE) && + (node.getLocalName().equals("property"))){ + Monitor.error(monitor, + this, + BUILDER_VALIDATION_BUNDLE, + "PolicyAttachedToProperty", + ps.getName().toString()); + break; + } + testNode = testNode.getParentNode(); + } + + if (applicableNodes == null || applicableNodes.contains(node)) { + // The node can be a component, service, reference or binding + String index = getStructuralURI(node); + PolicySubject subject = lookup(composite, index); + if (subject != null) { + subject.getPolicySets().add(ps); + } else { + // raise a warning that the XPath node didn't match a node in the + // models + Monitor.warning(monitor, + this, + BUILDER_VALIDATION_BUNDLE, + "PolicyDOMModelMissmatch", + ps.getName().toString(), + index); + } + } + } + } + } + + return composite; + } finally { + monitor.popContext(); + } + } + + protected Document saveAsDOM(Composite composite) throws XMLStreamException, ContributionWriteException, IOException, + SAXException { + // First write the composite into a DOM document so that we can apply the xpath + StringWriter sw = new StringWriter(); + XMLStreamWriter writer = staxHelper.createXMLStreamWriter(sw); + // Write the composite into a DOM document + processor.write(composite, writer, new ProcessorContext(registry)); + writer.close(); + + Document document = domHelper.load(sw.toString()); + + // Debugging + //System.out.println("<!-- DOM to which XPath will be applies is -->\n" + sw.toString()); + + return document; + } + + private static final QName COMPONENT = new QName(Base.SCA11_NS, "component"); + private static final QName SERVICE = new QName(Base.SCA11_NS, "service"); + private static final QName REFERENCE = new QName(Base.SCA11_NS, "reference"); + + protected static String getStructuralURI(Node node) { + if (node != null) { + QName name = new QName(node.getNamespaceURI(), node.getLocalName()); + if (COMPONENT.equals(name)) { + Element element = (Element)node; + return element.getAttributeNS(null, "uri"); + } else if (SERVICE.equals(name)) { + Element component = (Element)node.getParentNode(); + String uri = component.getAttributeNS(null, "uri"); + String service = ((Element)node).getAttributeNS(null, "name"); + return uri + "#service(" + service + ")"; + } else if (REFERENCE.equals(name)) { + Element component = (Element)node.getParentNode(); + String uri = component.getAttributeNS(null, "uri"); + String reference = ((Element)node).getAttributeNS(null, "name"); + return uri + "#reference(" + reference + ")"; + } else { + String localName = node.getLocalName(); + if (localName.startsWith("binding.")) { + String bindingName = ((Element)node).getAttributeNS(null, "name"); + Element contract = (Element)node.getParentNode(); + String contractName = contract.getAttributeNS(null, "name"); + Element component = (Element)node.getParentNode().getParentNode(); + String uri = component.getAttributeNS(null, "uri"); + return uri + "#" + contract.getLocalName() + "(" + contractName + "/" + bindingName + ")"; + } else if (localName.startsWith("implementation.")) { + Element component = (Element)node.getParentNode(); + String uri = component.getAttributeNS(null, "uri"); + return uri + "#implementation()"; + } + } + } + return null; + } + + protected Binding getBinding(Contract contract, String name) { + for (Binding binding : contract.getBindings()) { + if (name.equals(binding.getName())) { + return binding; + } + } + return null; + } + + protected PolicySubject lookup(Composite composite, String structuralURI) { + if (structuralURI == null) { + return null; + } + int index = structuralURI.indexOf('#'); + String componentURI = structuralURI; + String service = null; + String reference = null; + String binding = null; + boolean impl = false; + + if (index != -1) { + componentURI = structuralURI.substring(0, index); + String fragment = structuralURI.substring(index + 1); + int begin = fragment.indexOf('('); + int end = fragment.indexOf(')'); + if (begin != -1 && end != -1) { + String path = fragment.substring(begin + 1, end).trim(); + String prefix = fragment.substring(0, begin).trim(); + if (prefix.equals("implementation")) { + impl = true; + } else { + int pos = path.indexOf('/'); + if (pos != -1) { + binding = path.substring(pos + 1); + path = path.substring(0, pos); + if ("service-binding".equals(prefix)) { + service = path; + } else if ("reference-binding".equals(prefix)) { + reference = path; + } + } + if ("service".equals(prefix)) { + service = path; + } else if ("reference".equals(prefix)) { + reference = path; + } + } + } + } + for (Component component : composite.getComponents()) { + if (component.getURI().equals(componentURI)) { + if (service != null) { + ComponentService componentService = component.getService(service); + if (binding != null) { + Binding b = getBinding(componentService, binding); + if (b instanceof PolicySubject) { + return (PolicySubject)b; + } + } else { + return componentService; + } + } else if (reference != null) { + ComponentReference componentReference = component.getReference(reference); + if (binding != null) { + Binding b = getBinding(componentReference, binding); + if (b instanceof PolicySubject) { + return (PolicySubject)b; + } + } else { + return componentReference; + } + } else if (impl) { + return component.getImplementation(); + } + return component; + } else if (structuralURI.startsWith(component.getURI() + "/")) { + Implementation implementation = component.getImplementation(); + if (implementation instanceof Composite) { + return lookup((Composite)implementation, structuralURI); + } else { + return null; + } + } + } + return null; + } +} diff --git a/sca-java-2.x/tags/2.0-M5.1-RC1/modules/builder/src/main/java/org/apache/tuscany/sca/builder/impl/StructuralURIBuilderImpl.java b/sca-java-2.x/tags/2.0-M5.1-RC1/modules/builder/src/main/java/org/apache/tuscany/sca/builder/impl/StructuralURIBuilderImpl.java new file mode 100644 index 0000000000..7c2d86862b --- /dev/null +++ b/sca-java-2.x/tags/2.0-M5.1-RC1/modules/builder/src/main/java/org/apache/tuscany/sca/builder/impl/StructuralURIBuilderImpl.java @@ -0,0 +1,191 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.apache.tuscany.sca.builder.impl; + +import java.net.URI; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import javax.xml.namespace.QName; + +import org.apache.tuscany.sca.assembly.Binding; +import org.apache.tuscany.sca.assembly.Component; +import org.apache.tuscany.sca.assembly.ComponentReference; +import org.apache.tuscany.sca.assembly.ComponentService; +import org.apache.tuscany.sca.assembly.Composite; +import org.apache.tuscany.sca.assembly.Contract; +import org.apache.tuscany.sca.assembly.Implementation; +import org.apache.tuscany.sca.assembly.Reference; +import org.apache.tuscany.sca.assembly.Service; +import org.apache.tuscany.sca.assembly.builder.BuilderContext; +import org.apache.tuscany.sca.assembly.builder.CompositeBuilder; +import org.apache.tuscany.sca.assembly.builder.CompositeBuilderException; +import org.apache.tuscany.sca.assembly.builder.Messages; +import org.apache.tuscany.sca.core.ExtensionPointRegistry; +import org.apache.tuscany.sca.definitions.Definitions; +import org.apache.tuscany.sca.monitor.Monitor; + +/** + * Configuration of binding URIs. + * + * @version $Rev$ $Date$ + */ +public class StructuralURIBuilderImpl implements CompositeBuilder { + + public StructuralURIBuilderImpl(ExtensionPointRegistry registry) { + } + + public String getID() { + return "org.apache.tuscany.sca.assembly.builder.StructualURIBuilder"; + } + + public Composite build(Composite composite, BuilderContext context) + throws CompositeBuilderException { + configureStructuralURIs(composite, + null, + context.getDefinitions(), + context.getBindingBaseURIs(), + context.getMonitor()); + return composite; + } + + + /** + * 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, Messages.ASSEMBLY_VALIDATION, "MultipleBindingsForService", contract + .getName(), binding.getName()); + } else { + Monitor.error(monitor, + this, + Messages.ASSEMBLY_VALIDATION, + "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, + Messages.ASSEMBLY_VALIDATION, + "MultipleBindingsForServiceCallback", + contract.getName(), + binding.getName()); + } else { + Monitor.error(monitor, + this, + Messages.ASSEMBLY_VALIDATION, + "MultipleBindingsForReferenceCallback", + contract.getName(), + binding.getName()); + } + } + } + } + } + + private void configureStructuralURIs(Composite composite, + String parentComponentURI, + Definitions definitions, + Map<QName, List<String>> defaultBindings, + Monitor monitor) throws CompositeBuilderException { + + monitor.pushContext("Composite: " + composite.getName().toString()); + try { + for (Service service : composite.getServices()) { + constructBindingNames(service, monitor); + } + + for (Reference reference : composite.getReferences()) { + constructBindingNames(reference, monitor); + } + + // Process nested composites recursively + for (Component component : composite.getComponents()) { + + // Initialize component URI + String componentURI; + if (parentComponentURI == null) { + componentURI = component.getName(); + } else { + componentURI = parentComponentURI + '/' + component.getName(); + } + component.setURI(componentURI); + + monitor.pushContext("Component: " + component.getName()); + try { + for (ComponentService service : component.getServices()) { + constructBindingNames(service, monitor); + } + for (ComponentReference service : component.getReferences()) { + constructBindingNames(service, monitor); + } + } finally { + monitor.popContext(); + } + + Implementation implementation = component.getImplementation(); + if (implementation instanceof Composite) { + // Process nested composite + configureStructuralURIs((Composite)implementation, + componentURI, + definitions, + defaultBindings, + monitor); + } + } + + } finally { + monitor.popContext(); + } + } + +} diff --git a/sca-java-2.x/tags/2.0-M5.1-RC1/modules/builder/src/main/java/org/apache/tuscany/sca/builder/impl/WireBuilderImpl.java b/sca-java-2.x/tags/2.0-M5.1-RC1/modules/builder/src/main/java/org/apache/tuscany/sca/builder/impl/WireBuilderImpl.java new file mode 100644 index 0000000000..21725fb1b1 --- /dev/null +++ b/sca-java-2.x/tags/2.0-M5.1-RC1/modules/builder/src/main/java/org/apache/tuscany/sca/builder/impl/WireBuilderImpl.java @@ -0,0 +1,1028 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.apache.tuscany.sca.builder.impl; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import org.apache.tuscany.sca.assembly.AssemblyFactory; +import org.apache.tuscany.sca.assembly.Binding; +import org.apache.tuscany.sca.assembly.Component; +import org.apache.tuscany.sca.assembly.ComponentReference; +import org.apache.tuscany.sca.assembly.ComponentService; +import org.apache.tuscany.sca.assembly.Composite; +import org.apache.tuscany.sca.assembly.CompositeReference; +import org.apache.tuscany.sca.assembly.Endpoint; +import org.apache.tuscany.sca.assembly.EndpointReference; +import org.apache.tuscany.sca.assembly.Implementation; +import org.apache.tuscany.sca.assembly.Multiplicity; +import org.apache.tuscany.sca.assembly.Reference; +import org.apache.tuscany.sca.assembly.SCABinding; +import org.apache.tuscany.sca.assembly.Wire; +import org.apache.tuscany.sca.assembly.builder.BuilderContext; +import org.apache.tuscany.sca.assembly.builder.CompositeBuilderException; +import org.apache.tuscany.sca.assembly.builder.Messages; +import org.apache.tuscany.sca.core.ExtensionPointRegistry; +import org.apache.tuscany.sca.core.FactoryExtensionPoint; +import org.apache.tuscany.sca.core.UtilityExtensionPoint; +import org.apache.tuscany.sca.interfacedef.InterfaceContractMapper; +import org.apache.tuscany.sca.monitor.Monitor; +import org.apache.tuscany.sca.policy.Intent; +import org.oasisopen.sca.ServiceRuntimeException; + +/** + * Creates endpoint reference models. + */ +public class WireBuilderImpl { + + private AssemblyFactory assemblyFactory; + private InterfaceContractMapper interfaceContractMapper; + + public WireBuilderImpl(ExtensionPointRegistry registry) { + UtilityExtensionPoint utilities = registry.getExtensionPoint(UtilityExtensionPoint.class); + interfaceContractMapper = utilities.getUtility(InterfaceContractMapper.class); + + FactoryExtensionPoint modelFactories = registry.getExtensionPoint(FactoryExtensionPoint.class); + assemblyFactory = modelFactories.getFactory(AssemblyFactory.class); + } + + /** + * Create endpoint references for all component references. + * + * @param composite + */ + public Composite build(Composite composite, BuilderContext context) + throws CompositeBuilderException { + Monitor monitor = context.getMonitor(); + + // process component references + processComponentReferences(composite, monitor); + + // validate component references + validateComponentReferences(composite, monitor); + + return composite; + } + + private void processComponentReferences(Composite composite, Monitor monitor) { + + monitor.pushContext("Composite: " + composite.getName().toString()); + try { + // Index components, services and references + Map<String, Component> components = new HashMap<String, Component>(); + Map<String, ComponentService> componentServices = new HashMap<String, ComponentService>(); + Map<String, ComponentReference> componentReferences = new HashMap<String, ComponentReference>(); + indexComponentsServicesAndReferences(composite, components, componentServices, componentReferences); + + // Connect component references as described in wires + connectWires(composite, componentServices, componentReferences, monitor); + + // create endpoint references for each component's references + for (Component component : composite.getComponents()) { + monitor.pushContext("Component: " + component.getName()); + + try { + + // recurse for composite implementations + Implementation implementation = component.getImplementation(); + if (implementation instanceof Composite) { + processComponentReferences((Composite)implementation, monitor); + } + + // create endpoint references to represent the component reference + for (ComponentReference reference : component.getReferences()) { + createReferenceEndpointReferences(composite, + component, + reference, + components, + componentServices, + monitor); + + // 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 + + // push down endpoint references into the leaf component references + // in the case where this component reference promotes a reference from + // a composite implementation + pushDownEndpointReferences(composite, + component, + reference, + monitor); + + } // end for + + // Validate that references are wired or promoted, according + // to their multiplicity. This validates as we go and catches cases + // where a reference has been configured directly incorrectly with its + // immediate multiplicity setting. We re-run this validation again later + // to catch to more complex cases where reference promotion causes + // multiplicity errors. + validateReferenceMultiplicity(composite, component, monitor); + + } finally { + monitor.popContext(); + } + } // end for + + } finally { + monitor.popContext(); + } + + } // end method processCompoenntReferences + + + /** + * The validate stage is separate from the process stage as enpoint references are + * pushed down the hierarchy. We don't know the full set of endpoint references until + * all processing is complete. Hence we can't validate as we go + * + * @param composite + * @param monitor + */ + private void validateComponentReferences(Composite composite, Monitor monitor) { + + monitor.pushContext("Composite: " + composite.getName().toString()); + try { + // 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) { + validateComponentReferences((Composite)implementation, monitor); + } + // Validate that references are wired or promoted, according + // to their multiplicity + validateReferenceMultiplicity(composite, component, monitor); + + } finally { + monitor.popContext(); + } + } + + } finally { + monitor.popContext(); + } + + } + + protected void indexComponentsServicesAndReferences(Composite composite, + Map<String, Component> components, + Map<String, ComponentService> componentServices, + Map<String, ComponentReference> componentReferences) { + + for (Component component : composite.getComponents()) { + + // Index components by name + components.put(component.getName(), component); + + ComponentService nonCallbackService = null; + int nonCallbackServices = 0; + for (ComponentService componentService : component.getServices()) { + + // Index component services by component name / service name + String uri = component.getName() + '/' + componentService.getName(); + componentServices.put(uri, componentService); + + // count how many non-callback services there are + // if there is only one the component name also acts as the + // service name + if (!componentService.isForCallback()) { + // Check how many non callback non-promoted services we have + if (nonCallbackServices == 0) { + nonCallbackService = componentService; + } + nonCallbackServices++; + } + } + + if (nonCallbackServices == 1) { + // If we have a single non callback service, index it by + // component name as well + componentServices.put(component.getName(), nonCallbackService); + } + + // Index references by component name / reference name + for (ComponentReference componentReference : component.getReferences()) { + String uri = component.getName() + '/' + componentReference.getName(); + componentReferences.put(uri, componentReference); + } + } + } + + /** + * Resolve wires and connect the sources to their targets + * + * @param composite + * @param componentServices + * @param componentReferences + * @param problems + */ + private void connectWires(Composite composite, + Map<String, ComponentService> componentServices, + Map<String, ComponentReference> componentReferences, + Monitor monitor) { + + // For each wire, resolve the source reference, the target service, and + // add it to the list of targets of the reference + List<Wire> wires = composite.getWires(); + for (int i = 0, n = wires.size(); i < n; i++) { + Wire wire = wires.get(i); + + ComponentReference resolvedReference; + ComponentService resolvedService; + + // Resolve the source reference + ComponentReference source = wire.getSource(); + if (source != null && source.isUnresolved()) { + resolvedReference = componentReferences.get(source.getName()); + if (resolvedReference != null) { + wire.setSource(resolvedReference); + } else { + Monitor.warning(monitor, this, Messages.ASSEMBLY_VALIDATION, "WireSourceNotFound", source + .getName()); + } + } else { + resolvedReference = wire.getSource(); + } + + // Resolve the target service + ComponentService target = wire.getTarget(); + if (target != null && target.isUnresolved()) { + resolvedService = componentServices.get(target.getName()); + if (resolvedService != null) { + wire.setTarget(target); + } else { + Monitor.warning(monitor, this, Messages.ASSEMBLY_VALIDATION, "WireTargetNotFound", target + .getName()); + } + } else { + resolvedService = wire.getTarget(); + } + + // Add the target service to the list of targets of the + // reference + if (resolvedReference != null && resolvedService != null) { + // Check that the target component service provides + // a superset of + // the component reference interface + if (resolvedReference.getInterfaceContract() == null || interfaceContractMapper + .isCompatibleSubset(resolvedReference.getInterfaceContract(), resolvedService.getInterfaceContract())) { + + //resolvedReference.getTargets().add(resolvedService); + if (wire.isReplace()) { + resolvedReference.getTargets().clear(); + } + resolvedReference.getTargets().add(wire.getTarget()); + } else { + Monitor.warning(monitor, this, Messages.ASSEMBLY_VALIDATION, "WireIncompatibleInterface", source + .getName(), target.getName()); + } + } + } + + // Clear the list of wires + composite.getWires().clear(); + } + + private void createReferenceEndpointReferences(Composite composite, + Component component, + ComponentReference reference, + Map<String, Component> components, + Map<String, ComponentService> componentServices, + Monitor monitor) { + + monitor.pushContext("Reference: " + reference.getName()); + + // Get reference targets + List<ComponentService> refTargets = getReferenceTargets(reference); + if (Boolean.TRUE.equals(reference.getAutowire()) && 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.isCompatibleSubset(reference + .getInterfaceContract(), targetComponentService.getInterfaceContract())) { + + if (intentsMatch(reference.getRequiredIntents(), targetComponentService.getRequiredIntents())) { + EndpointReference endpointRef = createEndpointRef(component, reference, false); + endpointRef.setTargetEndpoint(createEndpoint(targetComponent, targetComponentService, true)); + endpointRef.setStatus(EndpointReference.Status.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, + Messages.ASSEMBLY_VALIDATION, + "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, + Messages.ASSEMBLY_VALIDATION, + "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.isCompatibleSubset(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.Status.WIRED_TARGET_FOUND_AND_MATCHED); + // 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.setStatus(EndpointReference.Status.WIRED_TARGET_NOT_FOUND); + reference.getEndpointReferences().add(endpointRef); + Monitor.warning(monitor, + this, + Messages.ASSEMBLY_VALIDATION, + "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.Status.WIRED_TARGET_FOUND_READY_FOR_MATCHING); + reference.getEndpointReferences().add(endpointRef); + } + } else { + Monitor.error(monitor, + this, + Messages.ASSEMBLY_VALIDATION, + "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.setStatus(EndpointReference.Status.WIRED_TARGET_NOT_FOUND); + reference.getEndpointReferences().add(endpointRef); + Monitor.warning(monitor, + this, + Messages.ASSEMBLY_VALIDATION, + "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.Status.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.Status.RESOLVED_BINDING); + } + 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.isCompatibleSubset(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.Status.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.setStatus(EndpointReference.Status.WIRED_TARGET_NOT_FOUND); + reference.getEndpointReferences().add(endpointRef); + Monitor.warning(monitor, + this, + Messages.ASSEMBLY_VALIDATION, + "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.Status.WIRED_TARGET_FOUND_READY_FOR_MATCHING); + reference.getEndpointReferences().add(endpointRef); + } + } else { + Monitor.warning(monitor, + this, + Messages.ASSEMBLY_VALIDATION, + "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.setStatus(EndpointReference.Status.RESOLVED_BINDING); + reference.getEndpointReferences().add(endpointRef); + } // end if + } + } + + monitor.popContext(); + + } // end method + + private boolean intentsMatch(List<Intent> referenceIntents, List<Intent> serviceIntents) { + Set<Intent> referenceIntentSet = new HashSet<Intent>(referenceIntents); + Set<Intent> serviceIntentSet = new HashSet<Intent>(serviceIntents); + return referenceIntentSet.equals(serviceIntentSet); + } + + /** + * Reference targets have to be resolved in the context in which they are + * defined so they can't be push down the hierarchy during the static build. + * So we wait until we have calculated the enpoint references before pushing them + * down. Muliplicity errors will be caught by the multiplicity validation check that + * comes next + * + * @param composite + * @param component + * @param reference + * @param monitor + */ + private void pushDownEndpointReferences(Composite composite, + Component component, + ComponentReference componentReference, + Monitor monitor) { + Reference reference = componentReference.getReference(); + + if (reference instanceof CompositeReference) { + List<ComponentReference> leafComponentReferences = getPromotedComponentReferences((CompositeReference)reference); + + // for each leaf component reference copy in the endpoint references for this + // higher level (promoting) reference + // TODO - the elements are inserted starting at 0 here because the code allows references multiplicity + // validation constraints to be broken if the reference is autowire. At runtime the + // first one is chosen if max multiplicity is 1. We have an OSOA test that assumes that + // promoted references overwrite leaf references. This insert gives the same effect in the + // autowire case. We need to think about if there is a more correct answer. + for (ComponentReference leafRef : leafComponentReferences){ + int insertLocation = 0; + for (EndpointReference epr : componentReference.getEndpointReferences()){ + // copy the epr + EndpointReference eprCopy = copyHigherReference(epr, leafRef); + leafRef.getEndpointReferences().add(insertLocation, eprCopy); + insertLocation++; + } + } + } + + // TODO - what to do about callbacks in the reference promotion case + } + + /** + * Follow a reference promotion chain down to the innermost (non composite) + * component references. + * + * @param compositeReference + * @return + */ + private List<ComponentReference> getPromotedComponentReferences(CompositeReference compositeReference) { + List<ComponentReference> componentReferences = new ArrayList<ComponentReference>(); + collectPromotedComponentReferences(compositeReference, componentReferences); + return componentReferences; + } + + /** + * Follow a reference promotion chain down to the innermost (non composite) + * component references. + * + * @param compositeReference + * @param componentReferences + * @return + */ + private void collectPromotedComponentReferences(CompositeReference compositeReference, + List<ComponentReference> componentReferences) { + for (ComponentReference componentReference : compositeReference.getPromotedReferences()) { + Reference reference = componentReference.getReference(); + if (reference instanceof CompositeReference) { + + // Continue to follow the reference promotion chain + collectPromotedComponentReferences((CompositeReference)reference, componentReferences); + + } else if (reference != null) { + + // Found a non-composite reference + componentReferences.add(componentReference); + } + } + } + + /** + * Copy a higher level EndpointReference down to a lower level reference which it promotes + * @param epRef - the endpoint reference + * @param promotedReference - the promoted reference + * @return - a copy of the EndpointReference with data merged from the promoted reference + */ + private EndpointReference copyHigherReference(EndpointReference epRef, ComponentReference promotedReference) { + EndpointReference epRefClone = null; + try { + epRefClone = (EndpointReference)epRef.clone(); + } catch (Exception e) { + throw new ServiceRuntimeException(e); + // Ignore (we know that EndpointReference2 can be cloned) + } // end try + // Copy across details of the inner reference + // ComponentReference ref = epRefClone.getReference(); + //FIXME + epRefClone.setReference(promotedReference); + return epRefClone; + } + + private void validateReferenceMultiplicity(Composite composite, Component component, Monitor monitor) { + for (ComponentReference componentReference : component.getReferences()) { + if (!validateMultiplicity(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, + Messages.ASSEMBLY_VALIDATION, + "ReferenceWithoutTargets", + composite.getName().toString(), + componentReference.getName()); + } + } else { + // no error if reference is autowire and more targets + // than multiplicity have been found + if (Boolean.TRUE.equals(componentReference.getAutowire())) { + break; + } + + Monitor.error(monitor, + this, + Messages.ASSEMBLY_VALIDATION, + "TooManyReferenceTargets", + componentReference.getName()); + } + } + } + + } + + private boolean validateMultiplicity(Multiplicity multiplicity, List<EndpointReference> endpointReferences) { + + // In some tests multiplicity is not set + if (multiplicity == null) { + return true; + } + + // Count targets + int count = endpointReferences.size(); + + switch (multiplicity) { + case ZERO_N: + break; + case ZERO_ONE: + if (count > 1) { + return false; + } + break; + case ONE_ONE: + if (count != 1) { + return false; + } + break; + case ONE_N: + if (count < 1) { + return false; + } + break; + } + return true; + } + + /** + * 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/sca-java-2.x/tags/2.0-M5.1-RC1/modules/builder/src/main/java/org/apache/tuscany/sca/builder/impl/WireMatcherImpl.java b/sca-java-2.x/tags/2.0-M5.1-RC1/modules/builder/src/main/java/org/apache/tuscany/sca/builder/impl/WireMatcherImpl.java new file mode 100644 index 0000000000..761f53ff11 --- /dev/null +++ b/sca-java-2.x/tags/2.0-M5.1-RC1/modules/builder/src/main/java/org/apache/tuscany/sca/builder/impl/WireMatcherImpl.java @@ -0,0 +1,64 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.apache.tuscany.sca.builder.impl; + +import org.apache.tuscany.sca.assembly.Endpoint; +import org.apache.tuscany.sca.assembly.EndpointReference; +import org.apache.tuscany.sca.assembly.builder.BuilderContext; +import org.apache.tuscany.sca.assembly.builder.BuilderExtensionPoint; +import org.apache.tuscany.sca.assembly.builder.PolicyBuilder; +import org.apache.tuscany.sca.assembly.builder.WireBuilder; +import org.apache.tuscany.sca.core.ExtensionPointRegistry; +import org.apache.tuscany.sca.core.UtilityExtensionPoint; +import org.apache.tuscany.sca.interfacedef.InterfaceContract; +import org.apache.tuscany.sca.interfacedef.InterfaceContractMapper; + +/** + * + */ +public class WireMatcherImpl implements WireBuilder { + private InterfaceContractMapper interfaceContractMapper; + private BuilderExtensionPoint builderExtensionPoint; + + /** + * @param registry + */ + public WireMatcherImpl(ExtensionPointRegistry registry) { + super(); + this.builderExtensionPoint = registry.getExtensionPoint(BuilderExtensionPoint.class); + UtilityExtensionPoint utilities = registry.getExtensionPoint(UtilityExtensionPoint.class); + this.interfaceContractMapper = utilities.getUtility(InterfaceContractMapper.class); + } + + public boolean build(EndpointReference endpointReference, Endpoint endpoint, BuilderContext context) { + InterfaceContract sourceIC = endpointReference.getComponentReferenceInterfaceContract(); + InterfaceContract targetIC = endpoint.getComponentServiceInterfaceContract(); + if (!interfaceContractMapper.isCompatibleSubset(sourceIC, targetIC)) { + return false; + } + for (PolicyBuilder policyBuilder : builderExtensionPoint.getPolicyBuilders()) { + if (!policyBuilder.build(endpointReference, endpoint, context)) { + return false; + } + } + return true; + } + +} diff --git a/sca-java-2.x/tags/2.0-M5.1-RC1/modules/builder/src/main/resources/META-INF/services/org.apache.tuscany.sca.assembly.builder.CompositeBuilder b/sca-java-2.x/tags/2.0-M5.1-RC1/modules/builder/src/main/resources/META-INF/services/org.apache.tuscany.sca.assembly.builder.CompositeBuilder new file mode 100644 index 0000000000..f7b8a0374f --- /dev/null +++ b/sca-java-2.x/tags/2.0-M5.1-RC1/modules/builder/src/main/resources/META-INF/services/org.apache.tuscany.sca.assembly.builder.CompositeBuilder @@ -0,0 +1,18 @@ +# 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.
+org.apache.tuscany.sca.builder.impl.ModelBuilderImpl;id=org.apache.tuscany.sca.assembly.builder.CompositeBuilder
+
diff --git a/sca-java-2.x/tags/2.0-M5.1-RC1/modules/builder/src/main/resources/org/apache/tuscany/sca/builder/builder-validation-messages.properties b/sca-java-2.x/tags/2.0-M5.1-RC1/modules/builder/src/main/resources/org/apache/tuscany/sca/builder/builder-validation-messages.properties new file mode 100644 index 0000000000..68b5787653 --- /dev/null +++ b/sca-java-2.x/tags/2.0-M5.1-RC1/modules/builder/src/main/resources/org/apache/tuscany/sca/builder/builder-validation-messages.properties @@ -0,0 +1,34 @@ +# +# +# 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. +# +# + +# there are a whole stack of builder related messages that +# are still yet to be moved here from assembly-validation-messages.properties +PolicyAttachedToProperty = [POL40002] The policy {0} has been attached to a property or one of its children. This is not allowed. +PolicyDOMModelMissmatch = The DOM node which has been found as a result of evaluating the XPath attachment of policy {0} cannot be mapped back to an element in the SCA model. The structural URI of the node is {1} +MultiplePolicyLanguagesInEP = The policy sets for endpoint {0} contain policies specified in more than one language {1} +MultiplePolicyLanguagesInEPR = The policy sets for endpoint reference {0} contain policies specified in more than one language {1} +MultiplePolicyLanguagesInImpl = The policy sets for component {0} implementation contain policies specified in more than one language {1} +JaxWSClientAsyncMethodsNotAllowed = [JCA100006] JAX-WS client-side asynchronous polling and callback methods are not allowed in service interfaces +PolicySetNotFoundAtBuild = PolicySet {0} is not defined in SCA definitions +IntentNotSatisfiedAtBuild = The intent {0} associated with policy subject {1} has no matching policy set +MutuallyExclusiveIntentsAtBuild = [POL40009,ASM60009,ASM60010,JCA70001,JCA70003] Intent {0} and {1} are mutually exclusive +IntentNotFoundAtBuild = Intent {0} is not defined in SCA definitions + |