Package org.apache.tuscany.sca.builder.impl

Source Code of org.apache.tuscany.sca.builder.impl.ComponentBuilderImpl

/*
* 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: 1291191 $ $Date: 2012-02-20 10:57:50 +0000 (Mon, 20 Feb 2012) $
*/
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);
    }

}
TOP

Related Classes of org.apache.tuscany.sca.builder.impl.ComponentBuilderImpl

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.