Configurable option to load models via Gizmo 78/73578/2
authorsblimkie <sb787e@att.com>
Mon, 26 Nov 2018 21:56:06 +0000 (16:56 -0500)
committersblimkie <steven.blimkie@amdocs.com>
Tue, 27 Nov 2018 16:33:38 +0000 (11:33 -0500)
Change-Id: I792e1a0db166ccab84f42a2d1beb92d7a630165b
Issue-ID: AAI-1957
Signed-off-by: sblimkie <steven.blimkie@amdocs.com>
12 files changed:
src/main/java/org/onap/aai/modelloader/config/ModelLoaderConfig.java
src/main/java/org/onap/aai/modelloader/entity/model/AbstractModelArtifact.java
src/main/java/org/onap/aai/modelloader/entity/model/ModelArtifact.java
src/main/java/org/onap/aai/modelloader/entity/model/NamedQueryArtifact.java
src/main/java/org/onap/aai/modelloader/gizmo/GizmoBulkPayload.java [new file with mode: 0644]
src/main/java/org/onap/aai/modelloader/gizmo/GizmoEdge.java [new file with mode: 0644]
src/main/java/org/onap/aai/modelloader/gizmo/GizmoEdgeOperation.java [new file with mode: 0644]
src/main/java/org/onap/aai/modelloader/gizmo/GizmoVertex.java [new file with mode: 0644]
src/main/java/org/onap/aai/modelloader/gizmo/GizmoVertexOperation.java [new file with mode: 0644]
src/main/java/org/onap/aai/modelloader/restclient/AaiRestClient.java
src/main/java/org/onap/aai/modelloader/util/GizmoTranslator.java [new file with mode: 0644]
src/test/java/org/onap/aai/modelloader/util/GizmoTranslatorTest.java [new file with mode: 0644]

