summaryrefslogtreecommitdiffstats
path: root/sca-java-2.x/tags/2.0.1-RC1/modules/builder/src/main/java/org/apache/tuscany/sca/builder/impl/ComponentBuilderImpl.java
diff options
context:
space:
mode:
Diffstat (limited to 'sca-java-2.x/tags/2.0.1-RC1/modules/builder/src/main/java/org/apache/tuscany/sca/builder/impl/ComponentBuilderImpl.java')
-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
1 files changed, 1735 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/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);
+ }
+
+}