2 * ============LICENSE_START==========================================
4 * ===================================================================
5 * Copyright (c) 2017-2018 AT&T Intellectual Property. All rights reserved.
6 * Copyright (c) 2017-2019 European Software Marketing Ltd.
7 * ===================================================================
8 * Licensed under the Apache License, Version 2.0 (the "License");
9 * you may not use this file except in compliance with the License.
10 * You may obtain a copy of the License at
12 * http://www.apache.org/licenses/LICENSE-2.0
14 * Unless required by applicable law or agreed to in writing, software
15 * distributed under the License is distributed on an "AS IS" BASIS,
16 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17 * See the License for the specific language governing permissions and
18 * limitations under the License.
19 * ============LICENSE_END============================================
22 package org.onap.aai.modelloader.util;
24 import java.io.IOException;
25 import java.io.StringReader;
26 import java.util.HashSet;
28 import java.util.Optional;
30 import java.util.stream.Collectors;
31 import java.util.stream.IntStream;
32 import java.util.stream.Stream;
33 import javax.xml.parsers.DocumentBuilder;
34 import javax.xml.parsers.DocumentBuilderFactory;
35 import javax.xml.parsers.ParserConfigurationException;
36 import org.onap.aai.cl.api.Logger;
37 import org.onap.aai.cl.eelf.LoggerFactory;
38 import org.onap.aai.modelloader.gizmo.GizmoBulkPayload;
39 import org.onap.aai.modelloader.gizmo.GizmoEdge;
40 import org.onap.aai.modelloader.gizmo.GizmoEdgeOperation;
41 import org.onap.aai.modelloader.gizmo.GizmoVertex;
42 import org.onap.aai.modelloader.gizmo.GizmoVertexOperation;
43 import org.onap.aai.modelloader.service.ModelLoaderMsgs;
44 import org.w3c.dom.Document;
45 import org.w3c.dom.Element;
46 import org.w3c.dom.Node;
47 import org.w3c.dom.NodeList;
48 import org.xml.sax.InputSource;
49 import org.xml.sax.SAXException;
51 public class GizmoTranslator {
53 private enum NodeType {
54 VERTEX, ATTRIBUTE, CONTAINER, RELATIONSHIP_LIST, RELATIONSHIP, RELATED_TO, RELATIONSHIP_DATA, RELATIONSHIP_KEY, RELATIONSHIP_VALUE, MODEL_ELEMENT_VERTEX, NQ_ELEMENT_VERTEX, UNKNOWN
57 private static Logger logger = LoggerFactory.getInstance().getLogger(GizmoTranslator.class.getName());
59 public static String translate(String xmlPayload) throws ParserConfigurationException, SAXException, IOException {
60 logger.info(ModelLoaderMsgs.DISTRIBUTION_EVENT, "Process XML model artifact: " + xmlPayload);
62 DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
63 factory.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true);
64 DocumentBuilder builder = factory.newDocumentBuilder();
65 InputSource is = new InputSource(new StringReader(xmlPayload));
66 Document doc = builder.parse(is);
68 GizmoBulkPayload gizmoPayload = new GizmoBulkPayload();
70 processNode(doc.getDocumentElement(), null, null, gizmoPayload);
72 return gizmoPayload.toJson();
75 private static void processNode(Node node, Node parentNode, GizmoVertexOperation parentVertexOp,
76 GizmoBulkPayload gizmoPayload) {
77 if (!(node instanceof Element)) {
81 Node newParent = null;
82 NodeType nodeType = getNodeType(node);
86 case MODEL_ELEMENT_VERTEX:
87 case NQ_ELEMENT_VERTEX:
88 parentVertexOp = createGizmoVertexOp(node, GizmoBulkPayload.ADD_OP);
89 gizmoPayload.addVertexOperation(parentVertexOp);
90 if (parentNode != null) {
91 gizmoPayload.addEdgeOperation(createGizmoEdgeOp(node, parentNode));
96 processRelationship((Element) node, parentVertexOp, gizmoPayload);
97 newParent = parentNode;
100 newParent = parentNode;
104 NodeList childNodes = node.getChildNodes();
105 for (int ix = 0; ix < childNodes.getLength(); ix++) {
106 processNode(childNodes.item(ix), newParent, parentVertexOp, gizmoPayload);
110 private static void processRelationship(Element relationshipNode, GizmoVertexOperation sourceNode,
111 GizmoBulkPayload gizmoPayload) {
112 NodeList relatedToList = relationshipNode.getElementsByTagName("related-to");
113 if (relatedToList.getLength() != 1) {
114 logger.error(ModelLoaderMsgs.DISTRIBUTION_EVENT_ERROR, "Unable to resolve relationship");
118 GizmoVertex targetVertex = new GizmoVertex();
119 targetVertex.setType(relatedToList.item(0).getTextContent().trim());
121 NodeList relationData = relationshipNode.getElementsByTagName("relationship-data");
122 for (int ix = 0; ix < relationData.getLength(); ix++) {
123 Element relationNode = (Element) relationData.item(ix);
124 NodeList keyList = relationNode.getElementsByTagName("relationship-key");
125 NodeList valueList = relationNode.getElementsByTagName("relationship-value");
127 if ((keyList.getLength() != 1) || (valueList.getLength() != 1)) {
128 logger.error(ModelLoaderMsgs.DISTRIBUTION_EVENT_ERROR,
129 "Unable to resolve relationship. Missing key/value.");
133 String[] keyBits = keyList.item(0).getTextContent().trim().split("\\.");
134 String value = valueList.item(0).getTextContent().trim();
136 if (keyBits[0].equalsIgnoreCase(targetVertex.getType())) {
137 targetVertex.setProperty(keyBits[1], value);
141 gizmoPayload.addVertexOperation(
142 new GizmoVertexOperation(GizmoBulkPayload.EXISTS_OP, getVertexId(targetVertex), targetVertex));
144 GizmoEdge edge = new GizmoEdge();
146 edge.setSource("$" + getVertexId(sourceNode.getVertex()));
147 edge.setTarget("$" + getVertexId(targetVertex));
149 gizmoPayload.addEdgeOperation(
150 new GizmoEdgeOperation(GizmoBulkPayload.ADD_OP, edge.getSource() + "_" + edge.getTarget(), edge));
153 private static GizmoEdgeOperation createGizmoEdgeOp(Node node, Node parentNode) {
154 GizmoEdge edge = new GizmoEdge();
156 edge.setSource("$" + getVertexId(createGizmoVertex(node)));
157 edge.setTarget("$" + getVertexId(createGizmoVertex(parentNode)));
159 return new GizmoEdgeOperation(GizmoBulkPayload.ADD_OP, edge.getSource() + "_" + edge.getTarget(), edge);
162 private static GizmoVertexOperation createGizmoVertexOp(Node node, String operationType) {
163 GizmoVertex vertex = createGizmoVertex(node);
164 return new GizmoVertexOperation(operationType, getVertexId(vertex), vertex);
167 private static String getVertexId(GizmoVertex vertex) {
168 StringBuilder sb = new StringBuilder();
169 sb.append(vertex.getType());
170 for (Map.Entry<String, String> entry : vertex.getProperties().entrySet()) {
171 sb.append("-" + entry.getValue());
174 return sb.toString();
177 private static GizmoVertex createGizmoVertex(Node node) {
178 GizmoVertex vertex = new GizmoVertex();
179 vertex.setType(node.getNodeName().trim());
181 NodeList childNodes = node.getChildNodes();
183 for (int ix = 0; ix < childNodes.getLength(); ix++) {
184 if (getNodeType(childNodes.item(ix)).equals(NodeType.ATTRIBUTE)) {
185 vertex.setProperty(childNodes.item(ix).getNodeName().trim(),
186 childNodes.item(ix).getTextContent().trim());
190 // Special case for model-element, where we need to generate an id field
191 if (getNodeType(node).equals(NodeType.MODEL_ELEMENT_VERTEX)) {
192 vertex.setProperty("model-element-uuid", generateModelElementId((Element) node));
195 // Special case for nq-element, where we need to generate an id field
196 if (getNodeType(node).equals(NodeType.NQ_ELEMENT_VERTEX)) {
197 vertex.setProperty("named-query-element-uuid", generateModelElementId((Element) node));
203 // Generate a unique hash to store as the id for this node
204 private static String generateModelElementId(Element node) {
205 // Get the parent model version / named query version
206 Optional<String> parentVersion = Optional.empty();
208 Node parentNode = node.getParentNode();
209 while (parentNode != null && !parentVersion.isPresent()) {
210 if (getNodeType(parentNode) == NodeType.VERTEX) {
211 NodeList childNodes = ((Element) parentNode).getElementsByTagName("*");
212 parentVersion = IntStream.range(0, childNodes.getLength()) //
213 .mapToObj(childNodes::item) //
214 .filter(child -> child.getNodeName().equalsIgnoreCase("named-query-uuid")
215 || child.getNodeName().equalsIgnoreCase("model-version-id")) //
216 .map(child -> child.getTextContent().trim()) //
219 parentNode = parentNode.getParentNode();
222 Set<String> elemSet = new HashSet<>();
223 parentVersion.ifPresent(elemSet::add);
225 Set<NodeType> validNodeTypes = //
226 Stream.of(NodeType.ATTRIBUTE, NodeType.RELATIONSHIP_KEY, NodeType.RELATIONSHIP_VALUE)
227 .collect(Collectors.toSet());
229 NodeList childNodes = node.getElementsByTagName("*");
230 IntStream.range(0, childNodes.getLength()) //
231 .mapToObj(childNodes::item) //
232 .filter(child -> validNodeTypes.contains(getNodeType(child))) //
233 .map(child -> child.getTextContent().trim()) //
234 .forEachOrdered(elemSet::add);
236 return Integer.toString(elemSet.hashCode());
239 private static NodeType getNodeType(Node node) {
240 if (!(node instanceof Element)) {
241 return NodeType.UNKNOWN;
244 if (node.getNodeName().equalsIgnoreCase("relationship-list")) {
245 return NodeType.RELATIONSHIP_LIST;
248 if (node.getNodeName().equalsIgnoreCase("relationship")) {
249 return NodeType.RELATIONSHIP;
252 if (node.getNodeName().equalsIgnoreCase("relationship-data")) {
253 return NodeType.RELATIONSHIP_DATA;
256 if (node.getNodeName().equalsIgnoreCase("related-to")) {
257 return NodeType.RELATED_TO;
260 if (node.getNodeName().equalsIgnoreCase("relationship-key")) {
261 return NodeType.RELATIONSHIP_KEY;
264 if (node.getNodeName().equalsIgnoreCase("relationship-value")) {
265 return NodeType.RELATIONSHIP_VALUE;
268 if (node.getNodeName().equalsIgnoreCase("model-element")) {
269 return NodeType.MODEL_ELEMENT_VERTEX;
272 if (node.getNodeName().equalsIgnoreCase("named-query-element")) {
273 return NodeType.NQ_ELEMENT_VERTEX;
276 NodeList childNodes = node.getChildNodes();
277 int childElements = countChildElements(childNodes);
279 if ((childElements == 0) && (node.getTextContent() != null) && (!node.getTextContent().trim().isEmpty())) {
280 return NodeType.ATTRIBUTE;
283 for (int ix = 0; ix < childNodes.getLength(); ix++) {
284 if (getNodeType(childNodes.item(ix)) == NodeType.ATTRIBUTE) {
285 return NodeType.VERTEX;
289 if (childElements > 0) {
290 return NodeType.CONTAINER;
293 return NodeType.UNKNOWN;
296 static int countChildElements(NodeList nodes) {
298 for (int ix = 0; ix < nodes.getLength(); ix++) {
299 if (nodes.item(ix) instanceof Element) {