index 01505ba..6a45f28 100644 (file)
@@ -81,6 +81,7 @@ public class ModelLoaderConfig implements IConfiguration {
     protected static final String PROP_AAI_VNF_IMAGE_RESOURCE_URL = PREFIX_AAI + "VNF_IMAGE_URL";
     protected static final String PROP_AAI_AUTHENTICATION_USER = PREFIX_AAI + "AUTH_USER";
     protected static final String PROP_AAI_AUTHENTICATION_PASSWORD = PREFIX_AAI + "AUTH_PASSWORD";
+    protected static final String PROP_AAI_USE_GIZMO = PREFIX_AAI + "USE_GIZMO";
 
     protected static final String PROP_BABEL_BASE_URL = PREFIX_BABEL + "BASE_URL";
     protected static final String PROP_BABEL_KEYSTORE_FILE = PREFIX_BABEL + SUFFIX_KEYSTORE_FILE;
@@ -289,6 +290,16 @@ public class ModelLoaderConfig implements IConfiguration {
         this.modelVersion = modelVersion;
     }
 
+    public boolean useGizmo() {
+        String useGizmo = modelLoaderProperties.getProperty(PROP_AAI_USE_GIZMO);
+
+        if ( (useGizmo == null) || (!useGizmo.equalsIgnoreCase("true")) ) {
+            return false;
+        }
+
+        return true;
+    }
+
     /**
      * @return password for AAI authentication that has been reverse-engineered from its obfuscated form.
      */
index 35c672a..f310ae3 100644 (file)
@@ -1,5 +1,5 @@
 /**
- * ============LICENSE_START=======================================================
+ * ============LICENSE_START=======================================================
  * org.onap.aai
  * ================================================================================
  * Copyright © 2017-2018 AT&T Intellectual Property. All rights reserved.
@@ -23,13 +23,25 @@ package org.onap.aai.modelloader.entity.model;
 import java.util.HashSet;
 import java.util.List;
 import java.util.Set;
+
+import javax.ws.rs.core.MediaType;
+
+import org.onap.aai.cl.api.Logger;
+import org.onap.aai.cl.eelf.LoggerFactory;
 import org.onap.aai.modelloader.config.ModelLoaderConfig;
 import org.onap.aai.modelloader.entity.Artifact;
 import org.onap.aai.modelloader.entity.ArtifactType;
 import org.onap.aai.modelloader.restclient.AaiRestClient;
+import org.onap.aai.modelloader.service.ModelLoaderMsgs;
+import org.onap.aai.modelloader.util.GizmoTranslator;
+import org.onap.aai.restclient.client.OperationResult;
+import org.springframework.http.HttpStatus;
+
 
 public abstract class AbstractModelArtifact extends Artifact implements IModelArtifact {
 
+    private static Logger logger = LoggerFactory.getInstance().getLogger(AbstractModelArtifact.class.getName());
+    
     private String modelNamespace;
     private String modelNamespaceVersion;
     private Set<String> referencedModelIds = new HashSet<>();
@@ -71,6 +83,32 @@ public abstract class AbstractModelArtifact extends Artifact implements IModelAr
 
     public abstract void rollbackModel(AaiRestClient aaiClient, ModelLoaderConfig config, String distId);
 
+    protected boolean pushToGizmo(AaiRestClient aaiClient, ModelLoaderConfig config, String distId, List<Artifact> completedArtifacts) { 
+        try {
+            String gizmoPayload = GizmoTranslator.translate(getPayload());
+            OperationResult postResponse =
+                    aaiClient.postResource(config.getAaiBaseUrl().trim(), gizmoPayload, distId, MediaType.APPLICATION_JSON_TYPE);
+            
+            if (postResponse.getResultCode() != HttpStatus.OK.value()) {
+                return false;
+            }
+            
+        } catch (Exception e) {
+            logErrorMsg("Ingest failed for " + getType().toString() + " " + getUniqueIdentifier() + ": " + e.getMessage());
+            return false;
+        }
+
+        return true;
+    }
+    
+    protected void logInfoMsg(String infoMsg) {
+        logger.info(ModelLoaderMsgs.DISTRIBUTION_EVENT, infoMsg);
+    }
+
+    protected void logErrorMsg(String errorMsg) {
+        logger.error(ModelLoaderMsgs.DISTRIBUTION_EVENT_ERROR, errorMsg);
+    }
+    
     @Override
     public String toString() {
         StringBuilder sb = new StringBuilder();
index 705ceb5..175f858 100644 (file)
@@ -1,5 +1,5 @@
 /**
- * ============LICENSE_START=======================================================
+ * ============LICENSE_START=======================================================
  * org.onap.aai
  * ================================================================================
  * Copyright © 2017-2018 AT&T Intellectual Property. All rights reserved.
@@ -31,16 +31,16 @@ import javax.xml.transform.TransformerException;
 import javax.xml.transform.TransformerFactory;
 import javax.xml.transform.dom.DOMSource;
 import javax.xml.transform.stream.StreamResult;
-import org.onap.aai.cl.api.Logger;
-import org.onap.aai.cl.eelf.LoggerFactory;
+
 import org.onap.aai.modelloader.config.ModelLoaderConfig;
-import org.onap.aai.modelloader.entity.Artifact;
 import org.onap.aai.modelloader.entity.ArtifactType;
 import org.onap.aai.modelloader.restclient.AaiRestClient;
-import org.onap.aai.modelloader.service.ModelLoaderMsgs;
+import org.onap.aai.modelloader.entity.Artifact;
 import org.onap.aai.restclient.client.OperationResult;
+
 import org.w3c.dom.Node;
 
+
 public class ModelArtifact extends AbstractModelArtifact {
 
     private static final String AAI_MODEL_VER_SUB_URL = "/model-vers/model-ver";
@@ -48,7 +48,6 @@ public class ModelArtifact extends AbstractModelArtifact {
     private static final String FAILURE_MSG_PREFIX = "Ingestion failed for ";
     private static final String ROLLBACK_MSG_SUFFIX = ". Rolling back distribution.";
 
-    private static Logger logger = LoggerFactory.getInstance().getLogger(ModelArtifact.class.getName());
 
     private String modelVerId;
     private String modelInvariantId;
@@ -119,6 +118,15 @@ public class ModelArtifact extends AbstractModelArtifact {
 
     @Override
     public boolean push(AaiRestClient aaiClient, ModelLoaderConfig config, String distId,
+            List<Artifact> completedArtifacts) {        
+        if (config.useGizmo()) {
+            return pushToGizmo(aaiClient, config, distId, completedArtifacts);
+        }
+
+        return pushToResources(aaiClient, config, distId, completedArtifacts);
+    }
+    
+    private boolean pushToResources(AaiRestClient aaiClient, ModelLoaderConfig config, String distId,
             List<Artifact> completedArtifacts) {
         boolean success;
 
@@ -145,7 +153,7 @@ public class ModelArtifact extends AbstractModelArtifact {
         }
 
         return success;
-    }
+    }    
 
     /**
      * @param aaiClient
@@ -184,6 +192,12 @@ public class ModelArtifact extends AbstractModelArtifact {
 
     @Override
     public void rollbackModel(AaiRestClient aaiClient, ModelLoaderConfig config, String distId) {
+        // Gizmo is resilient and doesn't require a rollback.  A redistribution will work fine even if 
+        // the model is partially loaded.
+        if (config.useGizmo()) {
+            return;
+        }
+        
         String url = getModelVerUrl(config);
         if (firstVersionOfModel) {
             // If this was the first version of the model which was added, we want to remove the entire
@@ -195,15 +209,6 @@ public class ModelArtifact extends AbstractModelArtifact {
         aaiClient.getAndDeleteResource(url, distId);
     }
 
-
-    private void logInfoMsg(String infoMsg) {
-        logger.info(ModelLoaderMsgs.DISTRIBUTION_EVENT, infoMsg);
-    }
-
-    private void logErrorMsg(String errorMsg) {
-        logger.error(ModelLoaderMsgs.DISTRIBUTION_EVENT_ERROR, errorMsg);
-    }
-
     private String getModelUrl(ModelLoaderConfig config) {
         String baseURL = config.getAaiBaseUrl().trim();
         String subURL = config.getAaiModelUrl(getModelNamespaceVersion()).trim();
index a8fdc8e..ba5d12b 100644 (file)
@@ -1,5 +1,5 @@
 /**
- * ============LICENSE_START=======================================================
+ * ============LICENSE_START=======================================================
  * org.onap.aai
  * ================================================================================
  * Copyright © 2017-2018 AT&T Intellectual Property. All rights reserved.
@@ -23,18 +23,16 @@ package org.onap.aai.modelloader.entity.model;
 import java.util.List;
 import javax.ws.rs.core.MediaType;
 import javax.ws.rs.core.Response;
-import org.onap.aai.cl.api.Logger;
-import org.onap.aai.cl.eelf.LoggerFactory;
+
 import org.onap.aai.modelloader.config.ModelLoaderConfig;
-import org.onap.aai.modelloader.entity.Artifact;
 import org.onap.aai.modelloader.entity.ArtifactType;
 import org.onap.aai.modelloader.restclient.AaiRestClient;
-import org.onap.aai.modelloader.service.ModelLoaderMsgs;
+
+import org.onap.aai.modelloader.entity.Artifact;
 import org.onap.aai.restclient.client.OperationResult;
 
-public class NamedQueryArtifact extends AbstractModelArtifact {
 
-    private Logger logger = LoggerFactory.getInstance().getLogger(NamedQueryArtifact.class.getName());
+public class NamedQueryArtifact extends AbstractModelArtifact {
 
     private String namedQueryUuid;
 
@@ -56,7 +54,15 @@ public class NamedQueryArtifact extends AbstractModelArtifact {
     }
 
     @Override
-    public boolean push(AaiRestClient aaiClient, ModelLoaderConfig config, String distId,
+    public boolean push(AaiRestClient aaiClient, ModelLoaderConfig config, String distId, List<Artifact> completedArtifacts) {
+        if (config.useGizmo()) {
+            return pushToGizmo(aaiClient, config, distId, completedArtifacts);
+        }
+
+        return pushToResources(aaiClient, config, distId, completedArtifacts);
+    }
+
+    private boolean pushToResources(AaiRestClient aaiClient, ModelLoaderConfig config, String distId,
             List<Artifact> completedArtifacts) {
         OperationResult getResponse =
                 aaiClient.getResource(getNamedQueryUrl(config), distId, MediaType.APPLICATION_XML_TYPE);
@@ -66,16 +72,14 @@ public class NamedQueryArtifact extends AbstractModelArtifact {
                     MediaType.APPLICATION_XML_TYPE);
             if (putResponse != null && putResponse.getResultCode() == Response.Status.CREATED.getStatusCode()) {
                 completedArtifacts.add(this);
-                logger.info(ModelLoaderMsgs.DISTRIBUTION_EVENT,
-                        getType().toString() + " " + getUniqueIdentifier() + " successfully ingested.");
+                logInfoMsg(getType().toString() + " " + getUniqueIdentifier() + " successfully ingested.");
             } else {
-                logger.error(ModelLoaderMsgs.DISTRIBUTION_EVENT_ERROR, "Ingestion failed for " + getType().toString()
+                logErrorMsg("Ingestion failed for " + getType().toString()
                         + " " + getUniqueIdentifier() + ". Rolling back distribution.");
                 return false;
             }
         } else {
-            logger.info(ModelLoaderMsgs.DISTRIBUTION_EVENT,
-                    getType().toString() + " " + getUniqueIdentifier() + " already exists.  Skipping ingestion.");
+            logInfoMsg(getType().toString() + " " + getUniqueIdentifier() + " already exists.  Skipping ingestion.");
         }
 
         return true;
@@ -83,6 +87,12 @@ public class NamedQueryArtifact extends AbstractModelArtifact {
 
     @Override
     public void rollbackModel(AaiRestClient aaiClient, ModelLoaderConfig config, String distId) {
+        // Gizmo is resilient and doesn't require a rollback.  A redistribution will work fine even if 
+        // the model is partially loaded.
+        if (config.useGizmo()) {
+            return;
+        }
+        
         // Best effort to delete. Nothing we can do in the event this fails.
         aaiClient.getAndDeleteResource(getNamedQueryUrl(config), distId);
     }
diff --git a/src/main/java/org/onap/aai/modelloader/gizmo/GizmoBulkPayload.java b/src/main/java/org/onap/aai/modelloader/gizmo/GizmoBulkPayload.java
new file mode 100644 (file)
index 0000000..11aa35d
--- /dev/null
@@ -0,0 +1,112 @@
+/**
+ * ============LICENSE_START=======================================================
+ * org.onap.aai
+ * ================================================================================
+ * Copyright © 2017-2018 AT&T Intellectual Property. All rights reserved.
+ * Copyright © 2017-2018 European Software Marketing Ltd.
+ * ================================================================================
+ * 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.
+ * ============LICENSE_END=========================================================
+ */
+package org.onap.aai.modelloader.gizmo;
+
+import com.google.gson.Gson;
+import com.google.gson.GsonBuilder;
+import com.google.gson.JsonElement;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class GizmoBulkPayload {
+
+    public static final String ADD_OP = "add";
+    public static final String UPDATE_OP = "modify";
+    public static final String DELETE_OP = "delete";
+    public static final String PATCH_OP = "patch";
+    public static final String EXISTS_OP = "exists";
+    public static final String ALL_OPS = "all";
+    public static final String OP_KEY = "operation";
+
+
+    private List<JsonElement> objects = new ArrayList<JsonElement>();
+    private List<JsonElement> relationships = new ArrayList<JsonElement>();
+
+    private static final Gson gson = new GsonBuilder().disableHtmlEscaping().create();
+
+    public String toJson() {
+        return gson.toJson(this);
+    }
+
+    public static GizmoBulkPayload fromJson(String payload) {
+        return gson.fromJson(payload, GizmoBulkPayload.class);
+    }
+
+    public List<JsonElement> getObjects() {
+        return objects;
+    }
+
+    public void setObjects(List<JsonElement> objects) {
+        this.objects = objects;
+    }
+
+    public List<JsonElement> getRelationships() {
+        return relationships;
+    }
+
+    public void setRelationships(List<JsonElement> relationships) {
+        this.relationships = relationships;
+    }
+
+    public List<GizmoVertexOperation> getVertexOperations() {
+        return getVertexOperations(ALL_OPS);
+    }
+    
+    public List<GizmoVertexOperation> getVertexOperations(String opType) {
+        List<GizmoVertexOperation> ops = new ArrayList<GizmoVertexOperation>();
+        for (JsonElement v : getObjects()) {
+            GizmoVertexOperation op = GizmoVertexOperation.fromJsonElement(v);
+                        
+            if ( (opType.equalsIgnoreCase(ALL_OPS)) || (op.getOperation().equalsIgnoreCase(opType)) ) {
+                ops.add(op);
+            }
+        }
+        
+        return ops;
+    }
+    
+    public void addVertexOperation(GizmoVertexOperation newOp) {
+        objects.add(newOp.toJsonElement());
+    }
+    
+    public List<GizmoEdgeOperation> getEdgeOperations() {
+        return getEdgeOperations(ALL_OPS);
+    }
+    
+    public List<GizmoEdgeOperation> getEdgeOperations(String opType) {
+        List<GizmoEdgeOperation> ops = new ArrayList<GizmoEdgeOperation>();
+
+        for (JsonElement v : getRelationships()) {
+            GizmoEdgeOperation op = GizmoEdgeOperation.fromJsonElement(v);
+                        
+            if ( (opType.equalsIgnoreCase(ALL_OPS)) || (op.getOperation().equalsIgnoreCase(opType)) ) {
+                ops.add(op);
+            }
+        }
+        
+        return ops;
+    }
+    
+    public void addEdgeOperation(GizmoEdgeOperation newOp) {
+        relationships.add(newOp.toJsonElement());
+    }
+}
diff --git a/src/main/java/org/onap/aai/modelloader/gizmo/GizmoEdge.java b/src/main/java/org/onap/aai/modelloader/gizmo/GizmoEdge.java
new file mode 100644 (file)
index 0000000..3e1e602
--- /dev/null
@@ -0,0 +1,68 @@
+/**
+ * ============LICENSE_START=======================================================
+ * org.onap.aai
+ * ================================================================================
+ * Copyright © 2017-2018 AT&T Intellectual Property. All rights reserved.
+ * Copyright © 2017-2018 European Software Marketing Ltd.
+ * ================================================================================
+ * 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.
+ * ============LICENSE_END=========================================================
+ */
+package org.onap.aai.modelloader.gizmo;
+
+
+import com.google.gson.Gson;
+import com.google.gson.GsonBuilder;
+
+
+public class GizmoEdge {
+    private static final Gson gson = new GsonBuilder().create();
+    
+    private String type;
+    private String source;
+    private String target;
+
+    public String toJson() {
+        return gson.toJson(this);
+    }
+
+    public static GizmoEdge fromJson(String jsonString) {
+        return gson.fromJson(jsonString, GizmoEdge.class);
+    }
+
+    public String getType() {
+        return type;
+    }
+
+    public void setType(String type) {
+        this.type = type;
+    }
+
+    public String getSource() {
+        return source;
+    }
+
+    public void setSource(String source) {
+        this.source = source;
+    }
+
+    public String getTarget() {
+        return target;
+    }
+
+    public void setTarget(String target) {
+        this.target = target;
+    }
+
+}
+
diff --git a/src/main/java/org/onap/aai/modelloader/gizmo/GizmoEdgeOperation.java b/src/main/java/org/onap/aai/modelloader/gizmo/GizmoEdgeOperation.java
new file mode 100644 (file)
index 0000000..eb578b5
--- /dev/null
@@ -0,0 +1,90 @@
+/**
+ * ============LICENSE_START=======================================================
+ * org.onap.aai
+ * ================================================================================
+ * Copyright © 2017-2018 AT&T Intellectual Property. All rights reserved.
+ * Copyright © 2017-2018 European Software Marketing Ltd.
+ * ================================================================================
+ * 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.
+ * ============LICENSE_END=========================================================
+ */
+package org.onap.aai.modelloader.gizmo;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+
+import com.google.gson.JsonElement;
+import com.google.gson.JsonObject;
+import com.google.gson.JsonParser;
+
+public class GizmoEdgeOperation {
+    private String operation;
+    private String internalId;
+    private GizmoEdge edge;
+    
+    public GizmoEdgeOperation(String op, String id, GizmoEdge edge) {
+        this.operation = op;
+        this.internalId = id;
+        this.edge = edge;
+    }
+    
+    public JsonElement toJsonElement() {
+        JsonObject opObj = new JsonObject();
+        JsonParser parser = new JsonParser();
+        JsonObject edgeObj = parser.parse(edge.toJson()).getAsJsonObject();
+        
+        opObj.addProperty(GizmoBulkPayload.OP_KEY, operation);
+        opObj.add(internalId, edgeObj);
+        
+        return opObj;
+    }
+    
+    public static GizmoEdgeOperation fromJsonElement(JsonElement element) {
+        List<Map.Entry<String, JsonElement>> entries = 
+                new ArrayList<Map.Entry<String, JsonElement>>(element.getAsJsonObject().entrySet());
+        
+        String op = null;
+        String id = null;
+        GizmoEdge edge = null;
+        
+        for (Map.Entry<String, JsonElement> entry : entries) {
+            if (entry.getKey().equalsIgnoreCase(GizmoBulkPayload.OP_KEY)) {
+                op = entry.getValue().getAsString();
+            }
+            else {
+                id = entry.getKey();
+                edge = GizmoEdge.fromJson(entry.getValue().getAsJsonObject().toString());
+            }
+        }
+        
+        if (op == null) {
+            // Use default
+            op = GizmoBulkPayload.EXISTS_OP;
+        }
+        
+        return new GizmoEdgeOperation(op, id, edge);      
+    }
+
+    public String getOperation() {
+        return operation;
+    }
+
+    public String getInternalId() {
+        return internalId;
+    }
+
+    public GizmoEdge getEdge() {
+        return edge;
+    }
+}
diff --git a/src/main/java/org/onap/aai/modelloader/gizmo/GizmoVertex.java b/src/main/java/org/onap/aai/modelloader/gizmo/GizmoVertex.java
new file mode 100644 (file)
index 0000000..9de94cd
--- /dev/null
@@ -0,0 +1,71 @@
+/**
+ * ============LICENSE_START=======================================================
+ * org.onap.aai
+ * ================================================================================
+ * Copyright © 2017-2018 AT&T Intellectual Property. All rights reserved.
+ * Copyright © 2017-2018 European Software Marketing Ltd.
+ * ================================================================================
+ * 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.
+ * ============LICENSE_END=========================================================
+ */
+package org.onap.aai.modelloader.gizmo;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import com.google.gson.Gson;
+import com.google.gson.GsonBuilder;
+
+public class GizmoVertex {
+    private static final Gson gson = new GsonBuilder().create();
+
+    private String type;
+    private Map<String, String> properties;
+
+    public String toJson() {
+        return gson.toJson(this);
+    }
+
+    public static GizmoVertex fromJson(String jsonString) {
+        return gson.fromJson(jsonString, GizmoVertex.class);
+    }
+
+    public String getType() {
+        return type;
+    }
+
+    public void setType(String type) {
+        this.type = type;
+    }
+
+    public Map<String, String> getProperties() {
+        return properties;
+    }
+
+    public String getProperty(String key) {
+        return properties.get(key);
+    }
+
+    public void setProperties(Map<String, String> properties) {
+        this.properties = properties;
+    }
+
+    public void setProperty(String key, String value) {
+        if (properties == null) {
+            properties = new HashMap<String,String>();
+        }
+
+        properties.put(key, value);
+    }
+
+}
diff --git a/src/main/java/org/onap/aai/modelloader/gizmo/GizmoVertexOperation.java b/src/main/java/org/onap/aai/modelloader/gizmo/GizmoVertexOperation.java
new file mode 100644 (file)
index 0000000..3adc284
--- /dev/null
@@ -0,0 +1,94 @@
+/**
+ * ============LICENSE_START=======================================================
+ * org.onap.aai
+ * ================================================================================
+ * Copyright © 2017-2018 AT&T Intellectual Property. All rights reserved.
+ * Copyright © 2017-2018 European Software Marketing Ltd.
+ * ================================================================================
+ * 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.
+ * ============LICENSE_END=========================================================
+ */
+package org.onap.aai.modelloader.gizmo;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+
+import com.google.gson.JsonElement;
+import com.google.gson.JsonObject;
+import com.google.gson.JsonParser;
+
+public class GizmoVertexOperation {
+    private String operation;
+    private String internalId;
+    private GizmoVertex vertex;
+    
+    public GizmoVertexOperation(String op, String id, GizmoVertex vertex) {
+        this.operation = op;
+        this.internalId = id;
+        this.vertex = vertex;
+    }
+    
+    public JsonElement toJsonElement() {
+        JsonObject opObj = new JsonObject();
+        JsonParser parser = new JsonParser();
+        JsonObject vertexObj = parser.parse(vertex.toJson()).getAsJsonObject();
+        
+        opObj.addProperty(GizmoBulkPayload.OP_KEY, getOperation());
+        opObj.add(internalId, vertexObj);
+        
+        return opObj;
+    }
+    
+    public static GizmoVertexOperation fromJsonElement(JsonElement element) {
+        List<Map.Entry<String, JsonElement>> entries = 
+                new ArrayList<Map.Entry<String, JsonElement>>(element.getAsJsonObject().entrySet());
+
+        String op = null;
+        String id = null;
+        GizmoVertex vertex = null;
+
+        for (Map.Entry<String, JsonElement> entry : entries) {
+            if (entry.getKey().equalsIgnoreCase(GizmoBulkPayload.OP_KEY)) {
+                op = entry.getValue().getAsString();
+            }
+            else {
+                id = entry.getKey();
+                vertex = GizmoVertex.fromJson(entry.getValue().getAsJsonObject().toString());
+            }
+        }
+
+        if (op == null) {
+            // Use default
+            op = GizmoBulkPayload.EXISTS_OP;
+        }
+
+        return new GizmoVertexOperation(op, id, vertex);
+    }
+
+    public String getOperation() {
+        return operation;
+    }
+    
+    public void setOperation(String op) {
+        operation = op;
+    }
+
+    public String getInternalId() {
+        return internalId;
+    }
+
+    public GizmoVertex getVertex() {
+        return vertex;
+    }
+}
index 27db741..a2a4c5b 100644 (file)
@@ -161,7 +161,9 @@ public class AaiRestClient {
         restClient.validateServerHostname(false)
                 .validateServerCertChain(false)
                 .clientCertFile(config.getAaiKeyStorePath())
-                .clientCertPassword(config.getAaiKeyStorePassword());
+                .clientCertPassword(config.getAaiKeyStorePassword())
+                .connectTimeoutMs(120000)
+                .readTimeoutMs(120000);
         // @formatter:on
 
         if (useBasicAuth()) {
diff --git a/src/main/java/org/onap/aai/modelloader/util/GizmoTranslator.java b/src/main/java/org/onap/aai/modelloader/util/GizmoTranslator.java
new file mode 100644 (file)
index 0000000..69e5971
--- /dev/null
@@ -0,0 +1,288 @@
+/**
+ * ============LICENSE_START==========================================
+ * org.onap.aai
+ * ===================================================================
+ * Copyright © 2017-2018 AT&T Intellectual Property. All rights reserved.
+ * Copyright © 2017-2018 Amdocs
+ * ===================================================================
+ * 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.
+ * ============LICENSE_END============================================
+ */
+package org.onap.aai.modelloader.util;
+
+import java.io.IOException;
+import java.io.StringReader;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+
+import javax.xml.parsers.DocumentBuilder;
+import javax.xml.parsers.DocumentBuilderFactory;
+import javax.xml.parsers.ParserConfigurationException;
+
+import org.onap.aai.cl.api.Logger;
+import org.onap.aai.cl.eelf.LoggerFactory;
+import org.onap.aai.modelloader.gizmo.GizmoBulkPayload;
+import org.onap.aai.modelloader.gizmo.GizmoEdge;
+import org.onap.aai.modelloader.gizmo.GizmoEdgeOperation;
+import org.onap.aai.modelloader.gizmo.GizmoVertex;
+import org.onap.aai.modelloader.gizmo.GizmoVertexOperation;
+import org.onap.aai.modelloader.service.ModelLoaderMsgs;
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+import org.w3c.dom.Node;
+import org.w3c.dom.NodeList;
+import org.xml.sax.InputSource;
+import org.xml.sax.SAXException;
+
+public class GizmoTranslator {
+    
+    private enum NodeType {
+        VERTEX,
+        ATTRIBUTE,
+        CONTAINER,
+        RELATIONSHIP_LIST,
+        RELATIONSHIP,
+        RELATED_TO,
+        RELATIONSHIP_DATA,
+        RELATIONSHIP_KEY,
+        RELATIONSHIP_VALUE,
+        MODEL_ELEMENT_VERTEX,
+        NQ_ELEMENT_VERTEX,
+        UNKNOWN
+    }
+    
+    private static Logger logger = LoggerFactory.getInstance().getLogger(GizmoTranslator.class.getName());
+    
+    public static String translate(String xmlPayload) throws ParserConfigurationException, SAXException, IOException {
+        DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
+        factory.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true);
+        DocumentBuilder builder = factory.newDocumentBuilder();
+        InputSource is = new InputSource(new StringReader(xmlPayload));
+        Document doc = builder.parse(is);
+        
+        GizmoBulkPayload gizmoPayload = new GizmoBulkPayload();
+        
+        processNode(doc.getDocumentElement(), null, null, gizmoPayload);
+        
+        return gizmoPayload.toJson();
+    }
+
+    private static void processNode(Node node, Node parentNode, GizmoVertexOperation parentVertexOp, GizmoBulkPayload gizmoPayload) {
+        if (!(node instanceof Element)) {
+            return;
+        }
+
+        Node newParent = null;
+        NodeType nodeType = getNodeType(node);
+        
+        switch (nodeType) {
+        case VERTEX: 
+        case MODEL_ELEMENT_VERTEX:
+        case NQ_ELEMENT_VERTEX:
+            parentVertexOp = createGizmoVertexOp(node, GizmoBulkPayload.ADD_OP);
+            gizmoPayload.addVertexOperation(parentVertexOp);
+            if (parentNode != null) {
+                gizmoPayload.addEdgeOperation(createGizmoEdgeOp(node, parentNode));
+            }
+            newParent = node;
+            break;
+        case RELATIONSHIP:
+            processRelationship((Element)node, parentVertexOp, gizmoPayload);
+            newParent = parentNode;
+            break;
+        default:
+            newParent = parentNode;
+            break;
+        }
+        
+        NodeList childNodes = node.getChildNodes();
+        for (int ix = 0; ix < childNodes.getLength(); ix++) {
+            processNode(childNodes.item(ix), newParent, parentVertexOp, gizmoPayload);
+        }
+    }
+
+    private static void processRelationship(Element relationshipNode, GizmoVertexOperation sourceNode, GizmoBulkPayload gizmoPayload) {
+        NodeList relatedToList = relationshipNode.getElementsByTagName("related-to");
+        if (relatedToList.getLength() != 1) {
+            logger.error(ModelLoaderMsgs.DISTRIBUTION_EVENT_ERROR, "Unable to resolve relationship");
+            return;
+        }
+        
+        GizmoVertex targetVertex = new GizmoVertex();
+        targetVertex.setType(relatedToList.item(0).getTextContent().trim());
+        
+        NodeList relationData = relationshipNode.getElementsByTagName("relationship-data");
+        for (int ix = 0; ix < relationData.getLength(); ix++) {
+            Element relationNode = (Element)relationData.item(ix);
+            NodeList keyList = relationNode.getElementsByTagName("relationship-key");
+            NodeList valueList = relationNode.getElementsByTagName("relationship-value");
+            
+            if ( (keyList.getLength() != 1) || (valueList.getLength() != 1) ) {
+                logger.error(ModelLoaderMsgs.DISTRIBUTION_EVENT_ERROR, "Unable to resolve relationship.  Missing key/value.");
+                return;
+            }
+            
+            String[] keyBits = keyList.item(0).getTextContent().trim().split("\\.");
+            String value = valueList.item(0).getTextContent().trim();
+            
+            if (keyBits[0].equalsIgnoreCase(targetVertex.getType())) {
+                targetVertex.setProperty(keyBits[1], value);
+            }
+        }
+        
+        gizmoPayload.addVertexOperation(new GizmoVertexOperation(GizmoBulkPayload.EXISTS_OP, getVertexId(targetVertex), targetVertex));
+        
+        GizmoEdge edge = new GizmoEdge();
+        
+        edge.setSource("$" + getVertexId(sourceNode.getVertex()));
+        edge.setTarget("$" + getVertexId(targetVertex));
+        
+        gizmoPayload.addEdgeOperation(new GizmoEdgeOperation(GizmoBulkPayload.ADD_OP, edge.getSource() + "_" + edge.getTarget(), edge));
+    }
+
+    private static GizmoEdgeOperation createGizmoEdgeOp(Node node, Node parentNode) {
+        GizmoEdge edge = new GizmoEdge();
+        
+        edge.setSource("$" + getVertexId(createGizmoVertex(node)));
+        edge.setTarget("$" + getVertexId(createGizmoVertex(parentNode)));
+        
+        GizmoEdgeOperation edgeOp = new GizmoEdgeOperation(GizmoBulkPayload.ADD_OP, edge.getSource() + "_" + edge.getTarget(), edge);
+        
+        return edgeOp;
+    }
+
+    private static GizmoVertexOperation createGizmoVertexOp(Node node, String operationType) {
+        GizmoVertex vertex = createGizmoVertex(node);  
+        GizmoVertexOperation addOp = new GizmoVertexOperation(operationType, getVertexId(vertex), vertex);
+        return addOp;
+    }
+
+    private static String getVertexId(GizmoVertex vertex) {
+        StringBuilder sb = new StringBuilder();
+        sb.append(vertex.getType());
+        for (Map.Entry<String, String> entry : vertex.getProperties().entrySet()) {
+            sb.append("-" + entry.getValue());
+        }
+        
+        return sb.toString();
+    }
+
+    private static GizmoVertex createGizmoVertex(Node node) {
+        GizmoVertex vertex = new GizmoVertex();
+        vertex.setType(node.getNodeName().trim());
+
+        NodeList childNodes = node.getChildNodes();
+
+        for (int ix = 0; ix < childNodes.getLength(); ix++) {
+            if (getNodeType(childNodes.item(ix)).equals(NodeType.ATTRIBUTE)) {
+                vertex.setProperty(childNodes.item(ix).getNodeName().trim(), childNodes.item(ix).getTextContent().trim());
+            }
+        }
+        
+        // Special case for model-element, where we need to generate an id field
+        if (getNodeType(node).equals(NodeType.MODEL_ELEMENT_VERTEX)) {
+            vertex.setProperty("model-element-uuid", generateModelElementId((Element)node));
+        }
+        
+        // Special case for nq-element, where we need to generate an id field
+        if (getNodeType(node).equals(NodeType.NQ_ELEMENT_VERTEX)) {
+            vertex.setProperty("named-query-element-uuid", generateModelElementId((Element)node));
+        }
+
+        return vertex;
+    }
+    
+    // Generate a unique hash to store as the id for this node
+    private static String generateModelElementId(Element node) {
+        Set<String> elemSet = new HashSet<String>();
+        
+        NodeList childNodes = node.getElementsByTagName("*");
+        for (int ix = 0; ix < childNodes.getLength(); ix++) {
+            NodeType nt = getNodeType(childNodes.item(ix));
+            if ( nt.equals(NodeType.ATTRIBUTE) || nt.equals(NodeType.RELATIONSHIP_KEY) || nt.equals(NodeType.RELATIONSHIP_VALUE) ) {
+                elemSet.add(childNodes.item(ix).getTextContent().trim());
+            }
+        }
+                
+        return Integer.toString(elemSet.hashCode());
+    }
+
+    private static NodeType getNodeType(Node node) {
+        if (!(node instanceof Element)) {
+            return NodeType.UNKNOWN;
+        }
+        
+        if (node.getNodeName().equalsIgnoreCase("relationship-list")) {
+            return NodeType.RELATIONSHIP_LIST;
+        }
+        
+        if (node.getNodeName().equalsIgnoreCase("relationship")) {
+            return NodeType.RELATIONSHIP;
+        }
+        
+        if (node.getNodeName().equalsIgnoreCase("relationship-data")) {
+            return NodeType.RELATIONSHIP_DATA;
+        }
+        
+        if (node.getNodeName().equalsIgnoreCase("related-to")) {
+            return NodeType.RELATED_TO;
+        }
+        
+        if (node.getNodeName().equalsIgnoreCase("relationship-key")) {
+            return NodeType.RELATIONSHIP_KEY;
+        }
+        
+        if (node.getNodeName().equalsIgnoreCase("relationship-value")) {
+            return NodeType.RELATIONSHIP_VALUE;
+        }
+        
+        if (node.getNodeName().equalsIgnoreCase("model-element")) {
+            return NodeType.MODEL_ELEMENT_VERTEX;
+        }
+        
+        if (node.getNodeName().equalsIgnoreCase("named-query-element")) {
+            return NodeType.NQ_ELEMENT_VERTEX;
+        }
+        
+        NodeList childNodes = node.getChildNodes();
+        int childElements = countChildElements(childNodes);
+        
+        if ( (childElements == 0) && (node.getTextContent() != null) && (!node.getTextContent().trim().isEmpty()) ) {
+            return NodeType.ATTRIBUTE;
+        }
+        
+        for (int ix = 0; ix < childNodes.getLength(); ix++) {
+            if (getNodeType(childNodes.item(ix)) == NodeType.ATTRIBUTE) {
+                return NodeType.VERTEX;
+            }
+        }
+        
+        if (childElements > 0) {
+            return NodeType.CONTAINER;
+        }
+        
+        return NodeType.UNKNOWN;
+    }
+    
+    static int countChildElements(NodeList nodes) {
+        int count = 0;
+        for (int ix = 0; ix < nodes.getLength(); ix++) {
+            if (nodes.item(ix) instanceof Element) {
+                count++;
+            }
+        }
+        
+        return count;   
+    }
+}
diff --git a/src/test/java/org/onap/aai/modelloader/util/GizmoTranslatorTest.java b/src/test/java/org/onap/aai/modelloader/util/GizmoTranslatorTest.java
new file mode 100644 (file)
index 0000000..5891931
--- /dev/null
@@ -0,0 +1,116 @@
+/**
+ * ============LICENSE_START=======================================================
+ * org.onap.aai
+ * ================================================================================
+ * Copyright © 2017-2018 AT&T Intellectual Property. All rights reserved.
+ * Copyright © 2017-2018 European Software Marketing Ltd.
+ * ================================================================================
+ * 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.
+ * ============LICENSE_END=========================================================
+ */
+package org.onap.aai.modelloader.util;
+
+import static org.junit.Assert.assertTrue;
+
+import java.nio.file.Files;
+import java.nio.file.Paths;
+import java.util.List;
+
+import org.junit.Test;
+import org.onap.aai.modelloader.gizmo.GizmoBulkPayload;
+import org.onap.aai.modelloader.gizmo.GizmoEdgeOperation;
+import org.onap.aai.modelloader.gizmo.GizmoVertexOperation;
+
+public class GizmoTranslatorTest {
+    
+    @Test
+    public void translateXmlModel1() throws Exception {
+        final String XML_MODEL_FILE = "src/test/resources/models/AAI-stellService-service-1.xml";
+
+        try {
+            byte[] encoded = Files.readAllBytes(Paths.get(XML_MODEL_FILE));
+            String originalXml = new String(encoded);
+            
+            String output = GizmoTranslator.translate(originalXml);
+            System.out.println("Test1 Outgoing:\n" + output);
+            
+            GizmoBulkPayload request = GizmoBulkPayload.fromJson(output);
+            
+            List<GizmoVertexOperation> ops = request.getVertexOperations(GizmoBulkPayload.ADD_OP);
+            assertTrue(ops.size() == 5);
+            
+            ops = request.getVertexOperations(GizmoBulkPayload.EXISTS_OP);
+            assertTrue(ops.size() == 3);
+            
+            List<GizmoEdgeOperation> edgeOps = request.getEdgeOperations(GizmoBulkPayload.ADD_OP);
+            assertTrue(edgeOps.size() == 7);                 
+        } catch (Exception e) {
+            e.printStackTrace();
+            assertTrue(false);
+        }     
+    }
+    
+    @Test
+    public void translateXmlModel2() throws Exception {
+        final String XML_MODEL_FILE2 = "src/test/resources/models/l3-network-widget.xml";
+
+        try {
+            byte[] encoded = Files.readAllBytes(Paths.get(XML_MODEL_FILE2));
+            String originalXml = new String(encoded);
+            
+            String output = GizmoTranslator.translate(originalXml);
+            System.out.println("Test2 Outgoing:\n" + output);
+            
+            GizmoBulkPayload request = GizmoBulkPayload.fromJson(output);
+            
+            List<GizmoVertexOperation> ops = request.getVertexOperations(GizmoBulkPayload.ADD_OP);
+            assertTrue(ops.size() == 2);
+            
+            ops = request.getVertexOperations(GizmoBulkPayload.EXISTS_OP);
+            assertTrue(ops.size() == 0);
+            
+            List<GizmoEdgeOperation> edgeOps = request.getEdgeOperations(GizmoBulkPayload.ADD_OP);
+            assertTrue(edgeOps.size() == 1);                     
+        } catch (Exception e) {
+            e.printStackTrace();
+            assertTrue(false);
+        }     
+    }
+    
+    @Test
+    public void translateXmlNamedQuery() throws Exception {
+        final String XML_MODEL_FILE3 = "src/test/resources/models/named-query-wan-connector.xml";
+
+        try {
+            byte[] encoded = Files.readAllBytes(Paths.get(XML_MODEL_FILE3));
+            String originalXml = new String(encoded);
+            
+            String output = GizmoTranslator.translate(originalXml);
+            System.out.println("Test3 Outgoing:\n" + output);
+            
+            GizmoBulkPayload request = GizmoBulkPayload.fromJson(output);
+            
+            List<GizmoVertexOperation> ops = request.getVertexOperations(GizmoBulkPayload.ADD_OP);
+            assertTrue(ops.size() == 5);
+            
+            ops = request.getVertexOperations(GizmoBulkPayload.EXISTS_OP);
+            assertTrue(ops.size() == 4);
+            
+            List<GizmoEdgeOperation> edgeOps = request.getEdgeOperations(GizmoBulkPayload.ADD_OP);
+            assertTrue(edgeOps.size() == 8);                     
+        } catch (Exception e) {
+            e.printStackTrace();
+            assertTrue(false);
+        }     
+    }
+}