diff options
Diffstat (limited to '')
-rw-r--r-- | sca-java-2.x/branches/2.0-Beta1/modules/assembly-xml/src/main/java/org/apache/tuscany/sca/assembly/xml/CompositeProcessor.java | 1259 |
1 files changed, 1259 insertions, 0 deletions
diff --git a/sca-java-2.x/branches/2.0-Beta1/modules/assembly-xml/src/main/java/org/apache/tuscany/sca/assembly/xml/CompositeProcessor.java b/sca-java-2.x/branches/2.0-Beta1/modules/assembly-xml/src/main/java/org/apache/tuscany/sca/assembly/xml/CompositeProcessor.java new file mode 100644 index 0000000000..eecb07e6cd --- /dev/null +++ b/sca-java-2.x/branches/2.0-Beta1/modules/assembly-xml/src/main/java/org/apache/tuscany/sca/assembly/xml/CompositeProcessor.java @@ -0,0 +1,1259 @@ +/* + * 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.assembly.xml; + +import static javax.xml.stream.XMLStreamConstants.END_ELEMENT; +import static javax.xml.stream.XMLStreamConstants.START_ELEMENT; +import static org.apache.tuscany.sca.assembly.xml.Constants.AUTOWIRE; +import static org.apache.tuscany.sca.assembly.xml.Constants.CALLBACK; +import static org.apache.tuscany.sca.assembly.xml.Constants.CALLBACK_QNAME; +import static org.apache.tuscany.sca.assembly.xml.Constants.COMPONENT; +import static org.apache.tuscany.sca.assembly.xml.Constants.COMPONENT_QNAME; +import static org.apache.tuscany.sca.assembly.xml.Constants.COMPOSITE; +import static org.apache.tuscany.sca.assembly.xml.Constants.COMPOSITE_QNAME; +import static org.apache.tuscany.sca.assembly.xml.Constants.ELEMENT; +import static org.apache.tuscany.sca.assembly.xml.Constants.EXTENSION_QNAME; +import static org.apache.tuscany.sca.assembly.xml.Constants.FILE; +import static org.apache.tuscany.sca.assembly.xml.Constants.IMPLEMENTATION_COMPOSITE; +import static org.apache.tuscany.sca.assembly.xml.Constants.IMPLEMENTATION_COMPOSITE_QNAME; +import static org.apache.tuscany.sca.assembly.xml.Constants.INCLUDE; +import static org.apache.tuscany.sca.assembly.xml.Constants.INCLUDE_QNAME; +import static org.apache.tuscany.sca.assembly.xml.Constants.INTENTS; +import static org.apache.tuscany.sca.assembly.xml.Constants.LOCAL; +import static org.apache.tuscany.sca.assembly.xml.Constants.MANY; +import static org.apache.tuscany.sca.assembly.xml.Constants.MUST_SUPPLY; +import static org.apache.tuscany.sca.assembly.xml.Constants.NAME; +import static org.apache.tuscany.sca.assembly.xml.Constants.NONOVERRIDABLE; +import static org.apache.tuscany.sca.assembly.xml.Constants.POLICY_SET_ATTACHMENT_QNAME; +import static org.apache.tuscany.sca.assembly.xml.Constants.PROMOTE; +import static org.apache.tuscany.sca.assembly.xml.Constants.PROPERTY; +import static org.apache.tuscany.sca.assembly.xml.Constants.PROPERTY_QNAME; +import static org.apache.tuscany.sca.assembly.xml.Constants.REFERENCE; +import static org.apache.tuscany.sca.assembly.xml.Constants.REFERENCE_QNAME; +import static org.apache.tuscany.sca.assembly.xml.Constants.REPLACE; +import static org.apache.tuscany.sca.assembly.xml.Constants.REQUIRES_QNAME; +import static org.apache.tuscany.sca.assembly.xml.Constants.SCA11_NS; +import static org.apache.tuscany.sca.assembly.xml.Constants.SERVICE; +import static org.apache.tuscany.sca.assembly.xml.Constants.SERVICE_QNAME; +import static org.apache.tuscany.sca.assembly.xml.Constants.SOURCE; +import static org.apache.tuscany.sca.assembly.xml.Constants.TARGET; +import static org.apache.tuscany.sca.assembly.xml.Constants.TARGET_NAMESPACE; +import static org.apache.tuscany.sca.assembly.xml.Constants.TYPE; +import static org.apache.tuscany.sca.assembly.xml.Constants.URI; +import static org.apache.tuscany.sca.assembly.xml.Constants.WIRE; +import static org.apache.tuscany.sca.assembly.xml.Constants.WIRED_BY_IMPL; +import static org.apache.tuscany.sca.assembly.xml.Constants.WIRE_QNAME; + +import java.util.ArrayList; +import java.util.List; +import java.util.StringTokenizer; + +import javax.xml.namespace.QName; +import javax.xml.stream.XMLInputFactory; +import javax.xml.stream.XMLStreamConstants; +import javax.xml.stream.XMLStreamException; +import javax.xml.stream.XMLStreamReader; +import javax.xml.stream.XMLStreamWriter; +import javax.xml.transform.dom.DOMSource; +import javax.xml.xpath.XPathExpressionException; + +import org.apache.tuscany.sca.assembly.Binding; +import org.apache.tuscany.sca.assembly.Callback; +import org.apache.tuscany.sca.assembly.Component; +import org.apache.tuscany.sca.assembly.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.Property; +import org.apache.tuscany.sca.assembly.Reference; +import org.apache.tuscany.sca.assembly.Service; +import org.apache.tuscany.sca.assembly.Wire; +import org.apache.tuscany.sca.common.xml.stax.StAXHelper; +import org.apache.tuscany.sca.common.xml.xpath.XPathHelper; +import org.apache.tuscany.sca.contribution.Artifact; +import org.apache.tuscany.sca.contribution.Contribution; +import org.apache.tuscany.sca.contribution.ContributionFactory; +import org.apache.tuscany.sca.contribution.processor.ContributionReadException; +import org.apache.tuscany.sca.contribution.processor.ContributionResolveException; +import org.apache.tuscany.sca.contribution.processor.ContributionWriteException; +import org.apache.tuscany.sca.contribution.processor.ProcessorContext; +import org.apache.tuscany.sca.contribution.processor.StAXArtifactProcessor; +import org.apache.tuscany.sca.contribution.processor.StAXAttributeProcessor; +import org.apache.tuscany.sca.contribution.resolver.ModelResolver; +import org.apache.tuscany.sca.contribution.resolver.ResolverExtension; +import org.apache.tuscany.sca.core.ExtensionPointRegistry; +import org.apache.tuscany.sca.core.FactoryExtensionPoint; +import org.apache.tuscany.sca.interfacedef.InterfaceContract; +import org.apache.tuscany.sca.monitor.Monitor; +import org.apache.tuscany.sca.policy.ExtensionType; +import org.apache.tuscany.sca.policy.Intent; +import org.apache.tuscany.sca.policy.PolicyFactory; +import org.apache.tuscany.sca.policy.PolicySet; +import org.apache.tuscany.sca.policy.PolicySubject; +import org.apache.tuscany.sca.xsd.XSDFactory; +import org.apache.tuscany.sca.xsd.XSDefinition; +import org.w3c.dom.Document; +import org.w3c.dom.Node; +import org.w3c.dom.NodeList; + +/** + * A composite processor. + * + * @version $Rev$ $Date$ + */ +public class CompositeProcessor extends BaseAssemblyProcessor implements StAXArtifactProcessor<Composite> { + private XPathHelper xpathHelper; + private PolicyFactory intentAttachPointTypeFactory; + private StAXAttributeProcessor<Object> extensionAttributeProcessor; + private ContributionFactory contributionFactory; + private XSDFactory xsdFactory; + + private StAXHelper staxHelper; + + /** + * Construct a new composite processor + * + * @param extensionPoints + * @param extensionProcessor + */ + public CompositeProcessor(ExtensionPointRegistry extensionPoints, + StAXArtifactProcessor extensionProcessor, + StAXAttributeProcessor extensionAttributeProcessor) { + + this(modelFactories(extensionPoints), extensionProcessor, extensionAttributeProcessor); + + this.xpathHelper = XPathHelper.getInstance(extensionPoints); + this.extensionAttributeProcessor = extensionAttributeProcessor; + + this.xsdFactory = extensionPoints.getExtensionPoint(XSDFactory.class); + + // + staxHelper = StAXHelper.getInstance(extensionPoints); + } + + /** + * Constructs a new composite processor + * + * @param modelFactories + * @param extensionProcessor + * @param monitor + */ + private CompositeProcessor(FactoryExtensionPoint modelFactories, + StAXArtifactProcessor extensionProcessor, + StAXAttributeProcessor extensionAttributeProcessor) { + + super(modelFactories, extensionProcessor); + this.intentAttachPointTypeFactory = modelFactories.getFactory(PolicyFactory.class); + this.contributionFactory = modelFactories.getFactory(ContributionFactory.class); + this.extensionAttributeProcessor = extensionAttributeProcessor; + + this.xsdFactory = modelFactories.getFactory(XSDFactory.class); + } + + public Composite read(XMLStreamReader reader, ProcessorContext context) throws ContributionReadException { + Composite composite = null; + Composite include = null; + Component component = null; + Property property = null; + ComponentService componentService = null; + ComponentReference componentReference = null; + ComponentProperty componentProperty = null; + CompositeService compositeService = null; + CompositeReference compositeReference = null; + Contract contract = null; + Wire wire = null; + Callback callback = null; + QName name = null; + Monitor monitor = context.getMonitor(); + try { + // Read the composite document + while (reader.hasNext()) { + int event = reader.getEventType(); + switch (event) { + case START_ELEMENT: + name = reader.getName(); + + if (COMPOSITE_QNAME.equals(name)) { + + // Read a <composite> + composite = assemblyFactory.createComposite(); + composite.setSpecVersion(Constants.SCA11_NS); + + composite.setName(new QName(getURIString(reader, TARGET_NAMESPACE), getString(reader, NAME))); + + if (!isSet(reader, TARGET_NAMESPACE)) { + // spec says that a composite must have a namespace + warning(monitor, "NoCompositeNamespace", composite, composite.getName().toString()); + } + + if (isSet(reader, AUTOWIRE)) { + composite.setAutowire(getBoolean(reader, AUTOWIRE)); + } + + //handle extension attributes + this.readExtendedAttributes(reader, name, composite, extensionAttributeProcessor, context); + + composite.setLocal(getBoolean(reader, LOCAL)); + policyProcessor.readPolicies(composite, reader); + + } else if (INCLUDE_QNAME.equals(name)) { + + // Read an <include> + include = assemblyFactory.createComposite(); + include.setName(getQName(reader, NAME)); + include.setURI(getURIString(reader, URI)); + include.setUnresolved(true); + composite.getIncludes().add(include); + + } else if (SERVICE_QNAME.equals(name)) { + if (component != null) { + + // Read a <component><service> + componentService = assemblyFactory.createComponentService(); + contract = componentService; + componentService.setName(getString(reader, NAME)); + + //handle extension attributes + this.readExtendedAttributes(reader, name, componentService, extensionAttributeProcessor, context); + + component.getServices().add(componentService); + policyProcessor.readPolicies(contract, reader); + } else { + + // Read a <composite><service> + compositeService = assemblyFactory.createCompositeService(); + contract = compositeService; + compositeService.setName(getString(reader, NAME)); + + String promoted = getURIString(reader, PROMOTE); + if (promoted != null) { + String promotedComponentName; + String promotedServiceName; + int s = promoted.indexOf('/'); + if (s == -1) { + promotedComponentName = promoted; + promotedServiceName = null; + } else { + promotedComponentName = promoted.substring(0, s); + promotedServiceName = promoted.substring(s + 1); + } + + Component promotedComponent = assemblyFactory.createComponent(); + promotedComponent.setUnresolved(true); + promotedComponent.setName(promotedComponentName); + compositeService.setPromotedComponent(promotedComponent); + + ComponentService promotedService = assemblyFactory.createComponentService(); + promotedService.setUnresolved(true); + promotedService.setName(promotedServiceName); + compositeService.setPromotedService(promotedService); + } + + //handle extension attributes + this.readExtendedAttributes(reader, name, compositeService, extensionAttributeProcessor, context); + + composite.getServices().add(compositeService); + policyProcessor.readPolicies(contract, reader); + } + + // set the parent model so that binding processing can + // detect it they're being read as part of a reference + // or a service + context.setParentModel(contract); + + } else if (REFERENCE_QNAME.equals(name)) { + if (component != null) { + // Read a <component><reference> + componentReference = assemblyFactory.createComponentReference(); + contract = componentReference; + componentReference.setName(getString(reader, NAME)); + readMultiplicity(componentReference, reader); + if (isSet(reader, AUTOWIRE)) { + componentReference.setAutowire(getBoolean(reader, AUTOWIRE)); + } + // Read @nonOverridable + String nonOverridable = reader.getAttributeValue(null, NONOVERRIDABLE); + if (nonOverridable != null) { + componentReference.setNonOverridable(Boolean.parseBoolean(nonOverridable)); + } + readTargets(componentReference, reader); + componentReference.setWiredByImpl(getBoolean(reader, WIRED_BY_IMPL)); + + //handle extension attributes + this.readExtendedAttributes(reader, + name, + componentReference, + extensionAttributeProcessor, context); + + component.getReferences().add(componentReference); + policyProcessor.readPolicies(contract, reader); + } else { + // Read a <composite><reference> + compositeReference = assemblyFactory.createCompositeReference(); + contract = compositeReference; + compositeReference.setName(getString(reader, NAME)); + readMultiplicity(compositeReference, reader); + readTargets(compositeReference, reader); + String promote = getString(reader, Constants.PROMOTE); + if (promote != null) { + for (StringTokenizer tokens = new StringTokenizer(promote); tokens.hasMoreTokens();) { + String refName = tokens.nextToken(); + Component promotedComponent = assemblyFactory.createComponent(); + int index = refName.indexOf('/'); + if (index == -1) { + error(monitor, "Invalid reference name", compositeReference, refName); + } + String promotedComponentName = refName.substring(0, index); + promotedComponent.setName(promotedComponentName); + promotedComponent.setUnresolved(true); + compositeReference.getPromotedComponents().add(promotedComponent); + ComponentReference promotedReference = + assemblyFactory.createComponentReference(); + promotedReference.setUnresolved(true); + promotedReference.setName(refName); + compositeReference.getPromotedReferences().add(promotedReference); + } + } + compositeReference.setWiredByImpl(getBoolean(reader, WIRED_BY_IMPL)); + + //handle extension attributes + this.readExtendedAttributes(reader, + name, + compositeReference, + extensionAttributeProcessor, context); + + composite.getReferences().add(compositeReference); + policyProcessor.readPolicies(contract, reader); + } + + // set the parent model so that binding processing can + // detect it they're being read as part of a reference + // or a service + context.setParentModel(contract); + + } else if (PROPERTY_QNAME.equals(name)) { + if (component != null) { + + // Read a <component><property> + componentProperty = assemblyFactory.createComponentProperty(); + property = componentProperty; + String source = getURIString(reader, SOURCE); + if (source != null) { + source = source.trim(); + } + componentProperty.setSource(source); + if (source != null) { + String xPath = prepareSourceXPathString( source ); + + try { + componentProperty.setSourceXPathExpression(xpathHelper.compile(reader + .getNamespaceContext(), xPath)); + } catch (XPathExpressionException e) { + ContributionReadException ce = new ContributionReadException(e); + error(monitor, "ContributionReadException", source, ce); + //throw ce; + } + } + componentProperty.setFile(getURIString(reader, FILE)); + + //handle extension attributes + this.readExtendedAttributes(reader, + name, + componentProperty, + extensionAttributeProcessor, context); + + policyProcessor.readPolicies(property, reader); + readAbstractProperty(componentProperty, reader, context); + + // Read the property value + Document value = + readPropertyValue(property.getXSDElement(), property.getXSDType(), property + .isMany(), reader, context); + property.setValue(value); + + component.getProperties().add(componentProperty); + } else { + + // Read a <composite><property> + property = assemblyFactory.createProperty(); + policyProcessor.readPolicies(property, reader); + readAbstractProperty(property, reader, context); + + // Read the property value + Document value = + readPropertyValue(property.getXSDElement(), property.getXSDType(), property + .isMany(), reader, context); + property.setValue(value); + + composite.getProperties().add(property); + } + + // TUSCANY-1949 + // If the property doesn't have a value, the END_ELEMENT event is read by the readPropertyValue + if (reader.getEventType() == END_ELEMENT && PROPERTY_QNAME.equals(reader.getName())) { + property = null; + componentProperty = null; + } + + } else if (COMPONENT_QNAME.equals(name)) { + + // Read a <component> + component = assemblyFactory.createComponent(); + component.setName(getString(reader, NAME)); + if (isSet(reader, AUTOWIRE)) { + component.setAutowire(getBoolean(reader, AUTOWIRE)); + } + if (isSet(reader, URI)) { + component.setURI(getURIString(reader, URI)); + } + + //handle extension attributes + this.readExtendedAttributes(reader, name, component, extensionAttributeProcessor, context); + + composite.getComponents().add(component); + policyProcessor.readPolicies(component, reader); + + } else if (WIRE_QNAME.equals(name)) { + + // Read a <wire> + wire = assemblyFactory.createWire(); + ComponentReference source = assemblyFactory.createComponentReference(); + source.setUnresolved(true); + source.setName(getURIString(reader, SOURCE)); + wire.setSource(source); + + ComponentService target = assemblyFactory.createComponentService(); + target.setUnresolved(true); + target.setName(getURIString(reader, TARGET)); + wire.setTarget(target); + + // Read @replace + String replace = reader.getAttributeValue(null, REPLACE); + if (replace != null) { + wire.setReplace(Boolean.parseBoolean(replace)); + } + + //handle extension attributes + this.readExtendedAttributes(reader, name, wire, extensionAttributeProcessor, context); + + composite.getWires().add(wire); + policyProcessor.readPolicies(wire, reader); + + } else if (CALLBACK_QNAME.equals(name)) { + + // Read a <callback> + callback = assemblyFactory.createCallback(); + contract.setCallback(callback); + callback.setParentContract(contract); + + //handle extension attributes + this.readExtendedAttributes(reader, name, callback, extensionAttributeProcessor, context); + + policyProcessor.readPolicies(callback, reader); + + // set the parent model so that binding processing can + // detect it they're being read as part of a callback + context.setParentModel(callback); + + } else if (IMPLEMENTATION_COMPOSITE_QNAME.equals(name)) { + + // Read an implementation.composite + Composite implementation = assemblyFactory.createComposite(); + implementation.setName(getQName(reader, NAME)); + implementation.setUnresolved(true); + + //handle extension attributes + this.readExtendedAttributes(reader, name, implementation, extensionAttributeProcessor, context); + + component.setImplementation(implementation); + policyProcessor.readPolicies(implementation, reader); + } else if (REQUIRES_QNAME.equals(name)) { + List<QName> intents = getQNames(reader, INTENTS); + for (QName i : intents) { + Intent intent = policyFactory.createIntent(); + intent.setName(i); + if (composite != null) { + composite.getRequiredIntents().add(intent); + } else if (component != null) { + component.getRequiredIntents().add(intent); + } else if (contract != null) { + contract.getRequiredIntents().add(intent); + } else if (callback != null) { + callback.getRequiredIntents().add(intent); + } + } + } else if (POLICY_SET_ATTACHMENT_QNAME.equals(name)) { + QName ps = getQName(reader, NAME); + if (ps != null) { + PolicySet policySet = policyFactory.createPolicySet(); + policySet.setName(ps); + if (composite != null) { + composite.getPolicySets().add(policySet); + } else if (component != null) { + component.getPolicySets().add(policySet); + } else if (contract != null) { + contract.getPolicySets().add(policySet); + } else if (callback != null) { + callback.getPolicySets().add(policySet); + } + } + } else if(EXTENSION_QNAME.equals(name)) { + // Handle <extension> + //ignore element as this is a wrapper for extensibility + break; + } else { + + // Read an extension element + Object extension = extensionProcessor.read(reader, context); + if (extension != null) { + if (extension instanceof InterfaceContract) { + + // <service><interface> and + // <reference><interface> + if (contract != null) { + contract.setInterfaceContract((InterfaceContract)extension); + } else { + if (name.getNamespaceURI().equals(SCA11_NS)) { + error(monitor, "UnexpectedInterfaceElement", extension); + //throw new ContributionReadException("Unexpected <interface> element found. It should appear inside a <service> or <reference> element"); + } else { + composite.getExtensions().add(extension); + } + } + } else if (extension instanceof Binding) { + if (extension instanceof PolicySubject) { + ExtensionType bindingType = intentAttachPointTypeFactory.createBindingType(); + bindingType.setType(name); + bindingType.setUnresolved(true); + ((PolicySubject)extension).setExtensionType(bindingType); + } + // <service><binding> and + // <reference><binding> + if (callback != null) { + callback.getBindings().add((Binding)extension); + } else { + if (contract != null) { + contract.getBindings().add((Binding)extension); + } else { + if (name.getNamespaceURI().equals(SCA11_NS)) { + error(monitor, "UnexpectedBindingElement", extension); + //throw new ContributionReadException("Unexpected <binding> element found. It should appear inside a <service> or <reference> element"); + } else { + composite.getExtensions().add(extension); + } + } + } + + } else if (extension instanceof Implementation) { + if (extension instanceof PolicySubject) { + ExtensionType implType = + intentAttachPointTypeFactory.createImplementationType(); + implType.setType(name); + implType.setUnresolved(true); + ((PolicySubject)extension).setExtensionType(implType); + } + // <component><implementation> + if (component != null) { + component.setImplementation((Implementation)extension); + } else { + if (name.getNamespaceURI().equals(SCA11_NS)) { + error(monitor, "UnexpectedImplementationElement", extension); + //throw new ContributionReadException("Unexpected <implementation> element found. It should appear inside a <component> element"); + } else { + composite.getExtensions().add(extension); + } + } + } else { + + // Add the extension element to the current + // element + if (callback != null) { + callback.getExtensions().add(extension); + } else if (contract != null) { + contract.getExtensions().add(extension); + } else if (property != null) { + property.getExtensions().add(extension); + } else if (component != null) { + component.getExtensions().add(extension); + } else { + composite.getExtensions().add(extension); + } + } + } + } + break; + + case XMLStreamConstants.CHARACTERS: + break; + + case END_ELEMENT: + name = reader.getName(); + + // Clear current state when reading reaching end element + if (SERVICE_QNAME.equals(name)) { + componentService = null; + compositeService = null; + contract = null; + } else if (INCLUDE_QNAME.equals(name)) { + include = null; + } else if (REFERENCE_QNAME.equals(name)) { + componentReference = null; + compositeReference = null; + contract = null; + } else if (PROPERTY_QNAME.equals(name)) { + componentProperty = null; + property = null; + } else if (COMPONENT_QNAME.equals(name)) { + component = null; + } else if (WIRE_QNAME.equals(name)) { + wire = null; + } else if (CALLBACK_QNAME.equals(name)) { + callback = null; + } + break; + } + + // Read the next element + if (reader.hasNext()) { + reader.next(); + } + } + } catch (XMLStreamException e) { + ContributionReadException ex = new ContributionReadException(e); + error(monitor, "XMLStreamException", reader, ex); + } + + return composite; + } + + /** + * Prepares the property @source XPath expression + * + * The form of the @source attribute in the composite file must take one of the forms + * $propertyName + * $propertyName/expression + * $propertyName[n] + * $propertyName[n]/expression + * Property values are stored as <sca:property> elements with one or more <sca:value> subelements or one or more + * global element subelements. The XPath constructed is designed to work against this XML structure and aims to + * retrieve one or more of the subelements or subportions of those subelements (eg some text content). + * Thus the XPath: + * - starts with "*", which means "all the child elements of the root" where root = the <property/> element + * - may then be followed by [xxx] (typically [n] to select one of the child elements) if the source string has [xxx] + * following the propertyName + * - may then be followed by /expression, if the source contains an expression, which will typically select some subportion + * of the child element(s) + * + * @param source - the @source attribute string from a <sca:property> element + * @return the XPath string to use for the source property + */ + private String prepareSourceXPathString( String source ) { + String output = null; + // Expression must begin with '$' + if( source.charAt(0) != '$' ) return output; + + int slash = source.indexOf('/'); + int bracket = source.indexOf('['); + if (slash == -1) { + // Form is $propertyName or $propertyName[n] + output = "*"; + if( bracket != -1 ) { + output = "*" + source.substring(bracket); + } + } else { + // Form is $propertyName/exp or $propertyName[n]/exp + output = "*/" + source.substring(slash + 1); + if( bracket != -1 && bracket < slash ) { + output = "*" + source.substring(bracket); + } + } // end if + + return output; + } // end method prepareSourceXPathString( source ) + + public void write(Composite composite, XMLStreamWriter writer, ProcessorContext context) throws ContributionWriteException, + XMLStreamException { + + // Write <composite> element + writeStartDocument(writer, + COMPOSITE, + new XAttr(TARGET_NAMESPACE, composite.getName().getNamespaceURI()), + new XAttr(NAME, composite.getName().getLocalPart()), + new XAttr(LOCAL, composite.isLocal() ? Boolean.TRUE : null), + new XAttr(AUTOWIRE, composite.getAutowire()), + policyProcessor.writePolicies(composite)); + + //write extended attributes + this.writeExtendedAttributes(writer, composite, extensionAttributeProcessor, context); + + // Write <include> elements + for (Composite include : composite.getIncludes()) { + String uri = include.isUnresolved() ? include.getURI() : null; + writeStart(writer, INCLUDE, new XAttr(NAME, include.getName()), new XAttr(URI, uri)); + + //write extended attributes + this.writeExtendedAttributes(writer, include, extensionAttributeProcessor, context); + + writeEnd(writer); + } + + // Write <service> elements + for (Service service : composite.getServices()) { + CompositeService compositeService = (CompositeService)service; + Component promotedComponent = compositeService.getPromotedComponent(); + ComponentService promotedService = compositeService.getPromotedService(); + String promote; + if (promotedService != null) { + if (promotedService.getName() != null) { + promote = promotedComponent.getName() + '/' + promotedService.getName(); + } else { + promote = promotedComponent.getName(); + } + } else { + promote = null; + } + writeStart(writer, + SERVICE, + new XAttr(NAME, service.getName()), + new XAttr(PROMOTE, promote), + policyProcessor.writePolicies(service)); + + //write extended attributes + this.writeExtendedAttributes(writer, service, extensionAttributeProcessor, context); + + // Write service interface + extensionProcessor.write(service.getInterfaceContract(), writer, context); + + // Write bindings + for (Binding binding : service.getBindings()) { + extensionProcessor.write(binding, writer, context); + } + + // Write <callback> element + if (service.getCallback() != null) { + Callback callback = service.getCallback(); + writeStart(writer, CALLBACK, policyProcessor.writePolicies(callback)); + + //write extended attributes + this.writeExtendedAttributes(writer, callback, extensionAttributeProcessor, context); + + // Write callback bindings + for (Binding binding : callback.getBindings()) { + extensionProcessor.write(binding, writer, context); + } + + // Write extensions + this.writeExtendedElements(writer, service, extensionProcessor, context); + + writeEnd(writer); + } + + // Write extensions + this.writeExtendedElements(writer, service, extensionProcessor, context); + + writeEnd(writer); + } + + // Write <component> elements + for (Component component : composite.getComponents()) { + writeStart(writer, + COMPONENT, + new XAttr(NAME, component.getName()), + new XAttr(URI, component.getURI()), + new XAttr(AUTOWIRE, component.getAutowire()), + policyProcessor.writePolicies(component)); + + //write extended attributes + this.writeExtendedAttributes(writer, component, extensionAttributeProcessor, context); + + // Write the component implementation + Implementation implementation = component.getImplementation(); + if (implementation instanceof Composite) { + writeStart(writer, IMPLEMENTATION_COMPOSITE, new XAttr(NAME, ((Composite)implementation).getName()), policyProcessor.writePolicies(implementation)); + + //write extended attributes + this.writeExtendedAttributes(writer, (Composite)implementation, extensionAttributeProcessor, context); + + writeEnd(writer); + } else { + extensionProcessor.write(component.getImplementation(), writer, context); + } + + for (Object extension : component.getExtensions()) { + extensionProcessor.write(extension, writer, context); + } + + // Write <service> elements + for (ComponentService service : component.getServices()) { + writeStart(writer, SERVICE, new XAttr(NAME, service.getName()), policyProcessor.writePolicies(service)); + + //write extended attributes + this.writeExtendedAttributes(writer, service, extensionAttributeProcessor, context); + + // Write service interface + extensionProcessor.write(service.getInterfaceContract(), writer, context); + + // Write bindings + for (Binding binding : service.getBindings()) { + extensionProcessor.write(binding, writer, context); + } + + // Write <callback> element + if (service.getCallback() != null) { + Callback callback = service.getCallback(); + writeStart(writer, CALLBACK, policyProcessor.writePolicies(callback)); + + //write extended attributes + this.writeExtendedAttributes(writer, callback, extensionAttributeProcessor, context); + + // Write bindings + for (Binding binding : callback.getBindings()) { + extensionProcessor.write(binding, writer, context); + } + + // Write extensions + this.writeExtendedElements(writer, callback, extensionProcessor, context); + + writeEnd(writer); + } + + // Write extensions + this.writeExtendedElements(writer, service, extensionProcessor, context); + + writeEnd(writer); + } + + // Write <reference> elements + for (ComponentReference reference : component.getReferences()) { + writeStart(writer, + REFERENCE, + new XAttr(NAME, reference.getName()), + new XAttr(AUTOWIRE, reference.getAutowire()), + (reference.isNonOverridable() ? new XAttr(NONOVERRIDABLE, true) : null), + writeMultiplicity(reference), + writeTargets(reference), + policyProcessor.writePolicies(reference)); + + //write extended attributes + this.writeExtendedAttributes(writer, reference, extensionAttributeProcessor, context); + + // Write reference interface + extensionProcessor.write(reference.getInterfaceContract(), writer, context); + + // Write bindings + for (Binding binding : reference.getBindings()) { + extensionProcessor.write(binding, writer, context); + } + + // Write callback + if (reference.getCallback() != null) { + Callback callback = reference.getCallback(); + writeStart(writer, CALLBACK, policyProcessor.writePolicies(callback)); + + //write extended attributes + this.writeExtendedAttributes(writer, callback, extensionAttributeProcessor, context); + + // Write callback bindings + for (Binding binding : callback.getBindings()) { + extensionProcessor.write(binding, writer, context); + } + + // Write extensions + this.writeExtendedElements(writer, callback, extensionProcessor, context); + + writeEnd(writer); + } + + // Write extensions + this.writeExtendedElements(writer, reference, extensionProcessor, context); + + writeEnd(writer); + } + + // Write <property> elements + for (ComponentProperty property : component.getProperties()) { + writeStart(writer, + PROPERTY, + new XAttr(NAME, property.getName()), + new XAttr(MUST_SUPPLY, property.isMustSupply()), + new XAttr(MANY, property.isMany()), + new XAttr(TYPE, property.getXSDType()), + new XAttr(ELEMENT, property.getXSDElement()), + new XAttr(SOURCE, property.getSource()), + new XAttr(FILE, property.getFile()), + policyProcessor.writePolicies(property)); + + //write extended attributes + this.writeExtendedAttributes(writer, property, extensionAttributeProcessor, context); + + // Write property value + writePropertyValue(property.getValue(), property.getXSDElement(), property.getXSDType(), writer); + + // Write extensions + for (Object extension : property.getExtensions()) { + extensionProcessor.write(extension, writer, context); + } + + writeEnd(writer); + } + + writeEnd(writer); + } + + // Write <reference> elements + for (Reference reference : composite.getReferences()) { + CompositeReference compositeReference = (CompositeReference)reference; + + // Write list of promoted references + List<String> promote = new ArrayList<String>(); + for (ComponentReference promoted : compositeReference.getPromotedReferences()) { + promote.add(promoted.getName()); + } + + // Write <reference> element + writeStart(writer, + REFERENCE, + new XAttr(NAME, reference.getName()), + new XAttr(PROMOTE, promote), + writeMultiplicity(reference), + policyProcessor.writePolicies(reference)); + + //write extended attributes + this.writeExtendedAttributes(writer, reference, extensionAttributeProcessor, context); + + // Write reference interface + extensionProcessor.write(reference.getInterfaceContract(), writer, context); + + // Write bindings + for (Binding binding : reference.getBindings()) { + extensionProcessor.write(binding, writer, context); + } + + // Write <callback> element + if (reference.getCallback() != null) { + Callback callback = reference.getCallback(); + writeStart(writer, CALLBACK); + + //write extended attributes + this.writeExtendedAttributes(writer, callback, extensionAttributeProcessor, context); + + // Write callback bindings + for (Binding binding : callback.getBindings()) { + extensionProcessor.write(binding, writer, context); + } + + // Write extensions + this.writeExtendedElements(writer, callback, extensionProcessor, context); + + writeEnd(writer); + } + + // Write extensions + this.writeExtendedElements(writer, reference, extensionProcessor, context); + + writeEnd(writer); + } + + // Write <property> elements + for (Property property : composite.getProperties()) { + writeStart(writer, + PROPERTY, + new XAttr(NAME, property.getName()), + new XAttr(MUST_SUPPLY, property.isMustSupply()), + new XAttr(MANY, property.isMany()), + new XAttr(TYPE, property.getXSDType()), + new XAttr(ELEMENT, property.getXSDElement()), + policyProcessor.writePolicies(property)); + + //write extended attributes + this.writeExtendedAttributes(writer, property, extensionAttributeProcessor, context); + + // Write property value + writePropertyValue(property.getValue(), property.getXSDElement(), property.getXSDType(), writer); + + // Write extensions + for (Object extension : property.getExtensions()) { + extensionProcessor.write(extension, writer, context); + } + + writeEnd(writer); + } + + // Write <wire> elements + for (Wire wire : composite.getWires()) { + writeStart(writer, WIRE, new XAttr(SOURCE, wire.getSource().getName()), new XAttr(TARGET, wire.getTarget() + .getName()), wire.isReplace() ? new XAttr(Constants.REPLACE, true) : null); + + //write extended attributes + this.writeExtendedAttributes(writer, wire, extensionAttributeProcessor, context); + + // Write extensions + for (Object extension : wire.getExtensions()) { + extensionProcessor.write(extension, writer, context); + } + writeEnd(writer); + } + + for (Object extension : composite.getExtensions()) { + extensionProcessor.write(extension, writer, context); + } + + writeEndDocument(writer); + } + + public void resolve(Composite composite, ModelResolver resolver, ProcessorContext context) throws ContributionResolveException { + + Monitor monitor = context.getMonitor(); + try { + monitor.pushContext("Composite: " + composite.getName()); + + // Resolve includes in the composite + for (int i = 0, n = composite.getIncludes().size(); i < n; i++) { + Composite include = composite.getIncludes().get(i); + if (include != null) { + Composite resolved = resolver.resolveModel(Composite.class, include, context); + if (!resolved.isUnresolved()) { + if ((composite.isLocal() && resolved.isLocal()) || (!composite.isLocal() && !resolved.isLocal())) { + composite.getIncludes().set(i, resolved); + } else { + ContributionResolveException ce = + new ContributionResolveException("[ASM60041] Error: Composite " + composite.getName() + + " can only include another composite with the identical @local attribute value"); + error(monitor, "ContributionResolveException", include, ce); + } + } else { + ContributionResolveException ce = + new ContributionResolveException("[ASM60042] Error: Composite " + include.getName() + + " is not a valid composite within the domain"); + error(monitor, "ContributionResolveException", include, ce); + } + } + } + + // Resolve extensions + for (Object extension : composite.getExtensions()) { + if (extension != null) { + extensionProcessor.resolve(extension, resolver, context); + } + } + + //Resolve composite services and references + resolveContracts(composite, composite.getServices(), resolver, context); + resolveContracts(composite, composite.getReferences(), resolver, context); + + for (Property property : composite.getProperties()){ + resolvePropertyType("composite " + composite.getName().toString(), + property, + context.getContribution(), context); + } + + // Resolve component implementations, services and references + for (Component component : composite.getComponents()) { + + //resolve component services and references + resolveContracts(component, component.getServices(), resolver, context); + resolveContracts(component, component.getReferences(), resolver, context); + + for (ComponentProperty componentProperty : component.getProperties()) { + // resolve a reference to a property file + if (componentProperty.getFile() != null) { + Artifact artifact = contributionFactory.createArtifact(); + artifact.setURI(componentProperty.getFile()); + artifact = resolver.resolveModel(Artifact.class, artifact, context); + if (artifact.getLocation() != null) { + componentProperty.setFile(artifact.getLocation()); + } + } + + // resolve the reference to a complex property + resolvePropertyType("component " + component.getName(), + componentProperty, + context.getContribution(), context); + } + + //resolve component implementation + Implementation implementation = component.getImplementation(); + if (implementation != null) { + //now resolve the implementation so that even if there is a shared instance + //for this that is resolved, the specified intents and policysets are safe in the + //component and not lost + + List<PolicySet> policySets = new ArrayList<PolicySet>(implementation.getPolicySets()); + List<Intent> intents = new ArrayList<Intent>(implementation.getRequiredIntents()); + implementation = resolveImplementation(implementation, resolver, context); + + // If there are any policy sets on the implementation or component we have to + // ignore policy sets from the component type (policy spec 4.9) + if ( !policySets.isEmpty() || !component.getPolicySets().isEmpty() ) { + implementation.getPolicySets().clear(); + implementation.getPolicySets().addAll(policySets); + } + + implementation.getRequiredIntents().addAll(intents); + + component.setImplementation(implementation); + } + + //add model resolver to component + if (component instanceof ResolverExtension) { + ((ResolverExtension)component).setModelResolver(resolver); + } + } + + // Add model resolver to promoted components + for (Service service : composite.getServices()) { + CompositeService compositeService = (CompositeService)service; + Component promotedComponent = compositeService.getPromotedComponent(); + if (promotedComponent instanceof ResolverExtension) { + ((ResolverExtension)promotedComponent).setModelResolver(resolver); + } + } // end for + + } finally { + // Pop context + monitor.popContext(); + } // end try + } + + public QName getArtifactType() { + return COMPOSITE_QNAME; + } + + public Class<Composite> getModelType() { + return Composite.class; + } + + /** + * Write the value of a property - override to use correct method of creating an XMLStreamReader + * @param document + * @param element + * @param type + * @param writer + * @throws XMLStreamException + */ + protected void writePropertyValue(Object propertyValue, QName element, QName type, XMLStreamWriter writer) + throws XMLStreamException { + + if (propertyValue instanceof Document) { + Document document = (Document)propertyValue; + NodeList nodeList = document.getDocumentElement().getChildNodes(); + + for (int item = 0; item < nodeList.getLength(); ++item) { + Node node = nodeList.item(item); + int nodeType = node.getNodeType(); + if (nodeType == Node.ELEMENT_NODE) { + // Correct way to create a reader for a node object... + XMLStreamReader reader = staxHelper.createXMLStreamReader(node); + + while (reader.hasNext()) { + switch (reader.next()) { + case XMLStreamConstants.START_ELEMENT: + QName name = reader.getName(); + writer.writeStartElement(name.getPrefix(), name.getLocalPart(), name.getNamespaceURI()); + + int namespaces = reader.getNamespaceCount(); + for (int i = 0; i < namespaces; i++) { + String prefix = reader.getNamespacePrefix(i); + String ns = reader.getNamespaceURI(i); + writer.writeNamespace(prefix, ns); + } + + if (!"".equals(name.getNamespaceURI())) { + writer.writeNamespace(name.getPrefix(), name.getNamespaceURI()); + } + + // add the attributes for this element + namespaces = reader.getAttributeCount(); + for (int i = 0; i < namespaces; i++) { + String ns = reader.getAttributeNamespace(i); + String prefix = reader.getAttributePrefix(i); + String qname = reader.getAttributeLocalName(i); + String value = reader.getAttributeValue(i); + + writer.writeAttribute(prefix, ns, qname, value); + } + + break; + case XMLStreamConstants.CDATA: + writer.writeCData(reader.getText()); + break; + case XMLStreamConstants.CHARACTERS: + writer.writeCharacters(reader.getText()); + break; + case XMLStreamConstants.END_ELEMENT: + writer.writeEndElement(); + break; + } + } + } else { + writer.writeCharacters(node.getTextContent()); + } + } + } + } // end method writePropertyValue + + + /** + * Returns the model factory extension point to use. + * + * @param extensionPoints + * @return + */ + private static FactoryExtensionPoint modelFactories(ExtensionPointRegistry extensionPoints) { + return extensionPoints.getExtensionPoint(FactoryExtensionPoint.class); + } + + /** + * Property elements can have XSD types attributes so, in the case of a complex type, we need to find + * the XSD definition that defines that type in the contribution while we still have access to the + * contribution. Later, in the builder, we use this XSD definition to ensure that the property value + * is of the correct type + * + * @param property + * @param contribution + */ + private void resolvePropertyType(String parentName, Property property, Contribution contribution, ProcessorContext context){ + // resolve the reference to a complex property + // we ignore any types in the schema namespace + if (property.getXSDType() != null && + property.getXSDType().getNamespaceURI().equals("http://www.w3.org/2001/XMLSchema") != true){ + XSDefinition xsdDefinition = xsdFactory.createXSDefinition(); + xsdDefinition.setUnresolved(true); + xsdDefinition.setNamespace(property.getXSDType().getNamespaceURI()); + // some unit tests don't set up contribution and model resolvers properly + if (contribution != null && contribution.getModelResolver() != null) { + XSDefinition resolved = contribution.getModelResolver().resolveModel(XSDefinition.class, xsdDefinition, context); + if (resolved == null || resolved.isUnresolved()){ + // raise an error + // [rfeng] The XSD might be not available if we use JAXB annotated classes, report it as a warning for now + warning(context.getMonitor(), "PropertyTypeNotFound", property, property.getXSDType().toString(), property.getName(), parentName); + } else { + // store the schema in the property + property.setXSDDefinition(resolved); + } + } + } + } + +} |