2 * ============LICENSE_START==========================================
4 * ===================================================================
5 * Copyright © 2017-2018 AT&T Intellectual Property. All rights reserved.
6 * Copyright © 2017-2018 Amdocs
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============================================
21 package org.onap.aai.modelloader.util;
23 import java.io.IOException;
24 import java.io.StringReader;
25 import java.util.HashSet;
28 import javax.xml.parsers.DocumentBuilder;
29 import javax.xml.parsers.DocumentBuilderFactory;
30 import javax.xml.parsers.ParserConfigurationException;
31 import org.onap.aai.cl.api.Logger;
32 import org.onap.aai.cl.eelf.LoggerFactory;
33 import org.onap.aai.modelloader.gizmo.GizmoBulkPayload;
34 import org.onap.aai.modelloader.gizmo.GizmoEdge;
35 import org.onap.aai.modelloader.gizmo.GizmoEdgeOperation;
36 import org.onap.aai.modelloader.gizmo.GizmoVertex;
37 import org.onap.aai.modelloader.gizmo.GizmoVertexOperation;
38 import org.onap.aai.modelloader.service.ModelLoaderMsgs;
39 import org.w3c.dom.Document;
40 import org.w3c.dom.Element;
41 import org.w3c.dom.Node;
42 import org.w3c.dom.NodeList;
43 import org.xml.sax.InputSource;
44 import org.xml.sax.SAXException;
46 public class GizmoTranslator {
48 private enum NodeType {
63 private static Logger logger = LoggerFactory.getInstance().getLogger(GizmoTranslator.class.getName());
65 public static String translate(String xmlPayload) throws ParserConfigurationException, SAXException, IOException {
66 logger.info(ModelLoaderMsgs.DISTRIBUTION_EVENT, "Process XML model artifact: " + xmlPayload);
68 DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
69 factory.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true);
70 DocumentBuilder builder = factory.newDocumentBuilder();
71 InputSource is = new InputSource(new StringReader(xmlPayload));
72 Document doc = builder.parse(is);
74 GizmoBulkPayload gizmoPayload = new GizmoBulkPayload();
76 processNode(doc.getDocumentElement(), null, null, gizmoPayload);
78 return gizmoPayload.toJson();
81 private static void processNode(Node node, Node parentNode, GizmoVertexOperation parentVertexOp, GizmoBulkPayload gizmoPayload) {
82 if (!(node instanceof Element)) {
86 Node newParent = null;
87 NodeType nodeType = getNodeType(node);
91 case MODEL_ELEMENT_VERTEX:
92 case NQ_ELEMENT_VERTEX:
93 parentVertexOp = createGizmoVertexOp(node, GizmoBulkPayload.ADD_OP);
94 gizmoPayload.addVertexOperation(parentVertexOp);
95 if (parentNode != null) {
96 gizmoPayload.addEdgeOperation(createGizmoEdgeOp(node, parentNode));
101 processRelationship((Element)node, parentVertexOp, gizmoPayload);
102 newParent = parentNode;
105 newParent = parentNode;
109 NodeList childNodes = node.getChildNodes();
110 for (int ix = 0; ix < childNodes.getLength(); ix++) {
111 processNode(childNodes.item(ix), newParent, parentVertexOp, gizmoPayload);
115 private static void processRelationship(Element relationshipNode, GizmoVertexOperation sourceNode, GizmoBulkPayload gizmoPayload) {
116 NodeList relatedToList = relationshipNode.getElementsByTagName("related-to");
117 if (relatedToList.getLength() != 1) {
118 logger.error(ModelLoaderMsgs.DISTRIBUTION_EVENT_ERROR, "Unable to resolve relationship");
122 GizmoVertex targetVertex = new GizmoVertex();
123 targetVertex.setType(relatedToList.item(0).getTextContent().trim());
125 NodeList relationData = relationshipNode.getElementsByTagName("relationship-data");
126 for (int ix = 0; ix < relationData.getLength(); ix++) {
127 Element relationNode = (Element)relationData.item(ix);
128 NodeList keyList = relationNode.getElementsByTagName("relationship-key");
129 NodeList valueList = relationNode.getElementsByTagName("relationship-value");
131 if ( (keyList.getLength() != 1) || (valueList.getLength() != 1) ) {
132 logger.error(ModelLoaderMsgs.DISTRIBUTION_EVENT_ERROR, "Unable to resolve relationship. Missing key/value.");
136 String[] keyBits = keyList.item(0).getTextContent().trim().split("\\.");
137 String value = valueList.item(0).getTextContent().trim();
139 if (keyBits[0].equalsIgnoreCase(targetVertex.getType())) {
140 targetVertex.setProperty(keyBits[1], value);
144 gizmoPayload.addVertexOperation(new GizmoVertexOperation(GizmoBulkPayload.EXISTS_OP, getVertexId(targetVertex), targetVertex));
146 GizmoEdge edge = new GizmoEdge();
148 edge.setSource("$" + getVertexId(sourceNode.getVertex()));
149 edge.setTarget("$" + getVertexId(targetVertex));
151 gizmoPayload.addEdgeOperation(new GizmoEdgeOperation(GizmoBulkPayload.ADD_OP, edge.getSource() + "_" + edge.getTarget(), edge));
154 private static GizmoEdgeOperation createGizmoEdgeOp(Node node, Node parentNode) {
155 GizmoEdge edge = new GizmoEdge();
157 edge.setSource("$" + getVertexId(createGizmoVertex(node)));
158 edge.setTarget("$" + getVertexId(createGizmoVertex(parentNode)));
160 return new GizmoEdgeOperation(GizmoBulkPayload.ADD_OP, edge.getSource() + "_" + edge.getTarget(), edge);
163 private static GizmoVertexOperation createGizmoVertexOp(Node node, String operationType) {
164 GizmoVertex vertex = createGizmoVertex(node);
165 return new GizmoVertexOperation(operationType, getVertexId(vertex), vertex);
168 private static String getVertexId(GizmoVertex vertex) {
169 StringBuilder sb = new StringBuilder();
170 sb.append(vertex.getType());
171 for (Map.Entry<String, String> entry : vertex.getProperties().entrySet()) {
172 sb.append("-" + entry.getValue());
175 return sb.toString();
178 private static GizmoVertex createGizmoVertex(Node node) {
179 GizmoVertex vertex = new GizmoVertex();
180 vertex.setType(node.getNodeName().trim());
182 NodeList childNodes = node.getChildNodes();
184 for (int ix = 0; ix < childNodes.getLength(); ix++) {
185 if (getNodeType(childNodes.item(ix)).equals(NodeType.ATTRIBUTE)) {
186 vertex.setProperty(childNodes.item(ix).getNodeName().trim(), 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 Set<String> elemSet = new HashSet<>();
207 // Get the parent model version / named query version
208 String parentVersion = null;
209 Node parentNode = node.getParentNode();
210 while ( (parentNode != null) && (parentVersion == null) ) {
211 if (getNodeType(parentNode).equals(NodeType.VERTEX)) {
212 NodeList childNodes = ((Element)parentNode).getElementsByTagName("*");
213 for (int ix = 0; ix < childNodes.getLength(); ix++) {
214 if (childNodes.item(ix).getNodeName().equalsIgnoreCase("named-query-uuid") ||
215 childNodes.item(ix).getNodeName().equalsIgnoreCase("model-version-id")) {
216 parentVersion = childNodes.item(ix).getTextContent().trim();
222 parentNode = parentNode.getParentNode();
225 if (parentVersion != null) {
226 elemSet.add(parentVersion);
229 NodeList childNodes = node.getElementsByTagName("*");
230 for (int ix = 0; ix < childNodes.getLength(); ix++) {
231 NodeType nt = getNodeType(childNodes.item(ix));
232 if ( nt.equals(NodeType.ATTRIBUTE) || nt.equals(NodeType.RELATIONSHIP_KEY) || nt.equals(NodeType.RELATIONSHIP_VALUE) ) {
233 elemSet.add(childNodes.item(ix).getTextContent().trim());
237 return Integer.toString(elemSet.hashCode());
240 private static NodeType getNodeType(Node node) {
241 if (!(node instanceof Element)) {
242 return NodeType.UNKNOWN;
245 if (node.getNodeName().equalsIgnoreCase("relationship-list")) {
246 return NodeType.RELATIONSHIP_LIST;
249 if (node.getNodeName().equalsIgnoreCase("relationship")) {
250 return NodeType.RELATIONSHIP;
253 if (node.getNodeName().equalsIgnoreCase("relationship-data")) {
254 return NodeType.RELATIONSHIP_DATA;
257 if (node.getNodeName().equalsIgnoreCase("related-to")) {
258 return NodeType.RELATED_TO;
261 if (node.getNodeName().equalsIgnoreCase("relationship-key")) {
262 return NodeType.RELATIONSHIP_KEY;
265 if (node.getNodeName().equalsIgnoreCase("relationship-value")) {
266 return NodeType.RELATIONSHIP_VALUE;
269 if (node.getNodeName().equalsIgnoreCase("model-element")) {
270 return NodeType.MODEL_ELEMENT_VERTEX;
273 if (node.getNodeName().equalsIgnoreCase("named-query-element")) {
274 return NodeType.NQ_ELEMENT_VERTEX;
277 NodeList childNodes = node.getChildNodes();
278 int childElements = countChildElements(childNodes);
280 if ( (childElements == 0) && (node.getTextContent() != null) && (!node.getTextContent().trim().isEmpty()) ) {
281 return NodeType.ATTRIBUTE;
284 for (int ix = 0; ix < childNodes.getLength(); ix++) {
285 if (getNodeType(childNodes.item(ix)) == NodeType.ATTRIBUTE) {
286 return NodeType.VERTEX;
290 if (childElements > 0) {
291 return NodeType.CONTAINER;
294 return NodeType.UNKNOWN;
297 static int countChildElements(NodeList nodes) {
299 for (int ix = 0; ix < nodes.getLength(); ix++) {
300 if (nodes.item(ix) instanceof Element) {