| /* |
| * 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.Interface; |
| import org.apache.tuscany.sca.interfacedef.InterfaceContract; |
| import org.apache.tuscany.sca.interfacedef.InterfaceContractMapper; |
| import org.apache.tuscany.sca.interfacedef.impl.DataTypeImpl; |
| import org.apache.tuscany.sca.interfacedef.java.JavaInterface; |
| import org.apache.tuscany.sca.interfacedef.java.JavaInterfaceContract; |
| import org.apache.tuscany.sca.interfacedef.util.XMLType; |
| import org.apache.tuscany.sca.monitor.Monitor; |
| import org.apache.tuscany.sca.policy.ExtensionType; |
| import org.apache.tuscany.sca.policy.PolicySubject; |
| import org.apache.tuscany.sca.xsd.XSDefinition; |
| import org.w3c.dom.Document; |
| import org.w3c.dom.Element; |
| import org.w3c.dom.Node; |
| import org.w3c.dom.NodeList; |
| import org.xml.sax.InputSource; |
| |
| /** |
| * @version $Rev$ $Date$ |
| */ |
| public class ComponentBuilderImpl { |
| protected static final String SCA11_NS = "http://docs.oasis-open.org/ns/opencsa/sca/200912"; |
| protected static final String BINDING_SCA = "binding.sca"; |
| protected static final QName BINDING_SCA_QNAME = new QName(SCA11_NS, BINDING_SCA); |
| |
| private CompositeComponentTypeBuilderImpl componentTypeBuilder; |
| protected ComponentPolicyBuilderImpl policyBuilder; |
| private AssemblyFactory assemblyFactory; |
| private SCABindingFactory scaBindingFactory; |
| private DocumentBuilderFactory documentBuilderFactory; |
| protected TransformerFactory transformerFactory; |
| private InterfaceContractMapper interfaceContractMapper; |
| private BuilderExtensionPoint builders; |
| private Mediator mediator; |
| private ContractBuilder contractBuilder; |
| |
| public ComponentBuilderImpl(ExtensionPointRegistry registry) { |
| UtilityExtensionPoint utilities = registry.getExtensionPoint(UtilityExtensionPoint.class); |
| |
| FactoryExtensionPoint modelFactories = registry.getExtensionPoint(FactoryExtensionPoint.class); |
| assemblyFactory = modelFactories.getFactory(AssemblyFactory.class); |
| scaBindingFactory = modelFactories.getFactory(SCABindingFactory.class); |
| documentBuilderFactory = modelFactories.getFactory(DocumentBuilderFactory.class); |
| transformerFactory = modelFactories.getFactory(TransformerFactory.class); |
| |
| interfaceContractMapper = utilities.getUtility(InterfaceContractMapper.class); |
| policyBuilder = new ComponentPolicyBuilderImpl(registry); |
| builders = registry.getExtensionPoint(BuilderExtensionPoint.class); |
| mediator = new MediatorImpl(registry); |
| contractBuilder = builders.getContractBuilder(); |
| } |
| |
| public void setComponentTypeBuilder(CompositeComponentTypeBuilderImpl componentTypeBuilder) { |
| this.componentTypeBuilder = componentTypeBuilder; |
| } |
| |
| /** |
| * Configure the component based on its component type using OASIS rules |
| * |
| * @Param outerCompoment the component that uses the parentComposite as its implementation |
| * @Param parentComposite the composite that contains the component being configured. Required for property processing |
| * @param component the component to be configured |
| */ |
| public void configureComponentFromComponentType(Component outerComponent, Composite parentComposite, Component component, BuilderContext context) { |
| |
| Monitor monitor = context.getMonitor(); |
| monitor.pushContext("Component: " + component.getName().toString()); |
| |
| try { |
| // do any work we need to do before we calculate the component type |
| // for this component. Anything that needs to be pushed down the promotion |
| // hierarchy must be done before we calculate the component type |
| |
| // check that the implementation is present |
| if (!isComponentImplementationPresent(component, monitor)){ |
| return; |
| } |
| |
| // carry out any implementation specific builder processing |
| Implementation impl = component.getImplementation(); |
| if (impl != null) { |
| ImplementationBuilder builder = builders.getImplementationBuilder(impl.getType()); |
| if (builder != null) { |
| builder.build(component, impl, context); |
| } |
| } |
| |
| // Properties on the composite component type are not affected by the components |
| // that the composite contains. Instead the child components might source |
| // composite level property values. Hence we have to calculate whether the component |
| // type property value should be overridden by this component's property value |
| // before we go ahead and calculate the component type |
| configureProperties(outerComponent, parentComposite, component, monitor); |
| |
| // create the component type for this component |
| // taking any nested composites into account |
| createComponentType(component, context); |
| |
| // configure services based on the calculated component type |
| configureServices(component, context); |
| |
| // configure services based on the calculated component type |
| configureReferences(component, context); |
| |
| // NOTE: configureServices/configureReferences may add callback references and services |
| policyBuilder.configure(component, context); |
| |
| } finally { |
| monitor.popContext(); |
| } |
| } |
| |
| /** |
| * Checks that a component implementation is present and resolved |
| * before doing anything else |
| * |
| * @param component |
| * @return true if the implementation is present and resolved |
| */ |
| private boolean isComponentImplementationPresent(Component component, Monitor monitor){ |
| Implementation implementation = component.getImplementation(); |
| if (implementation == null) { |
| // A component must have an implementation |
| Monitor.error(monitor, |
| this, |
| Messages.ASSEMBLY_VALIDATION, |
| "NoComponentImplementation", |
| component.getName()); |
| return false; |
| } else if (implementation.isUnresolved()) { |
| // The implementation must be fully resolved |
| Monitor.error(monitor, |
| this, |
| Messages.ASSEMBLY_VALIDATION, |
| "UnresolvedComponentImplementation", |
| component, |
| component.getName(), |
| implementation.getURI()); |
| return false; |
| } |
| |
| return true; |
| } |
| |
| /** |
| * Use the component type builder to build the component type for |
| * this component. |
| * |
| * @param component |
| */ |
| private void createComponentType(Component component, BuilderContext context) { |
| Implementation implementation = component.getImplementation(); |
| if (implementation instanceof Composite) { |
| componentTypeBuilder.createComponentType(component, (Composite)implementation, context); |
| } |
| } |
| |
| /** |
| * Configure this component's services based on the services in its |
| * component type and the configuration from the composite file |
| * |
| * @param component |
| */ |
| private void configureServices(Component component, BuilderContext context) { |
| Monitor monitor = context.getMonitor(); |
| |
| // If the component type has services that are not described in this |
| // component then create services for this component |
| addServicesFromComponentType(component, monitor); |
| |
| // Connect this component's services to the |
| // services from its component type |
| connectServicesToComponentType(component, monitor); |
| |
| // look at each component service in turn and calculate its |
| // configuration based on OASIS rules |
| for (ComponentService componentService : component.getServices()) { |
| |
| Service componentTypeService = componentService.getService(); |
| |
| if (componentTypeService == null) { |
| // raise error? |
| // can be null in some of the assembly-xml unit tests |
| continue; |
| } |
| |
| // interface contracts |
| calculateServiceInterfaceContract(component, componentService, componentTypeService, monitor); |
| |
| // bindings |
| calculateBindings(component, componentService, componentTypeService, monitor); |
| |
| // add callback reference model objects |
| createCallbackReference(component, componentService); |
| } |
| } |
| |
| /** |
| * Configure this component's references based on the references in its |
| * component type and the configuration from the composite file |
| * |
| * @param component |
| */ |
| private void configureReferences(Component component, BuilderContext context) { |
| Monitor monitor = context.getMonitor(); |
| |
| // If the component type has references that are not described in this |
| // component then create references for this component |
| addReferencesFromComponentType(component, monitor); |
| |
| // Connect this component's references to the |
| // references from its component type |
| connectReferencesToComponentType(component, monitor); |
| |
| // look at each component reference in turn and calculate its |
| // configuration based on OASIS rules |
| for (ComponentReference componentReference : component.getReferences()) { |
| Reference componentTypeReference = componentReference.getReference(); |
| |
| if (componentTypeReference == null) { |
| // raise error? |
| // can be null in some of the assembly-xml unit tests |
| continue; |
| } |
| |
| // reference multiplicity |
| reconcileReferenceMultiplicity(component, componentReference, componentTypeReference, monitor); |
| |
| // interface contracts |
| calculateReferenceInterfaceContract(component, componentReference, componentTypeReference, monitor); |
| |
| // bindings |
| calculateBindings(componentReference, componentTypeReference); |
| |
| // add callback service model objects |
| createCallbackService(component, componentReference); |
| |
| // Propagate autowire setting from the component down the structural |
| // hierarchy |
| if (componentReference.getAutowire() == null) { |
| componentReference.setAutowire(component.getAutowire()); |
| } |
| } |
| } |
| |
| /** |
| * Configure this component's properties based on the properties in its |
| * component type and the configuration from the composite file |
| * |
| * @param component |
| */ |
| private void configureProperties(Component outerComponent, Composite parentComposite, Component component, Monitor monitor) { |
| // If the component type has properties that are not described in this |
| // component then create properties for this component |
| addPropertiesFromComponentType(component, monitor); |
| |
| // Connect this component's properties to the |
| // properties from its component type |
| connectPropertiesToComponentType(component, monitor); |
| |
| // Reconcile component properties and their component type properties |
| for (ComponentProperty componentProperty : component.getProperties()) { |
| reconcileComponentPropertyWithComponentType(component, componentProperty, monitor); |
| |
| // configure the property value based on the @source attribute |
| // At the moment this is done in the parent composite component |
| // type calculation |
| processPropertySourceAttribute(outerComponent, parentComposite, component, componentProperty, monitor); |
| |
| // configure the property value based on the @file attribute |
| processPropertyFileAttribute(component, componentProperty, monitor); |
| |
| // Check that a value is supplied |
| if (componentProperty.isMustSupply() && !isPropertyValueSet(componentProperty)) { |
| Monitor.error(monitor, |
| this, |
| Messages.ASSEMBLY_VALIDATION, |
| "PropertyMustSupplyNull", |
| component.getName(), |
| componentProperty.getName()); |
| } |
| |
| // check that not too many values are supplied |
| if (!componentProperty.isMany() && isPropertyManyValued(componentProperty)){ |
| Monitor.error(monitor, |
| this, |
| Messages.ASSEMBLY_VALIDATION, |
| "PropertyHasManyValues", |
| component.getName(), |
| componentProperty.getName()); |
| } |
| |
| // check the property type |
| checkComponentPropertyType(component, componentProperty, monitor); |
| |
| } |
| } |
| |
| private void addServicesFromComponentType(Component component, Monitor monitor) { |
| |
| // Create a component service for each service |
| if (component.getImplementation() != null) { |
| for (Service service : component.getImplementation().getServices()) { |
| // check for duplicate service names in implementation |
| if (service != component.getImplementation().getService(service.getName())){ |
| Monitor.error(monitor, |
| this, |
| Messages.ASSEMBLY_VALIDATION, |
| "DuplicateImplementationServiceName", |
| component.getName(), |
| service.getName()); |
| } |
| |
| ComponentService componentService = (ComponentService)component.getService(service.getName()); |
| |
| // if the component doesn't have a service with the same name as the |
| // component type service then create one |
| if (componentService == null) { |
| componentService = assemblyFactory.createComponentService(); |
| componentService.setForCallback(service.isForCallback()); |
| String name = service.getName(); |
| componentService.setName(name); |
| component.getServices().add(componentService); |
| } |
| } |
| } |
| } |
| |
| private void addReferencesFromComponentType(Component component, Monitor monitor) { |
| |
| // Create a component reference for each reference |
| if (component.getImplementation() != null) { |
| for (Reference reference : component.getImplementation().getReferences()) { |
| // check for duplicate reference names in implementation |
| if (reference != component.getImplementation().getReference(reference.getName())){ |
| Monitor.error(monitor, |
| this, |
| Messages.ASSEMBLY_VALIDATION, |
| "DuplicateImplementationReferenceName", |
| component.getName(), |
| reference.getName()); |
| } |
| |
| ComponentReference componentReference = (ComponentReference)component.getReference(reference.getName()); |
| |
| // if the component doesn't have a reference with the same name as the |
| // component type reference then create one |
| if (componentReference == null) { |
| componentReference = assemblyFactory.createComponentReference(); |
| componentReference.setForCallback(reference.isForCallback()); |
| componentReference.setName(reference.getName()); |
| componentReference.setReference(reference); |
| component.getReferences().add(componentReference); |
| } |
| } |
| } |
| } |
| |
| private void addPropertiesFromComponentType(Component component, Monitor monitor) { |
| |
| // Create component property for each property |
| if (component.getImplementation() != null) { |
| for (Property property : component.getImplementation().getProperties()) { |
| // check for duplicate property names in implementation |
| if (property != component.getImplementation().getProperty(property.getName())){ |
| Monitor.error(monitor, |
| this, |
| Messages.ASSEMBLY_VALIDATION, |
| "DuplicateImplementationPropertyName", |
| component.getName(), |
| property.getName()); |
| } |
| ComponentProperty componentProperty = (ComponentProperty)component.getProperty(property.getName()); |
| |
| // if the component doesn't have a property with the same name as |
| // the component type property then create one |
| if (componentProperty == null) { |
| componentProperty = assemblyFactory.createComponentProperty(); |
| componentProperty.setName(property.getName()); |
| componentProperty.setValue(property.getValue()); |
| componentProperty.setMany(property.isMany()); |
| componentProperty.setMustSupply(property.isMustSupply()); |
| componentProperty.setXSDElement(property.getXSDElement()); |
| componentProperty.setXSDType(property.getXSDType()); |
| componentProperty.setProperty(property); |
| component.getProperties().add(componentProperty); |
| } |
| } |
| } |
| } |
| |
| private void connectServicesToComponentType(Component component, Monitor monitor) { |
| |
| // Connect each component service to the corresponding component type service |
| for (ComponentService componentService : component.getServices()) { |
| // check for duplicate service names in component |
| if (componentService != component.getService(componentService.getName())){ |
| Monitor.error(monitor, |
| this, |
| Messages.ASSEMBLY_VALIDATION, |
| "DuplicateComponentServiceName", |
| component.getName(), |
| componentService.getName()); |
| } |
| |
| if (componentService.getService() != null || componentService.isForCallback()) { |
| continue; |
| } |
| |
| if (component.getImplementation() == null) { |
| // is null in some of our basic unit tests |
| continue; |
| } |
| |
| Service service = component.getImplementation().getService(componentService.getName()); |
| |
| if (service != null) { |
| componentService.setService(service); |
| } else { |
| Monitor.error(monitor, |
| this, |
| Messages.ASSEMBLY_VALIDATION, |
| "ServiceNotFoundForComponentService", |
| component.getName(), |
| componentService.getName()); |
| } |
| } |
| } |
| |
| private void connectReferencesToComponentType(Component component, Monitor monitor) { |
| |
| // Connect each component reference to the corresponding component type reference |
| for (ComponentReference componentReference : component.getReferences()) { |
| // check for duplicate reference names in component |
| if (componentReference != component.getReference(componentReference.getName())){ |
| Monitor.error(monitor, |
| this, |
| Messages.ASSEMBLY_VALIDATION, |
| "DuplicateComponentReferenceName", |
| component.getName(), |
| componentReference.getName()); |
| } |
| |
| if (componentReference.getReference() != null || componentReference.isForCallback()) { |
| continue; |
| } |
| |
| if (component.getImplementation() == null) { |
| // is null in some of our basic unit tests |
| continue; |
| } |
| |
| Reference reference = component.getImplementation().getReference(componentReference.getName()); |
| |
| if (reference != null) { |
| componentReference.setReference(reference); |
| } else { |
| Monitor.error(monitor, |
| this, |
| Messages.ASSEMBLY_VALIDATION, |
| "ReferenceNotFoundForComponentReference", |
| component.getName(), |
| componentReference.getName()); |
| } |
| } |
| } |
| |
| private void connectPropertiesToComponentType(Component component, Monitor monitor) { |
| // Connect each component property to the corresponding component type property |
| for (ComponentProperty componentProperty : component.getProperties()) { |
| // check for duplicate property names in component |
| if (componentProperty != component.getProperty(componentProperty.getName())){ |
| Monitor.error(monitor, |
| this, |
| Messages.ASSEMBLY_VALIDATION, |
| "DuplicateComponentPropertyName", |
| component.getName(), |
| componentProperty.getName()); |
| } |
| |
| Property property = component.getImplementation().getProperty(componentProperty.getName()); |
| |
| if (property != null) { |
| componentProperty.setProperty(property); |
| } else { |
| Monitor.error(monitor, |
| this, |
| Messages.ASSEMBLY_VALIDATION, |
| "PropertyNotFound", |
| component.getName(), |
| componentProperty.getName()); |
| } |
| } |
| } |
| |
| private void reconcileReferenceMultiplicity(Component component, |
| Reference componentReference, |
| Reference componentTypeReference, |
| Monitor monitor) { |
| if (componentReference.getMultiplicity() != null) { |
| if (!isValidMultiplicityOverride(componentTypeReference.getMultiplicity(), componentReference |
| .getMultiplicity())) { |
| Monitor.error(monitor, |
| this, |
| Messages.ASSEMBLY_VALIDATION, |
| "ReferenceIncompatibleMultiplicity", |
| component.getName(), |
| componentReference.getName()); |
| } |
| } else { |
| componentReference.setMultiplicity(componentTypeReference.getMultiplicity()); |
| } |
| } |
| |
| private void reconcileComponentPropertyWithComponentType(Component component, ComponentProperty componentProperty, Monitor monitor) { |
| Property componentTypeProperty = componentProperty.getProperty(); |
| if (componentTypeProperty != null) { |
| |
| // Check that a component property does not override the |
| // mustSupply attribute |
| if (!componentTypeProperty.isMustSupply() && componentProperty.isMustSupply()) { |
| Monitor.error(monitor, |
| this, |
| Messages.ASSEMBLY_VALIDATION, |
| "PropertyMustSupplyIncompatible", |
| component.getName(), |
| componentProperty.getName()); |
| } |
| |
| // Default to the mustSupply attribute specified on the property |
| if (!componentProperty.isMustSupply()) |
| componentProperty.setMustSupply(componentTypeProperty.isMustSupply()); |
| |
| // Default to the value specified on the component type property |
| if (!isPropertyValueSet(componentProperty)) { |
| componentProperty.setValue(componentTypeProperty.getValue()); |
| } |
| |
| // Override the property value for the composite |
| if (component.getImplementation() instanceof Composite) { |
| componentTypeProperty.setValue(componentProperty.getValue()); |
| } |
| |
| // Check that a component property does not override the |
| // many attribute |
| if (!componentTypeProperty.isMany() && componentProperty.isMany()) { |
| Monitor.error(monitor, |
| this, |
| Messages.ASSEMBLY_VALIDATION, |
| "PropertyOverrideManyAttribute", |
| component.getName(), |
| componentProperty.getName()); |
| } |
| |
| // Default to the many attribute defined on the property |
| componentProperty.setMany(componentTypeProperty.isMany()); |
| |
| // Default to the type and element defined on the property |
| if (componentProperty.getXSDType() == null) { |
| componentProperty.setXSDType(componentTypeProperty.getXSDType()); |
| } |
| if (componentProperty.getXSDElement() == null) { |
| componentProperty.setXSDElement(componentTypeProperty.getXSDElement()); |
| } |
| |
| // Check that a type or element are specified |
| if (componentProperty.getXSDElement() == null && componentProperty.getXSDType() == null) { |
| Monitor.error(monitor, |
| this, |
| Messages.ASSEMBLY_VALIDATION, |
| "NoTypeForComponentProperty", |
| component.getName(), |
| componentProperty.getName()); |
| } |
| |
| // check that the types specified in the component type and component property match |
| if ( componentProperty.getXSDElement() != null && |
| !componentProperty.getXSDElement().equals(componentTypeProperty.getXSDElement())){ |
| Monitor.error(monitor, |
| this, |
| Messages.ASSEMBLY_VALIDATION, |
| "PropertXSDElementsDontMatch", |
| component.getName(), |
| componentProperty.getName(), |
| componentProperty.getXSDElement(), |
| componentTypeProperty.getXSDElement()); |
| } |
| |
| if ( componentProperty.getXSDType() != null && |
| !componentProperty.getXSDType().equals(componentTypeProperty.getXSDType())){ |
| Monitor.error(monitor, |
| this, |
| Messages.ASSEMBLY_VALIDATION, |
| "PropertXSDTypesDontMatch", |
| component.getName(), |
| componentProperty.getName(), |
| componentProperty.getXSDType(), |
| componentTypeProperty.getXSDType()); |
| } |
| } |
| } |
| |
| /** |
| * checks that the component property value is correctly typed when compared with |
| * the type specified in the composite file property |
| * |
| * TODO - Don't yet handle multiplicity |
| * Need to check composite properties also |
| * |
| * @param component |
| * @param componentProperty |
| * @param monitor |
| */ |
| private void checkComponentPropertyType(Component component, ComponentProperty componentProperty, Monitor monitor) { |
| |
| QName propertyXSDType = componentProperty.getXSDType(); |
| QName propertyElementType = componentProperty.getXSDElement(); |
| |
| if (propertyXSDType != null){ |
| if (propertyXSDType.getNamespaceURI().equals("http://www.w3.org/2001/XMLSchema")) { |
| // The property has a simple schema type so we can use the |
| // data binding framework to see if the XML value can be transformed |
| // into a simple Java value |
| Document doc = (Document)componentProperty.getValue(); |
| Node source = (doc == null) ? null : doc.getDocumentElement().getFirstChild(); |
| DataType<XMLType> sourceDataType = new DataTypeImpl<XMLType>(DOMDataBinding.NAME, |
| Node.class, |
| new XMLType(null, componentProperty.getXSDType())); |
| DataType<XMLType> targetDataType = new DataTypeImpl<XMLType>(JAXBDataBinding.NAME, |
| Object.class, |
| new XMLType(null, componentProperty.getXSDType())); |
| try { |
| mediator.mediate(source, sourceDataType, targetDataType, null); |
| } catch (Exception ex){ |
| Monitor.error(monitor, |
| this, |
| Messages.ASSEMBLY_VALIDATION, |
| "PropertyValueDoesNotMatchSimpleType", |
| componentProperty.getName(), |
| component.getName(), |
| componentProperty.getXSDType().toString()); |
| } |
| } else { |
| // The property has a complex schema type so we fluff up a schema |
| // and use that to validate the property value |
| XSDefinition xsdDefinition = (XSDefinition)componentProperty.getXSDDefinition(); |
| |
| if (xsdDefinition != null) { |
| try { |
| // create schema factory for XML schema |
| SchemaFactory factory = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI); |
| |
| Document schemaDom = xsdDefinition.getSchema().getSchemaDocument(); |
| |
| String valueSchema = null; |
| Schema schema = null; |
| |
| if (componentProperty.getXSDType().getNamespaceURI().equals(Constants.SCA11_NS)){ |
| // include the referenced schema as it's already in the OASIS namespace |
| valueSchema = "<?xml version=\"1.0\" encoding=\"UTF-8\"?> " + |
| "<schema xmlns=\"http://www.w3.org/2001/XMLSchema\" "+ |
| "xmlns:sca=\"http://docs.oasis-open.org/ns/opencsa/sca/200912\" "+ |
| "xmlns:__tmp=\"" + componentProperty.getXSDType().getNamespaceURI() + "\" "+ |
| "targetNamespace=\"http://docs.oasis-open.org/ns/opencsa/sca/200912\" " + |
| "elementFormDefault=\"qualified\">" + |
| "<include schemaLocation=\"" + xsdDefinition.getLocation() + "\"/>" + |
| // "<element name=\"value\" type=\"" + "__tmp:" + componentProperty.getXSDType().getLocalPart() + "\"/>" + |
| "</schema>"; |
| // Source sources[] = {new StreamSource(new StringReader(valueSchema))}; |
| Source sources[] = {new DOMSource(schemaDom)}; |
| schema = factory.newSchema(sources); |
| |
| // The SCA schema already contains a "value" element so I can't create this schema |
| // the SCA value element is an any so return assuming that it validates. |
| return; |
| } else { |
| // import the referenced schema |
| valueSchema = "<?xml version=\"1.0\" encoding=\"UTF-8\"?> " + |
| "<schema xmlns=\"http://www.w3.org/2001/XMLSchema\" "+ |
| "xmlns:sca=\"http://docs.oasis-open.org/ns/opencsa/sca/200912\" "+ |
| "xmlns:__tmp=\"" + componentProperty.getXSDType().getNamespaceURI() + "\" "+ |
| "targetNamespace=\"http://docs.oasis-open.org/ns/opencsa/sca/200912\" " + |
| "elementFormDefault=\"qualified\">" + |
| "<import namespace=\"" + componentProperty.getXSDType().getNamespaceURI() + "\"/>" + |
| "<element name=\"value\" type=\"" + "__tmp:" + componentProperty.getXSDType().getLocalPart() + "\"/>" + |
| "</schema>"; |
| Source sources[] = {new DOMSource(schemaDom), new StreamSource(new StringReader(valueSchema))}; |
| schema = factory.newSchema(sources); |
| } |
| |
| // get the value child of the property element |
| Document property = (Document)componentProperty.getValue(); |
| Element value = (Element)property.getDocumentElement().getFirstChild(); |
| |
| // validate the element property/value from the DOM |
| Validator validator = schema.newValidator(); |
| validator.validate(new DOMSource(value)); |
| |
| } catch (Exception e) { |
| Monitor.error(monitor, |
| this, |
| Messages.ASSEMBLY_VALIDATION, |
| "PropertyValueDoesNotMatchComplexType", |
| componentProperty.getName(), |
| component.getName(), |
| componentProperty.getXSDType().toString(), |
| e.getMessage()); |
| } |
| } |
| } |
| } else if (propertyElementType != null) { |
| // TODO - TUSCANY-3530 - still need to add validation for element type |
| |
| } |
| } |
| |
| /** |
| * If the property has a source attribute use this to retrieve the value from a |
| * property in the parent composite |
| * |
| * @param parentCompoent the composite that contains the component |
| * @param component |
| * @param componentProperty |
| */ |
| private void processPropertySourceAttribute(Component outerComponent, |
| Composite parentComposite, |
| Component component, |
| ComponentProperty componentProperty, |
| Monitor monitor) { |
| String source = componentProperty.getSource(); |
| |
| if (source != null) { |
| // $<name>/... |
| int index = source.indexOf('/'); |
| if (index == -1) { |
| // Tolerating $prop |
| source = source + "/"; |
| index = source.length() - 1; |
| } |
| if (source.charAt(0) == '$') { |
| String name = source.substring(1, index); |
| Property sourceProp = null; |
| if (outerComponent != null) { |
| sourceProp = outerComponent.getProperty(name); |
| } else { |
| sourceProp = parentComposite.getProperty(name); |
| } |
| if (sourceProp == null) { |
| Monitor.error(monitor, |
| this, |
| Messages.ASSEMBLY_VALIDATION, |
| "PropertySourceNotFound", |
| source, |
| componentProperty.getName(), |
| component.getName()); |
| } |
| |
| Document sourcePropValue = (Document)sourceProp.getValue(); |
| |
| try { |
| // FIXME: How to deal with namespaces? |
| Document node = |
| evaluateXPath(sourcePropValue, |
| componentProperty.getSourceXPathExpression(), |
| documentBuilderFactory); |
| |
| if (node != null) { |
| componentProperty.setValue(node); |
| } else { |
| Monitor.warning(monitor, |
| this, |
| Messages.ASSEMBLY_VALIDATION, |
| "PropertyXpathExpressionReturnedNull", |
| component.getName(), |
| componentProperty.getName(), |
| componentProperty.getSource()); |
| } |
| } catch (Exception ex) { |
| Monitor.error(monitor, |
| this, |
| Messages.ASSEMBLY_VALIDATION, |
| "PropertySourceXpathInvalid", |
| source, |
| componentProperty.getName(), |
| component.getName(), |
| ex); |
| } |
| } else { |
| Monitor.error(monitor, |
| this, |
| Messages.ASSEMBLY_VALIDATION, |
| "PropertySourceValueInvalid", |
| source, |
| componentProperty.getName(), |
| component.getName()); |
| } |
| } |
| } |
| |
| /** |
| * If the property has a file attribute use this to retrieve the value from a |
| * local file |
| |
| * |
| * @param parentCompoent the composite that contains the component |
| * @param component |
| */ |
| private void processPropertyFileAttribute(Component component, ComponentProperty componentProperty, Monitor monitor) { |
| String file = componentProperty.getFile(); |
| if (file != null) { |
| try { |
| URI uri = URI.create(file); |
| // URI resolution for relative URIs is done when the composite is resolved. |
| URL url = uri.toURL(); |
| URLConnection connection = url.openConnection(); |
| connection.setUseCaches(false); |
| InputStream is = null; |
| try { |
| is = connection.getInputStream(); |
| |
| Source streamSource = new SAXSource(new InputSource(is)); |
| DOMResult result = new DOMResult(); |
| javax.xml.transform.Transformer transformer = transformerFactory.newTransformer(); |
| transformer.transform(streamSource, result); |
| |
| Document document = (Document)result.getNode(); |
| |
| // TUSCANY-2377, Add a fake value element so it's consistent with |
| // the DOM tree loaded from inside SCDL |
| if (!document.getDocumentElement().getLocalName().equals("value")){ |
| Element root = document.createElementNS(null, "value"); |
| root.appendChild(document.getDocumentElement()); |
| |
| // remove all the child nodes as they will be replaced by |
| // the "value" node |
| NodeList children = document.getChildNodes(); |
| for (int i=0; i < children.getLength(); i++){ |
| document.removeChild(children.item(i)); |
| } |
| |
| // add the value node back in |
| document.appendChild(root); |
| } |
| |
| componentProperty.setValue(document); |
| } finally { |
| if (is != null) { |
| is.close(); |
| } |
| } |
| } catch (Exception ex) { |
| Monitor.error(monitor, |
| this, |
| Messages.ASSEMBLY_VALIDATION, |
| "PropertyFileValueInvalid", |
| file, |
| componentProperty.getName(), |
| component.getName(), |
| ex); |
| } |
| } |
| |
| } |
| |
| /** |
| * Evaluate an XPath expression against a Property value, returning the result as a Property value |
| * @param node - the document root element of a Property value |
| * @param expression - the XPath expression |
| * @param documentBuilderFactory - a DOM document builder factory |
| * @return - a DOM Document representing the result of the evaluation as a Property value |
| * @throws XPathExpressionException |
| * @throws ParserConfigurationException |
| */ |
| private Document evaluateXPath(Document node, |
| XPathExpression expression, |
| DocumentBuilderFactory documentBuilderFactory) throws XPathExpressionException, |
| ParserConfigurationException { |
| |
| // The document element is a <sca:property/> element |
| Node property = node.getDocumentElement(); |
| // The first child of the <property/> element is a <value/> element |
| Node value = property.getFirstChild(); |
| |
| Node result = (Node)expression.evaluate(value, XPathConstants.NODE); |
| if (result == null) { |
| return null; |
| } |
| |
| if (result instanceof Document) { |
| return (Document)result; |
| } else { |
| Document document = documentBuilderFactory.newDocumentBuilder().newDocument(); |
| Element newProperty = document.createElementNS(SCA11_NS, "property"); |
| |
| if (result.getNodeType() == Node.ELEMENT_NODE) { |
| // If the result is a <value/> element, use it directly in the result |
| newProperty.appendChild(document.importNode(result, true)); |
| } else { |
| // If the result is not a <value/> element, create a <value/> element to contain the result |
| Element newValue = document.createElementNS(SCA11_NS, "value"); |
| newValue.appendChild(document.importNode(result, true)); |
| newProperty.appendChild(newValue); |
| } // end if |
| document.appendChild(newProperty); |
| |
| return document; |
| } |
| } |
| |
| /** |
| * Create a callback reference for a component service |
| * |
| * @param component |
| * @param service |
| */ |
| private void createCallbackReference(Component component, ComponentService service) { |
| |
| // if the service has a callback interface create a reference |
| // to represent the callback |
| if (service.getInterfaceContract() != null && // can be null in unit tests |
| service.getInterfaceContract().getCallbackInterface() != null) { |
| |
| ComponentReference callbackReference = assemblyFactory.createComponentReference(); |
| callbackReference.setForCallback(true); |
| callbackReference.setName(service.getName()); |
| // MJE: multiplicity = 0..n for these callback references |
| callbackReference.setMultiplicity(Multiplicity.ZERO_N); |
| try { |
| InterfaceContract contract = (InterfaceContract)service.getInterfaceContract().clone(); |
| contract.setInterface(contract.getCallbackInterface()); |
| contract.setCallbackInterface(null); |
| callbackReference.setInterfaceContract(contract); |
| } catch (CloneNotSupportedException e) { |
| // will not happen |
| } |
| Service implService = service.getService(); |
| if (implService != null) { |
| |
| // If the implementation service is a CompositeService, ensure that the Reference that is |
| // created is a CompositeReference, otherwise create a Reference |
| Reference implReference; |
| if (implService instanceof CompositeService) { |
| CompositeReference implCompReference = assemblyFactory.createCompositeReference(); |
| // Set the promoted component from the promoted component of the composite service |
| implCompReference.getPromotedComponents().add(((CompositeService)implService) |
| .getPromotedComponent()); |
| |
| // Get the promoted component reference corresponding to the service with the callback |
| // fist checking that the promoted service is resolved lest we get a NPE trying to |
| // retrieve the promoted component. It could be unresolved if the user gets the |
| // promotes string wrong |
| // TODO - is there any danger that the callback reference name will clash with other |
| // reference names. Old code used to qualify it with promoted component name |
| if (((CompositeService)implService).getPromotedService().isUnresolved() == false){ |
| String referenceName = ((CompositeService)implService).getPromotedService().getName(); |
| ComponentReference promotedReference = ((CompositeService)implService).getPromotedComponent().getReference(referenceName); |
| implCompReference.getPromotedReferences().add(promotedReference); |
| } |
| implReference = implCompReference; |
| |
| // Add the composite reference to the composite implementation artifact |
| Implementation implementation = component.getImplementation(); |
| if (implementation != null && implementation instanceof Composite) { |
| ((Composite)implementation).getReferences().add(implCompReference); |
| } |
| } else { |
| implReference = assemblyFactory.createReference(); |
| } |
| |
| implReference.setName(implService.getName()); |
| // MJE: Fixup multiplicity as 0..n for callback references in the component type |
| implReference.setMultiplicity(Multiplicity.ZERO_N); |
| try { |
| InterfaceContract implContract = (InterfaceContract)implService.getInterfaceContract().clone(); |
| implContract.setInterface(implContract.getCallbackInterface()); |
| implContract.setCallbackInterface(null); |
| implReference.setInterfaceContract(implContract); |
| } catch (CloneNotSupportedException e) { |
| // will not happen |
| } |
| callbackReference.setReference(implReference); |
| } |
| component.getReferences().add(callbackReference); |
| |
| // Set the bindings of the callback reference |
| if (callbackReference.getBindings().isEmpty()) { |
| // If there are specific callback bindings set in the SCDL service |
| // callback element then use them |
| // at runtime a callback binding will be selected based on the forward call |
| if (service.getCallback() != null && service.getCallback().getBindings().size() > 0) { |
| callbackReference.getBindings().addAll(service.getCallback().getBindings()); |
| } else { |
| // otherwise take a copy of all the bindings on the forward service |
| // at runtime a callback binding will be selected based on the forward call |
| List<Binding> serviceBindings = service.getBindings(); |
| for ( Binding serviceBinding: serviceBindings ) { |
| try { |
| Binding referenceBinding = (Binding)serviceBinding.clone(); |
| referenceBinding.setURI(null); |
| callbackReference.getBindings().add(referenceBinding); |
| } catch (CloneNotSupportedException e) { |
| // will not happen |
| } // end try |
| } // end for |
| |
| // if there are still no bindings for the callback create a default binding which |
| // will cause the EPR for this reference to be marked as EndpointReference.NOT_CONFIGURED |
| if( serviceBindings.size() == 0 ) { |
| createSCABinding(callbackReference, null); |
| } // end if |
| } |
| } |
| service.setCallbackReference(callbackReference); |
| } |
| } |
| |
| /** |
| * Create a callback service for a component reference |
| * |
| * @param component |
| * @param service |
| */ |
| private void createCallbackService(Component component, ComponentReference reference) { |
| if (reference.getInterfaceContract() != null && // can be null in unit tests |
| reference.getInterfaceContract().getCallbackInterface() != null) { |
| ComponentService callbackService = assemblyFactory.createComponentService(); |
| callbackService.setForCallback(true); |
| callbackService.setName(reference.getName()); |
| try { |
| InterfaceContract contract = (InterfaceContract)reference.getInterfaceContract().clone(); |
| contract.setInterface(contract.getCallbackInterface()); |
| contract.setCallbackInterface(null); |
| callbackService.setInterfaceContract(contract); |
| } catch (CloneNotSupportedException e) { |
| // will not happen |
| } |
| Reference implReference = reference.getReference(); |
| if (implReference != null) { |
| // If the implementation reference is a CompositeReference, ensure that the Service that is |
| // created is a CompositeService, otherwise create a Service |
| Service implService; |
| if (implReference instanceof CompositeReference) { |
| CompositeService implCompService = assemblyFactory.createCompositeService(); |
| // TODO The reality here is that the composite reference which has the callback COULD promote more than |
| // one component reference - and there must be a separate composite callback service for each of these component |
| // references |
| |
| // Set the promoted component from the promoted component of the composite reference |
| implCompService.setPromotedComponent(((CompositeReference)implReference).getPromotedComponents().get(0)); |
| implCompService.setForCallback(true); |
| |
| // Get the promoted component service corresponding to the reference with the callback |
| // fist checking that the promoted reference is resolved lest we get a NPE trying to |
| // retrieve the promoted component. It could be unresolved if the user gets the |
| // promotes string wrong |
| if (((CompositeReference)implReference).getPromotedReferences().get(0).isUnresolved() == false){ |
| String serviceName = ((CompositeReference)implReference).getPromotedReferences().get(0).getName(); |
| ComponentService promotedService = ((CompositeReference)implReference).getPromotedComponents().get(0).getService(serviceName); |
| implCompService.setPromotedService(promotedService); |
| } |
| |
| implService = implCompService; |
| // Add the composite service to the composite implementation artifact |
| Implementation implementation = component.getImplementation(); |
| if (implementation != null && implementation instanceof Composite) { |
| ((Composite)implementation).getServices().add(implCompService); |
| } // end if |
| // |
| } else { |
| implService = assemblyFactory.createService(); |
| } // end if |
| // |
| implService.setName(implReference.getName()); |
| try { |
| InterfaceContract implContract = (InterfaceContract)implReference.getInterfaceContract().clone(); |
| implContract.setInterface(implContract.getCallbackInterface()); |
| implContract.setCallbackInterface(null); |
| implService.setInterfaceContract(implContract); |
| } catch (CloneNotSupportedException e) { |
| // will not happen |
| } |
| callbackService.setService(implService); |
| } |
| component.getServices().add(callbackService); |
| |
| // configure bindings for the callback service |
| if (callbackService.getBindings().isEmpty()) { |
| if (reference.getCallback() != null && reference.getCallback().getBindings().size() > 0) { |
| // set bindings of the callback service based on the information provided in |
| // SCDL reference callback element |
| callbackService.getBindings().addAll(reference.getCallback().getBindings()); |
| } else if (reference.getBindings().size() > 0) { |
| // use any bindings explicitly declared on the forward reference |
| for (Binding binding : reference.getBindings()) { |
| try { |
| Binding clonedBinding = (Binding)binding.clone(); |
| // binding uri will be calculated during runtime build |
| clonedBinding.setURI(null); |
| callbackService.getBindings().add(clonedBinding); |
| } catch (CloneNotSupportedException ex) { |
| |
| } |
| } |
| } else { |
| // create a default binding which will have the correct policy |
| // and URI added. We check later to see if a new binding is required |
| // based on the forward binding but can then copy policy and URI |
| // details from here. |
| // TODO - there is a hole here. If the user explicitly specified an |
| // SCA callback binding that is different from the forward |
| // binding type then we're in trouble |
| createSCABinding(callbackService, null); |
| } |
| } |
| |
| reference.setCallbackService(callbackService); |
| } |
| } |
| |
| /** |
| * Create a default SCA binding in the case that no binding |
| * is specified by the user |
| * |
| * @param contract |
| * @param definitions |
| */ |
| protected void createSCABinding(Contract contract, Definitions definitions) { |
| |
| SCABinding scaBinding = scaBindingFactory.createSCABinding(); |
| scaBinding.setName(contract.getName()); |
| |
| if (definitions != null) { |
| for (ExtensionType attachPointType : definitions.getBindingTypes()) { |
| if (attachPointType.getType().equals(BINDING_SCA_QNAME)) { |
| ((PolicySubject)scaBinding).setExtensionType(attachPointType); |
| } |
| } |
| } |
| |
| contract.getBindings().add(scaBinding); |
| contract.setOverridingBindings(false); |
| } |
| |
| /** |
| * Look to see if any value elements have been set into the property |
| * A bit involved as the value is stored as a DOM Document |
| * |
| * @param property the property to be tested |
| * @return true is values are present |
| */ |
| private boolean isPropertyValueSet(Property property) { |
| Document value = (Document)property.getValue(); |
| |
| if (value == null) { |
| return false; |
| } |
| |
| if (value.getDocumentElement() == null) { |
| return false; |
| } |
| |
| if (value.getDocumentElement().getChildNodes().getLength() == 0) { |
| return false; |
| } |
| |
| return true; |
| } |
| |
| /** |
| * Look to see is a property has more than one value |
| * |
| * @param property |
| * @return true is the property has more than one value |
| */ |
| private boolean isPropertyManyValued(Property property) { |
| |
| if (isPropertyValueSet(property)){ |
| Document value = (Document)property.getValue(); |
| if (value.getDocumentElement().getChildNodes().getLength() > 1){ |
| return true; |
| } |
| } |
| return false; |
| } |
| |
| private boolean isValidMultiplicityOverride(Multiplicity definedMul, Multiplicity overridenMul) { |
| if (definedMul != overridenMul) { |
| switch (definedMul) { |
| case ZERO_N: |
| return overridenMul == Multiplicity.ZERO_ONE || overridenMul == Multiplicity.ONE_ONE |
| || overridenMul == Multiplicity.ONE_N; |
| case ONE_N: |
| return overridenMul == Multiplicity.ONE_ONE; |
| case ZERO_ONE: |
| return overridenMul == Multiplicity.ONE_ONE; |
| default: |
| return false; |
| } |
| } else { |
| return true; |
| } |
| } |
| |
| |
| /** |
| * Interface contract from higher in the implementation hierarchy takes precedence |
| * When it comes to checking compatibility the top level service interface is a |
| * subset of the promoted service interface so treat the top level interface as |
| * the source |
| * |
| * @param topContract the top contract |
| * @param bottomContract the bottom contract |
| */ |
| private void calculateServiceInterfaceContract(Component component, Service topContract, Service bottomContract, Monitor monitor) { |
| |
| // Use the interface contract from the bottom level contract if |
| // none is specified on the top level contract |
| InterfaceContract topInterfaceContract = topContract.getInterfaceContract(); |
| InterfaceContract bottomInterfaceContract = bottomContract.getInterfaceContract(); |
| |
| if (topInterfaceContract == null) { |
| topContract.setInterfaceContract(bottomInterfaceContract); |
| } else if (bottomInterfaceContract != null) { |
| // Check that the top and bottom interface contracts are compatible |
| boolean isCompatible = true; |
| String incompatibilityReason = ""; |
| try{ |
| isCompatible = checkSubsetCompatibility(topInterfaceContract, |
| bottomInterfaceContract); |
| } catch (IncompatibleInterfaceContractException ex){ |
| isCompatible = false; |
| incompatibilityReason = ex.getMessage(); |
| } |
| if (!isCompatible) { |
| Monitor.error(monitor, |
| this, |
| Messages.ASSEMBLY_VALIDATION, |
| "ServiceIncompatibleComponentInterface", |
| component.getName(), |
| topContract.getName(), |
| incompatibilityReason); |
| } |
| |
| // TODO - there is an issue with the following code if the |
| // contracts of of different types. Need to use the |
| // normalized form |
| |
| // fix up the forward interface based on the promoted component |
| // Someone might have manually specified a callback interface but |
| // left out the forward interface |
| if (topInterfaceContract.getInterface() == null){ |
| topInterfaceContract.setInterface(bottomInterfaceContract.getInterface()); |
| } |
| |
| // fix up the callback interface based on the promoted component |
| // Someone might have manually specified a forward interface but |
| // left out the callback interface |
| if (topInterfaceContract.getCallbackInterface() == null){ |
| topInterfaceContract.setCallbackInterface(bottomInterfaceContract.getCallbackInterface()); |
| } |
| } |
| } |
| |
| /** |
| * Interface contract from higher in the implementation hierarchy takes precedence |
| * When it comes to checking compatibility the top level reference interface is a |
| * superset of the promoted reference interface so treat the promoted |
| * (bottom) interface as the source |
| * |
| * @param topContract the top contract |
| * @param bottomContract the bottom contract |
| */ |
| private void calculateReferenceInterfaceContract(Component component, Reference topContract, Reference bottomContract, Monitor monitor) { |
| |
| // Use the interface contract from the bottom level contract if |
| // none is specified on the top level contract |
| InterfaceContract topInterfaceContract = topContract.getInterfaceContract(); |
| InterfaceContract bottomInterfaceContract = bottomContract.getInterfaceContract(); |
| |
| if (topInterfaceContract == null) { |
| topContract.setInterfaceContract(bottomInterfaceContract); |
| } else if (bottomInterfaceContract != null) { |
| // Check that the top and bottom interface contracts are compatible |
| boolean isCompatible = true; |
| String incompatibilityReason = ""; |
| try{ |
| isCompatible = checkSubsetCompatibility(bottomInterfaceContract, |
| topInterfaceContract); |
| } catch (IncompatibleInterfaceContractException ex){ |
| isCompatible = false; |
| incompatibilityReason = ex.getMessage(); |
| } |
| if (!isCompatible) { |
| Monitor.error(monitor, |
| this, |
| Messages.ASSEMBLY_VALIDATION, |
| "ReferenceIncompatibleComponentInterface", |
| component.getName(), |
| topContract.getName(), |
| incompatibilityReason); |
| } |
| |
| // TODO - there is an issue with the following code if the |
| // contracts of of different types. Need to use the |
| // normalized form |
| |
| // fix up the forward interface based on the promoted component |
| // Someone might have manually specified a callback interface but |
| // left out the forward interface |
| if (topInterfaceContract.getInterface() == null){ |
| topInterfaceContract.setInterface(bottomInterfaceContract.getInterface()); |
| } |
| |
| // fix up the callback interface based on the promoted component |
| // Someone might have manually specified a forward interface but |
| // left out the callback interface |
| if (topInterfaceContract.getCallbackInterface() == null){ |
| topInterfaceContract.setCallbackInterface(bottomInterfaceContract.getCallbackInterface()); |
| } |
| } |
| } |
| |
| /** |
| * Bindings from higher in the hierarchy take precedence |
| * |
| * @param componentService the top service |
| * @param componentTypeService the bottom service |
| */ |
| private void calculateBindings(Component component, Service componentService, Service componentTypeService, Monitor monitor) { |
| // forward bindings |
| if (componentService.getBindings().isEmpty()) { |
| componentService.getBindings().addAll(componentTypeService.getBindings()); |
| } |
| |
| if (componentService.getBindings().isEmpty()) { |
| createSCABinding(componentService, null); |
| } |
| |
| // callback bindings |
| if (componentService.getCallback() == null) { |
| componentService.setCallback(componentTypeService.getCallback()); |
| if (componentService.getCallback() == null) { |
| // Create an empty callback to avoid null check |
| componentService.setCallback(assemblyFactory.createCallback()); |
| } |
| } else if (componentService.getCallback().getBindings().isEmpty() && componentTypeService.getCallback() != null) { |
| componentService.getCallback().getBindings().addAll(componentTypeService.getCallback().getBindings()); |
| } |
| |
| // [ASM90005] validate that binding.sca has no uri set |
| for (Binding binding : componentService.getBindings()){ |
| if (binding instanceof SCABinding){ |
| if ((binding.getURI() != null) && |
| (binding.getURI().length() > 0)){ |
| Monitor.error(monitor, |
| this, |
| Messages.ASSEMBLY_VALIDATION, |
| "URIFoundOnServiceSCABinding", |
| binding.getName(), |
| component.getName(), |
| componentService.getName(), |
| binding.getURI()); |
| } |
| } |
| } |
| |
| } |
| |
| /** |
| * Bindings from higher in the hierarchy take precedence |
| * |
| * @param componentReference the top service |
| * @param componentTypeReference the bottom service |
| */ |
| private void calculateBindings(Reference componentReference, Reference componentTypeReference) { |
| // forward bindings |
| if (componentReference.getBindings().isEmpty()) { |
| componentReference.getBindings().addAll(componentTypeReference.getBindings()); |
| } |
| |
| // callback bindings |
| if (componentReference.getCallback() == null) { |
| componentReference.setCallback(componentTypeReference.getCallback()); |
| } else if (componentReference.getCallback().getBindings().isEmpty() && componentTypeReference.getCallback() != null) { |
| componentReference.getCallback().getBindings().addAll(componentTypeReference.getCallback().getBindings()); |
| } |
| } |
| |
| /** |
| * A local wrapper for the interace contract mapper as we need to normalize the |
| * interface contracts if appropriate and the mapper doesn't have the right |
| * dependencies to be able to do it. |
| * |
| * Sometimes the two interfaces can be presented using different IDLs, for example |
| * Java and WSDL. In this case interfaces are converted so that they are both WSDL1.1 interfaces |
| * and they are then compared. The generated WSDL is cached on the interface object for |
| * any subsequent matching |
| * |
| * @param contractA |
| * @param contractB |
| * @return true if the interface contracts match |
| */ |
| private boolean checkSubsetCompatibility(InterfaceContract contractA, InterfaceContract contractB) |
| throws IncompatibleInterfaceContractException { |
| |
| if (contractA.getClass() != contractB.getClass()) { |
| |
| if (contractA instanceof JavaInterfaceContract){ |
| contractBuilder.build(contractA, null); |
| contractA = ((JavaInterfaceContract)contractA).getNormalizedWSDLContract(); |
| } |
| |
| if (contractB instanceof JavaInterfaceContract){ |
| contractBuilder.build(contractB, null); |
| contractB = ((JavaInterfaceContract)contractB).getNormalizedWSDLContract(); |
| } |
| } |
| |
| return interfaceContractMapper.checkCompatibility(contractA, |
| contractB, |
| Compatibility.SUBSET, |
| false, |
| false); |
| } |
| |
| } |