diff options
12 files changed, 936 insertions, 31 deletions
diff --git a/src/main/java/org/onap/aai/modelloader/config/ModelLoaderConfig.java b/src/main/java/org/onap/aai/modelloader/config/ModelLoaderConfig.java index 01505ba..6a45f28 100644 --- a/src/main/java/org/onap/aai/modelloader/config/ModelLoaderConfig.java +++ b/src/main/java/org/onap/aai/modelloader/config/ModelLoaderConfig.java @@ -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. */ diff --git a/src/main/java/org/onap/aai/modelloader/entity/model/AbstractModelArtifact.java b/src/main/java/org/onap/aai/modelloader/entity/model/AbstractModelArtifact.java index 35c672a..f310ae3 100644 --- a/src/main/java/org/onap/aai/modelloader/entity/model/AbstractModelArtifact.java +++ b/src/main/java/org/onap/aai/modelloader/entity/model/AbstractModelArtifact.java @@ -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(); diff --git a/src/main/java/org/onap/aai/modelloader/entity/model/ModelArtifact.java b/src/main/java/org/onap/aai/modelloader/entity/model/ModelArtifact.java index 705ceb5..175f858 100644 --- a/src/main/java/org/onap/aai/modelloader/entity/model/ModelArtifact.java +++ b/src/main/java/org/onap/aai/modelloader/entity/model/ModelArtifact.java @@ -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(); diff --git a/src/main/java/org/onap/aai/modelloader/entity/model/NamedQueryArtifact.java b/src/main/java/org/onap/aai/modelloader/entity/model/NamedQueryArtifact.java index a8fdc8e..ba5d12b 100644 --- a/src/main/java/org/onap/aai/modelloader/entity/model/NamedQueryArtifact.java +++ b/src/main/java/org/onap/aai/modelloader/entity/model/NamedQueryArtifact.java @@ -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 index 0000000..11aa35d --- /dev/null +++ b/src/main/java/org/onap/aai/modelloader/gizmo/GizmoBulkPayload.java @@ -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 index 0000000..3e1e602 --- /dev/null +++ b/src/main/java/org/onap/aai/modelloader/gizmo/GizmoEdge.java @@ -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 index 0000000..eb578b5 --- /dev/null +++ b/src/main/java/org/onap/aai/modelloader/gizmo/GizmoEdgeOperation.java @@ -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 index 0000000..9de94cd --- /dev/null +++ b/src/main/java/org/onap/aai/modelloader/gizmo/GizmoVertex.java @@ -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 index 0000000..3adc284 --- /dev/null +++ b/src/main/java/org/onap/aai/modelloader/gizmo/GizmoVertexOperation.java @@ -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; + } +} diff --git a/src/main/java/org/onap/aai/modelloader/restclient/AaiRestClient.java b/src/main/java/org/onap/aai/modelloader/restclient/AaiRestClient.java index 27db741..a2a4c5b 100644 --- a/src/main/java/org/onap/aai/modelloader/restclient/AaiRestClient.java +++ b/src/main/java/org/onap/aai/modelloader/restclient/AaiRestClient.java @@ -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 index 0000000..69e5971 --- /dev/null +++ b/src/main/java/org/onap/aai/modelloader/util/GizmoTranslator.java @@ -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 index 0000000..5891931 --- /dev/null +++ b/src/test/java/org/onap/aai/modelloader/util/GizmoTranslatorTest.java @@ -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); + } + } +} |