/* * Copyright 2013 JBoss Inc * * Licensed 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.artificer.integration.switchyard.artifactbuilder; import org.oasis_open.docs.s_ramp.ns.s_ramp_v1.BaseArtifactType; import org.oasis_open.docs.s_ramp.ns.s_ramp_v1.ExtendedArtifactType; import org.oasis_open.docs.s_ramp.ns.s_ramp_v1.Relationship; import org.artificer.common.ArtifactType; import org.artificer.common.ArtifactTypeEnum; import org.artificer.common.ArtificerModelUtils; import org.artificer.integration.artifactbuilder.QNameRelationshipSource; import org.artificer.integration.artifactbuilder.XmlArtifactBuilder; import org.artificer.common.query.xpath.StaticNamespaceContext; import org.artificer.integration.java.model.JavaModel; import org.artificer.integration.switchyard.model.SwitchYardModel; import org.w3c.dom.Element; import org.w3c.dom.NodeList; import javax.xml.namespace.QName; import javax.xml.xpath.XPathConstants; import javax.xml.xpath.XPathExpressionException; import java.io.IOException; import java.util.Collection; import java.util.UUID; /** * This artifact builder operates on the switchyard.xml file found in a typical SwitchYard * application JAR/WAR. * * @author eric.wittmann@redhat.com */ public class SwitchYardXmlArtifactBuilder extends XmlArtifactBuilder { @Override protected void configureNamespaceMappings(StaticNamespaceContext namespaceContext) { super.configureNamespaceMappings(namespaceContext); SwitchYardModel.addNamespaceMappings(namespaceContext); } @Override protected void derive() throws IOException { try { // Pull out the target namespace and save it as a custom property String targetNS = rootElement.getAttribute("targetNamespace"); ArtificerModelUtils.setCustomProperty(getPrimaryArtifact(), "targetNamespace", targetNS); // Pull out the name and set it (unless the name has already been set) if ("switchyard.xml".equals(getPrimaryArtifact().getName()) && rootElement.hasAttribute("name")) { String name = rootElement.getAttribute("name"); getPrimaryArtifact().setName(name); } processComponents(); // Note - process services after components so that components can be promoted easily. processServices(); processTransformers(); processValidators(); } catch (XPathExpressionException e) { throw new IOException(e); } } private void processServices() throws XPathExpressionException { // xpath expression to find all services NodeList nodes = (NodeList) query(rootElement, "./sca:composite/sca:service", XPathConstants.NODESET); for (int idx = 0; idx < nodes.getLength(); idx++) { Element node = (Element) nodes.item(idx); String name = node.getAttribute("name"); ExtendedArtifactType serviceArtifact = SwitchYardModel.newServiceArtifact(name); getDerivedArtifacts().add(serviceArtifact); if (node.hasAttribute("promote")) { String promote = node.getAttribute("promote"); BaseArtifactType component = findComponentByName(getDerivedArtifacts(), promote); if (component != null) { ArtificerModelUtils.addGenericRelationship(serviceArtifact, SwitchYardModel.REL_PROMOTES, component.getUuid()); } } Element iface = (Element) query(node, "sca:interface.java", XPathConstants.NODE); if (iface != null) { if (iface.hasAttribute("interface")) { String ifaceName = iface.getAttribute("interface"); Relationship relationship = ArtificerModelUtils.addGenericRelationship(serviceArtifact, SwitchYardModel.REL_IMPLEMENTS, null); relationshipSources.add(new JavaRelationshipSource(ifaceName, null, relationship.getRelationshipTarget(), "ext", JavaModel.TYPE_JAVA_INTERFACE)); } } iface = (Element) query(node, "sca:interface.wsdl", XPathConstants.NODE); if (iface != null) { if (iface.hasAttribute("interface")) { String wsdlInfo = iface.getAttribute("interface"); Relationship relationship = ArtificerModelUtils.addGenericRelationship(serviceArtifact, SwitchYardModel.REL_IMPLEMENTS, null); // TODO Implement finding an artifact in the s-ramp repo given the wsdl information in switchyard.xml (why couldn't a QName be used in there???) } } } } private void processComponents() throws XPathExpressionException { // xpath expression to find all services NodeList nodes = (NodeList) query(rootElement, "./sca:composite/sca:component", XPathConstants.NODESET); for (int idx = 0; idx < nodes.getLength(); idx++) { Element node = (Element) nodes.item(idx); String name = node.getAttribute("name"); ExtendedArtifactType componentArtifact = SwitchYardModel.newComponentArtifact(name); getDerivedArtifacts().add(componentArtifact); Element implBean = (Element) query(node, "bean:implementation.bean", XPathConstants.NODE); if (implBean != null) { if (implBean.hasAttribute("class")) { String implClassName = implBean.getAttribute("class"); Relationship relationship = ArtificerModelUtils.addGenericRelationship(componentArtifact, SwitchYardModel.REL_IMPLEMENTED_BY, null); relationshipSources.add(new JavaRelationshipSource(implClassName, null, relationship.getRelationshipTarget(), "ext", JavaModel.TYPE_JAVA_CLASS)); } if (implBean.hasAttribute("requires")) { String requires = implBean.getAttribute("requires"); ArtificerModelUtils.setCustomProperty(componentArtifact, "requires", requires); } } Element implCamel = (Element) query(node, "camel:implementation.camel", XPathConstants.NODE); if (implCamel != null) { Element xml = (Element) query(implCamel, "camel:xml", XPathConstants.NODE); if (xml != null) { String path = xml.getAttribute("path"); Relationship relationship = ArtificerModelUtils.addGenericRelationship(componentArtifact, SwitchYardModel.REL_IMPLEMENTED_BY, null); // TODO Implement finding a camel config artifact in the repository } if (implCamel.hasAttribute("requires")) { String requires = implCamel.getAttribute("requires"); ArtificerModelUtils.setCustomProperty(componentArtifact, "requires", requires); } } // Process references ('service' children of the component) NodeList refs = (NodeList) query(node, "sca:reference", XPathConstants.NODESET); for (int jdx = 0; jdx < refs.getLength(); jdx++) { Element ref = (Element) refs.item(jdx); Element iface = (Element) query(ref, "sca:interface.java", XPathConstants.NODE); if (iface != null) { if (iface.hasAttribute("interface")) { String ifaceName = iface.getAttribute("interface"); Relationship relationship = ArtificerModelUtils.addGenericRelationship(componentArtifact, SwitchYardModel.REL_REFERENCES, null); relationshipSources.add(new JavaRelationshipSource(ifaceName, null, relationship.getRelationshipTarget(), "ext", JavaModel.TYPE_JAVA_INTERFACE)); } } iface = (Element) query(ref, "sca:interface.wsdl", XPathConstants.NODE); if (iface != null) { if (iface.hasAttribute("interface")) { String wsdlInfo = iface.getAttribute("interface"); Relationship relationship = ArtificerModelUtils.addGenericRelationship(componentArtifact, SwitchYardModel.REL_REFERENCES, null); // TODO Implement finding an artifact in the s-ramp repo given the wsdl information in switchyard.xml (why couldn't a QName be used in there???) } } } // Process component services ('service' children of the component) NodeList services = (NodeList) query(node, "sca:service", XPathConstants.NODESET); for (int jdx = 0; jdx < services.getLength(); jdx++) { Element componentSvc = (Element) services.item(jdx); name = componentSvc.getAttribute("name"); ExtendedArtifactType componentServiceArtifact = SwitchYardModel.newComponentServiceArtifact(name); componentServiceArtifact.setUuid(UUID.randomUUID().toString()); getDerivedArtifacts().add(componentServiceArtifact); ArtificerModelUtils.addGenericRelationship(componentArtifact, SwitchYardModel.REL_OFFERS, componentServiceArtifact.getUuid()); Element iface = (Element) query(componentSvc, "sca:interface.java", XPathConstants.NODE); if (iface != null) { if (iface.hasAttribute("interface")) { String ifaceName = iface.getAttribute("interface"); Relationship relationship = ArtificerModelUtils.addGenericRelationship(componentServiceArtifact, SwitchYardModel.REL_IMPLEMENTS, null); relationshipSources.add(new JavaRelationshipSource(ifaceName, null, relationship.getRelationshipTarget(), "ext", JavaModel.TYPE_JAVA_INTERFACE)); } } iface = (Element) query(componentSvc, "sca:interface.wsdl", XPathConstants.NODE); if (iface != null) { if (iface.hasAttribute("interface")) { String wsdlInfo = iface.getAttribute("interface"); Relationship relationship = ArtificerModelUtils.addGenericRelationship(componentServiceArtifact, SwitchYardModel.REL_IMPLEMENTS, null); // TODO Implement finding an artifact in the s-ramp repo given the wsdl information in switchyard.xml (why couldn't a QName be used in there???) } } if (componentSvc.hasAttribute("requires")) { String requires = componentSvc.getAttribute("requires"); ArtificerModelUtils.setCustomProperty(componentServiceArtifact, "requires", requires); } } } } private void processTransformers() throws XPathExpressionException { // xpath expression to find all services NodeList nodes = (NodeList) query(rootElement, "./swyd:transforms/tf:transform.java | ./swyd:transforms/tf:transform.xslt | ./swyd:transforms/tf:transform.json | ./swyd:transforms/tf:transform.smooks | ./swyd:transforms/tf:transform.jaxb", XPathConstants.NODESET); for (int idx = 0; idx < nodes.getLength(); idx++) { Element node = (Element) nodes.item(idx); String name = node.getAttribute("name"); // in case SY supports named transformers at some point if (name == null || name.trim().length() == 0) { if (node.hasAttribute("from") && node.hasAttribute("to")) { String from = node.getAttribute("from"); String to = node.getAttribute("to"); if (from.startsWith("{")) { name = from.substring(from.lastIndexOf("}")+1); } else if (from.startsWith("java:")) { name = from.substring(from.lastIndexOf('.')+1); } if (to.startsWith("{")) { name = name + "->" + to.substring(to.lastIndexOf("}")+1); } else if (to.startsWith("java:")) { name = name + "->" + to.substring(to.lastIndexOf('.')+1); } } else { name = node.getLocalName(); } } ExtendedArtifactType transformerArtifact = SwitchYardModel.newTransformerArtifact(name); String type = node.getLocalName(); type = type.substring(type.lastIndexOf('.') + 1); ArtificerModelUtils.setCustomProperty(transformerArtifact, SwitchYardModel.PROP_TRANSFORMER_TYPE, type); if (node.hasAttribute("class")) { Relationship relationship = ArtificerModelUtils.addGenericRelationship(transformerArtifact, SwitchYardModel.REL_IMPLEMENTED_BY, null); relationshipSources.add(new JavaRelationshipSource(node.getAttribute("class"), null, relationship.getRelationshipTarget(), "ext", JavaModel.TYPE_JAVA_CLASS)); } if (node.hasAttribute("bean")) { Relationship relationship = ArtificerModelUtils.addGenericRelationship(transformerArtifact, SwitchYardModel.REL_IMPLEMENTED_BY, null); // TODO Implement finding a java class artifact by its cdi bean name } if (node.hasAttribute("xsltFile")) { Relationship relationship = ArtificerModelUtils.addGenericRelationship(transformerArtifact, SwitchYardModel.REL_IMPLEMENTED_BY, null); // TODO Implement finding an xslt artifact in the repository } if (node.hasAttribute("config")) { Relationship relationship = ArtificerModelUtils.addGenericRelationship(transformerArtifact, SwitchYardModel.REL_IMPLEMENTED_BY, null); // TODO Implement finding a smooks config artifact in the repository } if (node.hasAttribute("from")) { Relationship relationship = ArtificerModelUtils.addGenericRelationship(transformerArtifact, SwitchYardModel.REL_TRANSFORMS_FROM, null); String from = node.getAttribute("from"); if (from.startsWith("{")) { relationshipSources.add(new QNameRelationshipSource(QName.valueOf(from), null, relationship.getRelationshipTarget(), ArtifactTypeEnum.ElementDeclaration.getModel(), ArtifactTypeEnum.ElementDeclaration.getType())); } else { relationshipSources.add(new JavaRelationshipSource(from, null, relationship.getRelationshipTarget(), "ext", JavaModel.TYPE_JAVA_CLASS)); } } if (node.hasAttribute("to")) { Relationship relationship = ArtificerModelUtils.addGenericRelationship(transformerArtifact, SwitchYardModel.REL_TRANSFORMS_TO, null); String to = node.getAttribute("to"); if (to.startsWith("{")) { relationshipSources.add(new QNameRelationshipSource(QName.valueOf(to), null, relationship.getRelationshipTarget(), ArtifactTypeEnum.ElementDeclaration.getModel(), ArtifactTypeEnum.ElementDeclaration.getType())); } else { relationshipSources.add(new JavaRelationshipSource(to, null, relationship.getRelationshipTarget(), "ext", JavaModel.TYPE_JAVA_CLASS)); } } getDerivedArtifacts().add(transformerArtifact); } } private void processValidators() throws XPathExpressionException { // xpath expression to find all services NodeList nodes = (NodeList) query(rootElement, "./swyd:validates/val:validate.java | ./swyd:validates/val:validate.xml", XPathConstants.NODESET); for (int idx = 0; idx < nodes.getLength(); idx++) { Element node = (Element) nodes.item(idx); if (!node.hasAttribute("name")) continue; String name = node.getAttribute("name"); ExtendedArtifactType validatorArtifact = SwitchYardModel.newValidateArtifact(name); String type = node.getLocalName(); type = type.substring(type.lastIndexOf('.') + 1); ArtificerModelUtils.setCustomProperty(validatorArtifact, SwitchYardModel.PROP_VALIDATE_TYPE, type); // Unresolved 'validates' reference Relationship relationship = ArtificerModelUtils.addGenericRelationship(validatorArtifact, SwitchYardModel.REL_VALIDATES, null); if (name.startsWith("{")) { relationshipSources.add(new QNameRelationshipSource(QName.valueOf(name), null, relationship.getRelationshipTarget(), ArtifactTypeEnum.ElementDeclaration.getModel(), ArtifactTypeEnum.ElementDeclaration.getType())); } else { relationshipSources.add(new JavaRelationshipSource(name, null, relationship.getRelationshipTarget(), "ext", JavaModel.TYPE_JAVA_INTERFACE)); } // Unresolved 'implementedBy' reference if (node.hasAttribute("class")) { relationship = ArtificerModelUtils.addGenericRelationship(validatorArtifact, SwitchYardModel.REL_IMPLEMENTED_BY, null); relationshipSources.add(new JavaRelationshipSource(node.getAttribute("class"), null, relationship.getRelationshipTarget(), "ext", JavaModel.TYPE_JAVA_CLASS)); } if (node.hasAttribute("bean")) { relationship = ArtificerModelUtils.addGenericRelationship(validatorArtifact, SwitchYardModel.REL_IMPLEMENTED_BY, null); // TODO Implement finding a java class artifact by its cdi bean name } if (node.hasAttribute("schemaType")) { // TODO handle relationships to the schemas // relationship = SrampModelUtils.addGenericRelationship(validatorArtifact, SwitchYardModel.REL_IMPLEMENTED_BY, null); // relationship.getOtherAttributes().put(UNRESOLVED_REF, "xml:" + node.getAttribute("schemaType")); } getDerivedArtifacts().add(validatorArtifact); } } /** * Finds a component artifact (previously created) with the given name. * @param derivedArtifacts * @param componentName */ private BaseArtifactType findComponentByName(Collection<BaseArtifactType> derivedArtifacts, String componentName) { for (BaseArtifactType artifact : derivedArtifacts) { ArtifactType at = ArtifactType.valueOf(artifact); if (at.getType().equals(SwitchYardModel.SwitchYardComponent) && artifact.getName().equals(componentName)) { return artifact; } } return null; } }