summaryrefslogtreecommitdiffstats
path: root/sca-java-2.x/tags/2.0.1-RC1/modules/builder/src/main/java/org
diff options
context:
space:
mode:
Diffstat (limited to 'sca-java-2.x/tags/2.0.1-RC1/modules/builder/src/main/java/org')
-rw-r--r--sca-java-2.x/tags/2.0.1-RC1/modules/builder/src/main/java/org/apache/tuscany/sca/builder/impl/BindingURIBuilderImpl.java364
-rw-r--r--sca-java-2.x/tags/2.0.1-RC1/modules/builder/src/main/java/org/apache/tuscany/sca/builder/impl/ComponentBuilderImpl.java1735
-rw-r--r--sca-java-2.x/tags/2.0.1-RC1/modules/builder/src/main/java/org/apache/tuscany/sca/builder/impl/ComponentPolicyBuilderImpl.java650
-rw-r--r--sca-java-2.x/tags/2.0.1-RC1/modules/builder/src/main/java/org/apache/tuscany/sca/builder/impl/ComponentReferenceBindingBuilderImpl.java81
-rw-r--r--sca-java-2.x/tags/2.0.1-RC1/modules/builder/src/main/java/org/apache/tuscany/sca/builder/impl/ComponentServiceBindingBuilderImpl.java80
-rw-r--r--sca-java-2.x/tags/2.0.1-RC1/modules/builder/src/main/java/org/apache/tuscany/sca/builder/impl/CompositeCloneBuilderImpl.java100
-rw-r--r--sca-java-2.x/tags/2.0.1-RC1/modules/builder/src/main/java/org/apache/tuscany/sca/builder/impl/CompositeComponentTypeBuilderImpl.java696
-rw-r--r--sca-java-2.x/tags/2.0.1-RC1/modules/builder/src/main/java/org/apache/tuscany/sca/builder/impl/CompositeIncludeBuilderImpl.java127
-rw-r--r--sca-java-2.x/tags/2.0.1-RC1/modules/builder/src/main/java/org/apache/tuscany/sca/builder/impl/CompositePolicyBuilderImpl.java492
-rw-r--r--sca-java-2.x/tags/2.0.1-RC1/modules/builder/src/main/java/org/apache/tuscany/sca/builder/impl/CompositeWireApplierImpl.java212
-rw-r--r--sca-java-2.x/tags/2.0.1-RC1/modules/builder/src/main/java/org/apache/tuscany/sca/builder/impl/EndpointBuilderImpl.java138
-rw-r--r--sca-java-2.x/tags/2.0.1-RC1/modules/builder/src/main/java/org/apache/tuscany/sca/builder/impl/EndpointReferenceBuilderImpl.java840
-rw-r--r--sca-java-2.x/tags/2.0.1-RC1/modules/builder/src/main/java/org/apache/tuscany/sca/builder/impl/IntentValidator.java139
-rw-r--r--sca-java-2.x/tags/2.0.1-RC1/modules/builder/src/main/java/org/apache/tuscany/sca/builder/impl/ModelBuilderImpl.java188
-rw-r--r--sca-java-2.x/tags/2.0.1-RC1/modules/builder/src/main/java/org/apache/tuscany/sca/builder/impl/PolicyAppliesToBuilderImpl.java288
-rw-r--r--sca-java-2.x/tags/2.0.1-RC1/modules/builder/src/main/java/org/apache/tuscany/sca/builder/impl/PolicyAttachmentBuilderImpl.java412
-rw-r--r--sca-java-2.x/tags/2.0.1-RC1/modules/builder/src/main/java/org/apache/tuscany/sca/builder/impl/StructuralURIBuilderImpl.java191
-rw-r--r--sca-java-2.x/tags/2.0.1-RC1/modules/builder/src/main/java/org/apache/tuscany/sca/builder/impl/WireBuilderImpl.java1028
-rw-r--r--sca-java-2.x/tags/2.0.1-RC1/modules/builder/src/main/java/org/apache/tuscany/sca/builder/impl/WireMatcherImpl.java64
19 files changed, 7825 insertions, 0 deletions
diff --git a/sca-java-2.x/tags/2.0.1-RC1/modules/builder/src/main/java/org/apache/tuscany/sca/builder/impl/BindingURIBuilderImpl.java b/sca-java-2.x/tags/2.0.1-RC1/modules/builder/src/main/java/org/apache/tuscany/sca/builder/impl/BindingURIBuilderImpl.java
new file mode 100644
index 0000000000..eff1e9f083
--- /dev/null
+++ b/sca-java-2.x/tags/2.0.1-RC1/modules/builder/src/main/java/org/apache/tuscany/sca/builder/impl/BindingURIBuilderImpl.java
@@ -0,0 +1,364 @@
+/*
+ * 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 {
+
+ private static final QName DEFAULT = new QName("default");
+
+ 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 (defaultBindings != null) {
+ List<String> uris = defaultBindings.get(binding.getType());
+ if (uris != null && uris.size() > 0) {
+ baseURI = new URI(addSlashToPath(uris.get(0)));
+ } else {
+ uris = defaultBindings.get(DEFAULT);
+ 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) {
+ if (bindingURI.toString().startsWith("/")) {
+ uriString = basedURI(baseURI, componentURI.resolve(bindingURI)).toString();
+ } else {
+ uriString = basedURI(baseURI, componentURI.resolve(name + "/" + bindingURI)).toString();
+ }
+ } else {
+ uriString = basedURI(baseURI, componentURI.resolve(name)).toString();
+ }
+ }
+ }
+
+ // tidy up by removing any trailing "/"
+ if (uriString.endsWith("/")) {
+ uriString = uriString.substring(0, uriString.length() - 1);
+ }
+
+ URI uri = URI.create(uriString);
+ if (!uri.isAbsolute()) {
+ uri = URI.create("/").resolve(uri);
+ }
+ return uri.toString();
+ }
+
+ /**
+ * Combine a URI with a base URI.
+ *
+ * @param baseURI
+ * @param uri
+ * @return
+ */
+ private static URI basedURI(URI baseURI, URI uri) {
+ if (uri.getScheme() != null) {
+ return uri;
+ }
+ String str = uri.toString();
+ if (str.startsWith("/")) {
+ str = str.substring(1);
+ }
+ return URI.create(baseURI.toString() + str).normalize();
+ }
+
+ public String getID() {
+ return "org.apache.tuscany.sca.assembly.builder.BindingURIBuilder";
+ }
+
+}
diff --git a/sca-java-2.x/tags/2.0.1-RC1/modules/builder/src/main/java/org/apache/tuscany/sca/builder/impl/ComponentBuilderImpl.java b/sca-java-2.x/tags/2.0.1-RC1/modules/builder/src/main/java/org/apache/tuscany/sca/builder/impl/ComponentBuilderImpl.java
new file mode 100644
index 0000000000..d67cb65bb0
--- /dev/null
+++ b/sca-java-2.x/tags/2.0.1-RC1/modules/builder/src/main/java/org/apache/tuscany/sca/builder/impl/ComponentBuilderImpl.java
@@ -0,0 +1,1735 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.tuscany.sca.builder.impl;
+
+import java.io.InputStream;
+import java.io.StringReader;
+import java.net.URI;
+import java.net.URL;
+import java.net.URLConnection;
+import 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.InterfaceContract;
+import org.apache.tuscany.sca.interfacedef.InterfaceContractMapper;
+import org.apache.tuscany.sca.interfacedef.impl.DataTypeImpl;
+import org.apache.tuscany.sca.interfacedef.java.JavaInterfaceContract;
+import org.apache.tuscany.sca.interfacedef.util.JavaXMLMapper;
+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, context);
+
+ // 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, context);
+
+ // 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 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 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);
+ // copy the types up if not specified at the component level
+ if (componentProperty.getXSDElement() == null){
+ componentProperty.setXSDElement(property.getXSDElement());
+ }
+ if (componentProperty.getXSDType() == null){
+ componentProperty.setXSDType(property.getXSDType());
+ }
+ } 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 the types specified in the component type and component property match
+ if ( componentProperty.getXSDElement() != null &&
+ componentTypeProperty.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 &&
+ componentTypeProperty.getXSDType() != null &&
+ !componentProperty.getXSDType().equals(componentTypeProperty.getXSDType())){
+ Monitor.error(monitor,
+ this,
+ Messages.ASSEMBLY_VALIDATION,
+ "PropertXSDTypesDontMatch",
+ component.getName(),
+ componentProperty.getName(),
+ componentProperty.getXSDType(),
+ componentTypeProperty.getXSDType());
+ }
+ }
+ }
+
+ /**
+ * checks that the component property value is correctly typed when compared with
+ * the type specified in the composite file property
+ *
+ * TODO - Don't yet handle multiplicity
+ * Need to check composite properties also
+ *
+ * @param component
+ * @param componentProperty
+ * @param monitor
+ */
+ private void checkComponentPropertyType(Component component, ComponentProperty componentProperty, Monitor monitor) {
+
+ QName propertyXSDType = componentProperty.getXSDType();
+ QName propertyElementType = componentProperty.getXSDElement();
+
+ if (propertyXSDType != null){
+ if (propertyXSDType.getNamespaceURI().equals("http://www.w3.org/2001/XMLSchema")) {
+ // The property has a simple schema type so we can use the
+ // data binding framework to see if the XML value can be transformed
+ // into a simple Java value
+ Document doc = (Document)componentProperty.getValue();
+ Node source = (doc == null) ? null : doc.getDocumentElement().getFirstChild();
+ DataType<XMLType> sourceDataType = new DataTypeImpl<XMLType>(DOMDataBinding.NAME,
+ Node.class,
+ new XMLType(null, componentProperty.getXSDType()));
+ DataType<XMLType> targetDataType = new DataTypeImpl<XMLType>(JAXBDataBinding.NAME,
+ Object.class,
+ new XMLType(null, componentProperty.getXSDType()));
+ try {
+ mediator.mediate(source, sourceDataType, targetDataType, null);
+ } catch (Exception ex){
+ Monitor.error(monitor,
+ this,
+ Messages.ASSEMBLY_VALIDATION,
+ "PropertyValueDoesNotMatchSimpleType",
+ componentProperty.getName(),
+ component.getName(),
+ componentProperty.getXSDType().toString());
+ }
+ } else {
+ // The property has a complex schema type so we fluff up a schema
+ // and use that to validate the property value
+ XSDefinition xsdDefinition = (XSDefinition)componentProperty.getXSDDefinition();
+
+ if (xsdDefinition != null) {
+ try {
+ // create schema factory for XML schema
+ SchemaFactory factory = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);
+
+ Document schemaDom = xsdDefinition.getSchema().getSchemaDocument();
+
+ String valueSchema = null;
+ Schema schema = null;
+
+ if (componentProperty.getXSDType().getNamespaceURI().equals(Constants.SCA11_NS)){
+ // include the referenced schema as it's already in the OASIS namespace
+ valueSchema = "<?xml version=\"1.0\" encoding=\"UTF-8\"?> " +
+ "<schema xmlns=\"http://www.w3.org/2001/XMLSchema\" "+
+ "xmlns:sca=\"http://docs.oasis-open.org/ns/opencsa/sca/200912\" "+
+ "xmlns:__tmp=\"" + componentProperty.getXSDType().getNamespaceURI() + "\" "+
+ "targetNamespace=\"http://docs.oasis-open.org/ns/opencsa/sca/200912\" " +
+ "elementFormDefault=\"qualified\">" +
+ "<include schemaLocation=\"" + xsdDefinition.getLocation() + "\"/>" +
+// "<element name=\"value\" type=\"" + "__tmp:" + componentProperty.getXSDType().getLocalPart() + "\"/>" +
+ "</schema>";
+// Source sources[] = {new StreamSource(new StringReader(valueSchema))};
+ Source sources[] = {new DOMSource(schemaDom)};
+ schema = factory.newSchema(sources);
+
+ // The SCA schema already contains a "value" element so I can't create this schema
+ // the SCA value element is an any so return assuming that it validates.
+ return;
+ } else {
+ // import the referenced schema
+ valueSchema = "<?xml version=\"1.0\" encoding=\"UTF-8\"?> " +
+ "<schema xmlns=\"http://www.w3.org/2001/XMLSchema\" "+
+ "xmlns:sca=\"http://docs.oasis-open.org/ns/opencsa/sca/200912\" "+
+ "xmlns:__tmp=\"" + componentProperty.getXSDType().getNamespaceURI() + "\" "+
+ "targetNamespace=\"http://docs.oasis-open.org/ns/opencsa/sca/200912\" " +
+ "elementFormDefault=\"qualified\">" +
+ "<import namespace=\"" + componentProperty.getXSDType().getNamespaceURI() + "\"/>" +
+ "<element name=\"value\" type=\"" + "__tmp:" + componentProperty.getXSDType().getLocalPart() + "\"/>" +
+ "</schema>";
+ Source sources[] = {new DOMSource(schemaDom), new StreamSource(new StringReader(valueSchema))};
+ schema = factory.newSchema(sources);
+ }
+
+ // get the value child of the property element
+ Document property = (Document)componentProperty.getValue();
+ Element value = (Element)property.getDocumentElement().getFirstChild();
+
+ // validate the element property/value from the DOM
+ Validator validator = schema.newValidator();
+ validator.validate(new DOMSource(value));
+
+ } catch (Exception e) {
+ Monitor.error(monitor,
+ this,
+ Messages.ASSEMBLY_VALIDATION,
+ "PropertyValueDoesNotMatchComplexType",
+ componentProperty.getName(),
+ component.getName(),
+ componentProperty.getXSDType().toString(),
+ e.getMessage());
+ }
+ }
+ }
+ } else if (propertyElementType != null) {
+ // TODO - TUSCANY-3530 - still need to add validation for element type
+
+ }
+ }
+
+ /**
+ * If the property has a source attribute use this to retrieve the value from a
+ * property in the parent composite
+ *
+ * @param parentCompoent the composite that contains the component
+ * @param component
+ * @param componentProperty
+ */
+ private void processPropertySourceAttribute(Component outerComponent,
+ Composite parentComposite,
+ Component component,
+ ComponentProperty componentProperty,
+ Monitor monitor) {
+ String source = componentProperty.getSource();
+
+ if (source == null) 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);
+ if(componentProperty.getXSDElement() == null){
+ componentProperty.setXSDElement(sourceProp.getXSDElement());
+ }
+ if(componentProperty.getXSDType() == null){
+ componentProperty.setXSDType(sourceProp.getXSDType());
+ }
+ } 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);
+ contract.setNormalizedWSDLContract(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);
+ implContract.setNormalizedWSDLContract(null);
+ implReference.setInterfaceContract(implContract);
+ } catch (CloneNotSupportedException e) {
+ // will not happen
+ }
+ // FIXME: We need to set the allowsPassByReference flag based on the annotations on the implementation and callback
+ // implReference.setAllowsPassByReference(allowsPassByReference);
+ 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);
+ contract.setNormalizedWSDLContract(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);
+ implContract.setNormalizedWSDLContract(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, BuilderContext context) {
+
+ // 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) {
+ // apply remotable override if it has been specified in the SCDL for the
+ // higher level contract
+ if (topInterfaceContract.getInterface().isRemotableSetFromSCDL() == true){
+ if (bottomInterfaceContract.getInterface().isRemotable() == false &&
+ topInterfaceContract.getInterface().isRemotable() == true){
+ bottomInterfaceContract.getInterface().setRemotable(true);
+ }
+ }
+
+ // Check that the top and bottom interface contracts are compatible
+ boolean isCompatible = true;
+ String incompatibilityReason = "";
+ try{
+ isCompatible = checkSubsetCompatibility(topInterfaceContract,
+ bottomInterfaceContract,
+ context);
+ } catch (IncompatibleInterfaceContractException ex){
+ isCompatible = false;
+ incompatibilityReason = ex.getMessage();
+ }
+ if (!isCompatible) {
+ Monitor.error(context.getMonitor(),
+ 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, BuilderContext context) {
+
+ // 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) {
+ // apply remotable override if it has been specified in the SCDL for the
+ // higher level contract
+ if (topInterfaceContract.getInterface().isRemotableSetFromSCDL() == true){
+ if (bottomInterfaceContract.getInterface().isRemotable() == false &&
+ topInterfaceContract.getInterface().isRemotable() == true){
+ bottomInterfaceContract.getInterface().setRemotable(true);
+ }
+ }
+ // Check that the top and bottom interface contracts are compatible
+ boolean isCompatible = true;
+ String incompatibilityReason = "";
+ try{
+ isCompatible = checkSubsetCompatibility(bottomInterfaceContract,
+ topInterfaceContract,
+ context);
+ } catch (IncompatibleInterfaceContractException ex){
+ isCompatible = false;
+ incompatibilityReason = ex.getMessage();
+ }
+ if (!isCompatible) {
+ Monitor.error(context.getMonitor(),
+ 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, BuilderContext context)
+ throws IncompatibleInterfaceContractException {
+
+ if (contractA.getClass() != contractB.getClass()) {
+
+ if (contractA instanceof JavaInterfaceContract){
+ contractBuilder.build(contractA, context);
+ contractA = ((JavaInterfaceContract)contractA).getNormalizedWSDLContract();
+ }
+
+ if (contractB instanceof JavaInterfaceContract){
+ contractBuilder.build(contractB, context);
+ contractB = ((JavaInterfaceContract)contractB).getNormalizedWSDLContract();
+ }
+ }
+
+ return interfaceContractMapper.checkCompatibility(contractA,
+ contractB,
+ Compatibility.SUBSET,
+ false,
+ false);
+ }
+
+}
diff --git a/sca-java-2.x/tags/2.0.1-RC1/modules/builder/src/main/java/org/apache/tuscany/sca/builder/impl/ComponentPolicyBuilderImpl.java b/sca-java-2.x/tags/2.0.1-RC1/modules/builder/src/main/java/org/apache/tuscany/sca/builder/impl/ComponentPolicyBuilderImpl.java
new file mode 100644
index 0000000000..cbade8d520
--- /dev/null
+++ b/sca-java-2.x/tags/2.0.1-RC1/modules/builder/src/main/java/org/apache/tuscany/sca/builder/impl/ComponentPolicyBuilderImpl.java
@@ -0,0 +1,650 @@
+/*
+ * 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.DefaultIntent;
+import org.apache.tuscany.sca.policy.DefaultingPolicySubject;
+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.
+ // Some policy plugins, e.g. JSR250, add resolved policy sets
+ // on the fly as they read details from annotations. So check
+ // that policy sets are unresolved befor blowing them away with
+ // a warning
+ Set<PolicySet> policySets = new HashSet<PolicySet>();
+ if (definitions != null) {
+ for (PolicySet policySet : subject.getPolicySets()) {
+ if (policySet.isUnresolved()){
+ 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);
+ }
+ } else {
+ policySets.add(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){
+
+ // 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 ) {
+ // The ExtensionType on the subject only has the binding name. The one in the system
+ // definitions will have the mayProvide/alwaysProvides values
+ if (type.getType().getLocalPart().startsWith("implementation")) {
+ for ( ExtensionType et : context.getDefinitions().getImplementationTypes() ) {
+ if ( type.getType().equals(et.getType()) ) {
+ type = et;
+ }
+ }
+ } else {
+ for ( ExtensionType et : context.getDefinitions().getBindingTypes() ) {
+ if ( type.getType().equals(et.getType()) ) {
+ type = et;
+ }
+ }
+ }
+ }
+
+ if ( type == null || !type.getAlwaysProvidedIntents().contains(intent) && !type.getMayProvidedIntents().contains(intent)) {
+ // 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 {
+ error(context.getMonitor(), "IntentNotSatisfiedAtBuild", subject, intent.getName(), subject.toString());
+ }
+ }
+ }
+ }
+ }
+
+ protected Set<String> getPolicyNames(PolicySubject subject) {
+ if (subject == null) {
+ return Collections.emptySet();
+ }
+ Set<String> names = new HashSet<String>();
+ for (PolicySet ps : subject.getPolicySets()) {
+ for (PolicyExpression exp : ps.getPolicies()) {
+ names.add(exp.getName().getNamespaceURI());
+ }
+ }
+ return names;
+ }
+
+ protected boolean isQualifiedBy(Intent qualifiableIntent, Intent qualifiedIntent){
+ if (qualifiedIntent.getQualifiableIntent() == qualifiableIntent){
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+ // Add in default intents. This looks at the default intent map for
+ // the policy subject and. If none of the mutually exclusive intents are
+ // already present adds in the default intent.
+ protected void addDefaultIntents(PolicySubject subject, Object defaultSubjectObject, BuilderContext context){
+ if (!(defaultSubjectObject instanceof DefaultingPolicySubject)){
+ return;
+ }
+
+ DefaultingPolicySubject defaultSubject = (DefaultingPolicySubject)defaultSubjectObject;
+ List<DefaultIntent> defaultIntents = defaultSubject.getDefaultIntents();
+
+ for(DefaultIntent defaultIntent : defaultIntents){
+ // check default intent against the intents already in the subject
+ boolean addDefaultIntent = true;
+
+ // first check the intents which, if present prevent the default being applied
+ for (Intent mutualExclusion : defaultIntent.getMutuallyExclusiveIntents()){
+ if (subject.getRequiredIntents().contains(mutualExclusion)){
+ addDefaultIntent = false;
+ break;
+ }
+ }
+
+ // then check that the default intent itself is not mutually exclusive
+ for (Intent userDefinedIntent : subject.getRequiredIntents()){
+ if (!checkMutualExclusionNoError(defaultIntent.getIntent(), userDefinedIntent, context)){
+ addDefaultIntent = false;
+ break;
+ }
+ }
+
+ if (addDefaultIntent == true){
+ subject.getRequiredIntents().add(defaultIntent.getIntent());
+ }
+ }
+ }
+
+ /**
+ * Same as checkMutualExclusion but doesn't throw and error on failure
+ */
+ protected boolean checkMutualExclusionNoError(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))) {
+ return true;
+ }
+
+ return false;
+ }
+
+}
diff --git a/sca-java-2.x/tags/2.0.1-RC1/modules/builder/src/main/java/org/apache/tuscany/sca/builder/impl/ComponentReferenceBindingBuilderImpl.java b/sca-java-2.x/tags/2.0.1-RC1/modules/builder/src/main/java/org/apache/tuscany/sca/builder/impl/ComponentReferenceBindingBuilderImpl.java
new file mode 100644
index 0000000000..38ab265c6e
--- /dev/null
+++ b/sca-java-2.x/tags/2.0.1-RC1/modules/builder/src/main/java/org/apache/tuscany/sca/builder/impl/ComponentReferenceBindingBuilderImpl.java
@@ -0,0 +1,81 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.tuscany.sca.builder.impl;
+
+import org.apache.tuscany.sca.assembly.Binding;
+import org.apache.tuscany.sca.assembly.Component;
+import org.apache.tuscany.sca.assembly.ComponentReference;
+import org.apache.tuscany.sca.assembly.Composite;
+import org.apache.tuscany.sca.assembly.Implementation;
+import org.apache.tuscany.sca.assembly.builder.BindingBuilder;
+import org.apache.tuscany.sca.assembly.builder.BuilderContext;
+import org.apache.tuscany.sca.assembly.builder.BuilderExtensionPoint;
+import org.apache.tuscany.sca.assembly.builder.CompositeBuilder;
+import org.apache.tuscany.sca.assembly.builder.CompositeBuilderException;
+import org.apache.tuscany.sca.core.ExtensionPointRegistry;
+
+/**
+ * A composite builder that performs any additional building steps that
+ * component reference bindings may need. Used for WSDL generation.
+ *
+ * @version $Rev$ $Date$
+ */
+public class ComponentReferenceBindingBuilderImpl implements CompositeBuilder {
+
+ private BuilderExtensionPoint builders;
+
+ public ComponentReferenceBindingBuilderImpl(ExtensionPointRegistry registry) {
+ this.builders = registry.getExtensionPoint(BuilderExtensionPoint.class);
+ }
+
+ public Composite build(Composite composite, BuilderContext context)
+ throws CompositeBuilderException {
+ buildReferenceBindings(composite, context);
+ return composite;
+ }
+
+ public String getID() {
+ return "org.apache.tuscany.sca.assembly.builder.ComponentReferenceBindingBuilder";
+ }
+
+ private void buildReferenceBindings(Composite composite, BuilderContext context) {
+
+ // find all the component reference bindings (starting at top level)
+ for (Component component : composite.getComponents()) {
+ for (ComponentReference componentReference : component.getReferences()) {
+ for (Binding binding : componentReference.getBindings()) {
+ BindingBuilder builder = builders.getBindingBuilder(binding.getType());
+ if (builder != null) {
+ builder.build(component, componentReference, binding, context, false);
+ }
+ }
+ }
+ }
+
+ // build bindings recursively
+ for (Component component : composite.getComponents()) {
+ Implementation implementation = component.getImplementation();
+ if (implementation instanceof Composite) {
+ buildReferenceBindings((Composite)implementation, context);
+ }
+ }
+ }
+
+}
diff --git a/sca-java-2.x/tags/2.0.1-RC1/modules/builder/src/main/java/org/apache/tuscany/sca/builder/impl/ComponentServiceBindingBuilderImpl.java b/sca-java-2.x/tags/2.0.1-RC1/modules/builder/src/main/java/org/apache/tuscany/sca/builder/impl/ComponentServiceBindingBuilderImpl.java
new file mode 100644
index 0000000000..2debe41f2d
--- /dev/null
+++ b/sca-java-2.x/tags/2.0.1-RC1/modules/builder/src/main/java/org/apache/tuscany/sca/builder/impl/ComponentServiceBindingBuilderImpl.java
@@ -0,0 +1,80 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.tuscany.sca.builder.impl;
+
+import org.apache.tuscany.sca.assembly.Binding;
+import org.apache.tuscany.sca.assembly.Component;
+import org.apache.tuscany.sca.assembly.ComponentService;
+import org.apache.tuscany.sca.assembly.Composite;
+import org.apache.tuscany.sca.assembly.Implementation;
+import org.apache.tuscany.sca.assembly.builder.BindingBuilder;
+import org.apache.tuscany.sca.assembly.builder.BuilderContext;
+import org.apache.tuscany.sca.assembly.builder.BuilderExtensionPoint;
+import org.apache.tuscany.sca.assembly.builder.CompositeBuilder;
+import org.apache.tuscany.sca.assembly.builder.CompositeBuilderException;
+import org.apache.tuscany.sca.core.ExtensionPointRegistry;
+
+/**
+ * A composite builder that performs any additional building steps that
+ * component service bindings may need. Used for WSDL generation.
+ *
+ * @version $Rev$ $Date$
+ */
+public class ComponentServiceBindingBuilderImpl implements CompositeBuilder {
+ private BuilderExtensionPoint builders;
+
+ public ComponentServiceBindingBuilderImpl(ExtensionPointRegistry registry) {
+ this.builders = registry.getExtensionPoint(BuilderExtensionPoint.class);
+ }
+
+ public String getID() {
+ return "org.apache.tuscany.sca.assembly.builder.ComponentServiceBindingBuilder";
+ }
+
+ public Composite build(Composite composite, BuilderContext context)
+ throws CompositeBuilderException {
+ buildServiceBindings(composite, context);
+ return composite;
+ }
+
+ private void buildServiceBindings(Composite composite, BuilderContext context) {
+
+ // build bindings recursively
+ for (Component component : composite.getComponents()) {
+ Implementation implementation = component.getImplementation();
+ if (implementation instanceof Composite) {
+ buildServiceBindings((Composite)implementation, context);
+ }
+ }
+
+ // find all the component service bindings
+ for (Component component : composite.getComponents()) {
+ for (ComponentService componentService : component.getServices()) {
+ for (Binding binding : componentService.getBindings()) {
+ BindingBuilder builder = builders.getBindingBuilder(binding.getType());
+ if (builder != null) {
+ builder.build(component, componentService, binding, context, false);
+ }
+ }
+ }
+ }
+ }
+
+}
diff --git a/sca-java-2.x/tags/2.0.1-RC1/modules/builder/src/main/java/org/apache/tuscany/sca/builder/impl/CompositeCloneBuilderImpl.java b/sca-java-2.x/tags/2.0.1-RC1/modules/builder/src/main/java/org/apache/tuscany/sca/builder/impl/CompositeCloneBuilderImpl.java
new file mode 100644
index 0000000000..148a3b5368
--- /dev/null
+++ b/sca-java-2.x/tags/2.0.1-RC1/modules/builder/src/main/java/org/apache/tuscany/sca/builder/impl/CompositeCloneBuilderImpl.java
@@ -0,0 +1,100 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.tuscany.sca.builder.impl;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.tuscany.sca.assembly.Component;
+import org.apache.tuscany.sca.assembly.Composite;
+import org.apache.tuscany.sca.assembly.Implementation;
+import org.apache.tuscany.sca.assembly.builder.BuilderContext;
+import org.apache.tuscany.sca.assembly.builder.CompositeBuilder;
+import org.apache.tuscany.sca.assembly.builder.CompositeBuilderException;
+
+/**
+ * A composite builder that clones nested composites.
+ *
+ * @version $Rev$ $Date$
+ */
+public class CompositeCloneBuilderImpl implements CompositeBuilder {
+
+ public CompositeCloneBuilderImpl() {
+ }
+
+ public Composite build(Composite composite, BuilderContext context)
+ throws CompositeBuilderException {
+
+ if (Composite.DOMAIN_COMPOSITE.equals(composite.getName())) {
+ // Try to avoid clone for top-level composites that are added to the domain composite
+ for (Composite included : composite.getIncludes()) {
+ cloneIncludes(included);
+ cloneCompositeImplementations(included);
+ }
+ } else {
+ // Clone the includes
+ cloneIncludes(composite);
+ cloneCompositeImplementations(composite);
+ }
+
+ return composite;
+ }
+
+ private void cloneIncludes(Composite composite) {
+ List<Composite> includes = new ArrayList<Composite>();
+ for (Composite included : composite.getIncludes()) {
+ try {
+ includes.add((Composite)included.clone());
+ } catch (CloneNotSupportedException e) {
+ throw new UnsupportedOperationException(e);
+ }
+ }
+ composite.getIncludes().clear();
+ composite.getIncludes().addAll(includes);
+ }
+
+ public String getID() {
+ return "org.apache.tuscany.sca.assembly.builder.CompositeCloneBuilder";
+ }
+
+ /**
+ * Clone composite component implementations
+ *
+ * @param composite
+ * @param problems
+ */
+ private void cloneCompositeImplementations(Composite composite) {
+ for (Component component : composite.getComponents()) {
+ Implementation implementation = component.getImplementation();
+ if (implementation instanceof Composite) {
+
+ Composite compositeImplementation = (Composite)implementation;
+ try {
+ // Please note the clone method is recursive
+ Composite clone = (Composite)compositeImplementation.clone();
+ component.setImplementation(clone);
+ } catch (CloneNotSupportedException e) {
+ throw new UnsupportedOperationException(e);
+ }
+ }
+ }
+ }
+
+}
diff --git a/sca-java-2.x/tags/2.0.1-RC1/modules/builder/src/main/java/org/apache/tuscany/sca/builder/impl/CompositeComponentTypeBuilderImpl.java b/sca-java-2.x/tags/2.0.1-RC1/modules/builder/src/main/java/org/apache/tuscany/sca/builder/impl/CompositeComponentTypeBuilderImpl.java
new file mode 100644
index 0000000000..83e007f39a
--- /dev/null
+++ b/sca-java-2.x/tags/2.0.1-RC1/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, context);
+
+ // 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, context);
+
+ // 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, BuilderContext context) {
+ // 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, context);
+ } catch (IncompatibleInterfaceContractException ex){
+ isCompatible = false;
+ incompatibilityReason = ex.getMessage();
+ }
+ if (!isCompatible) {
+ Monitor.error(context.getMonitor(),
+ 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, BuilderContext context) {
+ // 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, context);
+ } catch (IncompatibleInterfaceContractException ex){
+ isCompatible = false;
+ incompatibilityReason = ex.getMessage();
+ }
+ if (!isCompatible) {
+ Monitor.error(context.getMonitor(),
+ 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, BuilderContext context)
+ throws IncompatibleInterfaceContractException {
+
+ if (contractA.getClass() != contractB.getClass()) {
+
+ if (contractA instanceof JavaInterfaceContract){
+ contractBuilder.build(contractA, context);
+ contractA = ((JavaInterfaceContract)contractA).getNormalizedWSDLContract();
+ }
+
+ if (contractB instanceof JavaInterfaceContract){
+ contractBuilder.build(contractB, context);
+ contractB = ((JavaInterfaceContract)contractB).getNormalizedWSDLContract();
+ }
+ }
+
+ return interfaceContractMapper.checkCompatibility(contractA,
+ contractB,
+ Compatibility.SUBSET,
+ false,
+ false);
+ }
+
+} //end class
diff --git a/sca-java-2.x/tags/2.0.1-RC1/modules/builder/src/main/java/org/apache/tuscany/sca/builder/impl/CompositeIncludeBuilderImpl.java b/sca-java-2.x/tags/2.0.1-RC1/modules/builder/src/main/java/org/apache/tuscany/sca/builder/impl/CompositeIncludeBuilderImpl.java
new file mode 100644
index 0000000000..453f1ad41b
--- /dev/null
+++ b/sca-java-2.x/tags/2.0.1-RC1/modules/builder/src/main/java/org/apache/tuscany/sca/builder/impl/CompositeIncludeBuilderImpl.java
@@ -0,0 +1,127 @@
+/*
+ * 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.getFusedIncludes().addAll(composite.getIncludes());
+ composite.getIncludes().clear();
+
+ // return the fused composite we have built up so far
+ return composite;
+ } finally {
+ monitor.popContext();
+ }
+ }
+}
diff --git a/sca-java-2.x/tags/2.0.1-RC1/modules/builder/src/main/java/org/apache/tuscany/sca/builder/impl/CompositePolicyBuilderImpl.java b/sca-java-2.x/tags/2.0.1-RC1/modules/builder/src/main/java/org/apache/tuscany/sca/builder/impl/CompositePolicyBuilderImpl.java
new file mode 100644
index 0000000000..9ef41dcf33
--- /dev/null
+++ b/sca-java-2.x/tags/2.0.1-RC1/modules/builder/src/main/java/org/apache/tuscany/sca/builder/impl/CompositePolicyBuilderImpl.java
@@ -0,0 +1,492 @@
+/*
+ * 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.PolicyExpression;
+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());
+ }
+
+ // add in default binding mayProvides intents
+ addDefaultIntents(ep, ep.getBinding(), context);
+
+ // 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());
+ }
+
+ // add in default binding mayProvides intents
+ addDefaultIntents(epr, epr.getBinding(), context);
+
+ // 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());
+ }
+ }
+ }
+ }
+ }
+ }
+
+/* TUSCANY-4006 - This is allowed; transactedOneWay applies only to the one-way methods when an interface also has two-way operations
+ */
+ 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<String> 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 (PolicySet ps : ep.getPolicySets()) {
+ for (PolicyExpression exp : ps.getPolicies()) {
+ PolicyBuilder builder = builders.getPolicyBuilder(exp.getName());
+ if (builder != null) {
+ builder.build(ep, context);
+ }
+ }
+ }
+ }
+ }
+ }
+
+ for (ComponentReference componentReference : component.getReferences()) {
+ for (EndpointReference epr : componentReference.getEndpointReferences()) {
+ Set<String> 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 (PolicySet ps : epr.getPolicySets()) {
+ for (PolicyExpression exp : ps.getPolicies()) {
+ PolicyBuilder builder = builders.getPolicyBuilder(exp.getName());
+ if (builder != null) {
+ builder.build(epr, context);
+ }
+ }
+ }
+ }
+ }
+ }
+
+ Implementation implementation = component.getImplementation();
+ if (implementation != null) {
+ Set<String> 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 (PolicySet ps : implementation.getPolicySets()) {
+ for (PolicyExpression exp : ps.getPolicies()) {
+ PolicyBuilder builder = builders.getPolicyBuilder(exp.getName());
+ if (builder != null) {
+ builder.build(component, implementation, context);
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/sca-java-2.x/tags/2.0.1-RC1/modules/builder/src/main/java/org/apache/tuscany/sca/builder/impl/CompositeWireApplierImpl.java b/sca-java-2.x/tags/2.0.1-RC1/modules/builder/src/main/java/org/apache/tuscany/sca/builder/impl/CompositeWireApplierImpl.java
new file mode 100644
index 0000000000..3167b8cdb6
--- /dev/null
+++ b/sca-java-2.x/tags/2.0.1-RC1/modules/builder/src/main/java/org/apache/tuscany/sca/builder/impl/CompositeWireApplierImpl.java
@@ -0,0 +1,212 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.tuscany.sca.builder.impl;
+
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.tuscany.sca.assembly.AssemblyFactory;
+import org.apache.tuscany.sca.assembly.Component;
+import org.apache.tuscany.sca.assembly.ComponentReference;
+import org.apache.tuscany.sca.assembly.ComponentService;
+import org.apache.tuscany.sca.assembly.Composite;
+import org.apache.tuscany.sca.assembly.Implementation;
+import org.apache.tuscany.sca.assembly.Reference;
+import org.apache.tuscany.sca.assembly.Service;
+import org.apache.tuscany.sca.assembly.Wire;
+import org.apache.tuscany.sca.assembly.builder.BuilderContext;
+import org.apache.tuscany.sca.assembly.builder.CompositeBuilder;
+import org.apache.tuscany.sca.assembly.builder.CompositeBuilderException;
+import org.apache.tuscany.sca.assembly.builder.Messages;
+import org.apache.tuscany.sca.core.ExtensionPointRegistry;
+import org.apache.tuscany.sca.core.FactoryExtensionPoint;
+import org.apache.tuscany.sca.core.UtilityExtensionPoint;
+import org.apache.tuscany.sca.interfacedef.InterfaceContractMapper;
+import org.apache.tuscany.sca.monitor.Monitor;
+
+/**
+ * Apply any <wire/> elements in the composites by creating suitable reference targets
+ *
+ * @version $Rev$ $Date$
+ */
+public class CompositeWireApplierImpl implements CompositeBuilder {
+
+ private InterfaceContractMapper interfaceContractMapper;
+
+
+ public CompositeWireApplierImpl(ExtensionPointRegistry registry) {
+ UtilityExtensionPoint utilities = registry.getExtensionPoint(UtilityExtensionPoint.class);
+ interfaceContractMapper = utilities.getUtility(InterfaceContractMapper.class);
+ }
+
+ public String getID() {
+ return "org.apache.tuscany.sca.assembly.builder.CompositeWireApplierImpl";
+ }
+
+ public Composite build(Composite composite, BuilderContext context)
+ throws CompositeBuilderException {
+
+ processComposite(composite, context);
+
+ return composite;
+ }
+
+ private void processComposite(Composite composite, BuilderContext context){
+ // Index components, services and references
+ Map<String, Component> components = new HashMap<String, Component>();
+ Map<String, ComponentService> componentServices = new HashMap<String, ComponentService>();
+ Map<String, ComponentReference> componentReferences = new HashMap<String, ComponentReference>();
+ indexComponentsServicesAndReferences(composite, components, componentServices, componentReferences);
+
+ // Connect component references as described in wires
+ connectWires(composite, componentServices, componentReferences, context.getMonitor());
+
+ for (Component component : composite.getComponents()) {
+ // recurse for composite implementations
+ Implementation implementation = component.getImplementation();
+ if (implementation instanceof Composite) {
+ processComposite((Composite)implementation, context);
+ }
+ }
+ }
+
+ protected void indexComponentsServicesAndReferences(Composite composite,
+ Map<String, Component> components,
+ Map<String, ComponentService> componentServices,
+ Map<String, ComponentReference> componentReferences) {
+
+ for (Component component : composite.getComponents()) {
+
+ // Index components by name
+ components.put(component.getName(), component);
+
+ ComponentService nonCallbackService = null;
+ int nonCallbackServices = 0;
+ for (ComponentService componentService : component.getServices()) {
+
+ // Index component services by component name / service name
+ String uri = component.getName() + '/'
+ + componentService.getName();
+ componentServices.put(uri, componentService);
+
+ // count how many non-callback services there are
+ // if there is only one the component name also acts as the
+ // service name
+ if (!componentService.isForCallback()) {
+ // Check how many non callback non-promoted services we have
+ if (nonCallbackServices == 0) {
+ nonCallbackService = componentService;
+ }
+ nonCallbackServices++;
+ }
+ }
+
+ if (nonCallbackServices == 1) {
+ // If we have a single non callback service, index it by
+ // component name as well
+ componentServices.put(component.getName(), nonCallbackService);
+ }
+
+ // Index references by component name / reference name
+ for (ComponentReference componentReference : component
+ .getReferences()) {
+ String uri = component.getName() + '/'
+ + componentReference.getName();
+ componentReferences.put(uri, componentReference);
+ }
+ }
+ }
+
+ /**
+ * Resolve wires and connect the sources to their targets
+ *
+ * @param composite
+ * @param componentServices
+ * @param componentReferences
+ * @param problems
+ */
+ private void connectWires(Composite composite,
+ Map<String, ComponentService> componentServices,
+ Map<String, ComponentReference> componentReferences,
+ Monitor monitor) {
+
+ // For each wire, resolve the source reference, the target service, and
+ // add it to the list of targets of the reference
+ List<Wire> wires = composite.getWires();
+ for (int i = 0, n = wires.size(); i < n; i++) {
+ Wire wire = wires.get(i);
+
+ ComponentReference resolvedReference;
+ ComponentService resolvedService;
+
+ // Resolve the source reference
+ ComponentReference source = wire.getSource();
+ if (source != null && source.isUnresolved()) {
+ resolvedReference = componentReferences.get(source.getName());
+ if (resolvedReference != null) {
+ wire.setSource(resolvedReference);
+ } else {
+ Monitor.warning(monitor, this, Messages.ASSEMBLY_VALIDATION, "WireSourceNotFound", source
+ .getName());
+ }
+ } else {
+ resolvedReference = wire.getSource();
+ }
+
+ // Resolve the target service
+ ComponentService target = wire.getTarget();
+ if (target != null && target.isUnresolved()) {
+ resolvedService = componentServices.get(target.getName());
+ if (resolvedService != null) {
+ wire.setTarget(target);
+ } else {
+ Monitor.warning(monitor, this, Messages.ASSEMBLY_VALIDATION, "WireTargetNotFound", target
+ .getName());
+ }
+ } else {
+ resolvedService = wire.getTarget();
+ }
+
+ // Add the target service to the list of targets of the
+ // reference
+ if (resolvedReference != null && resolvedService != null) {
+ // Check that the target component service provides
+ // a superset of
+ // the component reference interface
+ if (resolvedReference.getInterfaceContract() == null || interfaceContractMapper
+ .isCompatibleSubset(resolvedReference.getInterfaceContract(), resolvedService.getInterfaceContract())) {
+
+ //resolvedReference.getTargets().add(resolvedService);
+ if (wire.isReplace()) {
+ resolvedReference.getTargets().clear();
+ }
+ resolvedReference.getTargets().add(wire.getTarget());
+ } else {
+ Monitor.warning(monitor, this, Messages.ASSEMBLY_VALIDATION, "WireIncompatibleInterface", source
+ .getName(), target.getName());
+ }
+ }
+ }
+
+ // Clear the list of wires
+ composite.getWires().clear();
+ }
+}
diff --git a/sca-java-2.x/tags/2.0.1-RC1/modules/builder/src/main/java/org/apache/tuscany/sca/builder/impl/EndpointBuilderImpl.java b/sca-java-2.x/tags/2.0.1-RC1/modules/builder/src/main/java/org/apache/tuscany/sca/builder/impl/EndpointBuilderImpl.java
new file mode 100644
index 0000000000..0c25790920
--- /dev/null
+++ b/sca-java-2.x/tags/2.0.1-RC1/modules/builder/src/main/java/org/apache/tuscany/sca/builder/impl/EndpointBuilderImpl.java
@@ -0,0 +1,138 @@
+/*
+ * 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.
+ service.getEndpoints().clear();
+ for (Binding binding : service.getBindings()) {
+ Endpoint endpoint = assemblyFactory.createEndpoint();
+ endpoint.setComponent(component);
+ endpoint.setService(service);
+ endpoint.setBinding(binding);
+ endpoint.setUnresolved(false);
+ service.getEndpoints().add(endpoint);
+ } // end for
+ } finally {
+ monitor.popContext();
+ }
+ }
+ } finally {
+ monitor.popContext();
+ }
+ }
+ }
+
+ public String getID() {
+ return "org.apache.tuscany.sca.assembly.builder.EndpointBuilder";
+ }
+}
diff --git a/sca-java-2.x/tags/2.0.1-RC1/modules/builder/src/main/java/org/apache/tuscany/sca/builder/impl/EndpointReferenceBuilderImpl.java b/sca-java-2.x/tags/2.0.1-RC1/modules/builder/src/main/java/org/apache/tuscany/sca/builder/impl/EndpointReferenceBuilderImpl.java
new file mode 100644
index 0000000000..95824afa8c
--- /dev/null
+++ b/sca-java-2.x/tags/2.0.1-RC1/modules/builder/src/main/java/org/apache/tuscany/sca/builder/impl/EndpointReferenceBuilderImpl.java
@@ -0,0 +1,840 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.tuscany.sca.builder.impl;
+
+import java.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;
+
+ String[] parts = getSCATargetParts(uri);
+
+ if (parts != null){
+ // 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);
+ if (binding instanceof SCABinding) {
+ // TUSCANY-3941
+ // if it's an SCA binding we store it to influence the matching at runtime
+ endpointRef.setBinding(binding);
+ }
+ endpointRef.setStatus(EndpointReference.Status.WIRED_TARGET_IN_BINDING_URI);
+ } else {
+ // 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);
+ endpoint.setRemote(true);
+ 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;
+ if (!leafRef.isNonOverridable()) {
+ leafRef.getEndpointReferences().clear();
+ }
+ 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()) {
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * 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) {
+ return null;
+ }
+ 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);
+
+ if (parts == null){
+ 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
+
+ /**
+ * 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 relate 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 that the OASIS spec
+ * is not very clear on. We need to decide which callback endpoint is associated with
+ * which endpointreference. For the time being we select the first one that matches the
+ * forward binding type as we assume that the user is simply using the callback binding
+ * configuration to further configure the type of binding they used for the forward call.
+ *
+ * @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()){
+ for(Endpoint callbackEndpoint : callbackEndpoints){
+ if((endpointReference.getBinding() != null) &&
+ (callbackEndpoint.getBinding() != null) &&
+ (callbackEndpoint.getBinding().getType().equals(endpointReference.getBinding().getType()))){
+ endpointReference.setCallbackEndpoint(callbackEndpoint);
+ break;
+ }
+ }
+ }
+ }
+ }
+
+ // 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()) {
+ for ( EndpointReference callbackEndpointReference : reference.getEndpointReferences()){
+ if((endpoint.getBinding() == null) &&
+ (callbackEndpointReference.getBinding() == null) &&
+ (callbackEndpointReference.getBinding().getType().equals(endpoint.getBinding().getType()))){
+ endpoint.getCallbackEndpointReferences().add(callbackEndpointReference);
+ break;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+}
diff --git a/sca-java-2.x/tags/2.0.1-RC1/modules/builder/src/main/java/org/apache/tuscany/sca/builder/impl/IntentValidator.java b/sca-java-2.x/tags/2.0.1-RC1/modules/builder/src/main/java/org/apache/tuscany/sca/builder/impl/IntentValidator.java
new file mode 100644
index 0000000000..b2f7a4ceed
--- /dev/null
+++ b/sca-java-2.x/tags/2.0.1-RC1/modules/builder/src/main/java/org/apache/tuscany/sca/builder/impl/IntentValidator.java
@@ -0,0 +1,139 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.tuscany.sca.builder.impl;
+
+import java.util.List;
+
+import javax.xml.namespace.QName;
+
+import org.apache.tuscany.sca.assembly.Component;
+import org.apache.tuscany.sca.assembly.Endpoint;
+import org.apache.tuscany.sca.assembly.EndpointReference;
+import org.apache.tuscany.sca.assembly.Implementation;
+import org.apache.tuscany.sca.assembly.builder.BuilderContext;
+import org.apache.tuscany.sca.assembly.builder.Messages;
+import org.apache.tuscany.sca.assembly.builder.PolicyBuilder;
+import org.apache.tuscany.sca.core.ExtensionPointRegistry;
+import org.apache.tuscany.sca.monitor.Monitor;
+import org.apache.tuscany.sca.policy.Intent;
+import org.apache.tuscany.sca.policy.PolicySubject;
+
+/**
+ * Intent Validator
+ */
+public class IntentValidator implements PolicyBuilder {
+
+ /**
+ * Defaut constructor
+ * @param registry Extension Registry
+ */
+ public IntentValidator(ExtensionPointRegistry registry) {
+ super();
+ }
+
+ public boolean build(Endpoint endpoint, BuilderContext context) {
+ return checkMutualExclusion(endpoint, context);
+ }
+
+ public boolean build(EndpointReference endpointReference, BuilderContext context) {
+ boolean ok = checkMutualExclusion(endpointReference, context);
+ if(!ok) {
+ return false;
+ }
+
+ Endpoint endpoint = endpointReference.getTargetEndpoint();
+ if (endpoint == null) {
+ return true;
+ }
+ ok = checkMutualExclusion(endpointReference, endpoint, context);
+ List<Intent> intentList1 = endpointReference.getRequiredIntents();
+ List<Intent> intentList2 = endpoint.getRequiredIntents();
+ return ok;
+ }
+
+ public boolean build(Component component, Implementation implementation, BuilderContext context) {
+ return true;
+ }
+
+ public boolean build(EndpointReference endpointReference, Endpoint endpoint, BuilderContext context) {
+ return true;
+ }
+
+ public QName getPolicyType() {
+ return null;
+ }
+
+ public List<QName> getSupportedBindings() {
+ return null;
+ }
+
+ /**
+ * Check if two policy subjects requires multually exclusive intents
+ * @param subject1
+ * @param subject2
+ * @param monitor
+ * @return
+ */
+ private boolean checkMutualExclusion(PolicySubject subject1, PolicySubject subject2, BuilderContext context) {
+ if (subject1 == subject2 || subject1 == null || subject2 == null) {
+ return false;
+ }
+ for (Intent i1 : subject1.getRequiredIntents()) {
+ for (Intent i2 : subject2.getRequiredIntents()) {
+ if (i1.getExcludedIntents().contains(i2) || i2.getExcludedIntents().contains(i1)) {
+ Monitor.error(context.getMonitor(),
+ this,
+ Messages.ASSEMBLY_VALIDATION,
+ "MutuallyExclusiveIntents",
+ new Object[] {subject1, subject2},
+ i1,
+ i2);
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+
+ private boolean checkMutualExclusion(PolicySubject subject, BuilderContext context) {
+ if (subject == null) {
+ return false;
+ }
+ List<Intent> intents = subject.getRequiredIntents();
+ int size = intents.size();
+ for (int i = 0; i < size; i++) {
+ for (int j = i + 1; j < size; j++) {
+ Intent i1 = intents.get(i);
+ Intent i2 = intents.get(j);
+ if (i1 != i2 && i1.getExcludedIntents().contains(i2) || i2.getExcludedIntents().contains(i1)) {
+ Monitor.error(context.getMonitor(),
+ this,
+ Messages.ASSEMBLY_VALIDATION,
+ "MutuallyExclusiveIntents",
+ subject,
+ i1,
+ i2);
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+}
diff --git a/sca-java-2.x/tags/2.0.1-RC1/modules/builder/src/main/java/org/apache/tuscany/sca/builder/impl/ModelBuilderImpl.java b/sca-java-2.x/tags/2.0.1-RC1/modules/builder/src/main/java/org/apache/tuscany/sca/builder/impl/ModelBuilderImpl.java
new file mode 100644
index 0000000000..cf1c9cb05f
--- /dev/null
+++ b/sca-java-2.x/tags/2.0.1-RC1/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/sca-java-2.x/tags/2.0.1-RC1/modules/builder/src/main/java/org/apache/tuscany/sca/builder/impl/PolicyAppliesToBuilderImpl.java b/sca-java-2.x/tags/2.0.1-RC1/modules/builder/src/main/java/org/apache/tuscany/sca/builder/impl/PolicyAppliesToBuilderImpl.java
new file mode 100644
index 0000000000..60b82b99f4
--- /dev/null
+++ b/sca-java-2.x/tags/2.0.1-RC1/modules/builder/src/main/java/org/apache/tuscany/sca/builder/impl/PolicyAppliesToBuilderImpl.java
@@ -0,0 +1,288 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.tuscany.sca.builder.impl;
+
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import javax.xml.xpath.XPathConstants;
+import javax.xml.xpath.XPathExpression;
+import javax.xml.xpath.XPathExpressionException;
+
+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.context.CompositeContext;
+import org.apache.tuscany.sca.core.ExtensionPointRegistry;
+import org.apache.tuscany.sca.definitions.Definitions;
+import org.apache.tuscany.sca.policy.PolicySet;
+import org.apache.tuscany.sca.policy.PolicySubject;
+import org.apache.tuscany.sca.runtime.RuntimeComponent;
+import org.apache.tuscany.sca.runtime.RuntimeEndpointReference;
+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 it 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";
+ }
+
+ // Build the whole composite
+ public Composite build(Composite composite, BuilderContext context)
+ throws CompositeBuilderException {
+ try {
+
+ Definitions definitions = context.getDefinitions();
+ if (definitions == null || (definitions.getPolicySets().isEmpty() && definitions.getExternalAttachments().isEmpty()) ) {
+ return composite;
+ }
+ // 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);
+ }
+ }
+
+ // Build just an endpoint reference that has just been matched against an endpoint. This
+ // can often happen at runtime so the policy attachTo for a reference policy cannot
+ // be assessed at build time
+ // THIS DOESN'T HANDLE THE NESTED COMPOSITE CASE
+ public void build(EndpointReference epr) throws CompositeBuilderException {
+ try {
+
+ // What we really need to be doing here is...
+ //
+ // - correct the composite model to add the service binding to the reference
+ // - turn the composite model into a DOM
+ // - apply the reference policy XPath and assess whether it appliesTo the binding
+ //
+ // I've had a go at making the code do that below. However there is some question
+ // about what the appliesTo field means and it's hard to get here from the
+ // binder so until we sort out the appliesTo question this code isn't used
+
+ CompositeContext compositeContext = ((RuntimeComponent)epr.getComponent()).getComponentContext().getCompositeContext();
+ Composite domainComposite = compositeContext.getDomainComposite();
+ Definitions systemDefinitions = compositeContext.getSystemDefinitions();
+
+ if (systemDefinitions == null ||
+ (systemDefinitions.getPolicySets().isEmpty() &&
+ systemDefinitions.getExternalAttachments().isEmpty()) ) {
+ return;
+ }
+
+ // temporarily add the endpoint binding to the reference model so that the
+ // XPath expression can be evaluated correctly
+ epr.getReference().getBindings().add(epr.getTargetEndpoint().getBinding());
+
+ // create a DOM for the Domain Composite Infoset
+ Document document = saveAsDOM(domainComposite);
+
+ // remove the binding again to retain the untainted model
+ epr.getReference().getBindings().remove(epr.getTargetEndpoint().getBinding());
+
+ // 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>>();
+
+ // can we get the composite within which the erp is defined
+
+ for (PolicySet ps : new ArrayList<PolicySet>(epr.getPolicySets()) ) {
+ // Check if this PolicySet applies to the binding, component reference, component, or composite. If not,
+ // remove it from the list of policy sets for this endpoint.
+ if ( epr.getBinding() instanceof PolicySubject ) {
+ if (isApplicableToSubject(document, appliesToSubjects, domainComposite, (PolicySubject)epr.getBinding(), ps))
+ continue;
+ }
+ if (isApplicableToSubject(document, appliesToSubjects, domainComposite, epr.getReference(), ps))
+ continue;
+ else if ( (epr.getReference().getInterfaceContract() != null) &&
+ (isApplicableToSubject(document, appliesToSubjects, domainComposite, epr.getReference().getInterfaceContract().getInterface(), ps)))
+ continue;
+ else if ( isApplicableToSubject(document, appliesToSubjects, domainComposite, epr.getComponent(), ps))
+ continue;
+ else if ( isApplicableToSubject(document, appliesToSubjects, domainComposite, domainComposite, ps))
+ continue;
+ else
+ epr.getPolicySets().remove(ps);
+ }
+
+ } 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()) {
+ for ( PolicySet ps : new ArrayList<PolicySet>(ep.getPolicySets()) ) {
+ // Check if this PolicySet applies to the binding, component service, interface, component, or composite. If not,
+ // remove it from the list of policy sets for this endpoint.
+ if ( ep.getBinding() instanceof PolicySubject ) {
+ if (isApplicableToSubject(document, appliesToSubjects, topComposite, (PolicySubject)ep.getBinding(), ps))
+ continue;
+ }
+
+ if (isApplicableToSubject(document, appliesToSubjects, topComposite, componentService, ps))
+ continue;
+ else if ( (componentService.getInterfaceContract() != null ) && (isApplicableToSubject(document, appliesToSubjects, topComposite, componentService.getInterfaceContract().getInterface(), ps)))
+ continue;
+ else if ( isApplicableToSubject(document, appliesToSubjects, topComposite, component, ps))
+ continue;
+ else if ( isApplicableToSubject(document, appliesToSubjects, topComposite, topComposite, ps))
+ continue;
+ else
+ ep.getPolicySets().remove(ps);
+ }
+ }
+ }
+
+ for (ComponentReference componentReference : component.getReferences()) {
+ for (EndpointReference epr : componentReference.getEndpointReferences()) {
+ // don't process the EPR yet if it's not resolved
+ if (epr.getStatus() == EndpointReference.Status.WIRED_TARGET_NOT_FOUND ||
+ epr.getBinding() == null){
+ continue;
+ }
+
+ for (PolicySet ps : new ArrayList<PolicySet>(epr.getPolicySets()) ) {
+ // Check if this PolicySet applies to the binding, component reference, component, or composite. If not,
+ // remove it from the list of policy sets for this endpoint.
+ if ( epr.getBinding() instanceof PolicySubject ) {
+ if (isApplicableToSubject(document, appliesToSubjects, topComposite, (PolicySubject)epr.getBinding(), ps))
+ continue;
+ }
+ if (isApplicableToSubject(document, appliesToSubjects, topComposite, componentReference, ps))
+ continue;
+ else if ( (componentReference.getInterfaceContract() != null) && (isApplicableToSubject(document, appliesToSubjects, topComposite, componentReference.getInterfaceContract().getInterface(), ps)))
+ continue;
+ else if ( isApplicableToSubject(document, appliesToSubjects, topComposite, component, ps))
+ continue;
+ else if ( isApplicableToSubject(document, appliesToSubjects, topComposite, topComposite, ps))
+ continue;
+ else
+ epr.getPolicySets().remove(ps);
+ }
+ }
+ }
+
+ Implementation implementation = component.getImplementation();
+ if (implementation != null &&
+ implementation instanceof PolicySubject) {
+ for ( PolicySet ps : new ArrayList<PolicySet>(implementation.getPolicySets())) {
+ if (!isApplicableToSubject(document, appliesToSubjects, topComposite, implementation, ps))
+ implementation.getPolicySets().remove(ps);
+ }
+ }
+
+ }
+ return topComposite;
+ }
+
+ /**
+ * Checks that the provided policy sets applies to the provided policy subject
+ *
+ * @param document
+ * @param appliesToSubjects
+ * @param policySubject
+ * @param policySet
+ * @return
+ * @throws XPathExpressionException
+ */
+ private boolean isApplicableToSubject(Document document, Map<PolicySet, List<PolicySubject>> appliesToSubjects, Composite composite, PolicySubject policySubject, PolicySet policySet) throws XPathExpressionException {
+
+ 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)){
+ return false;
+ } else {
+ return true;
+ }
+ }
+
+ return false;
+
+ }
+}
diff --git a/sca-java-2.x/tags/2.0.1-RC1/modules/builder/src/main/java/org/apache/tuscany/sca/builder/impl/PolicyAttachmentBuilderImpl.java b/sca-java-2.x/tags/2.0.1-RC1/modules/builder/src/main/java/org/apache/tuscany/sca/builder/impl/PolicyAttachmentBuilderImpl.java
new file mode 100644
index 0000000000..771bd0b8fa
--- /dev/null
+++ b/sca-java-2.x/tags/2.0.1-RC1/modules/builder/src/main/java/org/apache/tuscany/sca/builder/impl/PolicyAttachmentBuilderImpl.java
@@ -0,0 +1,412 @@
+/*
+ * 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.Callback;
+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, implementation, 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();
+
+ // Debugging
+ //System.out.println("<!-- DOM to which XPath will be applied is -->\n" + sw.toString());
+
+ Document document = domHelper.load(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");
+ private static final QName CALLBACK = new QName(Base.SCA11_NS, "callback");
+ private static final QName COMPOSITE = new QName(Base.SCA11_NS, "composite");
+
+ 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 ( COMPOSITE.equals(name)) {
+ return "";
+ } else {
+ String localName = node.getLocalName();
+ if (localName.startsWith("binding.")) {
+ boolean callback = false;
+ String bindingName = ((Element)node).getAttributeNS(null, "name");
+ Element contract = (Element)node.getParentNode();
+ if ( "callback".equals(contract.getLocalName()) ) {
+ callback = true;
+ contract = (Element)contract.getParentNode();
+ }
+ String contractName = contract.getAttributeNS(null, "name");
+ Element component = (Element)contract.getParentNode();
+ String uri = component.getAttributeNS(null, "uri");
+ if ( callback )
+ return uri + "#" + contract.getLocalName() + "(" + contractName + "/callback/" + bindingName + ")";
+ else
+ 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, boolean isCallback) {
+ List<Binding> bindings = null;
+ if ( isCallback ) {
+ bindings = contract.getCallback().getBindings();
+ } else {
+ bindings = contract.getBindings();
+ }
+
+ for (Binding binding : bindings) {
+ 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;
+ boolean isCallback = 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);
+ if ( binding.startsWith("callback/")) {
+ binding = path.substring(pos + 10);
+ isCallback = true;
+ }
+ 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, isCallback);
+ 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, isCallback);
+ if (b instanceof PolicySubject) {
+ return (PolicySubject)b;
+ }
+ } else {
+ return componentReference;
+ }
+ } else if (impl) {
+ return component.getImplementation();
+ }
+ return component;
+ } else if (structuralURI.startsWith(component.getURI() + "/")) {
+ Implementation implementation = component.getImplementation();
+ if (implementation instanceof Composite) {
+ return lookup((Composite)implementation, structuralURI);
+ } else {
+ return null;
+ }
+ }
+ }
+ return null;
+ }
+}
diff --git a/sca-java-2.x/tags/2.0.1-RC1/modules/builder/src/main/java/org/apache/tuscany/sca/builder/impl/StructuralURIBuilderImpl.java b/sca-java-2.x/tags/2.0.1-RC1/modules/builder/src/main/java/org/apache/tuscany/sca/builder/impl/StructuralURIBuilderImpl.java
new file mode 100644
index 0000000000..7c2d86862b
--- /dev/null
+++ b/sca-java-2.x/tags/2.0.1-RC1/modules/builder/src/main/java/org/apache/tuscany/sca/builder/impl/StructuralURIBuilderImpl.java
@@ -0,0 +1,191 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.tuscany.sca.builder.impl;
+
+import java.net.URI;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import javax.xml.namespace.QName;
+
+import org.apache.tuscany.sca.assembly.Binding;
+import org.apache.tuscany.sca.assembly.Component;
+import org.apache.tuscany.sca.assembly.ComponentReference;
+import org.apache.tuscany.sca.assembly.ComponentService;
+import org.apache.tuscany.sca.assembly.Composite;
+import org.apache.tuscany.sca.assembly.Contract;
+import org.apache.tuscany.sca.assembly.Implementation;
+import org.apache.tuscany.sca.assembly.Reference;
+import org.apache.tuscany.sca.assembly.Service;
+import org.apache.tuscany.sca.assembly.builder.BuilderContext;
+import org.apache.tuscany.sca.assembly.builder.CompositeBuilder;
+import org.apache.tuscany.sca.assembly.builder.CompositeBuilderException;
+import org.apache.tuscany.sca.assembly.builder.Messages;
+import org.apache.tuscany.sca.core.ExtensionPointRegistry;
+import org.apache.tuscany.sca.definitions.Definitions;
+import org.apache.tuscany.sca.monitor.Monitor;
+
+/**
+ * Configuration of binding URIs.
+ *
+ * @version $Rev$ $Date$
+ */
+public class StructuralURIBuilderImpl implements CompositeBuilder {
+
+ public StructuralURIBuilderImpl(ExtensionPointRegistry registry) {
+ }
+
+ public String getID() {
+ return "org.apache.tuscany.sca.assembly.builder.StructualURIBuilder";
+ }
+
+ public Composite build(Composite composite, BuilderContext context)
+ throws CompositeBuilderException {
+ configureStructuralURIs(composite,
+ null,
+ context.getDefinitions(),
+ context.getBindingBaseURIs(),
+ context.getMonitor());
+ return composite;
+ }
+
+
+ /**
+ * If a binding name is not provided by the user, construct it based on the service
+ * or reference name
+ *
+ * @param contract the service or reference
+ */
+ private void constructBindingNames(Contract contract, Monitor monitor) {
+ List<Binding> bindings = contract.getBindings();
+ Map<String, Binding> bindingMap = new HashMap<String, Binding>();
+ for (Binding binding : bindings) {
+ // set the default binding name if one is required
+ // if there is no name on the binding then set it to the service or reference name
+ if (binding.getName() == null) {
+ binding.setName(contract.getName());
+ }
+ Binding existed = bindingMap.put(binding.getName(), binding);
+ // Check that multiple bindings do not have the same name
+ if (existed != null && existed != binding) {
+ if (contract instanceof Service) {
+ Monitor.error(monitor, this, Messages.ASSEMBLY_VALIDATION, "MultipleBindingsForService", contract
+ .getName(), binding.getName());
+ } else {
+ Monitor.error(monitor,
+ this,
+ Messages.ASSEMBLY_VALIDATION,
+ "MultipleBindingsForReference",
+ contract.getName(),
+ binding.getName());
+ }
+ }
+ }
+
+ if (contract.getCallback() != null) {
+ bindings = contract.getCallback().getBindings();
+ bindingMap.clear();
+ for (Binding binding : bindings) {
+ // set the default binding name if one is required
+ // if there is no name on the binding then set it to the service or reference name
+ if (binding.getName() == null) {
+ binding.setName(contract.getName());
+ }
+ Binding existed = bindingMap.put(binding.getName(), binding);
+ // Check that multiple bindings do not have the same name
+ if (existed != null && existed != binding) {
+ if (contract instanceof Service) {
+ Monitor.error(monitor,
+ this,
+ Messages.ASSEMBLY_VALIDATION,
+ "MultipleBindingsForServiceCallback",
+ contract.getName(),
+ binding.getName());
+ } else {
+ Monitor.error(monitor,
+ this,
+ Messages.ASSEMBLY_VALIDATION,
+ "MultipleBindingsForReferenceCallback",
+ contract.getName(),
+ binding.getName());
+ }
+ }
+ }
+ }
+ }
+
+ private void configureStructuralURIs(Composite composite,
+ String parentComponentURI,
+ Definitions definitions,
+ Map<QName, List<String>> defaultBindings,
+ Monitor monitor) throws CompositeBuilderException {
+
+ monitor.pushContext("Composite: " + composite.getName().toString());
+ try {
+ for (Service service : composite.getServices()) {
+ constructBindingNames(service, monitor);
+ }
+
+ for (Reference reference : composite.getReferences()) {
+ constructBindingNames(reference, monitor);
+ }
+
+ // Process nested composites recursively
+ for (Component component : composite.getComponents()) {
+
+ // Initialize component URI
+ String componentURI;
+ if (parentComponentURI == null) {
+ componentURI = component.getName();
+ } else {
+ componentURI = parentComponentURI + '/' + component.getName();
+ }
+ component.setURI(componentURI);
+
+ monitor.pushContext("Component: " + component.getName());
+ try {
+ for (ComponentService service : component.getServices()) {
+ constructBindingNames(service, monitor);
+ }
+ for (ComponentReference service : component.getReferences()) {
+ constructBindingNames(service, monitor);
+ }
+ } finally {
+ monitor.popContext();
+ }
+
+ Implementation implementation = component.getImplementation();
+ if (implementation instanceof Composite) {
+ // Process nested composite
+ configureStructuralURIs((Composite)implementation,
+ componentURI,
+ definitions,
+ defaultBindings,
+ monitor);
+ }
+ }
+
+ } finally {
+ monitor.popContext();
+ }
+ }
+
+}
diff --git a/sca-java-2.x/tags/2.0.1-RC1/modules/builder/src/main/java/org/apache/tuscany/sca/builder/impl/WireBuilderImpl.java b/sca-java-2.x/tags/2.0.1-RC1/modules/builder/src/main/java/org/apache/tuscany/sca/builder/impl/WireBuilderImpl.java
new file mode 100644
index 0000000000..21725fb1b1
--- /dev/null
+++ b/sca-java-2.x/tags/2.0.1-RC1/modules/builder/src/main/java/org/apache/tuscany/sca/builder/impl/WireBuilderImpl.java
@@ -0,0 +1,1028 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.tuscany.sca.builder.impl;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import org.apache.tuscany.sca.assembly.AssemblyFactory;
+import org.apache.tuscany.sca.assembly.Binding;
+import org.apache.tuscany.sca.assembly.Component;
+import org.apache.tuscany.sca.assembly.ComponentReference;
+import org.apache.tuscany.sca.assembly.ComponentService;
+import org.apache.tuscany.sca.assembly.Composite;
+import org.apache.tuscany.sca.assembly.CompositeReference;
+import org.apache.tuscany.sca.assembly.Endpoint;
+import org.apache.tuscany.sca.assembly.EndpointReference;
+import org.apache.tuscany.sca.assembly.Implementation;
+import org.apache.tuscany.sca.assembly.Multiplicity;
+import org.apache.tuscany.sca.assembly.Reference;
+import org.apache.tuscany.sca.assembly.SCABinding;
+import org.apache.tuscany.sca.assembly.Wire;
+import org.apache.tuscany.sca.assembly.builder.BuilderContext;
+import org.apache.tuscany.sca.assembly.builder.CompositeBuilderException;
+import org.apache.tuscany.sca.assembly.builder.Messages;
+import org.apache.tuscany.sca.core.ExtensionPointRegistry;
+import org.apache.tuscany.sca.core.FactoryExtensionPoint;
+import org.apache.tuscany.sca.core.UtilityExtensionPoint;
+import org.apache.tuscany.sca.interfacedef.InterfaceContractMapper;
+import org.apache.tuscany.sca.monitor.Monitor;
+import org.apache.tuscany.sca.policy.Intent;
+import org.oasisopen.sca.ServiceRuntimeException;
+
+/**
+ * Creates endpoint reference models.
+ */
+public class WireBuilderImpl {
+
+ private AssemblyFactory assemblyFactory;
+ private InterfaceContractMapper interfaceContractMapper;
+
+ public WireBuilderImpl(ExtensionPointRegistry registry) {
+ UtilityExtensionPoint utilities = registry.getExtensionPoint(UtilityExtensionPoint.class);
+ interfaceContractMapper = utilities.getUtility(InterfaceContractMapper.class);
+
+ FactoryExtensionPoint modelFactories = registry.getExtensionPoint(FactoryExtensionPoint.class);
+ assemblyFactory = modelFactories.getFactory(AssemblyFactory.class);
+ }
+
+ /**
+ * Create endpoint references for all component references.
+ *
+ * @param composite
+ */
+ public Composite build(Composite composite, BuilderContext context)
+ throws CompositeBuilderException {
+ Monitor monitor = context.getMonitor();
+
+ // process component references
+ processComponentReferences(composite, monitor);
+
+ // validate component references
+ validateComponentReferences(composite, monitor);
+
+ return composite;
+ }
+
+ private void processComponentReferences(Composite composite, Monitor monitor) {
+
+ monitor.pushContext("Composite: " + composite.getName().toString());
+ try {
+ // Index components, services and references
+ Map<String, Component> components = new HashMap<String, Component>();
+ Map<String, ComponentService> componentServices = new HashMap<String, ComponentService>();
+ Map<String, ComponentReference> componentReferences = new HashMap<String, ComponentReference>();
+ indexComponentsServicesAndReferences(composite, components, componentServices, componentReferences);
+
+ // Connect component references as described in wires
+ connectWires(composite, componentServices, componentReferences, monitor);
+
+ // create endpoint references for each component's references
+ for (Component component : composite.getComponents()) {
+ monitor.pushContext("Component: " + component.getName());
+
+ try {
+
+ // recurse for composite implementations
+ Implementation implementation = component.getImplementation();
+ if (implementation instanceof Composite) {
+ processComponentReferences((Composite)implementation, monitor);
+ }
+
+ // create endpoint references to represent the component reference
+ for (ComponentReference reference : component.getReferences()) {
+ createReferenceEndpointReferences(composite,
+ component,
+ reference,
+ components,
+ componentServices,
+ monitor);
+
+ // fix up links between endpoints and endpoint references that represent callbacks
+ for (ComponentService service : component.getServices()) {
+ if ((service.getInterfaceContract() != null) && (service.getInterfaceContract()
+ .getCallbackInterface() != null)) {
+ if (reference.getName().equals(service.getName())) {
+ for (Endpoint endpoint : service.getEndpoints()) {
+ endpoint.getCallbackEndpointReferences().addAll(reference
+ .getEndpointReferences());
+ }
+ break;
+ } // end if
+ } // end if
+ } // end for
+
+ // push down endpoint references into the leaf component references
+ // in the case where this component reference promotes a reference from
+ // a composite implementation
+ pushDownEndpointReferences(composite,
+ component,
+ reference,
+ monitor);
+
+ } // end for
+
+ // Validate that references are wired or promoted, according
+ // to their multiplicity. This validates as we go and catches cases
+ // where a reference has been configured directly incorrectly with its
+ // immediate multiplicity setting. We re-run this validation again later
+ // to catch to more complex cases where reference promotion causes
+ // multiplicity errors.
+ validateReferenceMultiplicity(composite, component, monitor);
+
+ } finally {
+ monitor.popContext();
+ }
+ } // end for
+
+ } finally {
+ monitor.popContext();
+ }
+
+ } // end method processCompoenntReferences
+
+
+ /**
+ * The validate stage is separate from the process stage as enpoint references are
+ * pushed down the hierarchy. We don't know the full set of endpoint references until
+ * all processing is complete. Hence we can't validate as we go
+ *
+ * @param composite
+ * @param monitor
+ */
+ private void validateComponentReferences(Composite composite, Monitor monitor) {
+
+ monitor.pushContext("Composite: " + composite.getName().toString());
+ try {
+ // create endpoint references for each component's references
+ for (Component component : composite.getComponents()) {
+ monitor.pushContext("Component: " + component.getName());
+
+ try {
+
+ // recurse for composite implementations
+ Implementation implementation = component.getImplementation();
+ if (implementation instanceof Composite) {
+ validateComponentReferences((Composite)implementation, monitor);
+ }
+ // Validate that references are wired or promoted, according
+ // to their multiplicity
+ validateReferenceMultiplicity(composite, component, monitor);
+
+ } finally {
+ monitor.popContext();
+ }
+ }
+
+ } finally {
+ monitor.popContext();
+ }
+
+ }
+
+ protected void indexComponentsServicesAndReferences(Composite composite,
+ Map<String, Component> components,
+ Map<String, ComponentService> componentServices,
+ Map<String, ComponentReference> componentReferences) {
+
+ for (Component component : composite.getComponents()) {
+
+ // Index components by name
+ components.put(component.getName(), component);
+
+ ComponentService nonCallbackService = null;
+ int nonCallbackServices = 0;
+ for (ComponentService componentService : component.getServices()) {
+
+ // Index component services by component name / service name
+ String uri = component.getName() + '/' + componentService.getName();
+ componentServices.put(uri, componentService);
+
+ // count how many non-callback services there are
+ // if there is only one the component name also acts as the
+ // service name
+ if (!componentService.isForCallback()) {
+ // Check how many non callback non-promoted services we have
+ if (nonCallbackServices == 0) {
+ nonCallbackService = componentService;
+ }
+ nonCallbackServices++;
+ }
+ }
+
+ if (nonCallbackServices == 1) {
+ // If we have a single non callback service, index it by
+ // component name as well
+ componentServices.put(component.getName(), nonCallbackService);
+ }
+
+ // Index references by component name / reference name
+ for (ComponentReference componentReference : component.getReferences()) {
+ String uri = component.getName() + '/' + componentReference.getName();
+ componentReferences.put(uri, componentReference);
+ }
+ }
+ }
+
+ /**
+ * Resolve wires and connect the sources to their targets
+ *
+ * @param composite
+ * @param componentServices
+ * @param componentReferences
+ * @param problems
+ */
+ private void connectWires(Composite composite,
+ Map<String, ComponentService> componentServices,
+ Map<String, ComponentReference> componentReferences,
+ Monitor monitor) {
+
+ // For each wire, resolve the source reference, the target service, and
+ // add it to the list of targets of the reference
+ List<Wire> wires = composite.getWires();
+ for (int i = 0, n = wires.size(); i < n; i++) {
+ Wire wire = wires.get(i);
+
+ ComponentReference resolvedReference;
+ ComponentService resolvedService;
+
+ // Resolve the source reference
+ ComponentReference source = wire.getSource();
+ if (source != null && source.isUnresolved()) {
+ resolvedReference = componentReferences.get(source.getName());
+ if (resolvedReference != null) {
+ wire.setSource(resolvedReference);
+ } else {
+ Monitor.warning(monitor, this, Messages.ASSEMBLY_VALIDATION, "WireSourceNotFound", source
+ .getName());
+ }
+ } else {
+ resolvedReference = wire.getSource();
+ }
+
+ // Resolve the target service
+ ComponentService target = wire.getTarget();
+ if (target != null && target.isUnresolved()) {
+ resolvedService = componentServices.get(target.getName());
+ if (resolvedService != null) {
+ wire.setTarget(target);
+ } else {
+ Monitor.warning(monitor, this, Messages.ASSEMBLY_VALIDATION, "WireTargetNotFound", target
+ .getName());
+ }
+ } else {
+ resolvedService = wire.getTarget();
+ }
+
+ // Add the target service to the list of targets of the
+ // reference
+ if (resolvedReference != null && resolvedService != null) {
+ // Check that the target component service provides
+ // a superset of
+ // the component reference interface
+ if (resolvedReference.getInterfaceContract() == null || interfaceContractMapper
+ .isCompatibleSubset(resolvedReference.getInterfaceContract(), resolvedService.getInterfaceContract())) {
+
+ //resolvedReference.getTargets().add(resolvedService);
+ if (wire.isReplace()) {
+ resolvedReference.getTargets().clear();
+ }
+ resolvedReference.getTargets().add(wire.getTarget());
+ } else {
+ Monitor.warning(monitor, this, Messages.ASSEMBLY_VALIDATION, "WireIncompatibleInterface", source
+ .getName(), target.getName());
+ }
+ }
+ }
+
+ // Clear the list of wires
+ composite.getWires().clear();
+ }
+
+ private void createReferenceEndpointReferences(Composite composite,
+ Component component,
+ ComponentReference reference,
+ Map<String, Component> components,
+ Map<String, ComponentService> componentServices,
+ Monitor monitor) {
+
+ monitor.pushContext("Reference: " + reference.getName());
+
+ // Get reference targets
+ List<ComponentService> refTargets = getReferenceTargets(reference);
+ if (Boolean.TRUE.equals(reference.getAutowire()) && reference.getTargets().isEmpty()) {
+
+ // Find suitable targets in the current composite for an
+ // autowired reference
+ Multiplicity multiplicity = reference.getMultiplicity();
+ for (Component targetComponent : composite.getComponents()) {
+
+ // Tuscany specific selection of the first autowire reference
+ // when there are more than one (ASM_60025)
+ if ((multiplicity == Multiplicity.ZERO_ONE || multiplicity == Multiplicity.ONE_ONE) && (reference
+ .getEndpointReferences().size() != 0)) {
+ break;
+ }
+
+ // Prevent autowire connecting to self
+ if (targetComponent == component)
+ continue;
+
+ for (ComponentService targetComponentService : targetComponent.getServices()) {
+ if (reference.getInterfaceContract() == null || interfaceContractMapper.isCompatibleSubset(reference
+ .getInterfaceContract(), targetComponentService.getInterfaceContract())) {
+
+ if (intentsMatch(reference.getRequiredIntents(), targetComponentService.getRequiredIntents())) {
+ EndpointReference endpointRef = createEndpointRef(component, reference, false);
+ endpointRef.setTargetEndpoint(createEndpoint(targetComponent, targetComponentService, true));
+ endpointRef.setStatus(EndpointReference.Status.WIRED_TARGET_FOUND_READY_FOR_MATCHING);
+ reference.getEndpointReferences().add(endpointRef);
+
+ // Stop with the first match for 0..1 and 1..1 references
+ if (multiplicity == Multiplicity.ZERO_ONE || multiplicity == Multiplicity.ONE_ONE) {
+ break;
+ } // end if
+ }
+
+ } // end if
+ } // end for
+ } // end for
+
+ if (multiplicity == Multiplicity.ONE_N || multiplicity == Multiplicity.ONE_ONE) {
+ if (reference.getEndpointReferences().size() == 0) {
+ Monitor.error(monitor,
+ this,
+ Messages.ASSEMBLY_VALIDATION,
+ "NoComponentReferenceTarget",
+ reference.getName());
+ }
+ }
+
+ setSingleAutoWireTarget(reference);
+
+ } else if (!refTargets.isEmpty()) {
+ // Check that the component reference does not mix the use of endpoint references
+ // specified via the target attribute with the presence of binding elements
+ if (bindingsIdentifyTargets(reference)) {
+ Monitor.error(monitor,
+ this,
+ Messages.ASSEMBLY_VALIDATION,
+ "ReferenceEndPointMixWithTarget",
+ composite.getName().toString(),
+ component.getName(),
+ reference.getName());
+ }
+
+ // Resolve targets specified on the component reference
+ for (ComponentService target : refTargets) {
+
+ String targetName = getComponentServiceName(target.getName());
+ String bindingName = getBindingName(target.getName());
+ ComponentService targetComponentService = componentServices.get(targetName);
+
+ Component targetComponent = getComponentFromTargetName(components, targetName);
+
+ if (targetComponentService != null) {
+ // Check that target component service provides a superset of the component reference interface
+ if (reference.getInterfaceContract() == null || interfaceContractMapper.isCompatibleSubset(reference
+ .getInterfaceContract(), targetComponentService.getInterfaceContract())) {
+
+ if (bindingName != null) {
+ // the user has selected a binding as part of the target name
+ Binding targetBinding = null;
+
+ for (Binding tmp : targetComponentService.getBindings()) {
+ if (tmp.getName().equals(bindingName)) {
+ targetBinding = tmp;
+ continue;
+ }
+ }
+
+ if (targetBinding != null) {
+ EndpointReference endpointRef = createEndpointRef(component, reference, false);
+ endpointRef.setTargetEndpoint(createEndpoint(targetComponent,
+ targetComponentService,
+ targetBinding,
+ true));
+ endpointRef.setStatus(EndpointReference.Status.WIRED_TARGET_FOUND_AND_MATCHED);
+ // relying on the registry here to resolve the real endpoint
+ reference.getEndpointReferences().add(endpointRef);
+
+ } else {
+ EndpointReference endpointRef = createEndpointRef(component, reference, true);
+ endpointRef.setTargetEndpoint(createEndpoint(component, targetName));
+ endpointRef.setStatus(EndpointReference.Status.WIRED_TARGET_NOT_FOUND);
+ reference.getEndpointReferences().add(endpointRef);
+ Monitor.warning(monitor,
+ this,
+ Messages.ASSEMBLY_VALIDATION,
+ "ComponentReferenceTargetNotFound",
+ composite.getName().toString(),
+ targetName);
+ }
+
+ } else {
+ // the user hasn't selected a binding as part of the target name
+
+ EndpointReference endpointRef = createEndpointRef(component, reference, false);
+ endpointRef
+ .setTargetEndpoint(createEndpoint(targetComponent, targetComponentService, true));
+ endpointRef.setStatus(EndpointReference.Status.WIRED_TARGET_FOUND_READY_FOR_MATCHING);
+ reference.getEndpointReferences().add(endpointRef);
+ }
+ } else {
+ Monitor.error(monitor,
+ this,
+ Messages.ASSEMBLY_VALIDATION,
+ "ReferenceIncompatibleInterface",
+ composite.getName().toString(),
+ component.getName() + "." + reference.getName(),
+ targetName);
+ }
+ } else {
+ // add an unresolved endpoint reference with an unresolved endpoint to go with it
+ EndpointReference endpointRef = createEndpointRef(component, reference, true);
+ endpointRef.setTargetEndpoint(createEndpoint(component, targetName));
+ endpointRef.setStatus(EndpointReference.Status.WIRED_TARGET_NOT_FOUND);
+ reference.getEndpointReferences().add(endpointRef);
+ Monitor.warning(monitor,
+ this,
+ Messages.ASSEMBLY_VALIDATION,
+ "ComponentReferenceTargetNotFound",
+ composite.getName().toString(),
+ targetName);
+ } // end if
+ } // end for
+ } // end if
+
+ // if no endpoints have found so far the bindings hold the targets.
+ if (reference.getEndpointReferences().isEmpty()) {
+ for (Binding binding : reference.getBindings()) {
+
+ String uri = binding.getURI();
+
+ // user hasn't put a uri on the binding so it's not a target name and the assumption is that
+ // the target is established via configuration of the binding element itself
+ if (uri == null) {
+ // Regular forward references are UNWIRED with no endpoint if they have an SCABinding with NO targets
+ // and NO URI set - but Callbacks with an SCABinding are wired and need an endpoint
+ if (!reference.isForCallback() && (binding instanceof SCABinding))
+ continue;
+
+ // create endpoint reference for manually configured bindings with a resolved endpoint to
+ // signify that this reference is pointing at some unwired endpoint
+ EndpointReference endpointRef = createEndpointRef(component, reference, binding, null, false);
+ if (binding instanceof SCABinding) {
+ // Assume that the system needs to resolve this binding later as
+ // it's the SCA binding
+ endpointRef.setTargetEndpoint(createEndpoint(true));
+ endpointRef.setStatus(EndpointReference.Status.NOT_CONFIGURED);
+ } else {
+ // The user has configured a binding so assume they know what
+ // they are doing and mark in as already resolved.
+ endpointRef.setTargetEndpoint(createEndpoint(false));
+ endpointRef.setStatus(EndpointReference.Status.RESOLVED_BINDING);
+ }
+ reference.getEndpointReferences().add(endpointRef);
+ continue;
+ } // end if
+
+ // user might have put a local target name in the uri - see if it refers to a target we know about
+ // - if it does the reference binding will be matched with a service binding
+ // - if it doesn't it is assumed to be an external reference
+ if (uri.startsWith("/")) {
+ uri = uri.substring(1);
+ }
+
+ String targetName = getComponentServiceName(uri);
+ String bindingName = getBindingName(uri);
+
+ // Resolve the target component and service
+ ComponentService targetComponentService = componentServices.get(targetName);
+ Component targetComponent = getComponentFromTargetName(components, targetName);
+
+ // If the binding URI matches a component in the composite, configure an endpoint reference with
+ // this component as the target.
+ // If not, the binding URI is assumed to reference an external service
+ if (targetComponentService != null) {
+
+ // Check that the target component service provides
+ // a superset of the component reference interface
+ if (reference.getInterfaceContract() == null || interfaceContractMapper.isCompatibleSubset(reference
+ .getInterfaceContract(), targetComponentService.getInterfaceContract())) {
+ if (bindingName != null) {
+ // the user has selected a binding as part of the target name
+ Binding targetBinding = null;
+
+ for (Binding tmp : targetComponentService.getBindings()) {
+ if (tmp.getName().equals(bindingName)) {
+ targetBinding = tmp;
+ continue;
+ }
+ }
+
+ if (targetBinding != null) {
+ EndpointReference endpointRef = createEndpointRef(component, reference, false);
+ endpointRef.setTargetEndpoint(createEndpoint(targetComponent,
+ targetComponentService,
+ targetBinding,
+ true));
+ endpointRef.setStatus(EndpointReference.Status.WIRED_TARGET_NOT_FOUND);
+ // relying on the registry here to resolve the real endpoint
+ reference.getEndpointReferences().add(endpointRef);
+
+ } else {
+ EndpointReference endpointRef = createEndpointRef(component, reference, true);
+ endpointRef.setTargetEndpoint(createEndpoint(component, targetName));
+ endpointRef.setStatus(EndpointReference.Status.WIRED_TARGET_NOT_FOUND);
+ reference.getEndpointReferences().add(endpointRef);
+ Monitor.warning(monitor,
+ this,
+ Messages.ASSEMBLY_VALIDATION,
+ "ComponentReferenceTargetNotFound",
+ composite.getName().toString(),
+ targetName);
+ }
+
+ } else {
+ // create endpoint reference with dummy endpoint which will be replaced when policies
+ // are matched and bindings are configured later
+ EndpointReference endpointRef =
+ createEndpointRef(component, reference, binding, null, false);
+ endpointRef
+ .setTargetEndpoint(createEndpoint(targetComponent, targetComponentService, true));
+ endpointRef.setStatus(EndpointReference.Status.WIRED_TARGET_FOUND_READY_FOR_MATCHING);
+ reference.getEndpointReferences().add(endpointRef);
+ }
+ } else {
+ Monitor.warning(monitor,
+ this,
+ Messages.ASSEMBLY_VALIDATION,
+ "ReferenceIncompatibleInterface",
+ composite.getName().toString(),
+ reference.getName(),
+ uri);
+ }
+ } else {
+ // create endpoint reference for manually configured bindings with resolved endpoint
+ // to signify that this reference is pointing at some unwired endpoint. The endpoint
+ // is given the configured binding as a representation of the endpoint configuration.
+ EndpointReference endpointRef = createEndpointRef(component, reference, binding, null, false);
+ Endpoint endpoint = createEndpoint(false);
+ endpoint.setBinding(binding);
+ endpointRef.setTargetEndpoint(endpoint);
+ endpointRef.setStatus(EndpointReference.Status.RESOLVED_BINDING);
+ reference.getEndpointReferences().add(endpointRef);
+ } // end if
+ }
+ }
+
+ monitor.popContext();
+
+ } // end method
+
+ private boolean intentsMatch(List<Intent> referenceIntents, List<Intent> serviceIntents) {
+ Set<Intent> referenceIntentSet = new HashSet<Intent>(referenceIntents);
+ Set<Intent> serviceIntentSet = new HashSet<Intent>(serviceIntents);
+ return referenceIntentSet.equals(serviceIntentSet);
+ }
+
+ /**
+ * Reference targets have to be resolved in the context in which they are
+ * defined so they can't be push down the hierarchy during the static build.
+ * So we wait until we have calculated the enpoint references before pushing them
+ * down. Muliplicity errors will be caught by the multiplicity validation check that
+ * comes next
+ *
+ * @param composite
+ * @param component
+ * @param reference
+ * @param monitor
+ */
+ private void pushDownEndpointReferences(Composite composite,
+ Component component,
+ ComponentReference componentReference,
+ Monitor monitor) {
+ Reference reference = componentReference.getReference();
+
+ if (reference instanceof CompositeReference) {
+ List<ComponentReference> leafComponentReferences = getPromotedComponentReferences((CompositeReference)reference);
+
+ // for each leaf component reference copy in the endpoint references for this
+ // higher level (promoting) reference
+ // TODO - the elements are inserted starting at 0 here because the code allows references multiplicity
+ // validation constraints to be broken if the reference is autowire. At runtime the
+ // first one is chosen if max multiplicity is 1. We have an OSOA test that assumes that
+ // promoted references overwrite leaf references. This insert gives the same effect in the
+ // autowire case. We need to think about if there is a more correct answer.
+ for (ComponentReference leafRef : leafComponentReferences){
+ int insertLocation = 0;
+ for (EndpointReference epr : componentReference.getEndpointReferences()){
+ // copy the epr
+ EndpointReference eprCopy = copyHigherReference(epr, leafRef);
+ leafRef.getEndpointReferences().add(insertLocation, eprCopy);
+ insertLocation++;
+ }
+ }
+ }
+
+ // TODO - what to do about callbacks in the reference promotion case
+ }
+
+ /**
+ * Follow a reference promotion chain down to the innermost (non composite)
+ * component references.
+ *
+ * @param compositeReference
+ * @return
+ */
+ private List<ComponentReference> getPromotedComponentReferences(CompositeReference compositeReference) {
+ List<ComponentReference> componentReferences = new ArrayList<ComponentReference>();
+ collectPromotedComponentReferences(compositeReference, componentReferences);
+ return componentReferences;
+ }
+
+ /**
+ * Follow a reference promotion chain down to the innermost (non composite)
+ * component references.
+ *
+ * @param compositeReference
+ * @param componentReferences
+ * @return
+ */
+ private void collectPromotedComponentReferences(CompositeReference compositeReference,
+ List<ComponentReference> componentReferences) {
+ for (ComponentReference componentReference : compositeReference.getPromotedReferences()) {
+ Reference reference = componentReference.getReference();
+ if (reference instanceof CompositeReference) {
+
+ // Continue to follow the reference promotion chain
+ collectPromotedComponentReferences((CompositeReference)reference, componentReferences);
+
+ } else if (reference != null) {
+
+ // Found a non-composite reference
+ componentReferences.add(componentReference);
+ }
+ }
+ }
+
+ /**
+ * Copy a higher level EndpointReference down to a lower level reference which it promotes
+ * @param epRef - the endpoint reference
+ * @param promotedReference - the promoted reference
+ * @return - a copy of the EndpointReference with data merged from the promoted reference
+ */
+ private EndpointReference copyHigherReference(EndpointReference epRef, ComponentReference promotedReference) {
+ EndpointReference epRefClone = null;
+ try {
+ epRefClone = (EndpointReference)epRef.clone();
+ } catch (Exception e) {
+ throw new ServiceRuntimeException(e);
+ // Ignore (we know that EndpointReference2 can be cloned)
+ } // end try
+ // Copy across details of the inner reference
+ // ComponentReference ref = epRefClone.getReference();
+ //FIXME
+ epRefClone.setReference(promotedReference);
+ return epRefClone;
+ }
+
+ private void validateReferenceMultiplicity(Composite composite, Component component, Monitor monitor) {
+ for (ComponentReference componentReference : component.getReferences()) {
+ if (!validateMultiplicity(componentReference.getMultiplicity(),
+ componentReference.getEndpointReferences())) {
+ if (componentReference.getEndpointReferences().isEmpty()) {
+
+ // No error if the reference is promoted out of the current composite
+ boolean promoted = false;
+ for (Reference reference : composite.getReferences()) {
+ CompositeReference compositeReference = (CompositeReference)reference;
+ if (compositeReference.getPromotedReferences().contains(componentReference)) {
+ promoted = true;
+ break;
+ }
+ }
+ if (!promoted && !componentReference.isForCallback() && !componentReference.isWiredByImpl()) {
+ Monitor.error(monitor,
+ this,
+ Messages.ASSEMBLY_VALIDATION,
+ "ReferenceWithoutTargets",
+ composite.getName().toString(),
+ componentReference.getName());
+ }
+ } else {
+ // no error if reference is autowire and more targets
+ // than multiplicity have been found
+ if (Boolean.TRUE.equals(componentReference.getAutowire())) {
+ break;
+ }
+
+ Monitor.error(monitor,
+ this,
+ Messages.ASSEMBLY_VALIDATION,
+ "TooManyReferenceTargets",
+ componentReference.getName());
+ }
+ }
+ }
+
+ }
+
+ private boolean validateMultiplicity(Multiplicity multiplicity, List<EndpointReference> endpointReferences) {
+
+ // In some tests multiplicity is not set
+ if (multiplicity == null) {
+ return true;
+ }
+
+ // Count targets
+ int count = endpointReferences.size();
+
+ switch (multiplicity) {
+ case ZERO_N:
+ break;
+ case ZERO_ONE:
+ if (count > 1) {
+ return false;
+ }
+ break;
+ case ONE_ONE:
+ if (count != 1) {
+ return false;
+ }
+ break;
+ case ONE_N:
+ if (count < 1) {
+ return false;
+ }
+ break;
+ }
+ return true;
+ }
+
+ /**
+ * Evaluates whether the bindings attached to a reference identify one or more target services.
+ * @param reference - the reference
+ * @return true if the bindings identify a target, false otherwise
+ */
+ private boolean bindingsIdentifyTargets(ComponentReference reference) {
+ for (Binding binding : reference.getBindings()) {
+ // <binding.sca without a URI does not identify a target
+ if ((binding instanceof SCABinding) && (binding.getURI() == null))
+ continue;
+ // any other binding implies a target
+ // TODO Processing for other binding types
+ return true;
+ } // end for
+ return false;
+ } // end bindingsIdentifyTargets
+
+ /**
+ * Helper method which obtains a list of targets for a reference
+ * @param reference - Component reference
+ * @return - the list of targets, which will be empty if there are no targets
+ */
+ private List<ComponentService> getReferenceTargets(ComponentReference reference) {
+ List<ComponentService> theTargets = reference.getTargets();
+ if (theTargets.isEmpty()) {
+ // Component reference list of targets is empty, try the implementation reference
+ if (reference.getReference() != null) {
+ theTargets = reference.getReference().getTargets();
+ } // end if
+ } // end if
+ return theTargets;
+ } // end method getReferenceTargets
+
+ /**
+ * Target names can take the form
+ * component/service/binding
+ * This extracts the component/service part
+ *
+ * @param targetName
+ * @return String the component/service name
+ */
+ private String getComponentServiceName(String targetName) {
+ String[] parts = targetName.split("/");
+
+ if (parts.length > 1) {
+ return parts[0] + "/" + parts[1];
+ } else {
+ return parts[0];
+ }
+ }
+
+ /**
+ * Target names can take the form
+ * component/service/binding
+ * This extracts the binding part and returns
+ * it. If there is no binding part it returns null
+ *
+ * @param targetName
+ * @return String the binding name or null if there is no binding name
+ */
+ private String getBindingName(String targetName) {
+ String[] parts = targetName.split("/");
+
+ if (parts.length == 3) {
+ return parts[2];
+ } else {
+ return null;
+ }
+ }
+
+ /**
+ * Helper method that finds the Component given a target name
+ * @param components
+ * @param targetName
+ * @return the component
+ */
+ private Component getComponentFromTargetName(Map<String, Component> components, String targetName) {
+ Component theComponent;
+ int s = targetName.indexOf('/');
+ if (s == -1) {
+ theComponent = components.get(targetName);
+ } else {
+ theComponent = components.get(targetName.substring(0, s));
+ }
+ return theComponent;
+ } // end method getComponentFromTargetName
+
+ /**
+ * Helper method to create an Endpoint Reference
+ * @param component
+ * @param reference
+ * @param binding
+ * @param endpoint
+ * @param unresolved
+ * @return the endpoint reference
+ */
+ private EndpointReference createEndpointRef(Component component,
+ ComponentReference reference,
+ Binding binding,
+ Endpoint endpoint,
+ boolean unresolved) {
+ EndpointReference endpointRef = createEndpointRef(component, reference, unresolved);
+ endpointRef.setBinding(binding);
+ endpointRef.setTargetEndpoint(endpoint);
+ return endpointRef;
+ } // end method
+
+ /**
+ * Helper method to create an Endpoint Reference
+ * @param component
+ * @param reference
+ * @param unresolved
+ * @return the endpoint reference
+ */
+ private EndpointReference createEndpointRef(Component component, ComponentReference reference, boolean unresolved) {
+ EndpointReference endpointRef = assemblyFactory.createEndpointReference();
+ endpointRef.setComponent(component);
+ endpointRef.setReference(reference);
+ endpointRef.setUnresolved(unresolved);
+ return endpointRef;
+ } // end method createEndpointRef
+
+ /**
+ * Helper method to create an endpoint
+ * @param component
+ * @param service
+ * @param unresolved
+ * @return the endpoint
+ */
+ private Endpoint createEndpoint(Component component, ComponentService service, boolean unresolved) {
+ Endpoint endpoint = createEndpoint(unresolved);
+ endpoint.setComponent(component);
+ endpoint.setService(service);
+ endpoint.setUnresolved(unresolved);
+ return endpoint;
+ } // end method createEndpoint
+
+ /**
+ * Helper method to create an endpoint
+ * @param component
+ * @param service
+ * @param binding
+ * @param unresolved
+ * @return the endpoint
+ */
+ private Endpoint createEndpoint(Component component, ComponentService service, Binding binding, boolean unresolved) {
+ Endpoint endpoint = createEndpoint(unresolved);
+ endpoint.setComponent(component);
+ endpoint.setService(service);
+ endpoint.setBinding(binding);
+ endpoint.setUnresolved(unresolved);
+ return endpoint;
+ } // end method createEndpoint
+
+ /**
+ * Helper method to create an Endpoint
+ * @param unresolved
+ * @return the endpoint
+ */
+ private Endpoint createEndpoint(boolean unresolved) {
+ Endpoint endpoint = assemblyFactory.createEndpoint();
+ endpoint.setUnresolved(unresolved);
+ return endpoint;
+ } // end method createEndpoint
+
+ /**
+ * Helper method to create an Endpoint
+ *
+ * @param component The component that owns the reference
+ * @param targetName It can be one of the following formats
+ * <ul>
+ * <li>componentName
+ * <li>componentName/serviceName
+ * <li>componentName/serviceName/bindingName
+ * </ul>
+ * @return the endpoint
+ */
+ private Endpoint createEndpoint(Component component, String targetName) {
+ String[] parts = targetName.split("/");
+ if (parts.length < 1 || parts.length > 3) {
+ throw new IllegalArgumentException("Invalid target URI: " + targetName);
+ }
+
+ // Find the parent uri
+ String uri = component.getURI();
+ int index = uri.lastIndexOf('/');
+ if (index == -1) {
+ uri = "";
+ } else {
+ uri = uri.substring(0, index);
+ }
+
+ if (parts.length >= 1) {
+ // Append the target component name
+ if (uri.length() == 0) {
+ uri = parts[0];
+ } else {
+ uri = uri + "/" + parts[0];
+ }
+ }
+ if (parts.length == 3) {
+ // <componentURI>#service-binding(serviceName/bindingName)
+ uri = uri + "#service-binding(" + parts[1] + "/" + parts[2] + ")";
+ } else if (parts.length == 2) {
+ // <componentURI>#service(serviceName)
+ uri = uri + "#service(" + parts[1] + ")";
+ }
+
+ Endpoint endpoint = assemblyFactory.createEndpoint();
+ endpoint.setUnresolved(true);
+ endpoint.setURI(uri);
+ return endpoint;
+ } // end method createEndpoint
+
+ /**
+ * ASM_5021: where a <reference/> of a <component/> has @autowire=true
+ * and where the <reference/> has a <binding/> child element which
+ * declares a single target service, the reference is wired only to
+ * the single service identified by the <wire/> element
+ */
+ private void setSingleAutoWireTarget(ComponentReference reference) {
+ if (reference.getEndpointReferences().size() > 1 && reference.getBindings() != null
+ && reference.getBindings().size() == 1) {
+ String uri = reference.getBindings().get(0).getURI();
+ if (uri != null) {
+ if (uri.indexOf('/') > -1) {
+ // TODO: must be a way to avoid this fiddling
+ int i = uri.indexOf('/');
+ String c = uri.substring(0, i);
+ String s = uri.substring(i + 1);
+ uri = c + "#service(" + s + ")";
+ }
+ for (EndpointReference er : reference.getEndpointReferences()) {
+ if (er.getTargetEndpoint() != null && uri.equals(er.getTargetEndpoint().getURI())) {
+ reference.getEndpointReferences().clear();
+ reference.getEndpointReferences().add(er);
+ return;
+ }
+ }
+ }
+ }
+ }
+
+} // end class
diff --git a/sca-java-2.x/tags/2.0.1-RC1/modules/builder/src/main/java/org/apache/tuscany/sca/builder/impl/WireMatcherImpl.java b/sca-java-2.x/tags/2.0.1-RC1/modules/builder/src/main/java/org/apache/tuscany/sca/builder/impl/WireMatcherImpl.java
new file mode 100644
index 0000000000..761f53ff11
--- /dev/null
+++ b/sca-java-2.x/tags/2.0.1-RC1/modules/builder/src/main/java/org/apache/tuscany/sca/builder/impl/WireMatcherImpl.java
@@ -0,0 +1,64 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.tuscany.sca.builder.impl;
+
+import org.apache.tuscany.sca.assembly.Endpoint;
+import org.apache.tuscany.sca.assembly.EndpointReference;
+import org.apache.tuscany.sca.assembly.builder.BuilderContext;
+import org.apache.tuscany.sca.assembly.builder.BuilderExtensionPoint;
+import org.apache.tuscany.sca.assembly.builder.PolicyBuilder;
+import org.apache.tuscany.sca.assembly.builder.WireBuilder;
+import org.apache.tuscany.sca.core.ExtensionPointRegistry;
+import org.apache.tuscany.sca.core.UtilityExtensionPoint;
+import org.apache.tuscany.sca.interfacedef.InterfaceContract;
+import org.apache.tuscany.sca.interfacedef.InterfaceContractMapper;
+
+/**
+ *
+ */
+public class WireMatcherImpl implements WireBuilder {
+ private InterfaceContractMapper interfaceContractMapper;
+ private BuilderExtensionPoint builderExtensionPoint;
+
+ /**
+ * @param registry
+ */
+ public WireMatcherImpl(ExtensionPointRegistry registry) {
+ super();
+ this.builderExtensionPoint = registry.getExtensionPoint(BuilderExtensionPoint.class);
+ UtilityExtensionPoint utilities = registry.getExtensionPoint(UtilityExtensionPoint.class);
+ this.interfaceContractMapper = utilities.getUtility(InterfaceContractMapper.class);
+ }
+
+ public boolean build(EndpointReference endpointReference, Endpoint endpoint, BuilderContext context) {
+ InterfaceContract sourceIC = endpointReference.getComponentReferenceInterfaceContract();
+ InterfaceContract targetIC = endpoint.getComponentServiceInterfaceContract();
+ if (!interfaceContractMapper.isCompatibleSubset(sourceIC, targetIC)) {
+ return false;
+ }
+ for (PolicyBuilder policyBuilder : builderExtensionPoint.getPolicyBuilders()) {
+ if (!policyBuilder.build(endpointReference, endpoint, context)) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+}