diff options
author | jsdelfino <jsdelfino@13f79535-47bb-0310-9956-ffa450edef68> | 2011-01-10 19:51:07 +0000 |
---|---|---|
committer | jsdelfino <jsdelfino@13f79535-47bb-0310-9956-ffa450edef68> | 2011-01-10 19:51:07 +0000 |
commit | c791fd804344b8719fb69be84b8174c84cc4f4dc (patch) | |
tree | 87852f7762ea06d4e47855e5176a65af8a4bee44 /sandbox/sebastien/java/wrapped/modules/builder | |
parent | 181bc548fd1a9b5a6f39882cb4102751230de642 (diff) |
Sandbox to experiment with Databinding automatic wrapper transformations.
git-svn-id: http://svn.us.apache.org/repos/asf/tuscany@1057335 13f79535-47bb-0310-9956-ffa450edef68
Diffstat (limited to '')
37 files changed, 8653 insertions, 0 deletions
diff --git a/sandbox/sebastien/java/wrapped/modules/builder/META-INF/MANIFEST.MF b/sandbox/sebastien/java/wrapped/modules/builder/META-INF/MANIFEST.MF new file mode 100644 index 0000000000..30e639f3f9 --- /dev/null +++ b/sandbox/sebastien/java/wrapped/modules/builder/META-INF/MANIFEST.MF @@ -0,0 +1,44 @@ +Manifest-Version: 1.0
+Bundle-Name: Apache Tuscany SCA Model Builders
+Bundle-Vendor: The Apache Software Foundation
+Bundle-Version: 2.0.0
+SCA-Version: 1.1
+Bundle-ManifestVersion: 2
+Bundle-License: http://www.apache.org/licenses/LICENSE-2.0.txt
+Bundle-Description: Apache Tuscany SCA Assembly Model
+Import-Package: javax.xml.namespace,
+ javax.xml.parsers,
+ javax.xml.stream,
+ javax.xml.transform,
+ javax.xml.transform.dom,
+ javax.xml.transform.sax,
+ javax.xml.xpath,
+ org.apache.tuscany.sca.assembly;version="2.0.0",
+ org.apache.tuscany.sca.assembly.builder;version="2.0.0",
+ org.apache.tuscany.sca.assembly.xml;version="2.0.0",
+ org.apache.tuscany.sca.assembly.xsd;version="2.0.0",
+ org.apache.tuscany.sca.common.xml.dom;version="2.0.0",
+ org.apache.tuscany.sca.common.xml.stax;version="2.0.0",
+ org.apache.tuscany.sca.contribution.processor;version="2.0.0",
+ org.apache.tuscany.sca.contribution.resolver;version="2.0.0";resolution:=optional,
+ org.apache.tuscany.sca.core;version="2.0.0",
+ org.apache.tuscany.sca.databinding;version="2.0.0",
+ org.apache.tuscany.sca.databinding.impl;version="2.0.0",
+ org.apache.tuscany.sca.databinding.jaxb;version="2.0.0",
+ org.apache.tuscany.sca.databinding.xml;version="2.0.0",
+ org.apache.tuscany.sca.definitions;version="2.0.0",
+ org.apache.tuscany.sca.interfacedef;version="2.0.0",
+ org.apache.tuscany.sca.interfacedef.impl;version="2.0.0",
+ org.apache.tuscany.sca.interfacedef.java;version="2.0.0",
+ org.apache.tuscany.sca.interfacedef.util;version="2.0.0",
+ org.apache.tuscany.sca.monitor;version="2.0.0",
+ org.apache.tuscany.sca.policy;version="2.0.0",
+ org.apache.tuscany.sca.policy.util;version="2.0.0",
+ org.apache.tuscany.sca.runtime;version="2.0.0",
+ org.apache.tuscany.sca.xsd;version="2.0.0",
+ org.apache.ws.commons.schema,
+ org.oasisopen.sca;version="2.0.0",
+ org.w3c.dom
+Bundle-SymbolicName: org.apache.tuscany.sca.builder
+Bundle-DocURL: http://www.apache.org/
+Bundle-RequiredExecutionEnvironment: J2SE-1.5,JavaSE-1.6 diff --git a/sandbox/sebastien/java/wrapped/modules/builder/pom.xml b/sandbox/sebastien/java/wrapped/modules/builder/pom.xml new file mode 100644 index 0000000000..13e7ecc8a5 --- /dev/null +++ b/sandbox/sebastien/java/wrapped/modules/builder/pom.xml @@ -0,0 +1,71 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + * 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. +--> +<project> + <modelVersion>4.0.0</modelVersion> + <parent> + <groupId>org.apache.tuscany.sca</groupId> + <artifactId>tuscany-modules</artifactId> + <version>2.0-SNAPSHOT</version> + <relativePath>../pom.xml</relativePath> + </parent> + <artifactId>tuscany-builder</artifactId> + <name>Apache Tuscany SCA Model Builders</name> + + <dependencies> + + <dependency> + <groupId>org.apache.tuscany.sca</groupId> + <artifactId>tuscany-assembly</artifactId> + <version>2.0-SNAPSHOT</version> + </dependency> + + <dependency> + <groupId>org.apache.tuscany.sca</groupId> + <artifactId>tuscany-xsd</artifactId> + <version>2.0-SNAPSHOT</version> + </dependency> + + <dependency> + <groupId>org.apache.tuscany.sca</groupId> + <artifactId>tuscany-contribution</artifactId> + <version>2.0-SNAPSHOT</version> + </dependency> + + <dependency> + <groupId>org.apache.tuscany.sca</groupId> + <artifactId>tuscany-databinding-jaxb</artifactId> + <version>2.0-SNAPSHOT</version> + </dependency> + + <dependency> + <groupId>org.apache.tuscany.sca</groupId> + <artifactId>tuscany-assembly-xml</artifactId> + <version>2.0-SNAPSHOT</version> + </dependency> + + <dependency> + <groupId>org.apache.tuscany.sca</groupId> + <artifactId>tuscany-assembly-xsd</artifactId> + <version>2.0-SNAPSHOT</version> + </dependency> + + </dependencies> + +</project> diff --git a/sandbox/sebastien/java/wrapped/modules/builder/src/main/java/org/apache/tuscany/sca/builder/impl/BindingURIBuilderImpl.java b/sandbox/sebastien/java/wrapped/modules/builder/src/main/java/org/apache/tuscany/sca/builder/impl/BindingURIBuilderImpl.java new file mode 100644 index 0000000000..4c5bca204b --- /dev/null +++ b/sandbox/sebastien/java/wrapped/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/sandbox/sebastien/java/wrapped/modules/builder/src/main/java/org/apache/tuscany/sca/builder/impl/ComponentBuilderImpl.java b/sandbox/sebastien/java/wrapped/modules/builder/src/main/java/org/apache/tuscany/sca/builder/impl/ComponentBuilderImpl.java new file mode 100644 index 0000000000..1a5051dd95 --- /dev/null +++ b/sandbox/sebastien/java/wrapped/modules/builder/src/main/java/org/apache/tuscany/sca/builder/impl/ComponentBuilderImpl.java @@ -0,0 +1,1698 @@ +/* + * 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.InputStream; +import java.io.StringReader; +import java.net.URI; +import java.net.URL; +import java.net.URLConnection; +import java.util.List; + +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.ContractBuilder; +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.Interface; +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.java.JavaInterface; +import org.apache.tuscany.sca.interfacedef.java.JavaInterfaceContract; +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.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; + private ContractBuilder contractBuilder; + + 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); + contractBuilder = builders.getContractBuilder(); + } + + 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 + + // inherit the intents and policy sets from the component type + 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, context); + + // add callback reference model objects + createCallbackReference(component, componentService, monitor); + } + } + + /** + * 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, monitor); + + // 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); + + // Equivalent to getSchema().getSchemaDocument(), but allows us to support older versions of XmlSchema + Document schemaDom = xsdDefinition.getSchema().getAllSchemas()[0]; + + 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) return; + + try { + String sourceName = extractSourcePropertyName( source ); + + Property sourceProp = null; + if (outerComponent != null) { + sourceProp = outerComponent.getProperty(sourceName); + } else { + sourceProp = parentComposite.getProperty(sourceName); + } + if (sourceProp == null) { + Monitor.error(monitor, + this, + Messages.ASSEMBLY_VALIDATION, + "PropertySourceNotFound", + source, + componentProperty.getName(), + component.getName()); + } else { + + Document sourcePropValue = (Document)sourceProp.getValue(); + + try { + // FIXME: How to deal with namespaces? + Document node = + evaluateXPath2(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()); + } // end if + + } catch (Exception ex) { + Monitor.error(monitor, + this, + Messages.ASSEMBLY_VALIDATION, + "PropertySourceXpathInvalid", + source, + componentProperty.getName(), + component.getName(), + ex); + } // end try + } // end if + } catch (IllegalArgumentException e ) { + Monitor.error(monitor, + this, + Messages.ASSEMBLY_VALIDATION, + "PropertySourceValueInvalid", + source, + componentProperty.getName(), + component.getName()); + } // end try + } // end method + + /** + * Extracts the name of the source property from the value of an @source attribute string + * @param source - the value of the @source attribute + * @return - the source property name as a String + */ + private String extractSourcePropertyName( String source ) throws IllegalArgumentException { + String propertyName = null; + + // Possible values for the source string: + // a) $name + // b) $name/expression + // c) $name[xx] + // d) $name[xx]/expression + // ...and note that the expression MAY contain '/' and '[' characters + if( source.charAt(0) != '$' ) throw new IllegalArgumentException("Source value does not start with '$'"); + + int index = source.indexOf('/'); + int bracket = source.indexOf('['); + + if( index == -1 && bracket == -1 ) { + // Format a) - simply remove the '$' + propertyName = source.substring(1); + } else if ( bracket == -1 ) { + // Format b) - remove the '$' and the '/' and everything following it + propertyName = source.substring(1, index); + } else if ( index == -1 ) { + // Format c) - remove the '$' and the '[' and everything following it + propertyName = source.substring(1, bracket); + } else { + // Format d) - but need to ensure that the '[' is BEFORE the '/' + if( bracket < index ) { + // Format d) - remove the '$' and the '[' and everything following it + propertyName = source.substring(1, bracket); + } else { + // Format b) variant where there is a '[' in the expression... + propertyName = source.substring(1, index); + } // end if + } // end if + + return propertyName; + } // end method extractSourcePropertyName( source, monitor ) + + /** + * If the property has a file attribute use this to retrieve the property value from a local file + * Format of the property value file is defined in the SCA Assembly specification in ASM50046 + * + * @param component the component holding the property + * @param componentProperty - the property + * @param monitor - a Monitor object for reporting problems + */ + /** + * Property file format: + * MUST contain a <sca:values/> element + * - either contains one or more <sca:value/> subelements (mandatory for property with a simple XML type) + * - or contains one or more global elements of the type of the property + * + * eg. + * <?xml version="1.0" encoding="UTF-8"?> + * <values> + * <value>MyValue</value> + * </values> + * + * <?xml version="1.0" encoding="UTF-8"?> + * <values> + * <foo:fooElement> + * <foo:a>AValue</foo:a> + * <foo:b>InterestingURI</foo:b> + * </foo:fooElement> + * </values/> + */ + private void processPropertyFileAttribute(Component component, ComponentProperty componentProperty, Monitor monitor) { + String file = componentProperty.getFile(); + if (file == null) return; + 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(); +*/ + Document document = readPropertyFileData( file ); + + Element docElement = document.getDocumentElement(); + if( docElement == null ) throw new Exception("Property File has no XML document element"); + + if( !"values".equals( docElement.getLocalName() ) ) { + throw new Exception("Property File does not start with <values/> element"); + } // end if + + // The property value is the subelement(s) of the <values/> element + NodeList values = docElement.getChildNodes(); + + Document newdoc = documentBuilderFactory.newDocumentBuilder().newDocument(); + Element newProperty = newdoc.createElementNS(SCA11_NS, "property"); + newdoc.appendChild( newProperty ); + + int count = 0; + + // Copy the property values under the new <property/> element + for( int i = 0 ; i < values.getLength() ; i++ ) { + Node valueNode = values.item(i); + // Only <value/> elements or global elements are valid values... + if( valueNode.getNodeType() == Node.ELEMENT_NODE ) { + newProperty.appendChild(newdoc.importNode(values.item(i), true)); + count++; + } // end if + } // end for + + if( count == 0 ) { + throw new Exception("Property File has no property values"); + } // end if + + componentProperty.setValue(newdoc); + +/* + // 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(); + } + } // end try +*/ + } catch (Exception ex) { + Monitor.error(monitor, + this, + Messages.ASSEMBLY_VALIDATION, + "PropertyFileValueInvalid", + file, + componentProperty.getName(), + component.getName(), + ex); + } // end try + } // end method processPropertyFileAttribute + + private Document readPropertyFileData( String file ) throws Exception { + Document doc = null; + + 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); + + doc = (Document)result.getNode(); + } finally { + if (is != null) { + is.close(); + } + } // end try + + return doc; + } // end method readPropertyFileData + + /** + * 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; + } + } + + /** + * Evaluate an XPath expression against a Property value, returning the result as a Property value + * - deals with multi-valued input property values and with multi-valued output property values + * @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 evaluateXPath2(Document node, + XPathExpression expression, + DocumentBuilderFactory documentBuilderFactory) throws XPathExpressionException, + ParserConfigurationException { + + // The document element is a <sca:property/> element + Element property = node.getDocumentElement(); + + NodeList result = (NodeList)expression.evaluate(property, XPathConstants.NODESET); + if (result == null || result.getLength() == 0) return null; + + if (result instanceof Document) { + return (Document)result; + } else { + Document document = documentBuilderFactory.newDocumentBuilder().newDocument(); + Element newProperty = document.createElementNS(SCA11_NS, "property"); + + for( int i = 0 ; i < result.getLength() ; i++ ) { + if (result.item(i).getNodeType() == Node.ELEMENT_NODE) { + // If the result is an element, use it directly in the result + newProperty.appendChild(document.importNode(result.item(i), true)); + } else { + // If the result is not an element, create a <value/> element to contain the result + Element newValue = document.createElementNS(SCA11_NS, "value"); + newValue.appendChild(document.importNode(result.item(i), true)); + newProperty.appendChild(newValue); + } // end if + } // end for + + document.appendChild(newProperty); + + return document; + } // end if + } // end method + + /** + * Create a callback reference for a component service + * + * @param component + * @param service + */ + private void createCallbackReference(Component component, ComponentService service, Monitor monitor) { + + // 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()); + // MJE: multiplicity = 0..n for these callback references + callbackReference.setMultiplicity(Multiplicity.ZERO_N); + 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()); + + // Get the promoted component reference corresponding to the service with the callback + // fist checking that the promoted service is resolved lest we get a NPE trying to + // retrieve the promoted component. It could be unresolved if the user gets the + // promotes string wrong + // TODO - is there any danger that the callback reference name will clash with other + // reference names. Old code used to qualify it with promoted component name + if (((CompositeService)implService).getPromotedService().isUnresolved() == false){ + String referenceName = ((CompositeService)implService).getPromotedService().getName(); + ComponentReference promotedReference = ((CompositeService)implService).getPromotedComponent().getReference(referenceName); + + if (promotedReference != null){ + implCompReference.getPromotedReferences().add(promotedReference); + } else { + Monitor.error(monitor, + this, + Messages.ASSEMBLY_VALIDATION, + "PromotedCallbackReferenceNotFound", + component.getName(), + service.getName(), + ((CompositeService)implService).getPromotedComponent().getName(), + referenceName); + } + } + 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()); + // MJE: Fixup multiplicity as 0..n for callback references in the component type + implReference.setMultiplicity(Multiplicity.ZERO_N); + 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 + // at runtime a callback binding will be selected based on the forward call + if (service.getCallback() != null && service.getCallback().getBindings().size() > 0) { + callbackReference.getBindings().addAll(service.getCallback().getBindings()); + } else { + // otherwise take a copy of all the bindings on the forward service + // at runtime a callback binding will be selected based on the forward call + List<Binding> serviceBindings = service.getBindings(); + for ( Binding serviceBinding: serviceBindings ) { + try { + Binding referenceBinding = (Binding)serviceBinding.clone(); + referenceBinding.setURI(null); + callbackReference.getBindings().add(referenceBinding); + } catch (CloneNotSupportedException e) { + // will not happen + } // end try + } // end for + + // if there are still no bindings for the callback create a default binding which + // will cause the EPR for this reference to be marked as EndpointReference.NOT_CONFIGURED + if( serviceBindings.size() == 0 ) { + createSCABinding(callbackReference, null); + } // end if + } + } + service.setCallbackReference(callbackReference); + } + } + + /** + * Create a callback service for a component reference + * + * @param component + * @param service + */ + private void createCallbackService(Component component, ComponentReference reference, Monitor monitor) { + if (reference.getInterfaceContract() != null && // can be null in unit tests + reference.getInterfaceContract().getCallbackInterface() != null) { + ComponentService callbackService = assemblyFactory.createComponentService(); + callbackService.setForCallback(true); + callbackService.setName(reference.getName()); + try { + InterfaceContract contract = (InterfaceContract)reference.getInterfaceContract().clone(); + contract.setInterface(contract.getCallbackInterface()); + contract.setCallbackInterface(null); + callbackService.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); + + // Get the promoted component service corresponding to the reference with the callback + // fist checking that the promoted reference is resolved lest we get a NPE trying to + // retrieve the promoted component. It could be unresolved if the user gets the + // promotes string wrong + if (((CompositeReference)implReference).getPromotedReferences().get(0).isUnresolved() == false){ + String serviceName = ((CompositeReference)implReference).getPromotedReferences().get(0).getName(); + ComponentService promotedService = ((CompositeReference)implReference).getPromotedComponents().get(0).getService(serviceName); + + if (promotedService != null){ + implCompService.setPromotedService(promotedService); + } else { + Monitor.error(monitor, + this, + Messages.ASSEMBLY_VALIDATION, + "PromotedCallbackServiceNotFound", + component.getName(), + reference.getName(), + ((CompositeReference)implReference).getPromotedComponents().get(0).getName(), + serviceName); + } + } + + 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 + } + callbackService.setService(implService); + } + component.getServices().add(callbackService); + + // configure bindings for the callback service + if (callbackService.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 + callbackService.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); + callbackService.getBindings().add(clonedBinding); + } catch (CloneNotSupportedException ex) { + + } + } + } else { + // create a default binding which will have the correct policy + // and URI added. We check later to see if a new binding is required + // based on the forward binding but can then copy policy and URI + // details from here. + // TODO - there is a hole here. If the user explicitly specified an + // SCA callback binding that is different from the forward + // binding type then we're in trouble + createSCABinding(callbackService, null); + } + } + + reference.setCallbackService(callbackService); + } + } + + /** + * 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 = checkSubsetCompatibility(topInterfaceContract, + bottomInterfaceContract); + } catch (IncompatibleInterfaceContractException ex){ + isCompatible = false; + incompatibilityReason = ex.getMessage(); + } + if (!isCompatible) { + Monitor.error(monitor, + this, + Messages.ASSEMBLY_VALIDATION, + "ServiceIncompatibleComponentInterface", + component.getName(), + topContract.getName(), + incompatibilityReason); + } + + // TODO - there is an issue with the following code if the + // contracts are of different types. Need to use the + // normalized form + + // fix up the forward interface based on the promoted component + // Someone might have manually specified a callback interface but + // left out the forward interface + if (topInterfaceContract.getInterface() == null){ + topInterfaceContract.setInterface(bottomInterfaceContract.getInterface()); + } + + // fix up the callback interface based on the promoted component + // Someone might have manually specified a forward interface but + // left out the callback interface + if (topInterfaceContract.getCallbackInterface() == null){ + topInterfaceContract.setCallbackInterface(bottomInterfaceContract.getCallbackInterface()); + } + } + } + + /** + * Interface contract from higher in the implementation hierarchy takes precedence + * When it comes to checking compatibility the top level reference interface is a + * superset of the promoted reference interface so treat the promoted + * (bottom) interface as the source + * + * @param topContract the top contract + * @param bottomContract the bottom contract + */ + private void 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 = checkSubsetCompatibility(bottomInterfaceContract, + topInterfaceContract); + } catch (IncompatibleInterfaceContractException ex){ + isCompatible = false; + incompatibilityReason = ex.getMessage(); + } + if (!isCompatible) { + Monitor.error(monitor, + this, + Messages.ASSEMBLY_VALIDATION, + "ReferenceIncompatibleComponentInterface", + component.getName(), + topContract.getName(), + incompatibilityReason); + } + + // TODO - there is an issue with the following code if the + // contracts of of different types. Need to use the + // normalized form + + // fix up the forward interface based on the promoted component + // Someone might have manually specified a callback interface but + // left out the forward interface + if (topInterfaceContract.getInterface() == null){ + topInterfaceContract.setInterface(bottomInterfaceContract.getInterface()); + } + + // fix up the callback interface based on the promoted component + // Someone might have manually specified a forward interface but + // left out the callback interface + if (topInterfaceContract.getCallbackInterface() == null){ + topInterfaceContract.setCallbackInterface(bottomInterfaceContract.getCallbackInterface()); + } + } + } + + /** + * Bindings from higher in the hierarchy take precedence + * + * @param componentService the top service + * @param componentTypeService the bottom service + */ + private void calculateBindings(Component component, Service componentService, Service componentTypeService, BuilderContext context) { + Monitor monitor = context.getMonitor(); + + // forward bindings + if (componentService.getBindings().isEmpty()) { + componentService.getBindings().addAll(componentTypeService.getBindings()); + } + + if (componentService.getBindings().isEmpty()) { + createSCABinding(componentService, context.getDefinitions()); + } + + // 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()); + } + } + + /** + * A local wrapper for the interface contract mapper as we need to normalize the + * interface contracts if appropriate and the mapper doesn't have the right + * dependencies to be able to do it. + * + * Sometimes the two interfaces can be presented using different IDLs, for example + * Java and WSDL. In this case interfaces are converted so that they are both WSDL1.1 interfaces + * and they are then compared. The generated WSDL is cached on the interface object for + * any subsequent matching + * + * @param contractA + * @param contractB + * @return true if the interface contracts match + */ + private boolean checkSubsetCompatibility(InterfaceContract contractA, InterfaceContract contractB) + throws IncompatibleInterfaceContractException { + + if (contractA.getClass() != contractB.getClass()) { + + if (contractA instanceof JavaInterfaceContract){ + contractBuilder.build(contractA, null); + contractA = ((JavaInterfaceContract)contractA).getNormalizedWSDLContract(); + } + + if (contractB instanceof JavaInterfaceContract){ + contractBuilder.build(contractB, null); + contractB = ((JavaInterfaceContract)contractB).getNormalizedWSDLContract(); + } + } + + return interfaceContractMapper.checkCompatibility(contractA, + contractB, + Compatibility.SUBSET, + false, + false); + } + +} diff --git a/sandbox/sebastien/java/wrapped/modules/builder/src/main/java/org/apache/tuscany/sca/builder/impl/ComponentPolicyBuilderImpl.java b/sandbox/sebastien/java/wrapped/modules/builder/src/main/java/org/apache/tuscany/sca/builder/impl/ComponentPolicyBuilderImpl.java new file mode 100644 index 0000000000..6ce0a3a7d5 --- /dev/null +++ b/sandbox/sebastien/java/wrapped/modules/builder/src/main/java/org/apache/tuscany/sca/builder/impl/ComponentPolicyBuilderImpl.java @@ -0,0 +1,582 @@ +/* + * 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.EndpointReference; +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 ((intent.getType() != null) && (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; + } + + // Replace qualifiable intents with their default qualifier. This can't be done until + // after inheritance. + protected void expandDefaultIntents(PolicySubject subject, BuilderContext context) { + + Set<Intent> copy = new HashSet<Intent>(subject.getRequiredIntents()); + for (Intent i : copy) { + if (i.getDefaultQualifiedIntent() != null) { + subject.getRequiredIntents().remove(i); + subject.getRequiredIntents().add(i.getDefaultQualifiedIntent()); + } + } + } + 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()); + } + + } + + + 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) { + List<ExtensionType> constrainedTypes = i.getConstrainedTypes(); + if (( constrainedTypes.size() == 0 ) && ( i.getQualifiableIntent() != null ) ) + constrainedTypes = i.getQualifiableIntent().getConstrainedTypes(); + + if (constrainedTypes.size() > 0){ + boolean constraintFound = false; + for (ExtensionType constrainedType : constrainedTypes){ + 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){ + + // Reference side intents can still be resolved by the service binding, so we can only issue a + // warning here. + if ( subject instanceof EndpointReference ) { + warning(context.getMonitor(), "IntentNotSatisfiedAtBuild", subject, intent.getName(), subject.toString()); + } else { + // Need to check the ExtensionType to see if the intent is provided there. If not, throw an error + ExtensionType type = subject.getExtensionType(); + + + if ( type == null ) { + error(context.getMonitor(), "IntentNotSatisfiedAtBuild", subject, intent.getName(), subject.toString()); + } else { + // The ExtensionType on the subject only has the binding name. The one in the system + // definitions will have the mayProvide/alwaysProvides values + for ( ExtensionType et : context.getDefinitions().getBindingTypes() ) { + if ( type.getType().equals(et.getType()) ) { + type = et; + } + } + + if ( !type.getAlwaysProvidedIntents().contains(intent) && !type.getMayProvidedIntents().contains(intent)) { + error(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/sandbox/sebastien/java/wrapped/modules/builder/src/main/java/org/apache/tuscany/sca/builder/impl/ComponentReferenceBindingBuilderImpl.java b/sandbox/sebastien/java/wrapped/modules/builder/src/main/java/org/apache/tuscany/sca/builder/impl/ComponentReferenceBindingBuilderImpl.java new file mode 100644 index 0000000000..38ab265c6e --- /dev/null +++ b/sandbox/sebastien/java/wrapped/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, false); + } + } + } + } + + // build bindings recursively + for (Component component : composite.getComponents()) { + Implementation implementation = component.getImplementation(); + if (implementation instanceof Composite) { + buildReferenceBindings((Composite)implementation, context); + } + } + } + +} diff --git a/sandbox/sebastien/java/wrapped/modules/builder/src/main/java/org/apache/tuscany/sca/builder/impl/ComponentServiceBindingBuilderImpl.java b/sandbox/sebastien/java/wrapped/modules/builder/src/main/java/org/apache/tuscany/sca/builder/impl/ComponentServiceBindingBuilderImpl.java new file mode 100644 index 0000000000..2debe41f2d --- /dev/null +++ b/sandbox/sebastien/java/wrapped/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, false); + } + } + } + } + } + +} diff --git a/sandbox/sebastien/java/wrapped/modules/builder/src/main/java/org/apache/tuscany/sca/builder/impl/CompositeCloneBuilderImpl.java b/sandbox/sebastien/java/wrapped/modules/builder/src/main/java/org/apache/tuscany/sca/builder/impl/CompositeCloneBuilderImpl.java new file mode 100644 index 0000000000..148a3b5368 --- /dev/null +++ b/sandbox/sebastien/java/wrapped/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/sandbox/sebastien/java/wrapped/modules/builder/src/main/java/org/apache/tuscany/sca/builder/impl/CompositeComponentTypeBuilderImpl.java b/sandbox/sebastien/java/wrapped/modules/builder/src/main/java/org/apache/tuscany/sca/builder/impl/CompositeComponentTypeBuilderImpl.java new file mode 100644 index 0000000000..f87854cac4 --- /dev/null +++ b/sandbox/sebastien/java/wrapped/modules/builder/src/main/java/org/apache/tuscany/sca/builder/impl/CompositeComponentTypeBuilderImpl.java @@ -0,0 +1,696 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.tuscany.sca.builder.impl; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.logging.Logger; + +import javax.xml.namespace.QName; + +import org.apache.tuscany.sca.assembly.AssemblyFactory; +import org.apache.tuscany.sca.assembly.Binding; +import org.apache.tuscany.sca.assembly.Component; +import org.apache.tuscany.sca.assembly.ComponentReference; +import org.apache.tuscany.sca.assembly.ComponentService; +import org.apache.tuscany.sca.assembly.ComponentType; +import org.apache.tuscany.sca.assembly.Composite; +import org.apache.tuscany.sca.assembly.CompositeReference; +import org.apache.tuscany.sca.assembly.CompositeService; +import org.apache.tuscany.sca.assembly.Contract; +import org.apache.tuscany.sca.assembly.Multiplicity; +import org.apache.tuscany.sca.assembly.Reference; +import org.apache.tuscany.sca.assembly.SCABinding; +import org.apache.tuscany.sca.assembly.SCABindingFactory; +import org.apache.tuscany.sca.assembly.Service; +import org.apache.tuscany.sca.assembly.builder.BuilderContext; +import org.apache.tuscany.sca.assembly.builder.BuilderExtensionPoint; +import org.apache.tuscany.sca.assembly.builder.ContractBuilder; +import org.apache.tuscany.sca.assembly.builder.Messages; +import org.apache.tuscany.sca.core.ExtensionPointRegistry; +import org.apache.tuscany.sca.core.FactoryExtensionPoint; +import org.apache.tuscany.sca.core.UtilityExtensionPoint; +import org.apache.tuscany.sca.definitions.Definitions; +import org.apache.tuscany.sca.interfacedef.Compatibility; +import org.apache.tuscany.sca.interfacedef.IncompatibleInterfaceContractException; +import org.apache.tuscany.sca.interfacedef.InterfaceContract; +import org.apache.tuscany.sca.interfacedef.InterfaceContractMapper; +import org.apache.tuscany.sca.interfacedef.java.JavaInterfaceContract; +import org.apache.tuscany.sca.monitor.Monitor; +import org.apache.tuscany.sca.policy.ExtensionType; +import org.apache.tuscany.sca.policy.PolicySubject; + +/** + * @version $Rev$ $Date$ + */ + +// TODO - really implementation.composite component type builder - CompositeComponentTypeBuilder? + +public class CompositeComponentTypeBuilderImpl { + private static final Logger logger = Logger.getLogger(CompositeComponentTypeBuilderImpl.class.getName()); + + protected static final String SCA11_NS = "http://docs.oasis-open.org/ns/opencsa/sca/200912"; + protected static final String BINDING_SCA = "binding.sca"; + protected static final QName BINDING_SCA_QNAME = new QName(SCA11_NS, BINDING_SCA); + + private ComponentBuilderImpl componentBuilder; + private AssemblyFactory assemblyFactory; + private SCABindingFactory scaBindingFactory; + private InterfaceContractMapper interfaceContractMapper; + private BuilderExtensionPoint builders; + private ContractBuilder contractBuilder; + + public CompositeComponentTypeBuilderImpl(ExtensionPointRegistry registry) { + UtilityExtensionPoint utilities = registry.getExtensionPoint(UtilityExtensionPoint.class); + + FactoryExtensionPoint modelFactories = registry.getExtensionPoint(FactoryExtensionPoint.class); + assemblyFactory = modelFactories.getFactory(AssemblyFactory.class); + scaBindingFactory = modelFactories.getFactory(SCABindingFactory.class); + + interfaceContractMapper = utilities.getUtility(InterfaceContractMapper.class); + builders = registry.getExtensionPoint(BuilderExtensionPoint.class); + contractBuilder = builders.getContractBuilder(); + } + + public void setComponentBuilder(ComponentBuilderImpl componentBuilder) { + this.componentBuilder = componentBuilder; + } + + /** + * Calculate the component type for the provided implementation + * + * @param implementation + * @return component type + */ + public void createComponentType(Component outerComponent, Composite composite, BuilderContext context) { + + Monitor monitor = context.getMonitor(); + monitor.pushContext("Composite: " + composite.getName().toString()); + + try { + // first make sure that each child component has been properly configured based + // on its own component type + for (Component component : composite.getComponents()) { + + // Check for duplicate component names + if (component != composite.getComponent(component.getName())) { + Monitor.error(monitor, + this, + Messages.ASSEMBLY_VALIDATION, + "DuplicateComponentName", + composite.getName().toString(), + component.getName()); + } + + // do any work we need to do before we configure the component + // Anything that needs to be pushed down the promotion + // hierarchy must be done before we configure the component + + // Push down the autowire flag from the composite to components + if (component.getAutowire() == null) { + component.setAutowire(composite.getAutowire()); + } + + // configure the component from its component type + componentBuilder.configureComponentFromComponentType(outerComponent, composite, component, context); + } + + // create the composite component type based on the promoted artifacts + // from the components that it contains + + // index all the components, services and references in the + // component type so that they are easy to find + Map<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 = checkSubsetCompatibility(topInterfaceContract, bottomInterfaceContract); + } catch (IncompatibleInterfaceContractException ex){ + isCompatible = false; + incompatibilityReason = ex.getMessage(); + } + if (!isCompatible) { + Monitor.error(monitor, + this, + Messages.ASSEMBLY_VALIDATION, + "ServiceInterfaceNotSubSet", + topContract.getName(), + incompatibilityReason); + } + + // TODO - there is an issue with the following code if the + // contracts of of different types. Need to use the + // normalized form + + // fix up the forward interface based on the promoted component + // Someone might have manually specified a callback interface but + // left out the forward interface + if (topInterfaceContract.getInterface() == null){ + topInterfaceContract.setInterface(bottomInterfaceContract.getInterface()); + } + + // fix up the callback interface based on the promoted component + // Someone might have manually specified a forward interface but + // left out the callback interface + if (topInterfaceContract.getCallbackInterface() == null){ + topInterfaceContract.setCallbackInterface(bottomInterfaceContract.getCallbackInterface()); + } + } + } + + /** + * Interface contract from higher in the implementation hierarchy takes precedence. + * When it comes to checking compatibility the top level reference interface is a + * superset of the promoted reference interface so treat the promoted + * (bottom) interface as the source + * + * @param topContract the top contract + * @param bottomContract the bottom contract + */ + private void calculatePromotedReferenceInterfaceContract(Reference topContract, Reference bottomContract, 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 = checkSubsetCompatibility(bottomInterfaceContract, topInterfaceContract); + } catch (IncompatibleInterfaceContractException ex){ + isCompatible = false; + incompatibilityReason = ex.getMessage(); + } + if (!isCompatible) { + Monitor.error(monitor, + this, + Messages.ASSEMBLY_VALIDATION, + "ReferenceInterfaceNotSubSet", + topContract.getName(), + incompatibilityReason); + } + + // TODO - there is an issue with the following code if the + // contracts of of different types. Need to use the + // normalized form + + // fix up the forward interface based on the promoted component + // Someone might have manually specified a callback interface but + // left out the forward interface + if (topInterfaceContract.getInterface() == null){ + topInterfaceContract.setInterface(bottomInterfaceContract.getInterface()); + } + + // fix up the callback interface based on the promoted component + // Someone might have manually specified a forward interface but + // left out the callback interface + if (topInterfaceContract.getCallbackInterface() == null){ + topInterfaceContract.setCallbackInterface(bottomInterfaceContract.getCallbackInterface()); + } + } + } + + /** + * Bindings from higher in the implementation hierarchy take precedence + * + * @param compositeService + * @param promotedComponentService + */ + private void calculatePromotedBindings(CompositeService compositeService, ComponentService promotedComponentService) { + // forward bindings + if (compositeService.getBindings().isEmpty()) { + for (Binding binding : promotedComponentService.getBindings()) { + try { + compositeService.getBindings().add((Binding)binding.clone()); + } catch (CloneNotSupportedException ex) { + // this binding can't be used in the promoted service + } + } + } + + if (compositeService.getBindings().isEmpty()) { + createSCABinding(compositeService, null); + } + + // callback bindings + if (promotedComponentService.getCallback() != null) { + if (compositeService.getCallback() != null) { + compositeService.getCallback().getBindings().clear(); + } else { + compositeService.setCallback(assemblyFactory.createCallback()); + } + + for (Binding binding : promotedComponentService.getCallback().getBindings()) { + try { + compositeService.getCallback().getBindings().add((Binding)binding.clone()); + } catch (CloneNotSupportedException ex) { + // this binding can't be used in the promoted service + } + } + } + } + + private void reconcileReferenceMultiplicity(ComponentType componentType, + Reference compositeReference, + Reference promotedComponentReference, + Monitor monitor) { + if (compositeReference.getMultiplicity() != null) { + if (!isValidMultiplicityOverride(promotedComponentReference.getTargets().size() > 0, + promotedComponentReference.getMultiplicity(), + compositeReference.getMultiplicity())) { + Monitor.error(monitor, + this, + Messages.ASSEMBLY_VALIDATION, + "CompositeReferenceIncompatibleMultiplicity", + componentType.getURI(), + compositeReference.getName(), + promotedComponentReference.getName()); + } + } else { + compositeReference.setMultiplicity(promotedComponentReference.getMultiplicity()); + } + } + + private boolean isValidMultiplicityOverride(boolean componentRefHasTarget, + Multiplicity componentRefMul, + Multiplicity compositeRefMul) { + if ((componentRefMul != null) && + (compositeRefMul != null) && + componentRefMul != compositeRefMul) { + if (componentRefHasTarget){ + switch (componentRefMul) { + case ZERO_ONE: + return compositeRefMul == Multiplicity.ZERO_ONE || + compositeRefMul == Multiplicity.ONE_ONE; + case ONE_ONE: + return compositeRefMul == Multiplicity.ZERO_ONE || + compositeRefMul == Multiplicity.ONE_ONE; + case ZERO_N: + return true; + case ONE_N: + return true; + default: + return false; + } + } else { + switch (componentRefMul) { + case ZERO_ONE: + return compositeRefMul == Multiplicity.ONE_ONE; + case ONE_ONE: + return compositeRefMul == Multiplicity.ONE_ONE; + case ZERO_N: + return true; + case ONE_N: + return compositeRefMul == Multiplicity.ONE_ONE || + compositeRefMul == Multiplicity.ONE_N; + + default: + return false; + } + } + } else { + return true; + } + } + + /** + * ASM50042 - Checks that if a component reference with multiplicity="1..1" is marked + * as nonOveridable then there are no composite references that promote it + * + * @param componentType + * @param compositeReference + * @param promotedComponentReference + * @param monitor + */ + private void validateNonOverridable(ComponentType componentType, + Reference compositeReference, + Reference promotedComponentReference, + Monitor monitor){ + if ((promotedComponentReference.getMultiplicity() == Multiplicity.ONE_ONE) && + (((ComponentReference)promotedComponentReference)).isNonOverridable() == true) { + Monitor.error(monitor, + this, + Messages.ASSEMBLY_VALIDATION, + "CompositeReferencePromotesNonOverridableReference", + componentType.getURI(), + compositeReference.getName(), + promotedComponentReference.getName()); + } + } + + /** + * A local wrapper for the interface contract mapper as we need to normalize the + * interface contracts if appropriate and the mapper doesn't have the right + * dependencies to be able to do it. + * + * Sometimes the two interfaces can be presented using different IDLs, for example + * Java and WSDL. In this case interfaces are converted so that they are both WSDL1.1 interfaces + * and they are then compared. The generated WSDL is cached on the interface object for + * any subsequent matching + * + * @param contractA + * @param contractB + * @return true if the interface contracts match + */ + private boolean checkSubsetCompatibility(InterfaceContract contractA, InterfaceContract contractB) + throws IncompatibleInterfaceContractException { + + if (contractA.getClass() != contractB.getClass()) { + + if (contractA instanceof JavaInterfaceContract){ + contractBuilder.build(contractA, null); + contractA = ((JavaInterfaceContract)contractA).getNormalizedWSDLContract(); + } + + if (contractB instanceof JavaInterfaceContract){ + contractBuilder.build(contractB, null); + contractB = ((JavaInterfaceContract)contractB).getNormalizedWSDLContract(); + } + } + + return interfaceContractMapper.checkCompatibility(contractA, + contractB, + Compatibility.SUBSET, + false, + false); + } + +} //end class diff --git a/sandbox/sebastien/java/wrapped/modules/builder/src/main/java/org/apache/tuscany/sca/builder/impl/CompositeIncludeBuilderImpl.java b/sandbox/sebastien/java/wrapped/modules/builder/src/main/java/org/apache/tuscany/sca/builder/impl/CompositeIncludeBuilderImpl.java new file mode 100644 index 0000000000..63864e5832 --- /dev/null +++ b/sandbox/sebastien/java/wrapped/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/sandbox/sebastien/java/wrapped/modules/builder/src/main/java/org/apache/tuscany/sca/builder/impl/CompositePolicyBuilderImpl.java b/sandbox/sebastien/java/wrapped/modules/builder/src/main/java/org/apache/tuscany/sca/builder/impl/CompositePolicyBuilderImpl.java new file mode 100644 index 0000000000..9c4da518d7 --- /dev/null +++ b/sandbox/sebastien/java/wrapped/modules/builder/src/main/java/org/apache/tuscany/sca/builder/impl/CompositePolicyBuilderImpl.java @@ -0,0 +1,477 @@ +/* + * 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 java.util.Set; + +import javax.xml.namespace.QName; + +import org.apache.tuscany.sca.assembly.Base; +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.assembly.xml.Constants; +import org.apache.tuscany.sca.core.ExtensionPointRegistry; +import org.apache.tuscany.sca.interfacedef.Operation; +import org.apache.tuscany.sca.monitor.Monitor; +import org.apache.tuscany.sca.policy.Intent; +import org.apache.tuscany.sca.policy.PolicySet; +import org.apache.tuscany.sca.policy.PolicySubject; +import org.apache.tuscany.sca.policy.util.PolicyHelper; + +/** + * 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 final static QName NOLISTENER_INTENT = new QName(Base.SCA11_NS, "noListener"); + 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()) { + + + // Inherit from binding + inherit(ep, null, true, ep.getBinding()); + + // Inherit from composite/component/service + inherit(ep, null, true, ep.getService(), ep.getComponent(), composite ); + + if (componentService.getInterfaceContract() != null) { + // Inherit from the component.service.interface + // Do not check mutual exclusion here.. interfaces do not follow normal rules + // of the structural hierarchy (Policy spec 4.10) + inherit(ep, null, false, componentService.getInterfaceContract().getInterface()); + } + + // 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); + + // Replace qualifiable intents with their default qualifier + expandDefaultIntents(ep, context); + + // Remove the intents whose @contraints do not include the current element + removeConstrainedIntents(ep, context); + + // Remove any direct policy sets if an external one has been applied + removeDirectPolicySetsIfExternalExists(ep, context); + + // Validate that noListener is not specified on a service endpoint + checkForNoListenerIntent(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 binding + inherit(epr, null, true, epr.getBinding()); + + // Inherit from composite/component/reference + inherit(epr, null, true, epr.getReference(), epr.getComponent(), composite); + + // Inherit from the component.reference.interface + if (componentReference.getInterfaceContract() != null) { + // Do not check mutual exclusion here.. interfaces do not follow normal rules + // of the structural hierarchy (Policy spec 4.10) + inherit(epr, null, true, componentReference.getInterfaceContract().getInterface()); + } + + // 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); + + // Replace qualifiable intents with their default qualifier + expandDefaultIntents(epr, context); + + // Remove the intents whose @contraints do not include the current element + removeConstrainedIntents(epr, context); + + removeDirectPolicySetsIfExternalExists(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) { + resolveAndCheck(implementation, context); + inherit(implementation, Intent.Type.implementation, true, component, composite); + computePolicies((Composite)implementation, context); + expandDefaultIntents(implementation,context); + checkIntentsResolved(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); + + removeDirectPolicySetsIfExternalExists(implementation, context); + + // Replace qualifiable intents with their default qualifier + expandDefaultIntents(implementation, context); + + // check that all intents are resolved + checkIntentsResolved(implementation, context); + } + } + } finally { + monitor.popContext(); + } + } + removeConstrainedIntents(composite, context); + } finally { + monitor.popContext(); + } + } + + private void validateTransactionIntents(Composite composite, BuilderContext context) { + + for ( Component component : composite.getComponents() ) { + if ( component.getImplementation() != null ) { + if ( component.getImplementation() instanceof Composite ) + validateTransactionIntents((Composite) component.getImplementation(), context); + + for ( Intent implIntent : component.getImplementation().getRequiredIntents() ) { + if ( Constants.MANAGED_TRANSACTION_LOCAL_INTENT.equals(implIntent.getName() ) ) { + for ( ComponentReference reference : component.getReferences() ) { + for ( EndpointReference epr : reference.getEndpointReferences() ) { + for ( Intent eprIntent : epr.getRequiredIntents() ) { + if ( Constants.TRANSACTED_ONE_WAY_INTENT.equals(eprIntent.getName())) { + error(context.getMonitor(), + "TransactedOneWayWithManagedTransactionLocal", + this, + "reference", + epr.getComponent().getName(), + epr.getReference().getName()); + } else if ( Constants.PROPAGATES_TRANSACTION_INTENT.equals(eprIntent.getName())) { + error(context.getMonitor(), + "PropagatesTransactionWithLocalTran", + this, + "reference", + epr.getComponent().getName(), + epr.getReference().getName()); + } + } + } + } + for ( ComponentService service : component.getServices() ) { + for ( Endpoint ep : service.getEndpoints() ) { + for ( Intent epIntent : ep.getRequiredIntents() ) { + if ( Constants.TRANSACTED_ONE_WAY_INTENT.equals(epIntent.getName())) { + error(context.getMonitor(), + "TransactedOneWayWithManagedTransactionLocal", + this, + "service", + ep.getComponent().getName(), + ep.getService().getName()); + } else if ( Constants.PROPAGATES_TRANSACTION_INTENT.equals(epIntent.getName())) { + error(context.getMonitor(), + "PropagatesTransactionWithLocalTran", + this, + "service", + ep.getComponent().getName(), + ep.getService().getName()); + } + } + } + } + } else if ( Constants.NO_MANAGED_TRANSACTION_INTENT.equals(implIntent.getName())) { + for ( ComponentService service : component.getServices() ) { + for ( Endpoint ep : service.getEndpoints() ) { + for ( Intent epIntent : ep.getRequiredIntents() ) { + if ( Constants.PROPAGATES_TRANSACTION_INTENT.equals(epIntent.getName())) { + error(context.getMonitor(), + "PropagatesTransactionWithNoManagedTran", + this, + "service", + ep.getComponent().getName(), + ep.getService().getName()); + } + } + } + } + for ( ComponentReference reference : component.getReferences() ) { + for ( EndpointReference epr : reference.getEndpointReferences() ) { + for ( Intent eprIntent : epr.getRequiredIntents() ) { + if ( Constants.PROPAGATES_TRANSACTION_INTENT.equals(eprIntent.getName())) { + error(context.getMonitor(), + "PropagatesTransactionWithNoManagedTran", + this, + "reference", + epr.getComponent().getName(), + epr.getReference().getName()); + } + } + } + } + } + } + + + for ( ComponentReference reference : component.getReferences()) { + for ( EndpointReference epr : reference.getEndpointReferences() ) { + for ( Intent eprIntent : epr.getRequiredIntents() ) { + if ( Constants.TRANSACTED_ONE_WAY_INTENT.equals(eprIntent.getName()) ) { + for ( Operation o : epr.getComponentReferenceInterfaceContract().getInterface().getOperations() ) { + if ( !o.isNonBlocking() ) { + error(context.getMonitor(), + "TransactedOneWayWithTwoWayOp", + this, + reference.getName(), + o.getName()); + } + + } + } else if ( Constants.IMMEDIATE_ONE_WAY_INTENT.equals(eprIntent.getName())) { + for ( Operation o : epr.getComponentReferenceInterfaceContract().getInterface().getOperations() ) { + if ( !o.isNonBlocking() ) { + error(context.getMonitor(), + "ImmediateOneWayWithTwoWayOp", + this, + reference.getName(), + o.getName()); + } + + } + } + } + + } + } + } + } + } + + + + private void checkForNoListenerIntent(Endpoint ep, BuilderContext context) { + PolicyHelper helper = new PolicyHelper(); + if ( helper.getIntent(ep, NOLISTENER_INTENT) != null ) { + error(context.getMonitor(), + "NoListenerIntentSpecifiedOnService", + this, + ep.toString()); + } + + } + + private void removeDirectPolicySetsIfExternalExists(PolicySubject subject, + BuilderContext context) { + boolean foundExternalPolicySet = false; + for (PolicySet ps : subject.getPolicySets() ) { + if ( ps.isExternalAttachment() ) { + foundExternalPolicySet = true; + break; + } + } + + if ( foundExternalPolicySet ) { + List<PolicySet> copy = new ArrayList<PolicySet>(subject.getPolicySets()); + for ( PolicySet ps : copy ) { + if ( !ps.isExternalAttachment() ) { + subject.getPolicySets().remove(ps); + } + } + } + + } + + /** + * 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); + validateTransactionIntents(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/sandbox/sebastien/java/wrapped/modules/builder/src/main/java/org/apache/tuscany/sca/builder/impl/CompositeWireApplierImpl.java b/sandbox/sebastien/java/wrapped/modules/builder/src/main/java/org/apache/tuscany/sca/builder/impl/CompositeWireApplierImpl.java new file mode 100644 index 0000000000..3167b8cdb6 --- /dev/null +++ b/sandbox/sebastien/java/wrapped/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/sandbox/sebastien/java/wrapped/modules/builder/src/main/java/org/apache/tuscany/sca/builder/impl/EndpointBuilderImpl.java b/sandbox/sebastien/java/wrapped/modules/builder/src/main/java/org/apache/tuscany/sca/builder/impl/EndpointBuilderImpl.java new file mode 100644 index 0000000000..c1ba47661a --- /dev/null +++ b/sandbox/sebastien/java/wrapped/modules/builder/src/main/java/org/apache/tuscany/sca/builder/impl/EndpointBuilderImpl.java @@ -0,0 +1,137 @@ +/* + * 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 + // Callback endpoints may not be added here in the case that the + // forward reference is not yet resolved. + 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/sandbox/sebastien/java/wrapped/modules/builder/src/main/java/org/apache/tuscany/sca/builder/impl/EndpointReferenceBuilderImpl.java b/sandbox/sebastien/java/wrapped/modules/builder/src/main/java/org/apache/tuscany/sca/builder/impl/EndpointReferenceBuilderImpl.java new file mode 100644 index 0000000000..c60a497bad --- /dev/null +++ b/sandbox/sebastien/java/wrapped/modules/builder/src/main/java/org/apache/tuscany/sca/builder/impl/EndpointReferenceBuilderImpl.java @@ -0,0 +1,817 @@ +/* + * 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.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; + + 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); + } + + /** + * 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()); + + 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()) { + // create the endpoint references for this component reference + processComponentReference(composite, + component, + reference, + context); + + // we assume that endpoints have already been created so we can now + // create the links between enpoint references and endpoints that + // represent callbacks + fixUpCallbackLinks(component, + reference); + + // 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 targets 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); + } + + reference.getEndpointReferences().add(endpointRef); + continue; + } // end if + + // if it's an absolute URI then assume that it's a resolved binding + try { + URI tmpURI = new URI(uri); + if (tmpURI.isAbsolute()){ + // The user has configured a binding with an absolute URI so assume + // they know what they are doing and mark in as already resolved. + EndpointReference endpointRef = createEndpointRef(component, reference, binding, null, false); + endpointRef.setTargetEndpoint(createEndpoint(false)); + endpointRef.setStatus(EndpointReference.Status.RESOLVED_BINDING); + reference.getEndpointReferences().add(endpointRef); + continue; + } + } catch (Exception ex){ + // do nothing and go to the next bit of code + // which assumes that the URI is an SCA URI + } + + // 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); + 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()) { + // If the user has entered an incorrect promotion string an error will be reported to + // tell them but the processing will still reach here so only continue processing + // if the promotion chain is well formed + if (componentReference != null){ + 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); + 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; + } + } + } + } + } + + /** + * The SCA callback model causes services and references to be automatically created + * to present the callback services and references. These are identifiable as their names + * will match the name of the forward reference or service to which they relate. In the general + * endpoint reference and endpoint processing we will have created endpoints and endpoint references + * for these callback services and references. We now need to related forward endpoint references with + * callback endpoints and forward endpoints with callback endpoint references. Here's the model... + * + * Client Component Target Component + * Reference (with callback iface) Service (with callback iface) + * EndpointReference ----------------------------------> Endpoint + * | | + * | | + * Service \/ (for the callback) Reference \/ (for the callback) + * Endpoint <--------------------------------------------EndpointReference + * + * TODO - there are issues here with callback binding multiplicities and which callback + * endpoint is associated with which endpointreference + * + * @param reference + * @param component + */ + private void fixUpCallbackLinks (Component component, ComponentReference reference){ + + // fix up the links between endpoint references and endpoints that represent callbacks + // [rfeng] Populate the callback endpoints + if (reference.getCallbackService() != null) { + List<Endpoint> callbackEndpoints = reference.getCallbackService().getEndpoints(); + if (!callbackEndpoints.isEmpty()) { + for (EndpointReference endpointReference : reference.getEndpointReferences()){ + // [rfeng] FIXME: how to select the callback endpoints? + endpointReference.setCallbackEndpoint(callbackEndpoints.get(0)); + } + } + } + + // 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; + } + } + } + } + +}
\ No newline at end of file diff --git a/sandbox/sebastien/java/wrapped/modules/builder/src/main/java/org/apache/tuscany/sca/builder/impl/IntentValidator.java b/sandbox/sebastien/java/wrapped/modules/builder/src/main/java/org/apache/tuscany/sca/builder/impl/IntentValidator.java new file mode 100644 index 0000000000..b2f7a4ceed --- /dev/null +++ b/sandbox/sebastien/java/wrapped/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/sandbox/sebastien/java/wrapped/modules/builder/src/main/java/org/apache/tuscany/sca/builder/impl/ModelBuilderImpl.java b/sandbox/sebastien/java/wrapped/modules/builder/src/main/java/org/apache/tuscany/sca/builder/impl/ModelBuilderImpl.java new file mode 100644 index 0000000000..cf1c9cb05f --- /dev/null +++ b/sandbox/sebastien/java/wrapped/modules/builder/src/main/java/org/apache/tuscany/sca/builder/impl/ModelBuilderImpl.java @@ -0,0 +1,188 @@ +/* + * 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) + 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 - Can you attach a policy to a component and have it promoted to the + // components services and references. If yes this call is in the + // right place + 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/sandbox/sebastien/java/wrapped/modules/builder/src/main/java/org/apache/tuscany/sca/builder/impl/PolicyAppliesToBuilderImpl.java b/sandbox/sebastien/java/wrapped/modules/builder/src/main/java/org/apache/tuscany/sca/builder/impl/PolicyAppliesToBuilderImpl.java new file mode 100644 index 0000000000..1c958f70d4 --- /dev/null +++ b/sandbox/sebastien/java/wrapped/modules/builder/src/main/java/org/apache/tuscany/sca/builder/impl/PolicyAppliesToBuilderImpl.java @@ -0,0 +1,180 @@ +/* + * 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 topComposite, BuilderContext context) throws Exception { + + for ( Component component : topComposite.getComponents() ) { + if ( component.getImplementation() instanceof Composite ) { + Composite nested = (Composite) component.getImplementation(); + checkAppliesTo(saveAsDOM(nested),new HashMap<PolicySet, List<PolicySubject>>(), nested, context ); + } + } + + for (Component component : topComposite.getComponents()) { + + for (ComponentService componentService : component.getServices()) { + for (Endpoint ep : componentService.getEndpoints()) { + List<PolicySet> policySetsToRemove = checkAppliesToSubject(document, appliesToSubjects, topComposite, (PolicySubject)ep.getService(), ep.getService().getPolicySets()); + ep.getPolicySets().removeAll(policySetsToRemove); + if (ep.getBinding() instanceof PolicySubject) { + policySetsToRemove = checkAppliesToSubject(document, appliesToSubjects, topComposite, (PolicySubject)ep.getBinding(), ((PolicySubject)ep.getBinding()).getPolicySets()); + ep.getPolicySets().removeAll(policySetsToRemove); + } + } + } + + for (ComponentReference componentReference : component.getReferences()) { + for (EndpointReference epr : componentReference.getEndpointReferences()) { + List<PolicySet> policySetsToRemove = checkAppliesToSubject(document, appliesToSubjects, topComposite, (PolicySubject)epr.getReference(), epr.getReference().getPolicySets()); + epr.getPolicySets().removeAll(policySetsToRemove); + if (epr.getBinding() instanceof PolicySubject) { + policySetsToRemove = checkAppliesToSubject(document, appliesToSubjects, topComposite, (PolicySubject)epr.getBinding(), ((PolicySubject)epr.getBinding()).getPolicySets()); + epr.getPolicySets().removeAll(policySetsToRemove); + } + } + } + + Implementation implementation = component.getImplementation(); + if (implementation != null && + implementation instanceof PolicySubject) { + checkAppliesToSubject(document, appliesToSubjects, topComposite, implementation, implementation.getPolicySets()); + } + } + + return topComposite; + } + + + /** + * 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 List<PolicySet> 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); + if ( subject != null ) + 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); + return policySetsToRemove; + } +} diff --git a/sandbox/sebastien/java/wrapped/modules/builder/src/main/java/org/apache/tuscany/sca/builder/impl/PolicyAttachmentBuilderImpl.java b/sandbox/sebastien/java/wrapped/modules/builder/src/main/java/org/apache/tuscany/sca/builder/impl/PolicyAttachmentBuilderImpl.java new file mode 100644 index 0000000000..4d1a7d52b6 --- /dev/null +++ b/sandbox/sebastien/java/wrapped/modules/builder/src/main/java/org/apache/tuscany/sca/builder/impl/PolicyAttachmentBuilderImpl.java @@ -0,0 +1,389 @@ +/* + * 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.ArrayList; +import java.util.List; + +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.ExternalAttachment; +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() && definitions.getExternalAttachments().isEmpty()) ) { + return composite; + } + + + Document document = null; + + for (PolicySet ps : definitions.getPolicySets()) { + XPathExpression exp = ps.getAttachToXPathExpression(); + if ( exp != null ) { + if ( document == null ) { + document = saveAsDOM(composite); + } + NodeList nodes = (NodeList) exp.evaluate(document, XPathConstants.NODESET); + attachPolicySetToNodes(composite, monitor, nodes, ps); + } + } + + for ( ExternalAttachment ea : definitions.getExternalAttachments() ) { + XPathExpression exp = ea.getAttachToXPathExpression(); + if ( exp != null ) { + if ( document == null ) { + document = saveAsDOM(composite); + } + NodeList nodes = (NodeList) exp.evaluate(document, XPathConstants.NODESET); + for ( PolicySet ps : ea.getPolicySets() ) { + attachPolicySetToNodes(composite, monitor, nodes, ps); + } + } + } + + // Recursively apply the xpath against the composites referenced by <implementation.composite> + // If the composite or component has policy sets attached, we have to ignore policy sets + // attached to the inner composite. + if ( composite.getPolicySets().isEmpty() ) { + for (Component component : composite.getComponents()) { + if ( component.getPolicySets().isEmpty() ) { + Implementation impl = component.getImplementation(); + if (impl instanceof Composite) { + Composite patched = applyXPath((Composite)impl, definitions, monitor); + if (patched != impl) { + component.setImplementation(patched); + } + } + } + } + } + + return composite; + } finally { + monitor.popContext(); + } + } + + private void attachPolicySetToNodes(Composite composite, + Monitor monitor, NodeList nodes, PolicySet ps) { + + for (int i = 0; i < nodes.getLength(); i++) { + Node node = nodes.item(i); + + if ( isAttachedToProperty(node) ) { + Monitor.error(monitor, + this, + BUILDER_VALIDATION_BUNDLE, + "PolicyAttachedToProperty", + ps.getName().toString()); + } + + + // The node can be a component, service, reference or binding + String index = getStructuralURI(node); + PolicySubject subject = lookup(composite, index); + if (subject != null) { + ps.setIsExternalAttachment(true); + // Remove any PolicySets with the same name that may have been added + List<PolicySet> subjectPSCopy = new ArrayList<PolicySet>(subject.getPolicySets()); + for ( PolicySet existingPS : subjectPSCopy ) { + if ( existingPS.getName().equals(ps.getName()) ) { + subject.getPolicySets().remove(existingPS); + } + } + 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); + } + + } + } + + /** + * 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 + * @param node + * @return + */ + private boolean isAttachedToProperty(Node node) { + + Node testNode = node; + while (testNode != null){ + if ((node.getNodeType() == Node.ELEMENT_NODE) && + (node.getLocalName().equals("property"))){ + return true; + } + testNode = testNode.getParentNode(); + } + return false; + } + + 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 if ( new QName(Base.SCA11_NS, "composite").equals(name)) { + return ""; + } 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()"; + } else if (localName.startsWith("interface.")) { + 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 + "#" + contractName + "#interface()"; //(" + contractName + "/" + interfaceName + ")" + } + } + } + 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; + } else if ( structuralURI.equals("")) { + return composite; + } + int index = structuralURI.indexOf('#'); + String componentURI = structuralURI; + String service = null; + String reference = null; + String binding = null; + boolean isInterface = false; + 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; + } else if ( prefix.indexOf("#interface") != -1 ) { + service = prefix.substring(0, prefix.indexOf("#interface")); + isInterface = true; + } + } + } + } + for (Component component : composite.getComponents()) { + if (component.getURI().equals(componentURI)) { + if (service != null) { + ComponentService componentService = component.getService(service); + if ( isInterface ) { + return componentService.getInterfaceContract().getInterface(); + } else 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/sandbox/sebastien/java/wrapped/modules/builder/src/main/java/org/apache/tuscany/sca/builder/impl/StructuralURIBuilderImpl.java b/sandbox/sebastien/java/wrapped/modules/builder/src/main/java/org/apache/tuscany/sca/builder/impl/StructuralURIBuilderImpl.java new file mode 100644 index 0000000000..7c2d86862b --- /dev/null +++ b/sandbox/sebastien/java/wrapped/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/sandbox/sebastien/java/wrapped/modules/builder/src/main/java/org/apache/tuscany/sca/builder/impl/WireBuilderImpl.java b/sandbox/sebastien/java/wrapped/modules/builder/src/main/java/org/apache/tuscany/sca/builder/impl/WireBuilderImpl.java new file mode 100644 index 0000000000..21725fb1b1 --- /dev/null +++ b/sandbox/sebastien/java/wrapped/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/sandbox/sebastien/java/wrapped/modules/builder/src/main/java/org/apache/tuscany/sca/builder/impl/WireMatcherImpl.java b/sandbox/sebastien/java/wrapped/modules/builder/src/main/java/org/apache/tuscany/sca/builder/impl/WireMatcherImpl.java new file mode 100644 index 0000000000..761f53ff11 --- /dev/null +++ b/sandbox/sebastien/java/wrapped/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/sandbox/sebastien/java/wrapped/modules/builder/src/main/resources/META-INF/services/org.apache.tuscany.sca.assembly.builder.CompositeBuilder b/sandbox/sebastien/java/wrapped/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/sandbox/sebastien/java/wrapped/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/sandbox/sebastien/java/wrapped/modules/builder/src/main/resources/org/apache/tuscany/sca/builder/builder-validation-messages.properties b/sandbox/sebastien/java/wrapped/modules/builder/src/main/resources/org/apache/tuscany/sca/builder/builder-validation-messages.properties new file mode 100644 index 0000000000..2d519a28ad --- /dev/null +++ b/sandbox/sebastien/java/wrapped/modules/builder/src/main/resources/org/apache/tuscany/sca/builder/builder-validation-messages.properties @@ -0,0 +1,39 @@ +# +# +# 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 +NoListenerIntentSpecifiedOnService = The noListener intent may only be specified on a reference. +TransactedOneWayWithManagedTransactionLocal = The Component {0} {2} can not require transactedOneWay because the implementation for Component {1} requires managedTransaction.local +PropagatesTransactionWithNoManagedTran = The component {0} {2} can not require propagatesTransaction because the implementation for component {1} requires noManagedTransaction +TransactedOneWayWithTwoWayOp = The component reference {0} can not require transactedOneWay because the operation {1} is a two way operation +ImmediateOneWayWithTwoWayOp = The component reference {0} can not require immediateOneWay because the operation {1} is a two way operation +PropagatesTransactionWithLocalTran = The component {0} {2} can not require propagatesTransaction because the implementation for component {1} requires managedTransaction.local diff --git a/sandbox/sebastien/java/wrapped/modules/builder/src/test/java/org/apache/tuscany/sca/builder/impl/BuildPolicyTestCase.java b/sandbox/sebastien/java/wrapped/modules/builder/src/test/java/org/apache/tuscany/sca/builder/impl/BuildPolicyTestCase.java new file mode 100644 index 0000000000..b3586a2346 --- /dev/null +++ b/sandbox/sebastien/java/wrapped/modules/builder/src/test/java/org/apache/tuscany/sca/builder/impl/BuildPolicyTestCase.java @@ -0,0 +1,132 @@ +/* + * 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 static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; + +import java.net.URI; +import java.net.URL; +import java.util.ArrayList; +import java.util.List; + +import javax.xml.namespace.QName; + +import org.apache.tuscany.sca.assembly.Component; +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.builder.BuilderContext; +import org.apache.tuscany.sca.assembly.builder.BuilderExtensionPoint; +import org.apache.tuscany.sca.assembly.builder.CompositeBuilder; +import org.apache.tuscany.sca.contribution.processor.DefaultURLArtifactProcessorExtensionPoint; +import org.apache.tuscany.sca.contribution.processor.ExtensibleURLArtifactProcessor; +import org.apache.tuscany.sca.contribution.processor.ProcessorContext; +import org.apache.tuscany.sca.contribution.processor.StAXArtifactProcessorExtensionPoint; +import org.apache.tuscany.sca.contribution.processor.URLArtifactProcessor; +import org.apache.tuscany.sca.contribution.processor.URLArtifactProcessorExtensionPoint; +import org.apache.tuscany.sca.contribution.resolver.DefaultModelResolver; +import org.apache.tuscany.sca.contribution.resolver.ModelResolver; +import org.apache.tuscany.sca.core.DefaultExtensionPointRegistry; +import org.apache.tuscany.sca.core.UtilityExtensionPoint; +import org.apache.tuscany.sca.definitions.Definitions; +import org.apache.tuscany.sca.monitor.Monitor; +import org.apache.tuscany.sca.monitor.MonitorFactory; +import org.apache.tuscany.sca.policy.PolicySubject; +import org.junit.BeforeClass; +import org.junit.Ignore; +import org.junit.Test; + +/** + * Test reading SCA XML assembly documents. + * + * @version $Rev$ $Date$ + */ +public class BuildPolicyTestCase { + private static URLArtifactProcessor<Object> documentProcessor; + private static URLArtifactProcessor<Definitions> policyDefinitionsProcessor; + private static ModelResolver resolver; + private static CompositeBuilder compositeBuilder; + private static Composite composite; + private static Monitor monitor; + private static ProcessorContext context; + + @BeforeClass + public static void setUp() throws Exception { + DefaultExtensionPointRegistry extensionPoints = new DefaultExtensionPointRegistry(); + context = new ProcessorContext(extensionPoints); + + compositeBuilder = + extensionPoints.getExtensionPoint(BuilderExtensionPoint.class) + .getCompositeBuilder("org.apache.tuscany.sca.assembly.builder.CompositeBuilder"); + + List<Definitions> policyDefinitions = new ArrayList<Definitions>(); + resolver = new DefaultModelResolver(); + + UtilityExtensionPoint utilities = extensionPoints.getExtensionPoint(UtilityExtensionPoint.class); + MonitorFactory monitorFactory = utilities.getUtility(MonitorFactory.class); + monitor = monitorFactory.createMonitor(); + + URLArtifactProcessorExtensionPoint documentProcessors = + new DefaultURLArtifactProcessorExtensionPoint(extensionPoints); + documentProcessor = new ExtensibleURLArtifactProcessor(documentProcessors); + policyDefinitionsProcessor = documentProcessors.getProcessor(Definitions.class); + + StAXArtifactProcessorExtensionPoint staxProcessors = + extensionPoints.getExtensionPoint(StAXArtifactProcessorExtensionPoint.class); + staxProcessors.addArtifactProcessor(new TestPolicyProcessor()); + + URL url = BuildPolicyTestCase.class.getResource("Calculator.composite"); + URI uri = URI.create("TestAllCalculator.composite"); + composite = (Composite)documentProcessor.read(null, uri, url, context); + assertNotNull(composite); + + url = BuildPolicyTestCase.class.getResource("test_definitions.xml"); + uri = URI.create("test_definitions.xml"); + Definitions definitions = (Definitions)policyDefinitionsProcessor.read(null, uri, url, context); + assertNotNull(definitions); + policyDefinitions.add(definitions); + + documentProcessor.resolve(definitions, resolver, context); + documentProcessor.resolve(composite, resolver, context); + + BuilderContext builderContext = new BuilderContext(definitions, null, monitor); + compositeBuilder.build(composite, builderContext); + } + + @Test + @Ignore("There are so many errors with this composite the builder doesn't have enough to go on") + public void testPolicyIntentInheritance() throws Exception { + String namespaceUri = "http://test"; + + PolicySubject policiedComposite = composite; + assertEquals(policiedComposite.getRequiredIntents().size(), 1); + assertEquals(policiedComposite.getRequiredIntents().get(0).getName(), + new QName(namespaceUri, "tuscanyIntent_1")); + + Component component = composite.getComponents().get(0); + Endpoint ep = component.getServices().get(0).getEndpoints().get(0); + EndpointReference epr = component.getReferences().get(0).getEndpointReferences().get(0); + + System.out.println(ep.getRequiredIntents()); + System.out.println(epr.getRequiredIntents()); + } + +} diff --git a/sandbox/sebastien/java/wrapped/modules/builder/src/test/java/org/apache/tuscany/sca/builder/impl/CompositeBuilderTestCase.java b/sandbox/sebastien/java/wrapped/modules/builder/src/test/java/org/apache/tuscany/sca/builder/impl/CompositeBuilderTestCase.java new file mode 100644 index 0000000000..a99d0df91c --- /dev/null +++ b/sandbox/sebastien/java/wrapped/modules/builder/src/test/java/org/apache/tuscany/sca/builder/impl/CompositeBuilderTestCase.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 static org.junit.Assert.assertTrue; + +import javax.xml.namespace.QName; + +import org.apache.tuscany.sca.assembly.AssemblyFactory; +import org.apache.tuscany.sca.assembly.Component; +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.DefaultAssemblyFactory; +import org.apache.tuscany.sca.assembly.builder.BuilderContext; +import org.apache.tuscany.sca.monitor.DefaultMonitorFactory; +import org.apache.tuscany.sca.monitor.Monitor; +import org.apache.tuscany.sca.monitor.MonitorFactory; +import org.junit.BeforeClass; +import org.junit.Test; + +/** + * Test the CompositeBuilder. + * + * @version $Rev$ $Date$ + */ +public class CompositeBuilderTestCase { + + private static AssemblyFactory assemblyFactory; + private static Monitor monitor; + + @BeforeClass + public static void setUp() throws Exception { + assemblyFactory = new DefaultAssemblyFactory(); + MonitorFactory mf = new DefaultMonitorFactory(); + monitor = mf.createMonitor(); + } + + @Test + public void testFuseIncludes() throws Exception { + Composite c1 = assemblyFactory.createComposite(); + c1.setName(new QName("http://foo", "C1")); + Component a = assemblyFactory.createComponent(); + a.setName("a"); + c1.getComponents().add(a); + CompositeService s = assemblyFactory.createCompositeService(); + s.setName("s"); + c1.getServices().add(s); + CompositeReference r = assemblyFactory.createCompositeReference(); + r.setName("r"); + c1.getReferences().add(r); + + Composite c2 = assemblyFactory.createComposite(); + c2.setName(new QName("http://foo", "C2")); + c1.getIncludes().add(c2); + Component b = assemblyFactory.createComponent(); + b.setName("b"); + c2.getComponents().add(b); + + Composite c = assemblyFactory.createComposite(); + c.setName(new QName("http://foo", "C")); + c.getIncludes().add(c1); + + new CompositeIncludeBuilderImpl().build(c, new BuilderContext(monitor)); + + assertTrue(c.getComponents().get(0).getName().equals("a")); + assertTrue(c.getComponents().get(1).getName().equals("b")); + assertTrue(c.getServices().get(0).getName().equals("s")); + assertTrue(c.getReferences().get(0).getName().equals("r")); + } + + @Test + public void testExpandComposites() throws Exception { + Composite c1 = assemblyFactory.createComposite(); + c1.setName(new QName("http://foo", "C1")); + Component a = assemblyFactory.createComponent(); + a.setName("a"); + c1.getComponents().add(a); + CompositeService s = assemblyFactory.createCompositeService(); + s.setName("s"); + c1.getServices().add(s); + CompositeReference r = assemblyFactory.createCompositeReference(); + r.setName("r"); + c1.getReferences().add(r); + + Composite c2 = assemblyFactory.createComposite(); + c2.setName(new QName("http://foo", "C2")); + Component b = assemblyFactory.createComponent(); + b.setName("b"); + c2.getComponents().add(b); + + Composite c = assemblyFactory.createComposite(); + c.setName(new QName("http://foo", "C")); + Component x = assemblyFactory.createComponent(); + x.setName("x"); + x.setImplementation(c1); + c.getComponents().add(x); + Component y = assemblyFactory.createComponent(); + y.setName("y"); + y.setImplementation(c2); + c.getComponents().add(y); + Component z = assemblyFactory.createComponent(); + z.setName("z"); + z.setImplementation(c1); + c.getComponents().add(z); + + new CompositeCloneBuilderImpl().build(c, new BuilderContext(monitor)); + + assertTrue(c.getComponents().get(0).getImplementation() != c1); + assertTrue(c.getComponents().get(1).getImplementation() != c2); + assertTrue(c.getComponents().get(2).getImplementation() != c1); + + Composite i = (Composite)c.getComponents().get(0).getImplementation(); + assertTrue(i.getComponents().get(0) != a); + assertTrue(i.getComponents().get(0).getName().equals("a")); + assertTrue(i.getServices().get(0).getName().equals("s")); + assertTrue(i.getServices().get(0) != s); + assertTrue(i.getReferences().get(0).getName().equals("r")); + assertTrue(i.getReferences().get(0) != r); + } + +} diff --git a/sandbox/sebastien/java/wrapped/modules/builder/src/test/java/org/apache/tuscany/sca/builder/impl/MockPolicy.java b/sandbox/sebastien/java/wrapped/modules/builder/src/test/java/org/apache/tuscany/sca/builder/impl/MockPolicy.java new file mode 100644 index 0000000000..dac50ec227 --- /dev/null +++ b/sandbox/sebastien/java/wrapped/modules/builder/src/test/java/org/apache/tuscany/sca/builder/impl/MockPolicy.java @@ -0,0 +1,39 @@ +/* + * 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 javax.xml.namespace.QName; + +/** + * Mocked Policy + */ +public class MockPolicy { + public QName getName() { + return new QName("http://schemas.xmlsoap.org/ws/2004/09/policy", "PolicyAttachment"); + } + + public boolean isUnresolved() { + return false; + } + + public void setUnresolved(boolean unresolved) { + } + +} diff --git a/sandbox/sebastien/java/wrapped/modules/builder/src/test/java/org/apache/tuscany/sca/builder/impl/PolicyAttachmentTestCase.java b/sandbox/sebastien/java/wrapped/modules/builder/src/test/java/org/apache/tuscany/sca/builder/impl/PolicyAttachmentTestCase.java new file mode 100644 index 0000000000..9102257b77 --- /dev/null +++ b/sandbox/sebastien/java/wrapped/modules/builder/src/test/java/org/apache/tuscany/sca/builder/impl/PolicyAttachmentTestCase.java @@ -0,0 +1,151 @@ +/* + * 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.InputStream; +import java.net.URL; + +import javax.xml.namespace.QName; +import javax.xml.stream.XMLInputFactory; +import javax.xml.stream.XMLStreamException; +import javax.xml.stream.XMLStreamReader; + +import org.apache.tuscany.sca.assembly.AssemblyFactory; +import org.apache.tuscany.sca.assembly.Base; +import org.apache.tuscany.sca.assembly.Composite; +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.contribution.processor.ContributionReadException; +import org.apache.tuscany.sca.contribution.processor.ExtensibleStAXArtifactProcessor; +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.DefaultExtensionPointRegistry; +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.monitor.DefaultMonitorFactory; +import org.apache.tuscany.sca.monitor.Monitor; +import org.apache.tuscany.sca.monitor.MonitorFactory; +import org.junit.BeforeClass; +import org.junit.Test; + +/** + * Test reading SCA XML assembly documents. + * + * @version $Rev$ $Date$ + */ +public class PolicyAttachmentTestCase { + + private static StAXArtifactProcessor<Object> staxProcessor; + private static Monitor monitor; + + private static ExtensionPointRegistry extensionPoints; + private static XMLInputFactory inputFactory; + private static AssemblyFactory assemblyFactory; + private static BuilderExtensionPoint builders; + private static ProcessorContext context; + + @BeforeClass + public static void init() throws Exception { + extensionPoints = new DefaultExtensionPointRegistry(); + context = new ProcessorContext(extensionPoints); + + FactoryExtensionPoint factories = extensionPoints.getExtensionPoint(FactoryExtensionPoint.class); + assemblyFactory = factories.getFactory(AssemblyFactory.class); + inputFactory = factories.getFactory(XMLInputFactory.class); + // Create a monitor + UtilityExtensionPoint utilities = extensionPoints.getExtensionPoint(UtilityExtensionPoint.class); + MonitorFactory monitorFactory = new DefaultMonitorFactory(); + if (monitorFactory != null) { + monitor = monitorFactory.createMonitor(); + utilities.addUtility(monitorFactory); + } + StAXArtifactProcessorExtensionPoint staxProcessors = + extensionPoints.getExtensionPoint(StAXArtifactProcessorExtensionPoint.class); + staxProcessor = new ExtensibleStAXArtifactProcessor(staxProcessors, inputFactory, null); + staxProcessors.addArtifactProcessor(new TestPolicyProcessor()); + + builders = extensionPoints.getExtensionPoint(BuilderExtensionPoint.class); + } + + @Test + public void testBuild() throws Exception { + Definitions definitions = load("test_definitions.xml"); + Composite composite = load("Calculator.composite"); + + CompositeBuilder uriBuilder = new StructuralURIBuilderImpl(extensionPoints); + + BuilderContext builderContext = new BuilderContext(extensionPoints); + builderContext.setDefinitions(definitions); + composite = uriBuilder.build(composite, builderContext); + PolicyAttachmentBuilderImpl builder = new PolicyAttachmentBuilderImpl(extensionPoints); + builder.build(composite, builderContext); + } + + private <T> T load(String file) throws IOException, XMLStreamException, ContributionReadException { + URL url = getClass().getResource(file); + InputStream urlStream = url.openStream(); + XMLStreamReader reader = inputFactory.createXMLStreamReader(urlStream); + reader.nextTag(); + + T model = (T)staxProcessor.read(reader, context); + reader.close(); + return model; + } + + @Test + public void testComplexBuild() throws Exception { + Definitions definitions = load("definitions.xml"); + Composite composite1 = load("Composite1.composite"); + Composite composite2 = load("Composite2.composite"); + Composite composite3 = load("Composite3.composite"); + Composite composite4 = load("Composite4.composite"); + composite1.getIncludes().clear(); + composite1.getIncludes().add(composite3); + + composite1.getComponent("Component1B").setImplementation(composite4); + composite2.getComponent("Component2B").setImplementation(composite4); + + Composite domainComposite = assemblyFactory.createComposite(); + domainComposite.setName(new QName(Base.SCA11_NS, "")); + domainComposite.setLocal(false); + domainComposite.getIncludes().add(composite1); + domainComposite.getIncludes().add(composite2); + + CompositeBuilder includeBuilder = new CompositeIncludeBuilderImpl(); + CompositeBuilder cloneBuilder = new CompositeCloneBuilderImpl(); + CompositeBuilder uriBuilder = new StructuralURIBuilderImpl(extensionPoints); + + BuilderContext context = new BuilderContext(extensionPoints); + context.setDefinitions(definitions); + domainComposite = cloneBuilder.build(domainComposite, context); + domainComposite = includeBuilder.build(domainComposite, context); + domainComposite = uriBuilder.build(domainComposite, context); + + PolicyAttachmentBuilderImpl builder = new PolicyAttachmentBuilderImpl(extensionPoints); + domainComposite = builder.build(domainComposite, context); + + } + +} diff --git a/sandbox/sebastien/java/wrapped/modules/builder/src/test/java/org/apache/tuscany/sca/builder/impl/TestPolicyProcessor.java b/sandbox/sebastien/java/wrapped/modules/builder/src/test/java/org/apache/tuscany/sca/builder/impl/TestPolicyProcessor.java new file mode 100644 index 0000000000..1201b6e36f --- /dev/null +++ b/sandbox/sebastien/java/wrapped/modules/builder/src/test/java/org/apache/tuscany/sca/builder/impl/TestPolicyProcessor.java @@ -0,0 +1,58 @@ +/* + * 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 javax.xml.namespace.QName; +import javax.xml.stream.XMLStreamException; +import javax.xml.stream.XMLStreamReader; +import javax.xml.stream.XMLStreamWriter; + +import org.apache.tuscany.sca.contribution.processor.ContributionReadException; +import org.apache.tuscany.sca.contribution.processor.ContributionResolveException; +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.resolver.ModelResolver; + +/** + * A PolicyProcessor used for testing. + * + * @version $Rev$ $Date$ + */ +public class TestPolicyProcessor implements StAXArtifactProcessor<MockPolicy> { + public QName getArtifactType() { + return new QName("http://schemas.xmlsoap.org/ws/2004/09/policy", "PolicyAttachment"); + } + + public MockPolicy read(XMLStreamReader arg0, ProcessorContext context) throws ContributionReadException, XMLStreamException { + return new MockPolicy(); + } + + public void write(MockPolicy arg0, XMLStreamWriter arg1, ProcessorContext context) throws ContributionWriteException, XMLStreamException { + } + + public Class<MockPolicy> getModelType() { + return MockPolicy.class; + } + + public void resolve(MockPolicy arg0, ModelResolver arg1, ProcessorContext context) throws ContributionResolveException { + + } + +} diff --git a/sandbox/sebastien/java/wrapped/modules/builder/src/test/resources/org/apache/tuscany/sca/builder/impl/Calculator.composite b/sandbox/sebastien/java/wrapped/modules/builder/src/test/resources/org/apache/tuscany/sca/builder/impl/Calculator.composite new file mode 100644 index 0000000000..0e7aad877e --- /dev/null +++ b/sandbox/sebastien/java/wrapped/modules/builder/src/test/resources/org/apache/tuscany/sca/builder/impl/Calculator.composite @@ -0,0 +1,49 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + * 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. +--> +<composite xmlns="http://docs.oasis-open.org/ns/opencsa/sca/200912" + targetNamespace="http://sample" + xmlns:sample="http://sample" + name="Calculator"> + + <component name="CalculatorServiceComponent" requires="confidentiality"> + <implementation.java class="calculator.CalculatorServiceImpl" xmlns:test="http://test" requiers="test:TestIntentOne"/> + <reference name="addService" target="AddServiceComponent" /> + <reference name="subtractService" target="SubtractServiceComponent" /> + <reference name="multiplyService" target="MultiplyServiceComponent" /> + <reference name="divideService" target="DivideServiceComponent" /> + </component> + + <component name="AddServiceComponent"> + <implementation.java class="calculator.AddServiceImpl"/> + </component> + + <component name="SubtractServiceComponent"> + <implementation.java class="calculator.SubtractServiceImpl"/> + </component> + + <component name="MultiplyServiceComponent"> + <implementation.java class="calculator.MultiplyServiceImpl"/> + </component> + + <component name="DivideServiceComponent"> + <implementation.java class="calculator.DivideServiceImpl"/> + </component> + +</composite> diff --git a/sandbox/sebastien/java/wrapped/modules/builder/src/test/resources/org/apache/tuscany/sca/builder/impl/Composite1.composite b/sandbox/sebastien/java/wrapped/modules/builder/src/test/resources/org/apache/tuscany/sca/builder/impl/Composite1.composite new file mode 100644 index 0000000000..584f27eea7 --- /dev/null +++ b/sandbox/sebastien/java/wrapped/modules/builder/src/test/resources/org/apache/tuscany/sca/builder/impl/Composite1.composite @@ -0,0 +1,34 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + * 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. +--> +<composite xmlns="http://docs.oasis-open.org/ns/opencsa/sca/200912" + targetNamespace="http://sample" + xmlns:sample="http://sample" + name="Composite1"> + <include composite="sample:Composite3"/> + + <component name="Component1A"> + <implementation.java class="sample.Component1AImpl"/> + </component> + + <component name="Component1B"> + <implementation.composite name="sample:Composite4"/> + </component> + +</composite> diff --git a/sandbox/sebastien/java/wrapped/modules/builder/src/test/resources/org/apache/tuscany/sca/builder/impl/Composite2.composite b/sandbox/sebastien/java/wrapped/modules/builder/src/test/resources/org/apache/tuscany/sca/builder/impl/Composite2.composite new file mode 100644 index 0000000000..12cf984b88 --- /dev/null +++ b/sandbox/sebastien/java/wrapped/modules/builder/src/test/resources/org/apache/tuscany/sca/builder/impl/Composite2.composite @@ -0,0 +1,33 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + * 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. +--> +<composite xmlns="http://docs.oasis-open.org/ns/opencsa/sca/200912" + targetNamespace="http://sample" + xmlns:sample="http://sample" + name="Composite2"> + + <component name="Component2A"> + <implementation.java class="sample.Component2AImpl"/> + </component> + + <component name="Component2B"> + <implementation.composite name="sample:Composite4"/> + </component> + +</composite> diff --git a/sandbox/sebastien/java/wrapped/modules/builder/src/test/resources/org/apache/tuscany/sca/builder/impl/Composite3.composite b/sandbox/sebastien/java/wrapped/modules/builder/src/test/resources/org/apache/tuscany/sca/builder/impl/Composite3.composite new file mode 100644 index 0000000000..e6be99195e --- /dev/null +++ b/sandbox/sebastien/java/wrapped/modules/builder/src/test/resources/org/apache/tuscany/sca/builder/impl/Composite3.composite @@ -0,0 +1,29 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + * 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. +--> +<composite xmlns="http://docs.oasis-open.org/ns/opencsa/sca/200912" + targetNamespace="http://sample" + xmlns:sample="http://sample" + name="Composite3"> + + <component name="Component3A"> + <implementation.java class="sample.Component3AImpl"/> + </component> + +</composite> diff --git a/sandbox/sebastien/java/wrapped/modules/builder/src/test/resources/org/apache/tuscany/sca/builder/impl/Composite4.composite b/sandbox/sebastien/java/wrapped/modules/builder/src/test/resources/org/apache/tuscany/sca/builder/impl/Composite4.composite new file mode 100644 index 0000000000..02167e43cf --- /dev/null +++ b/sandbox/sebastien/java/wrapped/modules/builder/src/test/resources/org/apache/tuscany/sca/builder/impl/Composite4.composite @@ -0,0 +1,32 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + * 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. +--> +<composite xmlns="http://docs.oasis-open.org/ns/opencsa/sca/200912" + targetNamespace="http://sample" + xmlns:sample="http://sample" + name="Composite4"> + + <service name="Service1" promote="Component4A/Service1"/> + <reference name="reference1" promote="Component4A/reference1"/> + + <component name="Component4A"> + <implementation.java class="sample.Component4AImpl"/> + </component> + +</composite> diff --git a/sandbox/sebastien/java/wrapped/modules/builder/src/test/resources/org/apache/tuscany/sca/builder/impl/definitions.xml b/sandbox/sebastien/java/wrapped/modules/builder/src/test/resources/org/apache/tuscany/sca/builder/impl/definitions.xml new file mode 100644 index 0000000000..5b22d5b596 --- /dev/null +++ b/sandbox/sebastien/java/wrapped/modules/builder/src/test/resources/org/apache/tuscany/sca/builder/impl/definitions.xml @@ -0,0 +1,38 @@ +<?xml version="1.0" encoding="ASCII"?> +<!-- + * 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. +--> +<definitions + xmlns="http://docs.oasis-open.org/ns/opencsa/sca/200912" + targetNamespace="http://sample" + xmlns:sample="http://sample" + xmlns:sca="http://docs.oasis-open.org/ns/opencsa/sca/200912"> + + <policySet name="PolicySet1" appliesTo="sca:implementation.java" + attachTo = "//composite[@name='']"> + </policySet> + + <policySet name="PolicySet2" appliesTo="sca:implementation.java" + attachTo = "//component[@name='Component3A']"> + </policySet> + + <policySet name="PolicySet3" appliesTo="sca:binding.ws" + attachTo = "//sca:component[sca:URIRef('Component2B/Component4A')]"> + </policySet> + +</definitions>
\ No newline at end of file diff --git a/sandbox/sebastien/java/wrapped/modules/builder/src/test/resources/org/apache/tuscany/sca/builder/impl/scenario.odg b/sandbox/sebastien/java/wrapped/modules/builder/src/test/resources/org/apache/tuscany/sca/builder/impl/scenario.odg Binary files differnew file mode 100644 index 0000000000..a010bb1bf1 --- /dev/null +++ b/sandbox/sebastien/java/wrapped/modules/builder/src/test/resources/org/apache/tuscany/sca/builder/impl/scenario.odg diff --git a/sandbox/sebastien/java/wrapped/modules/builder/src/test/resources/org/apache/tuscany/sca/builder/impl/scenario.png b/sandbox/sebastien/java/wrapped/modules/builder/src/test/resources/org/apache/tuscany/sca/builder/impl/scenario.png Binary files differnew file mode 100644 index 0000000000..e1f78f6423 --- /dev/null +++ b/sandbox/sebastien/java/wrapped/modules/builder/src/test/resources/org/apache/tuscany/sca/builder/impl/scenario.png diff --git a/sandbox/sebastien/java/wrapped/modules/builder/src/test/resources/org/apache/tuscany/sca/builder/impl/test_definitions.xml b/sandbox/sebastien/java/wrapped/modules/builder/src/test/resources/org/apache/tuscany/sca/builder/impl/test_definitions.xml new file mode 100644 index 0000000000..dc7f5c422c --- /dev/null +++ b/sandbox/sebastien/java/wrapped/modules/builder/src/test/resources/org/apache/tuscany/sca/builder/impl/test_definitions.xml @@ -0,0 +1,207 @@ +<?xml version="1.0" encoding="ASCII"?> +<!-- + * 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. +--> +<definitions xmlns="http://docs.oasis-open.org/ns/opencsa/sca/200912" targetNamespace="http://test" + xmlns:test="http://test" xmlns:sca="http://docs.oasis-open.org/ns/opencsa/sca/200912"> + + <!-- Extension Types Metadata --> + <implementationType type="sca:implementation.java" alwaysProvides="test:logging" mayProvide="test:tracing" /> + <bindingType type="sca:binding.ws" alwaysProvides="test:confidentiality" mayProvide="test:integrity" /> + + <!-- Intents and Policysets to assume targetnamespace --> + <intent name="TestIntentOne" constrains="sca:binding"> + <description> + Test Intent + </description> + </intent> + + <intent name="TestIntentTwo" constrains="sca:binding" requires="test:TestIntentOne"> + <description> + Protect messages from unauthorized reading or modification + </description> + </intent> + + <policySet name="TestPolicySetOne" provides="test:TestIntentOne" appliesTo="sca:binding.ws" + attachTo = "//sca:component[@name='CalculatorServiceComponent']/sca:reference[@name='addService']" + xmlns="http://docs.oasis-open.org/ns/opencsa/sca/200912" xmlns:wsp="http://schemas.xmlsoap.org/ws/2004/09/policy"> + <wsp:PolicyAttachment> + <!-- policy expression and policy subject for + "basic authentication" --> + </wsp:PolicyAttachment> + <wsp:PolicyAttachment> + <!-- policy expression and policy subject for + "reliability" --> + </wsp:PolicyAttachment> + </policySet> + + <!-- POLICY SETS --> + <policySet name="SecureReliablePolicy" provides="test:confidentiality.transport test:integrity" appliesTo="sca:binding.ws" + xmlns="http://docs.oasis-open.org/ns/opencsa/sca/200912" xmlns:wsp="http://schemas.xmlsoap.org/ws/2004/09/policy"> + <wsp:PolicyAttachment> + <!-- policy expression and policy subject for + "basic authentication" --> + </wsp:PolicyAttachment> + <wsp:PolicyAttachment> + <!-- policy expression and policy subject for + "reliability" --> + </wsp:PolicyAttachment> + </policySet> + + <policySet name="SecureMessagingPolicies" provides="test:confidentiality" appliesTo="binding.ws" + xmlns="http://docs.oasis-open.org/ns/opencsa/sca/200912" xmlns:wsp="http://schemas.xmlsoap.org/ws/2004/09/policy"> + <intentMap provides="test:confidentiality"> + <qualifier name="transport"> + <wsp:PolicyAttachment> + <!-- policy expression and policy subject for "transport" alternative --> + </wsp:PolicyAttachment> + <wsp:PolicyAttachment>...</wsp:PolicyAttachment> + </qualifier> + <qualifier name="message"> + <wsp:PolicyAttachment> + <!-- policy expression and policy subject for "message" alternative" --> + </wsp:PolicyAttachment> + </qualifier> + </intentMap> + </policySet> + + <policySet name="SecurityPolicy" provides="test:confidentiality" appliesTo="binding.ws" + xmlns="http://docs.oasis-open.org/ns/opencsa/sca/200912" xmlns:wsp="http://schemas.xmlsoap.org/ws/2004/09/policy"> + <intentMap provides="test:confidentiality"> + <qualifier name="message"> + <wsp:PolicyAttachment> + <!-- policy attachment for body encryption --> + </wsp:PolicyAttachment> + <wsp:PolicyAttachment> + <!-- policy attachment for whole message encryption --> + </wsp:PolicyAttachment> + </qualifier> + <qualifier name="transport"> + <wsp:PolicyAttachment> + <!-- policy attachment for transport encryption --> + </wsp:PolicyAttachment> + </qualifier> + </intentMap> + </policySet> + + <policySet name="BasicAuthMsgProtSecurity" provides="test:authentication test:confidentiality" appliesTo="binding.ws" + xmlns="http://docs.oasis-open.org/ns/opencsa/sca/200912"> + <policySetReference name="test:AuthenticationPolicies" /> + <policySetReference name="test:ConfidentialityPolicies" /> + </policySet> + + <policySet name="AuthenticationPolicies" provides="test:authentication" appliesTo="binding.ws" + xmlns="http://docs.oasis-open.org/ns/opencsa/sca/200912" xmlns:wsp="http://schemas.xmlsoap.org/ws/2004/09/policy"> + <wsp:PolicyAttachment> + <!-- policy expression and policy subject for "basic + authentication" --> + </wsp:PolicyAttachment> + </policySet> + + <policySet name="ConfidentialityPolicies" provides="test:confidentiality" appliesTo="binding.ws" + xmlns="http://docs.oasis-open.org/ns/opencsa/sca/200912" xmlns:wsp="http://schemas.xmlsoap.org/ws/2004/09/policy"> + <intentMap provides="test:confidentiality"> + <qualifier name="transport"> + <wsp:PolicyAttachment> + <!-- policy expression and policy subject for "transport" + alternative --> + </wsp:PolicyAttachment> + <wsp:PolicyAttachment>...</wsp:PolicyAttachment> + </qualifier> + <qualifier name="message"> + <wsp:PolicyAttachment> + <!-- policy expression and policy subject for "message" + alternative" --> + ... + </wsp:PolicyAttachment> + </qualifier> + </intentMap> + </policySet> + + <policySet name="SecureWSPolicy" provides="test:confidentiality" appliesTo="sca:binding.ws" + xmlns="http://docs.oasis-open.org/ns/opencsa/sca/200912" xmlns:sp="http://schemas.xmlsoap.org/ws/2002/12/secext" + xmlns:wsp="http://schemas.xmlsoap.org/ws/2004/09/policy"> + <wsp:Policy> + <wsp:ExactlyOne> + <wsp:All> + <sp:SecurityToken> + <sp:TokenType>sp:X509v3</sp:TokenType> + </sp:SecurityToken> + <sp:UsernameToken /> + <sp:SignedParts /> + <sp:EncryptedParts> + <sp:Body /> + </sp:EncryptedParts> + <sp:TransportBinding> + <sp:IncludeTimeStamp /> + </sp:TransportBinding> + </wsp:All> + </wsp:ExactlyOne> + </wsp:Policy> + </policySet> + + <!-- profile intent --> + <intent name="reliableMessageProtection" constrains="sca:binding" requires="test:messageProtection"> + <description> + Protect messages from unauthorized reading or modification + </description> + </intent> + + <intent name="messageProtection" constrains="sca:binding" requires="test:confidentiality test:integrity"> + <description> + Protect messages from unauthorized reading or modification + </description> + </intent> + + <!-- simple intent --> + <intent name="confidentiality" constrains="sca:binding"> + <description> + Communitcation thro this binding must prevent + unauthorized users from reading the messages. + </description> + <qualifier name="transport" /> + <qualifier name="message" default="true" /> + </intent> + + <intent name="integrity" constrains="sca:binding"> + <description> + Communitcation thro this binding must prevent + unauthorized modification of the messages. + </description> + </intent> + + <intent name="authentication" constrains="sca:binding"> + <description> + Communitcation thro this binding required + Authentication. + </description> + </intent> + + <intent name="logging" constrains="sca:implementation"> + <description> + All messages to and from this implementation must be logged + </description> + </intent> + + <intent name="tracing" constrains="sca:implementation.java"> + <description> + Need to figure out some description for this + </description> + </intent> + +</definitions>
\ No newline at end of file |