From 132aa8a77685ec92bc90c03f987650d275a7b639 Mon Sep 17 00:00:00 2001 From: lresende Date: Mon, 30 Sep 2013 06:59:11 +0000 Subject: 2.0.1 RC1 release tag git-svn-id: http://svn.us.apache.org/repos/asf/tuscany@1527464 13f79535-47bb-0310-9956-ffa450edef68 --- .../builder/impl/PolicyAttachmentBuilderImpl.java | 412 +++++++++++++++++++++ 1 file changed, 412 insertions(+) create mode 100644 sca-java-2.x/tags/2.0.1-RC1/modules/builder/src/main/java/org/apache/tuscany/sca/builder/impl/PolicyAttachmentBuilderImpl.java (limited to 'sca-java-2.x/tags/2.0.1-RC1/modules/builder/src/main/java/org/apache/tuscany/sca/builder/impl/PolicyAttachmentBuilderImpl.java') diff --git a/sca-java-2.x/tags/2.0.1-RC1/modules/builder/src/main/java/org/apache/tuscany/sca/builder/impl/PolicyAttachmentBuilderImpl.java b/sca-java-2.x/tags/2.0.1-RC1/modules/builder/src/main/java/org/apache/tuscany/sca/builder/impl/PolicyAttachmentBuilderImpl.java new file mode 100644 index 0000000000..771bd0b8fa --- /dev/null +++ b/sca-java-2.x/tags/2.0.1-RC1/modules/builder/src/main/java/org/apache/tuscany/sca/builder/impl/PolicyAttachmentBuilderImpl.java @@ -0,0 +1,412 @@ +/* + * 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.IOException; +import java.io.StringWriter; +import java.util.ArrayList; +import java.util.List; + +import javax.xml.namespace.QName; +import javax.xml.stream.XMLStreamException; +import javax.xml.stream.XMLStreamWriter; +import javax.xml.xpath.XPathConstants; +import javax.xml.xpath.XPathExpression; + +import org.apache.tuscany.sca.assembly.Base; +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.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.builder.BuilderContext; +import org.apache.tuscany.sca.assembly.builder.CompositeBuilder; +import org.apache.tuscany.sca.assembly.builder.CompositeBuilderException; +import org.apache.tuscany.sca.common.xml.dom.DOMHelper; +import org.apache.tuscany.sca.common.xml.stax.StAXHelper; +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.StAXArtifactProcessorExtensionPoint; +import org.apache.tuscany.sca.core.ExtensionPointRegistry; +import org.apache.tuscany.sca.definitions.Definitions; +import org.apache.tuscany.sca.monitor.Monitor; +import org.apache.tuscany.sca.policy.ExternalAttachment; +import org.apache.tuscany.sca.policy.PolicySet; +import org.apache.tuscany.sca.policy.PolicySubject; +import org.w3c.dom.Document; +import org.w3c.dom.Element; +import org.w3c.dom.Node; +import org.w3c.dom.NodeList; +import org.xml.sax.SAXException; + +/** + * A builder that attaches policy sets to the domain composite using the xpath defined by + * the attachTo attribute. It first creates a DOM model for the composite so that the xpath + * expression can be evaluated. For the nodes selected by the xpath, caluclate the element + * URI and add the policy set into the composite model + * + * @version $Rev$ $Date$ + */ +public class PolicyAttachmentBuilderImpl implements CompositeBuilder { + protected static final String BUILDER_VALIDATION_BUNDLE = "org.apache.tuscany.sca.builder.builder-validation-messages"; + + protected StAXHelper staxHelper; + protected DOMHelper domHelper; + protected ExtensionPointRegistry registry; + protected StAXArtifactProcessor processor; + + public PolicyAttachmentBuilderImpl(ExtensionPointRegistry registry) { + this.registry = registry; + domHelper = DOMHelper.getInstance(registry); + staxHelper = StAXHelper.getInstance(registry); + StAXArtifactProcessorExtensionPoint processors = + registry.getExtensionPoint(StAXArtifactProcessorExtensionPoint.class); + processor = processors.getProcessor(Composite.class); + } + + public String getID() { + return "org.apache.tuscany.sca.policy.builder.PolicyAttachmentBuilder"; + } + + public Composite build(Composite composite, BuilderContext context) + throws CompositeBuilderException { + try { + Composite patched = applyXPath(composite, context.getDefinitions(), context.getMonitor()); + return patched; + } catch (Exception e) { + throw new CompositeBuilderException(e); + } + } + + /** + * Apply the attachTo XPath against the composite model + * @param composite The orginal composite + * @param definitions SCA definitions that contain the policy sets + * @param monitor The monitor + * @return A reloaded composite + * @throws Exception + */ + private Composite applyXPath(Composite composite, Definitions definitions, Monitor monitor) throws Exception { + + monitor.pushContext("Composite: " + composite.getName().toString()); + + try { + if (definitions == null || (definitions.getPolicySets().isEmpty() && definitions.getExternalAttachments().isEmpty()) ) { + return composite; + } + + + Document document = null; + + for (PolicySet ps : definitions.getPolicySets()) { + XPathExpression exp = ps.getAttachToXPathExpression(); + if ( exp != null ) { + if ( document == null ) { + document = saveAsDOM(composite); + } + NodeList nodes = (NodeList) exp.evaluate(document, XPathConstants.NODESET); + attachPolicySetToNodes(composite, monitor, nodes, ps); + } + } + + for ( ExternalAttachment ea : definitions.getExternalAttachments() ) { + XPathExpression exp = ea.getAttachToXPathExpression(); + if ( exp != null ) { + if ( document == null ) { + document = saveAsDOM(composite); + } + NodeList nodes = (NodeList) exp.evaluate(document, XPathConstants.NODESET); + for ( PolicySet ps : ea.getPolicySets() ) { + attachPolicySetToNodes(composite, monitor, nodes, ps); + } + } + } + + // Recursively apply the xpath against the composites referenced by + // If the composite or component has policy sets attached, we have to ignore policy sets + // attached to the inner composite. + if ( composite.getPolicySets().isEmpty() ) { + for (Component component : composite.getComponents()) { + if ( component.getPolicySets().isEmpty() ) { + Implementation impl = component.getImplementation(); + if (impl instanceof Composite) { + Composite patched = applyXPath((Composite)impl, definitions, monitor); + if (patched != impl) { + component.setImplementation(patched); + } + } + } + } + } + + return composite; + } finally { + monitor.popContext(); + } + } + + private void attachPolicySetToNodes(Composite composite, + Monitor monitor, NodeList nodes, PolicySet ps) { + + for (int i = 0; i < nodes.getLength(); i++) { + Node node = nodes.item(i); + + if ( isAttachedToProperty(node) ) { + Monitor.error(monitor, + this, + BUILDER_VALIDATION_BUNDLE, + "PolicyAttachedToProperty", + ps.getName().toString()); + } + + + // The node can be a component, implementation, service, reference or binding + String index = getStructuralURI(node); + PolicySubject subject = lookup(composite, index); + if (subject != null) { + ps.setIsExternalAttachment(true); + // Remove any PolicySets with the same name that may have been added + List subjectPSCopy = new ArrayList(subject.getPolicySets()); + for ( PolicySet existingPS : subjectPSCopy ) { + if ( existingPS.getName().equals(ps.getName()) ) { + subject.getPolicySets().remove(existingPS); + } + } + subject.getPolicySets().add(ps); + } else { + // raise a warning that the XPath node didn't match a node in the + // models + Monitor.warning(monitor, + this, + BUILDER_VALIDATION_BUNDLE, + "PolicyDOMModelMissmatch", + ps.getName().toString(), + index); + } + + } + } + + /** + * POL_40002 - you can't attach a policy to a property node + * or one of it's children. walk backwards up the node tree + * looking for an element called property and raise an error + * if we find one + * @param node + * @return + */ + private boolean isAttachedToProperty(Node node) { + + Node testNode = node; + while (testNode != null){ + if ((node.getNodeType() == Node.ELEMENT_NODE) && + (node.getLocalName().equals("property"))){ + return true; + } + testNode = testNode.getParentNode(); + } + return false; + } + + protected Document saveAsDOM(Composite composite) throws XMLStreamException, ContributionWriteException, IOException, + SAXException { + // First write the composite into a DOM document so that we can apply the xpath + StringWriter sw = new StringWriter(); + XMLStreamWriter writer = staxHelper.createXMLStreamWriter(sw); + // Write the composite into a DOM document + processor.write(composite, writer, new ProcessorContext(registry)); + writer.close(); + + // Debugging + //System.out.println("\n" + sw.toString()); + + Document document = domHelper.load(sw.toString()); + + return document; + } + + private static final QName COMPONENT = new QName(Base.SCA11_NS, "component"); + private static final QName SERVICE = new QName(Base.SCA11_NS, "service"); + private static final QName REFERENCE = new QName(Base.SCA11_NS, "reference"); + private static final QName CALLBACK = new QName(Base.SCA11_NS, "callback"); + private static final QName COMPOSITE = new QName(Base.SCA11_NS, "composite"); + + protected static String getStructuralURI(Node node) { + if (node != null) { + QName name = new QName(node.getNamespaceURI(), node.getLocalName()); + if (COMPONENT.equals(name)) { + Element element = (Element)node; + return element.getAttributeNS(null, "uri"); + } else if (SERVICE.equals(name)) { + Element component = (Element)node.getParentNode(); + String uri = component.getAttributeNS(null, "uri"); + String service = ((Element)node).getAttributeNS(null, "name"); + return uri + "#service(" + service + ")"; + } else if (REFERENCE.equals(name)) { + Element component = (Element)node.getParentNode(); + String uri = component.getAttributeNS(null, "uri"); + String reference = ((Element)node).getAttributeNS(null, "name"); + return uri + "#reference(" + reference + ")"; + } else if ( COMPOSITE.equals(name)) { + return ""; + } else { + String localName = node.getLocalName(); + if (localName.startsWith("binding.")) { + boolean callback = false; + String bindingName = ((Element)node).getAttributeNS(null, "name"); + Element contract = (Element)node.getParentNode(); + if ( "callback".equals(contract.getLocalName()) ) { + callback = true; + contract = (Element)contract.getParentNode(); + } + String contractName = contract.getAttributeNS(null, "name"); + Element component = (Element)contract.getParentNode(); + String uri = component.getAttributeNS(null, "uri"); + if ( callback ) + return uri + "#" + contract.getLocalName() + "(" + contractName + "/callback/" + bindingName + ")"; + else + return uri + "#" + contract.getLocalName() + "(" + contractName + "/" + bindingName + ")"; + } else if (localName.startsWith("implementation.")) { + Element component = (Element)node.getParentNode(); + String uri = component.getAttributeNS(null, "uri"); + return uri + "#implementation()"; + } else if (localName.startsWith("interface.")) { + Element contract = (Element)node.getParentNode(); + String contractName = contract.getAttributeNS(null, "name"); + Element component = (Element)node.getParentNode().getParentNode(); + String uri = component.getAttributeNS(null, "uri"); + return uri + "#" + contractName + "#interface()"; //(" + contractName + "/" + interfaceName + ")" + } + } + } + return null; + } + + protected Binding getBinding(Contract contract, String name, boolean isCallback) { + List bindings = null; + if ( isCallback ) { + bindings = contract.getCallback().getBindings(); + } else { + bindings = contract.getBindings(); + } + + for (Binding binding : bindings) { + if (name.equals(binding.getName())) { + return binding; + } + } + return null; + } + + protected PolicySubject lookup(Composite composite, String structuralURI) { + if (structuralURI == null) { + return null; + } else if ( structuralURI.equals("")) { + return composite; + } + int index = structuralURI.indexOf('#'); + String componentURI = structuralURI; + String service = null; + String reference = null; + String binding = null; + boolean isInterface = false; + boolean impl = false; + boolean isCallback = false; + + if (index != -1) { + componentURI = structuralURI.substring(0, index); + String fragment = structuralURI.substring(index + 1); + int begin = fragment.indexOf('('); + int end = fragment.indexOf(')'); + if (begin != -1 && end != -1) { + String path = fragment.substring(begin + 1, end).trim(); + String prefix = fragment.substring(0, begin).trim(); + if (prefix.equals("implementation")) { + impl = true; + } else { + int pos = path.indexOf('/'); + if (pos != -1) { + binding = path.substring(pos + 1); + if ( binding.startsWith("callback/")) { + binding = path.substring(pos + 10); + isCallback = true; + } + path = path.substring(0, pos); + if ("service-binding".equals(prefix)) { + service = path; + } else if ("reference-binding".equals(prefix)) { + reference = path; + } + } + if ("service".equals(prefix)) { + service = path; + } else if ("reference".equals(prefix)) { + reference = path; + } else if ( prefix.indexOf("#interface") != -1 ) { + service = prefix.substring(0, prefix.indexOf("#interface")); + isInterface = true; + } + } + } + } + for (Component component : composite.getComponents()) { + if (component.getURI().equals(componentURI)) { + if (service != null) { + ComponentService componentService = component.getService(service); + if ( isInterface ) { + return componentService.getInterfaceContract().getInterface(); + } else if (binding != null) { + Binding b = getBinding(componentService, binding, isCallback); + if (b instanceof PolicySubject) { + return (PolicySubject)b; + } + } else { + return componentService; + } + } else if (reference != null) { + ComponentReference componentReference = component.getReference(reference); + if (binding != null) { + Binding b = getBinding(componentReference, binding, isCallback); + if (b instanceof PolicySubject) { + return (PolicySubject)b; + } + } else { + return componentReference; + } + } else if (impl) { + return component.getImplementation(); + } + return component; + } else if (structuralURI.startsWith(component.getURI() + "/")) { + Implementation implementation = component.getImplementation(); + if (implementation instanceof Composite) { + return lookup((Composite)implementation, structuralURI); + } else { + return null; + } + } + } + return null; + } +} -- cgit v1.2.3