package org.opentosca.planbuilder.model.utils; import java.io.IOException; import java.io.StringReader; import java.io.StringWriter; import java.util.ArrayList; import java.util.Collection; import java.util.HashSet; import java.util.List; import java.util.Objects; import java.util.Set; import javax.xml.namespace.QName; import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.parsers.ParserConfigurationException; import javax.xml.transform.OutputKeys; import javax.xml.transform.Transformer; import javax.xml.transform.TransformerException; import javax.xml.transform.TransformerFactory; import javax.xml.transform.dom.DOMSource; import javax.xml.transform.stream.StreamResult; import org.eclipse.winery.model.tosca.TNodeTemplate; import org.eclipse.winery.model.tosca.TNodeType; import org.apache.http.annotation.Obsolete; import org.opentosca.container.core.common.NotFoundException; import org.opentosca.container.core.engine.ToscaEngine; import org.opentosca.container.core.model.csar.Csar; import org.opentosca.container.core.tosca.convention.Types; import org.opentosca.planbuilder.model.tosca.AbstractArtifactTemplate; import org.opentosca.planbuilder.model.tosca.AbstractArtifactType; import org.opentosca.planbuilder.model.tosca.AbstractDeploymentArtifact; import org.opentosca.planbuilder.model.tosca.AbstractInterface; import org.opentosca.planbuilder.model.tosca.AbstractNodeTemplate; import org.opentosca.planbuilder.model.tosca.AbstractNodeType; import org.opentosca.planbuilder.model.tosca.AbstractNodeTypeImplementation; import org.opentosca.planbuilder.model.tosca.AbstractOperation; import org.opentosca.planbuilder.model.tosca.AbstractRelationshipTemplate; import org.opentosca.planbuilder.model.tosca.AbstractRelationshipType; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.w3c.dom.Document; import org.w3c.dom.Element; import org.w3c.dom.Node; import org.xml.sax.InputSource; import org.xml.sax.SAXException; /** * <p> * This class holds utility methods * </p> * Copyright 2013 IAAS University of Stuttgart <br> * <br> * * @author Kalman Kepes - [email protected] */ public class ModelUtils { private final static Logger LOG = LoggerFactory.getLogger(ModelUtils.class); public static String makeValidNCName(final String string) { return string.replaceAll("\\.", "_").replaceAll(" ", "_").replace("{", "_").replace("}", "_").replace("/", "_") .replace(":", "_"); } /** * Returns true if the given QName type denotes to a NodeType in the type hierarchy of the given NodeTemplate * * @param nodeTemplate an AbstractNodeTemplate * @param type the Type as a QName to check against * @return true iff the given NodeTemplate contains the given type in its type hierarchy */ public static boolean checkForTypeInHierarchy(final AbstractNodeTemplate nodeTemplate, final QName type) { final List<QName> typeHierarchy = ModelUtils.getNodeTypeHierarchy(nodeTemplate.getType()); // as somehow contains won't work here, we must cycle trough for (final QName qname : typeHierarchy) { if (qname.equals(type)) { return true; } } return false; } /** * Returns true if the given QName type denotes to a RelationshipType in the type hierarchy of the given * RelationshipTemplate * * @param relationshipTemplate an AbstractRelationshipTemplate * @param type the Type as a QName to check against * @return true iff the given RelationshipTemplate contains the given type in its type hierarchy */ public static boolean checkForTypeInHierarchy(final AbstractRelationshipTemplate relationshipTemplate, final QName type) { final List<QName> typeHierarchy = ModelUtils.getRelationshipTypeHierarchy(relationshipTemplate.getRelationshipType()); // as somehow contains won't work here, we must cycle trough for (final QName qname : typeHierarchy) { if (qname.equals(type)) { return true; } } return false; } /** * Removes duplicates from the given List * * @param nodeTemplates a List of AbstractNodeTemplate */ private static void cleanDuplciates(final Collection<AbstractNodeTemplate> nodeTemplates) { final List<AbstractNodeTemplate> list = new ArrayList<>(); for (final AbstractNodeTemplate template : nodeTemplates) { boolean match = false; for (final AbstractNodeTemplate template2 : list) { if (template.getId().equals(template2.getId()) & template == template2) { match = true; } } if (!match) { list.add(template); } } nodeTemplates.clear(); nodeTemplates.addAll(list); } /** * <p> * Converts the given DOM Document to a String * </p> * * @param doc a DOM Document * @return a String representation of the complete Document given */ public static String getStringFromDoc(final org.w3c.dom.Document doc) { try { final DOMSource domSource = new DOMSource(doc); final StringWriter writer = new StringWriter(); final StreamResult result = new StreamResult(writer); final TransformerFactory tf = TransformerFactory.newInstance(); final Transformer transformer = tf.newTransformer(); transformer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "no"); transformer.setOutputProperty(OutputKeys.METHOD, "xml"); transformer.setOutputProperty(OutputKeys.INDENT, "yes"); transformer.setOutputProperty(OutputKeys.ENCODING, "UTF-8"); transformer.setOutputProperty("{http://xml.apache.org/xslt}indent-amount", "4"); transformer.transform(domSource, result); writer.flush(); return writer.toString(); } catch (final TransformerException ex) { ModelUtils.LOG.error("Couldn't transform DOM Document to a String", ex); return null; } } /** * Removes duplicates from the given List * * @param relationshipTemplates a List of AbstractRelationshipTemplate */ private static void cleanDuplicates(final List<AbstractRelationshipTemplate> relationshipTemplates) { final List<AbstractRelationshipTemplate> list = new ArrayList<>(); for (final AbstractRelationshipTemplate template : relationshipTemplates) { boolean match = false; for (final AbstractRelationshipTemplate template2 : list) { if (template.getId().equals(template2.getId()) & template == template2) { match = true; } } if (!match) { list.add(template); } } relationshipTemplates.clear(); relationshipTemplates.addAll(list); } public static Set<AbstractDeploymentArtifact> computeEffectiveDeploymentArtifacts(final AbstractNodeTemplate nodeTemplate, final AbstractNodeTypeImplementation nodeImpl) { final Set<AbstractDeploymentArtifact> effectiveDAs = new HashSet<>(); effectiveDAs.addAll(nodeTemplate.getDeploymentArtifacts()); for (final AbstractDeploymentArtifact da : nodeImpl.getDeploymentArtifacts()) { if (!effectiveDAs.contains(da)) { effectiveDAs.add(da); } } return effectiveDAs; } public static List<QName> getArtifactTypeHierarchy(final AbstractArtifactTemplate artifactTemplate) { final List<QName> qnames = new ArrayList<>(); qnames.add(artifactTemplate.getAbstractArtifactType().getId()); AbstractArtifactType ref = artifactTemplate.getAbstractArtifactType().getTypeRef(); while (ref != null) { qnames.add(ref.getId()); ref = ref.getTypeRef(); } return qnames; } /** * Adds the InfrastructureEdges of the given NodeTemplate to the given List * * @param nodeTemplate an AbstractNodeTemplate * @param infrastructureEdges a List of AbstractRelationshipTemplate to add the InfrastructureEdges to */ public static void getInfrastructureEdges(final AbstractNodeTemplate nodeTemplate, final List<AbstractRelationshipTemplate> infrastructureEdges) { // fetch all infrastructureNodes final List<AbstractNodeTemplate> infraNodes = new ArrayList<>(); ModelUtils.getInfrastructureNodes(nodeTemplate, infraNodes); // check all outgoing edges on those nodes, if they are infrastructure // edges for (final AbstractNodeTemplate infraNode : infraNodes) { for (final AbstractRelationshipTemplate outgoingEdge : infraNode.getOutgoingRelations()) { if (isInfrastructureRelationshipType(outgoingEdge.getType())) { infrastructureEdges.add(outgoingEdge); } } } // check outgoing edges of given node for (final AbstractRelationshipTemplate outgoingEdge : nodeTemplate.getOutgoingRelations()) { if (isInfrastructureRelationshipType(outgoingEdge.getType())) { infrastructureEdges.add(outgoingEdge); } } ModelUtils.cleanDuplicates(infrastructureEdges); } /** * Adds the InfrastructureEdges of the given RelationshipTemplate to the given List * * @param relationshipTemplate an AbstractRelationshipTemplate * @param infraEdges a List of AbstractRelationshipTemplate to add the InfrastructureEdges to * @param forSource whether to search for InfrastructureEdges along the SourceInterface or * TargetInterface */ public static void getInfrastructureEdges(final AbstractRelationshipTemplate relationshipTemplate, final List<AbstractRelationshipTemplate> infraEdges, final boolean forSource) { if (forSource) { ModelUtils.getInfrastructureEdges(relationshipTemplate.getSource(), infraEdges); } else { ModelUtils.getInfrastructureEdges(relationshipTemplate.getTarget(), infraEdges); } } /** * Calculates all Infrastructure Nodes of all Infrastructure Paths originating from the given NodeTemplate * * @param nodeTemplate AbstractNodeTemplate from where the search for Infrastructure Nodes begin * @param infrastructureNodes a List of AbstractNodeTemplates which represent Infrastructure Nodes of the given * NodeTemplate (including itself when applicable as an infrastructure node) * @Info the infrastructureNodes List must be empty */ public static void getInfrastructureNodes(final AbstractNodeTemplate nodeTemplate, final Collection<AbstractNodeTemplate> infrastructureNodes) { ModelUtils.LOG.debug("BaseType of NodeTemplate " + nodeTemplate.getId() + " is " + ModelUtils.getNodeBaseType(nodeTemplate)); if (org.opentosca.container.core.tosca.convention.Utils.isSupportedInfrastructureNodeType(ModelUtils.getNodeBaseType(nodeTemplate)) || org.opentosca.container.core.tosca.convention.Utils.isSupportedCloudProviderNodeType(ModelUtils.getNodeBaseType(nodeTemplate))) { infrastructureNodes.add(nodeTemplate); } for (final AbstractRelationshipTemplate relation : nodeTemplate.getOutgoingRelations()) { ModelUtils.LOG.debug("Checking if relation is infrastructure edge, relation: " + relation.getId()); if (ModelUtils.getRelationshipBaseType(relation).equals(Types.hostedOnRelationType) || ModelUtils.getRelationshipBaseType(relation).equals(Types.deployedOnRelationType)) { ModelUtils.LOG.debug("traversing edge to node: " + relation.getTarget().getId()); if (org.opentosca.container.core.tosca.convention.Utils.isSupportedInfrastructureNodeType(ModelUtils.getNodeBaseType(relation.getTarget())) || org.opentosca.container.core.tosca.convention.Utils.isSupportedCloudProviderNodeType(ModelUtils.getNodeBaseType(relation.getTarget()))) { ModelUtils.LOG.debug("Found infrastructure node: " + relation.getTarget().getId()); infrastructureNodes.add(relation.getTarget()); } ModelUtils.getInfrastructureNodes(relation.getTarget(), infrastructureNodes); } } ModelUtils.cleanDuplciates(infrastructureNodes); } /** * Adds InfrastructureNodes of the given RelaitonshipTemplate to the given List of NodeTemplates * * @param relationshipTemplate an AbstractRelationshipTemplate to search its InfrastructureNodes * @param infrastructureNodes a List of AbstractNodeTemplate where the InfrastructureNodes will be added * @param forSource whether to search for InfrastructureNodes along the SourceInterface or * TargetInterface */ public static void getInfrastructureNodes(final AbstractRelationshipTemplate relationshipTemplate, final List<AbstractNodeTemplate> infrastructureNodes, final boolean forSource) { if (forSource) { ModelUtils.getInfrastructureNodes(relationshipTemplate.getSource(), infrastructureNodes); } else { ModelUtils.getInfrastructureNodes(relationshipTemplate.getTarget(), infrastructureNodes); } } public static List<AbstractRelationshipTemplate> getIngoingRelations(final AbstractNodeTemplate nodeTemplate, final QName... relationshipTypes) { final List<AbstractRelationshipTemplate> relations = new ArrayList<>(); for (final AbstractRelationshipTemplate relation : nodeTemplate.getIngoingRelations()) { for (final QName relationshipTypeHierarchyMember : ModelUtils.getRelationshipTypeHierarchy(relation.getRelationshipType())) { final boolean match = false; for (final QName relationshipType : relationshipTypes) { if (relationshipTypeHierarchyMember.equals(relationshipType)) { relations.add(relation); break; } } if (match) { break; } } } return relations; } /** * Returns the baseType of the given NodeTemplate * * @param nodeTemplate an AbstractNodeTemplate * @return a QName which represents the baseType of the given NodeTemplate */ @Deprecated public static QName getNodeBaseType(final AbstractNodeTemplate nodeTemplate) { ModelUtils.LOG.debug("Beginning search for basetype of: " + nodeTemplate.getId()); final List<QName> typeHierarchy = ModelUtils.getNodeTypeHierarchy(nodeTemplate.getType()); for (final QName type : typeHierarchy) { ModelUtils.LOG.debug("Checking Type in Hierarchy, type: " + type.toString()); if (type.equals(Types.TOSCABASETYPE_SERVER)) { return type; } else if (type.equals(Types.TOSCABASETYPE_OS)) { return type; } } // FIXME: when there are no basetypes we're screwed return typeHierarchy.get(typeHierarchy.size() - 1); } public static TNodeType getNodeBaseType(Csar csar, final TNodeTemplate nodeTemplate) { LOG.debug("Beginning search for basetype of: " + nodeTemplate.getId()); final List<TNodeType> typeHierarchy; try { typeHierarchy = ToscaEngine.resolveNodeTypeHierarchy(csar, nodeTemplate); } catch (NotFoundException e) { return null; } for (final TNodeType type : typeHierarchy) { ModelUtils.LOG.debug("Checking Type in Hierarchy, type: " + type.toString()); if (type.getQName().equals(Types.TOSCABASETYPE_SERVER)) { return type; } else if (type.getQName().equals(Types.TOSCABASETYPE_OS)) { return type; } } // FIXME: when there are no basetypes we're screwed return typeHierarchy.get(typeHierarchy.size() - 1); } /** * Returns all NodeTemplates from the given NodeTemplate going along the path of relation following the target * interfaces * * @param nodeTemplate an AbstractNodeTemplate * @param nodes a List of AbstractNodeTemplate to add the result to */ public static void getNodesFromNodeToSink(final AbstractNodeTemplate nodeTemplate, final List<AbstractNodeTemplate> nodes) { nodes.add(nodeTemplate); for (final AbstractRelationshipTemplate outgoingTemplate : nodeTemplate.getOutgoingRelations()) { if (outgoingTemplate.getType().equals(Types.connectsToRelationType)) { // we skip connectTo relations, as they are connecting stacks // and // make the result even more ambigious continue; } ModelUtils.getNodesFromRelationToSink(outgoingTemplate, nodes); } ModelUtils.cleanDuplciates(nodes); } public static void getNodesFromNodeToSink(final AbstractNodeTemplate nodeTemplate, final QName relationshipType, final Collection<AbstractNodeTemplate> nodes) { nodes.add(nodeTemplate); for (final AbstractRelationshipTemplate outgoingTemplate : nodeTemplate.getOutgoingRelations()) { if (ModelUtils.getRelationshipTypeHierarchy(outgoingTemplate.getRelationshipType()) .contains(relationshipType)) { // we skip connectTo relations, as they are connecting stacks // and // make the result even more ambigious ModelUtils.getNodesFromRelationToSink(outgoingTemplate, nodes); } } ModelUtils.cleanDuplciates(nodes); } public static void getNodesFromNodeToSource(final AbstractNodeTemplate nodeTemplate, final List<AbstractNodeTemplate> nodes) { nodes.add(nodeTemplate); for (final AbstractRelationshipTemplate ingoingTemplate : nodeTemplate.getIngoingRelations()) { if (ingoingTemplate.getType().equals(Types.connectsToRelationType)) { // we skip connectTo relations, as they are connecting stacks // and // make the result even more ambigious continue; } ModelUtils.getNodesFromRelationToSources(ingoingTemplate, nodes); } ModelUtils.cleanDuplciates(nodes); } /** * Returns all NodeTemplates from the given RelationshipTemplate going along all occuring Relationships using the * Target * * @param relationshipTemplate an AbstractRelationshipTemplate * @param nodes a List of AbstractNodeTemplate to add the result to */ public static void getNodesFromRelationToSink(final AbstractRelationshipTemplate relationshipTemplate, final Collection<AbstractNodeTemplate> nodes) { final AbstractNodeTemplate nodeTemplate = relationshipTemplate.getTarget(); nodes.add(nodeTemplate); for (final AbstractRelationshipTemplate outgoingTemplate : nodeTemplate.getOutgoingRelations()) { if (isCommunicationRelationshipType(outgoingTemplate.getType())) { // we skip connectTo relations, as they are connecting stacks // and // make the result even more ambigious continue; } ModelUtils.getNodesFromRelationToSink(outgoingTemplate, nodes); } ModelUtils.cleanDuplciates(nodes); } public static void getNodesFromRelationToSink(final AbstractRelationshipTemplate relationshipTemplate, final QName relationshipType, final List<AbstractNodeTemplate> nodes) { final AbstractNodeTemplate nodeTemplate = relationshipTemplate.getTarget(); nodes.add(nodeTemplate); for (final AbstractRelationshipTemplate outgoingTemplate : nodeTemplate.getOutgoingRelations()) { if (ModelUtils.getRelationshipTypeHierarchy(outgoingTemplate.getRelationshipType()) .contains(relationshipType)) { ModelUtils.getNodesFromRelationToSink(outgoingTemplate, relationshipType, nodes); } } ModelUtils.cleanDuplciates(nodes); } private static void getNodesFromRelationToSources(final AbstractRelationshipTemplate ingoingTemplate, final List<AbstractNodeTemplate> nodes) { final AbstractNodeTemplate nodeTemplate = ingoingTemplate.getSource(); nodes.add(nodeTemplate); for (final AbstractRelationshipTemplate outgoingTemplate : nodeTemplate.getIngoingRelations()) { if (outgoingTemplate.getType().equals(Types.connectsToRelationType)) { continue; } ModelUtils.getNodesFromRelationToSources(outgoingTemplate, nodes); } ModelUtils.cleanDuplciates(nodes); } /** * Returns a ordered list of QNames. The order represents the inheritance of NodeTypes defining the given NodeType. * E.g. NodeType "someNodeType" inherits properties from "someOtherNodeType". The returns list would have * {someNs}someNodeType,{someNs}someOtherNodeType inside, in the exact same order. * * @param nodeType the nodeType to get the hierarchy for * @return a List containing an order of inheritance of NodeTypes for this NodeType with itself at the first spot in * the list. */ @Obsolete public static List<QName> getNodeTypeHierarchy(final AbstractNodeType nodeType) { ModelUtils.LOG.debug("Beginning calculating NodeType Hierarchy for: " + nodeType.getId().toString()); final List<QName> typeHierarchy = new ArrayList<>(); typeHierarchy.add(nodeType.getId()); boolean wasNotNull = true; // changed from search with qname to search with abstract classes and // typeref AbstractNodeType lastFoundNodeType = nodeType; while (wasNotNull) { final AbstractNodeType referencedNodeType = lastFoundNodeType.getTypeRef(); if (referencedNodeType == null) { wasNotNull = false; } else { ModelUtils.LOG.debug("Found referenced NodeType: " + referencedNodeType.getId().toString()); typeHierarchy.add(referencedNodeType.getId()); lastFoundNodeType = referencedNodeType; } } return typeHierarchy; } public static List<AbstractRelationshipTemplate> getOutgoingInfrastructureEdges(final AbstractNodeTemplate nodeTemplate) { final List<AbstractRelationshipTemplate> relations = new ArrayList<>(); for (final AbstractRelationshipTemplate relation : nodeTemplate.getOutgoingRelations()) { final List<QName> types = ModelUtils.getRelationshipTypeHierarchy(relation.getRelationshipType()); if (types.contains(Types.dependsOnRelationType) | types.contains(Types.deployedOnRelationType) | types.contains(Types.hostedOnRelationType)) { relations.add(relation); } } return relations; } public static List<AbstractRelationshipTemplate> getOutgoingRelations(final AbstractNodeTemplate nodeTemplate, final QName... relationshipTypes) { final List<AbstractRelationshipTemplate> relations = new ArrayList<>(); for (final AbstractRelationshipTemplate relation : nodeTemplate.getOutgoingRelations()) { for (final QName relationshipTypeHierarchyMember : ModelUtils.getRelationshipTypeHierarchy(relation.getRelationshipType())) { final boolean match = false; for (final QName relationshipType : relationshipTypes) { if (relationshipTypeHierarchyMember.equals(relationshipType)) { relations.add(relation); break; } } if (match) { break; } } } return relations; } /** * Returns the baseType of the given RelationshipTemplate * * @param relationshipTemplate an AbstractRelationshipTemplate * @return a QName representing the baseType of the given RelationshipTemplate */ public static QName getRelationshipBaseType(final AbstractRelationshipTemplate relationshipTemplate) { ModelUtils.LOG.debug("Beginning search for basetype of: " + relationshipTemplate.getId()); final List<QName> typeHierarchy = ModelUtils.getRelationshipTypeHierarchy(relationshipTemplate.getRelationshipType()); for (final QName type : typeHierarchy) { ModelUtils.LOG.debug("Checking Type QName: " + type.toString()); if (type.equals(Types.connectsToRelationType)) { return type; } else if (type.equals(Types.dependsOnRelationType)) { return type; } else if (type.equals(Types.hostedOnRelationType)) { return type; } else if (type.equals(Types.deployedOnRelationType)) { return type; } } // FIXME: when there are no basetypes we're screwed return typeHierarchy.get(typeHierarchy.size() - 1); } /** * Returns a ordered list of QNames. The order represents the inheritance of RelationshipTypes defining the given * RelationshipType. E.g. Relationship "someRelationType" and it inherits properties from "someOtherRelationType". * The returns list would have {someNs}someRelationType,{someNs}someOtherRelationType inside, in the exact same * order. Var * * @param definitions the Definitions to look in * @param relationshipType the RelationshipType to get the hierarchy for * @return a List containing an order of inheritance of RelationshipTypes of the given RelationshipType */ public static List<QName> getRelationshipTypeHierarchy(final AbstractRelationshipType relationshipType) { final List<QName> typeHierarchy = new ArrayList<>(); typeHierarchy.add(relationshipType.getId()); boolean wasNotNull = true; AbstractRelationshipType lastFoundRelationshipType = relationshipType; while (wasNotNull) { final AbstractRelationshipType referencedRelationshipType = lastFoundRelationshipType.getReferencedType(); if (referencedRelationshipType == null) { wasNotNull = false; } else { typeHierarchy.add(referencedRelationshipType.getId()); lastFoundRelationshipType = referencedRelationshipType; } } return typeHierarchy; } /** * Looks for a childelement with an attribute with the given name and value * * @param element the element to look in * @param attributeName the name of the attribute * @param attributeValue the value of the attribute * @return true if the given element has a child element with an attribute where attrname.equals(attributeName) & * attr.value(attributeValue), else false */ public static boolean hasChildElementWithAttribute(final Element element, final String attributeName, final String attributeValue) { if (element == null) { return false; } for (int i = 0; i < element.getChildNodes().getLength(); i++) { final Node child = element.getChildNodes().item(i); if (child.getAttributes().getNamedItem(attributeName) != null && child.getAttributes().getNamedItem(attributeName).getNodeValue().equals(attributeValue)) { return true; } } return false; } public static boolean isCommunicationRelationshipType(final QName relationshipType) { return relationshipType.equals(Types.connectsToRelationType); } public static boolean isInfrastructureRelationshipType(final QName relationshipType) { return relationshipType.equals(Types.dependsOnRelationType) | relationshipType.equals(Types.hostedOnRelationType) | relationshipType.equals(Types.deployedOnRelationType); } public static Collection<String> getPropertyNames(final AbstractNodeTemplate nodeTemplate) { if (Objects.nonNull(nodeTemplate.getProperties())) { return nodeTemplate.getProperties().asMap().keySet(); } else { return new HashSet<>(); } } /** * Transforms the given string to a DOM node * * @param xmlString the xml to transform as String * @return a DOM Node representing the given string */ public static Node string2dom(final String xmlString) throws ParserConfigurationException, SAXException, IOException { final DocumentBuilderFactory docFactory = DocumentBuilderFactory.newInstance(); docFactory.setNamespaceAware(true); final DocumentBuilder docBuilder = DocumentBuilderFactory.newInstance().newDocumentBuilder(); final InputSource is = new InputSource(); is.setCharacterStream(new StringReader(xmlString)); final Document doc = docBuilder.parse(is); return doc.getFirstChild(); } public static Node string2domQuietly(final String xmlString) { try { return string2dom(xmlString); } catch (ParserConfigurationException | SAXException | IOException e) { throw new RuntimeException(e); } } /** * Get the AbstractInterface with a certain name from a NodeTemplate * * @param nodeTemplate the name of the NodeTemplate * @param interfaceName the name of the interface * @return the AbstractInterface if found, <code>null</code> otherwise */ public static AbstractInterface getInterfaceOfNode(final AbstractNodeTemplate nodeTemplate, final String interfaceName) { return nodeTemplate.getType().getInterfaces().stream().filter(iface -> iface.getName().equals(interfaceName)) .findFirst().orElse(null); } /** * Get the AbstractOperation with a certain name from a NodeTemplate * * @param nodeTemplate the name of the NodeTemplate * @param interfaceName the name of the interface containing the operation * @param operationName the name of the operation * @return the AbstractOperation if found, <code>null>/code> otherwise */ public static AbstractOperation getOperationOfNode(final AbstractNodeTemplate nodeTemplate, final String interfaceName, final String operationName) { final AbstractInterface iface = ModelUtils.getInterfaceOfNode(nodeTemplate, interfaceName); if (Objects.nonNull(iface)) { return iface.getOperations().stream().filter(op -> op.getName().equals(operationName)).findFirst() .orElse(null); } else { LOG.error("Unable to find interface {} for NodeTemplate {}", interfaceName, nodeTemplate.getName()); return null; } } }