diff options
Diffstat (limited to 'sca-java-2.x/tags/2.0-M4-RC2/modules/builder/src/main/java/org/apache/tuscany/sca/builder/impl/BaseBuilderImpl.java')
-rw-r--r-- | sca-java-2.x/tags/2.0-M4-RC2/modules/builder/src/main/java/org/apache/tuscany/sca/builder/impl/BaseBuilderImpl.java | 703 |
1 files changed, 703 insertions, 0 deletions
diff --git a/sca-java-2.x/tags/2.0-M4-RC2/modules/builder/src/main/java/org/apache/tuscany/sca/builder/impl/BaseBuilderImpl.java b/sca-java-2.x/tags/2.0-M4-RC2/modules/builder/src/main/java/org/apache/tuscany/sca/builder/impl/BaseBuilderImpl.java new file mode 100644 index 0000000000..111680b2b4 --- /dev/null +++ b/sca-java-2.x/tags/2.0-M4-RC2/modules/builder/src/main/java/org/apache/tuscany/sca/builder/impl/BaseBuilderImpl.java @@ -0,0 +1,703 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.apache.tuscany.sca.builder.impl; + +import java.util.Map; + +import javax.xml.namespace.QName; +import javax.xml.parsers.DocumentBuilderFactory; +import javax.xml.transform.TransformerFactory; + +import org.apache.tuscany.sca.assembly.AssemblyFactory; +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.Contract; +import org.apache.tuscany.sca.assembly.Implementation; +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.BuilderExtensionPoint; +import org.apache.tuscany.sca.assembly.builder.CompositeBuilder; +import org.apache.tuscany.sca.assembly.builder.Messages; +import org.apache.tuscany.sca.core.ExtensionPointRegistry; +import org.apache.tuscany.sca.core.FactoryExtensionPoint; +import org.apache.tuscany.sca.core.UtilityExtensionPoint; +import org.apache.tuscany.sca.definitions.Definitions; +import org.apache.tuscany.sca.interfacedef.InterfaceContract; +import org.apache.tuscany.sca.interfacedef.InterfaceContractMapper; +import org.apache.tuscany.sca.monitor.Monitor; +import org.apache.tuscany.sca.monitor.Problem; +import org.apache.tuscany.sca.monitor.Problem.Severity; +import org.apache.tuscany.sca.policy.ExtensionType; +import org.apache.tuscany.sca.policy.PolicySubject; +import org.w3c.dom.Document; + +/** + * Base class for Builder implementations + * + * @version $Rev$ $Date$ + */ +public abstract class BaseBuilderImpl implements CompositeBuilder { + protected static final String SCA11_NS = "http://docs.oasis-open.org/ns/opencsa/sca/200903"; + protected static final String BINDING_SCA = "binding.sca"; + protected static final QName BINDING_SCA_QNAME = new QName(SCA11_NS, BINDING_SCA); + + protected AssemblyFactory assemblyFactory; + protected SCABindingFactory scaBindingFactory; + protected InterfaceContractMapper interfaceContractMapper; + protected DocumentBuilderFactory documentBuilderFactory; + protected TransformerFactory transformerFactory; + protected BuilderExtensionPoint builders; + + protected BaseBuilderImpl(BuilderExtensionPoint builders, + AssemblyFactory assemblyFactory, + SCABindingFactory scaBindingFactory, + DocumentBuilderFactory documentBuilderFactory, + TransformerFactory transformerFactory, + InterfaceContractMapper interfaceContractMapper) { + this.builders = builders; + this.assemblyFactory = assemblyFactory; + this.scaBindingFactory = scaBindingFactory; + this.documentBuilderFactory = documentBuilderFactory; + this.transformerFactory = transformerFactory; + this.interfaceContractMapper = interfaceContractMapper; + } + + /** + * Construct a builder from the extension point registry + * @param registry + */ + protected BaseBuilderImpl(ExtensionPointRegistry registry) { + this.builders = registry.getExtensionPoint(BuilderExtensionPoint.class); + FactoryExtensionPoint factoryExtensionPoint = registry.getExtensionPoint(FactoryExtensionPoint.class); + this.assemblyFactory = factoryExtensionPoint.getFactory(AssemblyFactory.class); + this.scaBindingFactory = factoryExtensionPoint.getFactory(SCABindingFactory.class); + this.documentBuilderFactory = factoryExtensionPoint.getFactory(DocumentBuilderFactory.class); + this.transformerFactory = factoryExtensionPoint.getFactory(TransformerFactory.class); + this.interfaceContractMapper = + registry.getExtensionPoint(UtilityExtensionPoint.class).getUtility(InterfaceContractMapper.class); + } + + /** + * Report a warning. + * + * @param monitor + * @param problems + * @param message + * @param model + */ + protected void warning(Monitor monitor, String message, Object model, Object... messageParameters) { + if (monitor != null) { + Problem problem = + monitor.createProblem(this.getClass().getName(), + Messages.ASSEMBLY_VALIDATION, + Severity.WARNING, + model, + message, + messageParameters); + monitor.problem(problem); + } + } + + /** + * Report a error. + * + * @param monitor + * @param problems + * @param message + * @param model + */ + protected void error(Monitor monitor, String message, Object model, Object... messageParameters) { + if (monitor != null) { + Problem problem = + monitor.createProblem(this.getClass().getName(), + Messages.ASSEMBLY_VALIDATION, + Severity.ERROR, + model, + message, + messageParameters); + monitor.problem(problem); + } + } + + /** + * Report a exception. + * + * @param problems + * @param message + * @param model + */ + protected void error(Monitor monitor, String message, Object model, Exception ex) { + if (monitor != null) { + Problem problem = null; + problem = + monitor.createProblem(this.getClass().getName(), + Messages.ASSEMBLY_VALIDATION, + Severity.ERROR, + model, + message, + ex); + monitor.problem(problem); + } + } + + /** + * Index components inside a composite + * + * @param composite + * @param componentServices + + */ + protected void indexComponents(Composite composite, Map<String, Component> components) { + for (Component component : composite.getComponents()) { + // Index components by name + components.put(component.getName(), component); + } + } + + /** + * Index services inside a composite + * + * @param composite + * @param componentServices + */ + protected void indexServices(Composite composite, Map<String, ComponentService> componentServices) { + + for (Component component : composite.getComponents()) { + + ComponentService nonCallbackService = null; + int nonCallbackServiceCount = 0; + + for (ComponentService componentService : component.getServices()) { + // Index component services by component name / service name + String uri = component.getName() + '/' + componentService.getName(); + componentServices.put(uri, componentService); + + // count how many non-callback there are + if (!componentService.isForCallback()) { + + if (nonCallbackServiceCount == 0) { + nonCallbackService = componentService; + } + nonCallbackServiceCount++; + } + } + if (nonCallbackServiceCount == 1) { + // If we have a single non callback service, index it by + // component name as well + componentServices.put(component.getName(), nonCallbackService); + } + } + } + + /** + * Index components, services and references inside a composite. + * @param composite + * @param components + * @param componentServices + * @param componentReferences + */ + protected void indexComponentsServicesAndReferences(Composite composite, + Map<String, Component> components, + Map<String, ComponentService> componentServices, + Map<String, ComponentReference> componentReferences) { + + for (Component component : composite.getComponents()) { + + // Index components by name + components.put(component.getName(), component); + + ComponentService nonCallbackService = null; + int nonCallbackServices = 0; + for (ComponentService componentService : component.getServices()) { + + // Index component services by component name / service name + String uri = component.getName() + '/' + componentService.getName(); + componentServices.put(uri, componentService); + + // TODO - EPR - $promoted$ no longer used but it doesn't do any harm here + boolean promotedService = false; + if (componentService.getName() != null && componentService.getName().indexOf("$promoted$") > -1) { + promotedService = true; + } + + // count how many non-callback, non-promoted services there are + // if there is only one the component name also acts as the service name + if ((!componentService.isForCallback()) && (!promotedService)) { + + // Check how many non callback non-promoted services we have + if (nonCallbackServices == 0) { + nonCallbackService = componentService; + } + nonCallbackServices++; + } + + } + + if (nonCallbackServices == 1) { + // If we have a single non callback service, index it by + // component name as well + componentServices.put(component.getName(), nonCallbackService); + } + + // Index references by component name / reference name + for (ComponentReference componentReference : component.getReferences()) { + String uri = component.getName() + '/' + componentReference.getName(); + componentReferences.put(uri, componentReference); + } + } + } + + protected void indexComponentPropertiesServicesAndReferences(Component component, + Map<String, ComponentService> componentServices, + Map<String, ComponentReference> componentReferences, + Map<String, ComponentProperty> componentProperties, + Monitor monitor) { + for (ComponentService componentService : component.getServices()) { + if (componentServices.containsKey(componentService.getName())) { + // [MJE 13/05/2009] Changed to "error" since allowing these violates the OASIS spec + error(monitor, "DuplicateComponentServiceName", component, component.getName(), componentService + .getName()); + } else { + componentServices.put(componentService.getName(), componentService); + } + } + for (ComponentReference componentReference : component.getReferences()) { + if (componentReferences.containsKey(componentReference.getName())) { + // [MJE 13/05/2009] Changed to "error" since allowing these violates the OASIS spec + error(monitor, "DuplicateComponentReferenceName", component, component.getName(), componentReference + .getName()); + } else { + componentReferences.put(componentReference.getName(), componentReference); + } + } + for (ComponentProperty componentProperty : component.getProperties()) { + if (componentProperties.containsKey(componentProperty.getName())) { + // [MJE 13/05/2009] Changed to "error" since allowing these violates the OASIS spec + error(monitor, "DuplicateComponentPropertyName", component, component.getName(), componentProperty + .getName()); + } else { + componentProperties.put(componentProperty.getName(), componentProperty); + } + } + + } + + protected void indexImplementationPropertiesServicesAndReferences(Component component, + Map<String, Service> services, + Map<String, Reference> references, + Map<String, Property> properties, + Monitor monitor) { + // First check that the component has a resolved implementation + Implementation implementation = component.getImplementation(); + if (implementation == null) { + // A component must have an implementation + error(monitor, "NoComponentImplementation", component, component.getName()); + + } else if (implementation.isUnresolved()) { + + // The implementation must be fully resolved + error(monitor, "UnresolvedComponentImplementation", component, component.getName(), implementation.getURI()); + + } else { + + // Index properties, services and references, also check for + // duplicates + for (Property property : implementation.getProperties()) { + if (properties.containsKey(property.getName())) { + // [MJE 13/05/2009] Changed to "error" since allowing these violates the OASIS spec + error(monitor, "DuplicateImplementationPropertyName", component, component.getName(), property + .getName()); + } else { + properties.put(property.getName(), property); + } + } + for (Service service : implementation.getServices()) { + if (services.containsKey(service.getName())) { + // [MJE 13/05/2009] Changed to "error" since allowing these violates the OASIS spec + error(monitor, "DuplicateImplementationServiceName", component, component.getName(), service + .getName()); + } else { + services.put(service.getName(), service); + } + } + for (Reference reference : implementation.getReferences()) { + if (references.containsKey(reference.getName())) { + // [MJE 13/05/2009] Changed to "error" since allowing these violates the OASIS spec + error(monitor, "DuplicateImplementationReferenceName", component, component.getName(), reference + .getName()); + } else { + references.put(reference.getName(), reference); + } + } + } + + } + + /** + * Reconcile component properties and the properties defined by the + * component type. + * + * @param component + * @param properties + * @param componentProperties + * @param problems + */ + protected void reconcileProperties(Component component, + Map<String, Property> properties, + Map<String, ComponentProperty> componentProperties, + Monitor monitor) { + + // Connect component properties to their properties + for (ComponentProperty componentProperty : component.getProperties()) { + Property property = properties.get(componentProperty.getName()); + if (property != null) { + componentProperty.setProperty(property); + } else { + error(monitor, "PropertyNotFound", component, component.getName(), componentProperty.getName()); + } + } + + // Create component properties for all properties + if (component.getImplementation() != null) { + for (Property property : component.getImplementation().getProperties()) { + if (!componentProperties.containsKey(property.getName())) { + ComponentProperty 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); + } + } + } + + // Reconcile component properties and their properties + for (ComponentProperty componentProperty : component.getProperties()) { + Property property = componentProperty.getProperty(); + if (property != null) { + + // Check that a component property does not override the + // mustSupply attribute + if (!property.isMustSupply() && componentProperty.isMustSupply()) { + warning(monitor, + "PropertyMustSupplyIncompatible", + component, + component.getName(), + componentProperty.getName()); + } + + // Default to the mustSupply attribute specified on the property + if (!componentProperty.isMustSupply()) + componentProperty.setMustSupply(property.isMustSupply()); + + // Default to the value specified on the component type property + if (!isPropertyValueSet(componentProperty)) { + componentProperty.setValue(property.getValue()); + } + + // Override the property value for the composite + if (component.getImplementation() instanceof Composite) { + property.setValue(componentProperty.getValue()); + } + + // Check that a value is supplied + if (!isPropertyValueSet(componentProperty) && property.isMustSupply()) { + error(monitor, "PropertyMustSupplyNull", component, component.getName(), componentProperty.getName()); + } + + // Check that a component property does not override the + // many attribute + if (!property.isMany() && componentProperty.isMany()) { + warning(monitor, "PropertyOverrideManyAttribute", component, component.getName(), componentProperty.getName()); + } + + // Default to the many attribute defined on the property + componentProperty.setMany(property.isMany()); + + // Default to the type and element defined on the property + if (componentProperty.getXSDType() == null) { + componentProperty.setXSDType(property.getXSDType()); + } + if (componentProperty.getXSDElement() == null) { + componentProperty.setXSDElement(property.getXSDElement()); + } + + // Check that a type or element are specified + if (componentProperty.getXSDElement() == null && componentProperty.getXSDType() == null) { + warning(monitor, "NoTypeForComponentProperty", component, component.getName(), componentProperty.getName()); + } + } + } + } + + /** + * 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.getFirstChild() == null) { + return false; + } + + if (value.getFirstChild().getChildNodes().getLength() == 0) { + return false; + } + + return true; + } + + /** + * Reconcile component references with the references defined on the + * component type. + * + * @param component + * @param references + * @param componentReferences + * @param monitor + */ + protected void reconcileReferences(Component component, + Map<String, Reference> references, + Map<String, ComponentReference> componentReferences, + Monitor monitor) { + + // Connect each component reference to the corresponding reference + for (ComponentReference componentReference : component.getReferences()) { + if (componentReference.getReference() != null || componentReference.isForCallback()) { + continue; + } + Reference reference = references.get(componentReference.getName()); + if (reference != null) { + componentReference.setReference(reference); + } else { + if (!componentReference.getName().startsWith("$self$.")) { + error(monitor, "ReferenceNotFound", component, component.getName(), componentReference.getName()); + } + } + } + + // Create a Component reference for each reference for which there is no declared Component reference + if (component.getImplementation() != null) { + for (Reference reference : component.getImplementation().getReferences()) { + if (!componentReferences.containsKey(reference.getName())) { + ComponentReference componentReference = assemblyFactory.createComponentReference(); + componentReference.setForCallback(reference.isForCallback()); + componentReference.setName(reference.getName()); + componentReference.setReference(reference); + component.getReferences().add(componentReference); + } + } + } + + // Reconcile each component reference with its reference + for (ComponentReference componentReference : component.getReferences()) { + Reference reference = componentReference.getReference(); + if (reference != null) { + // Reconcile multiplicity + if (componentReference.getMultiplicity() != null) { + if (!ReferenceConfigurationUtil.isValidMultiplicityOverride(reference.getMultiplicity(), + componentReference.getMultiplicity())) { + error(monitor, + "ReferenceIncompatibleMultiplicity", + component, + component.getName(), + componentReference.getName()); + } + } else { + componentReference.setMultiplicity(reference.getMultiplicity()); + } + + // Reconcile interface + InterfaceContract interfaceContract = reference.getInterfaceContract(); + if (componentReference.getInterfaceContract() != null) { + if (interfaceContract != null && !componentReference.getInterfaceContract().equals(reference + .getInterfaceContract())) { + if (!interfaceContractMapper.isCompatible(interfaceContract, componentReference + .getInterfaceContract())) { + error(monitor, + "ReferenceIncompatibleComponentInterface", + component, + component.getName(), + componentReference.getName()); + } + } + } else { + componentReference.setInterfaceContract(interfaceContract); + } + + // Reconcile bindings + if (componentReference.getBindings().isEmpty()) { + componentReference.getBindings().addAll(reference.getBindings()); + } + + // Reconcile callback bindings + if (componentReference.getCallback() == null) { + componentReference.setCallback(reference.getCallback()); + if (componentReference.getCallback() == null) { + // Create an empty callback to avoid null check + componentReference.setCallback(assemblyFactory.createCallback()); + } + + } else if (componentReference.getCallback().getBindings().isEmpty() && reference.getCallback() != null) { + componentReference.getCallback().getBindings().addAll(reference.getCallback().getBindings()); + } + + // Propagate autowire setting from the component + if (componentReference.getAutowire() == null) { + componentReference.setAutowire(component.getAutowire()); + } + + // Reconcile targets + if (componentReference.getTargets().isEmpty()) { + componentReference.getTargets().addAll(reference.getTargets()); + } + } + } + } + + /** + * Reconcile component services and services defined on the component type. + * + * @param component + * @param services + * @param componentServices + * @param monitor + */ + protected void reconcileServices(Component component, + Map<String, Service> services, + Map<String, ComponentService> componentServices, + Monitor monitor) { + + // Connect each component service to the corresponding service + for (ComponentService componentService : component.getServices()) { + if (componentService.getService() != null || componentService.isForCallback()) { + continue; + } + Service service = services.get(componentService.getName()); + if (service != null) { + componentService.setService(service); + } else { + warning(monitor, "ServiceNotFoundForComponentService", component, component.getName(), componentService + .getName()); + } + } + + // Create a component service for each service + if (component.getImplementation() != null) { + for (Service service : component.getImplementation().getServices()) { + if (!componentServices.containsKey(service.getName())) { + ComponentService componentService = assemblyFactory.createComponentService(); + componentService.setForCallback(service.isForCallback()); + String name = service.getName(); + componentService.setName(name); + componentService.setService(service); + component.getServices().add(componentService); + componentServices.put(name, componentService); + } + } + } + + //Reconcile each component service with its service + for (ComponentService componentService : component.getServices()) { + Service service = componentService.getService(); + if (service != null) { + // Reconcile interface + InterfaceContract interfaceContract = service.getInterfaceContract(); + if (componentService.getInterfaceContract() != null) { + if (interfaceContract != null && !componentService.getInterfaceContract().equals(interfaceContract)) { + if (!interfaceContractMapper.isCompatible(componentService.getInterfaceContract(), + interfaceContract)) { + // MJE, 16/05/2009 - Upgraded from "warning" to "error" since this is a fatal problem - TUSCANY-3036 + error(monitor, + "ServiceIncompatibleComponentInterface", + component, + component.getName(), + componentService.getName()); + } + } + } else { + componentService.setInterfaceContract(interfaceContract); + } + + // Reconcile bindings + if (componentService.getBindings().isEmpty()) { + componentService.getBindings().addAll(service.getBindings()); + } + + // Reconcile callback bindings + if (componentService.getCallback() == null) { + componentService.setCallback(service.getCallback()); + if (componentService.getCallback() == null) { + // Create an empty callback to avoid null check + componentService.setCallback(assemblyFactory.createCallback()); + } + } else if (componentService.getCallback().getBindings().isEmpty() && service.getCallback() != null) { + componentService.getCallback().getBindings().addAll(service.getCallback().getBindings()); + } + } + } + } + + protected void attachSCABinding(Contract contract, Definitions definitions) { + if (!contract.getBindings().isEmpty()) { + contract.setOverridingBindings(true); + // No need to set binding.sca + return; + } + contract.setOverridingBindings(false); + + // Only add binding.sca for services + // FIXME: The latest OASIS spec only adds binding.sca to services + /* + if (!(contract instanceof Service)) { + return; + } + */ + 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); + } +} |