aboutsummaryrefslogtreecommitdiffstats
path: root/aai-resources/src/main/java/org/onap/aai/rest
diff options
context:
space:
mode:
authorVenkata Harish K Kajur <vk250x@att.com>2017-09-28 13:56:02 -0400
committerVenkata Harish K Kajur <vk250x@att.com>2017-09-28 17:46:16 -0400
commitb33b55b16d1c230fb1bf454d7d517f2c2d57941b (patch)
tree4802fbdf61c2e8c1cf19c35cd3dc9b0df96d5ed3 /aai-resources/src/main/java/org/onap/aai/rest
parent9d5eff1a6c19f9af9329f76f3e58d8935eb28dad (diff)
Change package names org.openecomp to org.onap
Issue-ID: AAI-61 AAI-82 Change-Id: Ib1d937fb31b1e737c4651eac9c0193fd05d97f01 Signed-off-by: Venkata Harish K Kajur <vk250x@att.com>
Diffstat (limited to 'aai-resources/src/main/java/org/onap/aai/rest')
-rw-r--r--aai-resources/src/main/java/org/onap/aai/rest/BulkAddConsumer.java43
-rw-r--r--aai-resources/src/main/java/org/onap/aai/rest/BulkConsumer.java485
-rw-r--r--aai-resources/src/main/java/org/onap/aai/rest/BulkProcessConsumer.java43
-rw-r--r--aai-resources/src/main/java/org/onap/aai/rest/ExampleConsumer.java105
-rw-r--r--aai-resources/src/main/java/org/onap/aai/rest/ExceptionHandler.java130
-rw-r--r--aai-resources/src/main/java/org/onap/aai/rest/LegacyMoxyConsumer.java597
-rw-r--r--aai-resources/src/main/java/org/onap/aai/rest/URLFromVertexIdConsumer.java121
-rw-r--r--aai-resources/src/main/java/org/onap/aai/rest/VertexIdConsumer.java146
-rw-r--r--aai-resources/src/main/java/org/onap/aai/rest/exceptions/AAIInvalidXMLNamespace.java41
-rw-r--r--aai-resources/src/main/java/org/onap/aai/rest/retired/RetiredConsumer.java144
-rw-r--r--aai-resources/src/main/java/org/onap/aai/rest/retired/V3ThroughV7Consumer.java29
-rw-r--r--aai-resources/src/main/java/org/onap/aai/rest/retired/V7V8Models.java29
-rw-r--r--aai-resources/src/main/java/org/onap/aai/rest/retired/V7V8NamedQueries.java29
-rw-r--r--aai-resources/src/main/java/org/onap/aai/rest/tools/ModelVersionTransformer.java410
-rw-r--r--aai-resources/src/main/java/org/onap/aai/rest/util/EchoResponse.java122
-rw-r--r--aai-resources/src/main/java/org/onap/aai/rest/util/LogFormatTools.java37
-rw-r--r--aai-resources/src/main/java/org/onap/aai/rest/util/ValidateEncoding.java161
17 files changed, 2672 insertions, 0 deletions
diff --git a/aai-resources/src/main/java/org/onap/aai/rest/BulkAddConsumer.java b/aai-resources/src/main/java/org/onap/aai/rest/BulkAddConsumer.java
new file mode 100644
index 0000000..b81c42c
--- /dev/null
+++ b/aai-resources/src/main/java/org/onap/aai/rest/BulkAddConsumer.java
@@ -0,0 +1,43 @@
+/**
+ * ============LICENSE_START=======================================================
+ * org.onap.aai
+ * ================================================================================
+ * Copyright © 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * 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=========================================================
+ *
+ * ECOMP is a trademark and service mark of AT&T Intellectual Property.
+ */
+package org.onap.aai.rest;
+
+import javax.ws.rs.Path;
+
+import org.onap.aai.restcore.HttpMethod;
+
+@Path("{version: v[8-9]|v1[01]}/bulkadd")
+public class BulkAddConsumer extends BulkConsumer {
+
+ @Override
+ protected boolean functionAllowed(HttpMethod method) {
+
+ return method.equals(HttpMethod.PUT);
+
+ }
+
+ @Override
+ protected boolean enableResourceVersion() {
+ return true;
+ }
+
+}
diff --git a/aai-resources/src/main/java/org/onap/aai/rest/BulkConsumer.java b/aai-resources/src/main/java/org/onap/aai/rest/BulkConsumer.java
new file mode 100644
index 0000000..fa74f7b
--- /dev/null
+++ b/aai-resources/src/main/java/org/onap/aai/rest/BulkConsumer.java
@@ -0,0 +1,485 @@
+/**
+ * ============LICENSE_START=======================================================
+ * org.onap.aai
+ * ================================================================================
+ * Copyright © 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * 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=========================================================
+ *
+ * ECOMP is a trademark and service mark of AT&T Intellectual Property.
+ */
+package org.onap.aai.rest;
+
+import java.io.UnsupportedEncodingException;
+import java.net.URI;
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.ws.rs.Consumes;
+import javax.ws.rs.PUT;
+import javax.ws.rs.PathParam;
+import javax.ws.rs.Produces;
+import javax.ws.rs.core.Context;
+import javax.ws.rs.core.HttpHeaders;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+import javax.ws.rs.core.Response.Status;
+import javax.ws.rs.core.UriBuilder;
+import javax.ws.rs.core.UriInfo;
+
+import org.javatuples.Pair;
+import org.javatuples.Triplet;
+
+import org.onap.aai.dbmap.DBConnectionType;
+import org.onap.aai.exceptions.AAIException;
+import org.onap.aai.introspection.Introspector;
+import org.onap.aai.introspection.Loader;
+import org.onap.aai.introspection.ModelType;
+import org.onap.aai.introspection.Version;
+import org.onap.aai.introspection.exceptions.AAIUnmarshallingException;
+import org.onap.aai.logging.ErrorObjectNotFoundException;
+import org.onap.aai.parsers.query.QueryParser;
+import org.onap.aai.rest.db.DBRequest;
+import org.onap.aai.rest.db.HttpEntry;
+import org.onap.aai.rest.util.ValidateEncoding;
+import org.onap.aai.restcore.HttpMethod;
+import org.onap.aai.restcore.RESTAPI;
+import org.onap.aai.serialization.engines.QueryStyle;
+import org.onap.aai.serialization.engines.TransactionalGraphEngine;
+import com.google.gson.Gson;
+import com.google.gson.GsonBuilder;
+import com.google.gson.JsonArray;
+import com.google.gson.JsonElement;
+import com.google.gson.JsonObject;
+import com.google.gson.JsonParser;
+import com.google.gson.JsonSyntaxException;
+
+/**
+ * The Class BulkAddConsumer.
+ */
+/*
+ * The purpose of this endpoint is to allow a client to add
+ * multiple objects with one request. It may take
+ * one or more transaction objects containing one or more
+ * objects to add.
+ * The transactions are independent of each other -
+ * if one fails, its effects are rolled back, but the others' aren't.
+ * Within a single transaction, if adding one object fails, all the others'
+ * changes are rolled back.
+ */
+public abstract class BulkConsumer extends RESTAPI {
+
+ /** The introspector factory type. */
+ private ModelType introspectorFactoryType = ModelType.MOXY;
+
+ /** The query style. */
+ private QueryStyle queryStyle = QueryStyle.TRAVERSAL;
+
+ /**
+ * Bulk add.
+ *
+ * @param content the content
+ * @param versionParam the version param
+ * @param uri the uri
+ * @param headers the headers
+ * @param info the info
+ * @param req the req
+ * @return the response
+ */
+ @PUT
+ @Consumes({ MediaType.APPLICATION_JSON})
+ @Produces({ MediaType.APPLICATION_JSON})
+ public Response bulkAdd(String content, @PathParam("version")String versionParam, @Context HttpHeaders headers, @Context UriInfo info, @Context HttpServletRequest req){
+
+ String transId = headers.getRequestHeaders().getFirst("X-TransactionId");
+ String sourceOfTruth = headers.getRequestHeaders().getFirst("X-FromAppId");
+ String realTime = headers.getRequestHeaders().getFirst("Real-Time");
+ String outputMediaType = getMediaType(headers.getAcceptableMediaTypes());
+ Version version = Version.valueOf(versionParam);
+ DBConnectionType type = this.determineConnectionType(sourceOfTruth, realTime);
+
+ Response response = null;
+
+ /* A Response will be generated for each object in each transaction.
+ * To keep track of what came from where to give organized feedback to the client,
+ * we keep responses from a given transaction together in one list (hence all being a list of lists)
+ * and pair each response with its matching URI (which will be null if there wasn't one).
+ */
+ List<List<Pair<URI, Response>>> allResponses = new ArrayList<List<Pair<URI, Response>>>();
+
+ try {
+ //TODO add auth check when this endpoint added to that auth properties files
+
+
+ JsonArray transactions = getTransactions(content);
+
+ for (int i = 0; i < transactions.size(); i++){
+ HttpEntry httpEntry = new HttpEntry(version, introspectorFactoryType, queryStyle, type);
+ Loader loader = httpEntry.getLoader();
+ TransactionalGraphEngine dbEngine = httpEntry.getDbEngine();
+ URI thisUri = null;
+ List<Triplet<URI, Introspector,HttpMethod>> triplet = new ArrayList<Triplet<URI, Introspector,HttpMethod>>();
+ HttpMethod method = null;
+ try {
+ JsonElement transObj = transactions.get(i);
+ if (!(transObj instanceof JsonObject)) {
+ throw new AAIException("AAI_6111", "input payload does not follow bulk add interface");
+ }
+ //JsonObject transaction = transObj.getAsJsonObject();
+
+ fillObjectTuplesFromTransaction(triplet, transObj.getAsJsonObject(), loader, dbEngine, outputMediaType);
+ if (triplet.size() == 0) {
+ //case where user sends a validly formatted transactions object but
+ //which has no actual things in it for A&AI to do anything with
+ //assuming we should count this as a user error
+ throw new AAIException("AAI_6118", "payload had no objects to operate on");
+ }
+
+ List<DBRequest> requests = new ArrayList<>();
+ for (Triplet<URI, Introspector, HttpMethod> tuple : triplet){
+ thisUri = tuple.getValue0();
+ method = tuple.getValue2();
+ QueryParser uriQuery = dbEngine.getQueryBuilder().createQueryFromURI(thisUri);
+ DBRequest request = new DBRequest.Builder(method, thisUri, uriQuery, tuple.getValue1(), headers, info, transId).build();
+ requests.add(request);
+ }
+
+ Pair<Boolean, List<Pair<URI, Response>>> results = httpEntry.process(requests, sourceOfTruth, this.enableResourceVersion());
+ List<Pair<URI, Response>> responses = results.getValue1();
+ allResponses.add(responses);
+ if (results.getValue0()) { //everything was processed without error
+ dbEngine.commit();
+ } else { //something failed
+ dbEngine.rollback();
+ }
+ } catch (Exception e) {
+ /* While httpEntry.process handles its exceptions, exceptions thrown in earlier helpers
+ * bubbles up to here. As we want to tie error messages to the URI of the object that caused
+ * them, we catch here, generate a Response, bundle it with that URI, and move on.
+ */
+ method = HttpMethod.PUT;
+ if (triplet.size() != 0) { //failed somewhere in the middle of tuple-filling
+ Triplet<URI, Introspector, HttpMethod> lastTuple = triplet.get(triplet.size()-1); //last one in there was the problem
+ if (lastTuple.getValue1() == null){
+ //failed out before thisUri could be set but after tuples started being filled
+ thisUri = lastTuple.getValue0();
+ method = lastTuple.getValue2();
+ }
+ } //else failed out on empty payload so tuples never filled (or failed out even earlier than tuple-filling)
+ addExceptionCaseFailureResponse(allResponses, e, i, thisUri, headers, info, method);
+ dbEngine.rollback();
+ continue; /* if an exception gets thrown within a transaction we want to keep going to
+ the next transaction, not break out of the whole request */
+ }
+ }
+
+ String returnPayload = generateResponsePayload(allResponses);
+
+ //unless a top level error gets thrown, we want to 201 bc the client wanted a "fire and forget" kind of setup
+ response = Response
+ .status(Status.CREATED)
+ .entity(returnPayload)
+ .build();
+ } catch (AAIException e) { //these catches needed for handling top level errors in payload parsing where the whole request must fail out
+ response = consumerExceptionResponseGenerator(headers, info, HttpMethod.PUT, e);
+ } catch(JsonSyntaxException e) {
+ AAIException ex = new AAIException("AAI_6111");
+ response = consumerExceptionResponseGenerator(headers, info, HttpMethod.PUT, ex);
+ } catch (Exception e ) {
+ AAIException ex = new AAIException("AAI_4000", e);
+ response = consumerExceptionResponseGenerator(headers, info, HttpMethod.PUT, ex);
+ }
+
+ return response;
+ }
+
+
+ /**
+ * Gets the transactions.
+ *
+ * @param content - input JSON payload string
+ * @return JsonArray - the array of transactions
+ * @throws AAIException the AAI exception
+ * @throws JsonSyntaxException Parses and breaks the single payload into an array of individual transaction
+ * bodies to be processed.
+ */
+ private JsonArray getTransactions(String content) throws AAIException, JsonSyntaxException {
+ JsonParser parser = new JsonParser();
+
+ JsonObject input = parser.parse(content).getAsJsonObject();
+
+ if (!(input.has("transactions"))) {
+ throw new AAIException("AAI_6118", "input payload does not follow bulk add interface - missing \"transactions\"");
+ }
+ JsonElement transactionsObj = input.get("transactions");
+
+ if (!(transactionsObj.isJsonArray())){
+ throw new AAIException("AAI_6111", "input payload does not follow bulk add interface");
+ }
+ JsonArray transactions = transactionsObj.getAsJsonArray();
+ if (transactions.size() == 0) {
+ //case where user sends a validly formatted transactions object but
+ //which has no actual things in it for A&AI to do anything with
+ //assuming we should count this as a user error
+ throw new AAIException("AAI_6118", "payload had no objects to operate on");
+ }
+ return transactions;
+ }
+
+ /**
+ * Fill object tuples from transaction.
+ *
+ * @param tuples the tuples
+ * @param transaction - JSON body containing the objects to be added
+ * each object must have a URI and an object body
+ * @param loader the loader
+ * @param dbEngine the db engine
+ * @param inputMediaType the input media type
+ * @return list of tuples containing each introspector-wrapped object and its given URI
+ * @throws AAIException the AAI exception
+ * @throws JsonSyntaxException the json syntax exception
+ * @throws UnsupportedEncodingException Walks through the given transaction and unmarshals each object in it, then bundles each
+ * with its URI.
+ */
+ private void fillObjectTuplesFromTransaction(List<Triplet<URI, Introspector, HttpMethod>> triplet,
+ JsonObject transaction, Loader loader, TransactionalGraphEngine dbEngine, String inputMediaType)
+ throws AAIException, JsonSyntaxException, UnsupportedEncodingException {
+
+
+ if (transaction.has("put") && this.functionAllowed(HttpMethod.PUT)) {
+ pairUp(triplet, transaction, loader, dbEngine, inputMediaType, HttpMethod.PUT);
+ }
+ else if (transaction.has("delete") && this.functionAllowed(HttpMethod.DELETE)) {
+ pairUp(triplet, transaction, loader, dbEngine, inputMediaType, HttpMethod.DELETE);
+ }
+ else if (transaction.has("patch") && this.functionAllowed(HttpMethod.MERGE_PATCH)) {
+ pairUp(triplet, transaction, loader, dbEngine, inputMediaType, HttpMethod.MERGE_PATCH);
+ }
+
+ else{
+
+ throw new AAIException("AAI_6118", "input payload does not follow bulk add interface - missing put delete or patch");
+ }
+
+
+
+ }
+
+
+
+ private void pairUp(List<Triplet<URI, Introspector, HttpMethod>> triplet, JsonObject item, Loader loader, TransactionalGraphEngine dbEngine, String inputMediaType, HttpMethod method) throws AAIException, JsonSyntaxException, UnsupportedEncodingException{
+
+
+ for (int i=0; i<item.size(); i++) {
+ Triplet<URI, Introspector, HttpMethod> tuple = Triplet.with(null, null,null);
+
+ tuple = tuple.setAt2(method);
+ try {
+ if (!(item.isJsonObject())) {
+ throw new AAIException("AAI_6111", "input payload does not follow bulk add interface");
+ }
+
+
+ JsonElement actionElement = null;
+
+ if(item.has("put")){
+ actionElement = item.get("put");
+ } else if(item.has("patch")){
+ actionElement = item.get("patch");
+ } else if(item.has("delete")){
+ actionElement = item.get("delete");
+ }
+
+ if ((actionElement == null) || !actionElement.isJsonArray()) {
+ throw new AAIException("AAI_6111", "input payload does not follow bulk add interface");
+ }
+ JsonArray httpArray = actionElement.getAsJsonArray();
+ for(int j = 0; j < httpArray.size(); ++j){
+ JsonObject it = httpArray.get(j).getAsJsonObject();
+ JsonElement itemURIfield = it.get("uri");
+ if (itemURIfield == null) {
+ throw new AAIException("AAI_6118", "must include object uri");
+ }
+ String uriStr = itemURIfield.getAsString();
+ if (uriStr.endsWith("/relationship-list/relationship")) {
+ if (method.equals(HttpMethod.PUT)) {
+ tuple = tuple.setAt2(HttpMethod.PUT_EDGE);
+ } else if (method.equals(HttpMethod.DELETE)) {
+ tuple = tuple.setAt2(HttpMethod.DELETE_EDGE);
+ }
+ } else {
+ tuple = tuple.setAt2(method);
+ }
+
+ URI uri = UriBuilder.fromPath(uriStr).build();
+
+ /* adding the uri as soon as we have one (valid or not) lets us
+ * keep any errors with their corresponding uris for client feedback
+ */
+ tuple = tuple.setAt0(uri);
+
+ if (!ValidateEncoding.getInstance().validate(uri)) {
+ throw new AAIException("AAI_3008", "uri=" + uri.getPath());
+ }
+
+ if (!(it.has("body"))){
+ throw new AAIException("AAI_6118", "input payload does not follow bulk add interface - missing \"body\"");
+ }
+ JsonElement bodyObj = it.get("body");
+ if (!(bodyObj.isJsonObject())) {
+ throw new AAIException("AAI_6111", "input payload does not follow bulk add interface");
+ }
+
+ Gson gson = new Gson();
+
+ String bodyStr = gson.toJson(bodyObj);
+
+ if (tuple.getValue2().equals(HttpMethod.PUT_EDGE)) {
+ Introspector obj;
+ try {
+ obj = loader.unmarshal("relationship", bodyStr, org.onap.aai.restcore.MediaType.getEnum(inputMediaType));
+ } catch (AAIUnmarshallingException e) {
+ throw new AAIException("AAI_3000", "object could not be unmarshalled:" + bodyStr);
+
+ }
+
+
+ tuple = tuple.setAt1(obj);
+
+ } else {
+ QueryParser uriQuery = dbEngine.getQueryBuilder().createQueryFromURI(uri);
+ String objName = uriQuery.getResultType();
+
+ Introspector obj;
+ try {
+ obj = loader.unmarshal(objName, bodyStr, org.onap.aai.restcore.MediaType.getEnum(inputMediaType));
+ } catch (AAIUnmarshallingException e) {
+ throw new AAIException("AAI_3000", "object could not be unmarshalled:" + bodyStr);
+
+ }
+
+ this.validateIntrospector(obj, loader, uri, tuple.getValue2());
+ tuple = tuple.setAt1(obj);
+ }
+ triplet.add(tuple);
+ }
+// JsonElement itemURIfield = item.get("uri");
+
+ } catch (AAIException e) {
+ // even if tuple doesn't have a uri or body, this way we keep all information associated with this error together
+ // even if both are null, that indicates how the input was messed up, so still useful to carry around like this
+ triplet.add(tuple);
+ throw e; //rethrow so the right response is generated on the level above
+ }
+ }
+ }
+
+
+
+ /**
+ * Generate response payload.
+ *
+ * @param allResponses - the list of the lists of responses from every action in every transaction requested
+ * @return A json string of similar format to the bulk add interface which for each response includes
+ * the original URI and a body with the status code of the response and the error message.
+ *
+ * Creates the payload for a single unified response from all responses generated
+ */
+ private String generateResponsePayload(List<List<Pair<URI,Response>>> allResponses){
+ JsonObject ret = new JsonObject();
+ JsonArray retArr = new JsonArray();
+
+ for(List<Pair<URI,Response>> responses : allResponses){
+ JsonObject tResp = new JsonObject();
+ JsonArray tArrResp = new JsonArray();
+
+ for (Pair<URI,Response> r : responses) {
+ JsonObject indPayload = new JsonObject();
+
+ URI origURI = r.getValue0();
+ if (origURI != null) {
+ indPayload.addProperty("uri", origURI.getPath());
+ } else {
+ indPayload.addProperty("uri", (String)null);
+ }
+
+ JsonObject body = new JsonObject();
+
+ int rStatus = r.getValue1().getStatus();
+ String rContents = null;
+
+ rContents = (String)r.getValue1().getEntity();
+
+ body.addProperty(new Integer(rStatus).toString(), rContents);
+ indPayload.add("body", body);
+
+ tArrResp.add(indPayload);
+ }
+
+ tResp.add("put", tArrResp);
+ retArr.add(tResp);
+ }
+ ret.add("transaction", retArr);
+ Gson gson = new GsonBuilder().serializeNulls().create();
+ String jsonStr = gson.toJson(ret);
+ return jsonStr;
+ }
+
+ /**
+ * Adds the exception case failure response.
+ *
+ * @param allResponses the all responses
+ * @param e the e
+ * @param index - index of which transaction was being processed when the exception was thrown
+ * @param thisUri the this uri
+ * @param headers the headers
+ * @param info the info
+ * @param templateAction the template action
+ * @param logline Generates a Response based on the given exception and adds it to the collection of responses for this request.
+ * @throws ErrorObjectNotFoundException
+ */
+ private void addExceptionCaseFailureResponse(List<List<Pair<URI, Response>>> allResponses, Exception e, int index, URI thisUri, HttpHeaders headers, UriInfo info, HttpMethod templateAction) {
+ AAIException ex = null;
+
+ if (!(e instanceof AAIException)){
+ ex = new AAIException("AAI_4000", e);
+ } else {
+ ex = (AAIException)e;
+ }
+
+ if (allResponses.size() != (index+1)) {
+ //index+1 bc if all transactions thus far have had a response list added
+ //the size will be one more than the current index (since those are offset by 1)
+
+ //this transaction doesn't have a response list yet, so create one
+ Response failResp = consumerExceptionResponseGenerator(headers, info, templateAction, ex);
+ Pair<URI, Response> uriResp = Pair.with(thisUri, failResp);
+ List<Pair<URI, Response>> transRespList = new ArrayList<Pair<URI,Response>>();
+ transRespList.add(uriResp);
+ allResponses.add(transRespList);
+ } else {
+ //this transaction already has a response list, so add this failure response to it
+ Response failResp = consumerExceptionResponseGenerator(headers, info, templateAction, ex);
+ Pair<URI, Response> uriResp = Pair.with(thisUri, failResp);
+ List<Pair<URI, Response>> tResps = allResponses.get(index);
+ tResps.add(uriResp);
+ }
+ }
+
+ protected abstract boolean functionAllowed(HttpMethod method);
+
+ protected abstract boolean enableResourceVersion();
+
+}
diff --git a/aai-resources/src/main/java/org/onap/aai/rest/BulkProcessConsumer.java b/aai-resources/src/main/java/org/onap/aai/rest/BulkProcessConsumer.java
new file mode 100644
index 0000000..d22fe21
--- /dev/null
+++ b/aai-resources/src/main/java/org/onap/aai/rest/BulkProcessConsumer.java
@@ -0,0 +1,43 @@
+/**
+ * ============LICENSE_START=======================================================
+ * org.onap.aai
+ * ================================================================================
+ * Copyright © 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * 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=========================================================
+ *
+ * ECOMP is a trademark and service mark of AT&T Intellectual Property.
+ */
+package org.onap.aai.rest;
+
+import javax.ws.rs.Path;
+
+import org.onap.aai.restcore.HttpMethod;
+
+@Path("{version: v[2789]|v1[01]}/bulkprocess")
+public class BulkProcessConsumer extends BulkConsumer {
+
+ @Override
+ protected boolean functionAllowed(HttpMethod method) {
+
+ return method.equals(HttpMethod.PUT) || method.equals(HttpMethod.DELETE) || method.equals(HttpMethod.MERGE_PATCH);
+ }
+
+ @Override
+ protected boolean enableResourceVersion() {
+ // TODO Auto-generated method stub
+ return true;
+ }
+
+}
diff --git a/aai-resources/src/main/java/org/onap/aai/rest/ExampleConsumer.java b/aai-resources/src/main/java/org/onap/aai/rest/ExampleConsumer.java
new file mode 100644
index 0000000..c942258
--- /dev/null
+++ b/aai-resources/src/main/java/org/onap/aai/rest/ExampleConsumer.java
@@ -0,0 +1,105 @@
+/**
+ * ============LICENSE_START=======================================================
+ * org.onap.aai
+ * ================================================================================
+ * Copyright © 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * 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=========================================================
+ *
+ * ECOMP is a trademark and service mark of AT&T Intellectual Property.
+ */
+package org.onap.aai.rest;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.ws.rs.GET;
+import javax.ws.rs.Path;
+import javax.ws.rs.PathParam;
+import javax.ws.rs.Produces;
+import javax.ws.rs.core.Context;
+import javax.ws.rs.core.HttpHeaders;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+import javax.ws.rs.core.Response.Status;
+import javax.ws.rs.core.UriInfo;
+
+import org.onap.aai.exceptions.AAIException;
+import org.onap.aai.introspection.Introspector;
+import org.onap.aai.introspection.Loader;
+import org.onap.aai.introspection.LoaderFactory;
+import org.onap.aai.introspection.MarshallerProperties;
+import org.onap.aai.introspection.ModelType;
+import org.onap.aai.introspection.Version;
+import org.onap.aai.introspection.generator.CreateExample;
+import org.onap.aai.restcore.HttpMethod;
+import org.onap.aai.restcore.RESTAPI;
+
+/**
+ * The Class ExampleConsumer.
+ */
+@Path("/{version: v[2789]|v1[01]}/examples")
+public class ExampleConsumer extends RESTAPI {
+
+
+ /**
+ * Gets the example.
+ *
+ * @param versionParam the version param
+ * @param type the type
+ * @param headers the headers
+ * @param info the info
+ * @param req the req
+ * @return the example
+ */
+ @GET
+ @Path("/{objectType: [^\\/]+}")
+ @Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
+ public Response getExample(@PathParam("version")String versionParam, @PathParam("objectType")String type, @Context HttpHeaders headers, @Context UriInfo info, @Context HttpServletRequest req) {
+
+ Status status = Status.INTERNAL_SERVER_ERROR;
+ Response response = null;
+
+ try {
+ String mediaType = getMediaType(headers.getAcceptableMediaTypes());
+ org.onap.aai.restcore.MediaType outputMediaType = org.onap.aai.restcore.MediaType.getEnum(mediaType);
+
+ Version version = Version.valueOf(versionParam);
+ Loader loader = LoaderFactory.createLoaderForVersion(ModelType.MOXY, version);
+
+ CreateExample example = new CreateExample(loader, type);
+
+ Introspector obj = example.getExampleObject();
+ String result = "";
+ if (obj != null) {
+ status = Status.OK;
+ MarshallerProperties properties =
+ new MarshallerProperties.Builder(outputMediaType).build();
+ result = obj.marshal(properties);
+ } else {
+
+ }
+ response = Response
+ .ok(obj)
+ .entity(result)
+ .status(status)
+ .type(outputMediaType.toString()).build();
+ } catch (AAIException e) {
+ //TODO check that the details here are sensible
+ response = consumerExceptionResponseGenerator(headers, info, HttpMethod.GET, e);
+ } catch (Exception e) {
+ AAIException ex = new AAIException("AAI_4000", e);
+ response = consumerExceptionResponseGenerator(headers, info, HttpMethod.GET, ex);
+ }
+ return response;
+ }
+}
diff --git a/aai-resources/src/main/java/org/onap/aai/rest/ExceptionHandler.java b/aai-resources/src/main/java/org/onap/aai/rest/ExceptionHandler.java
new file mode 100644
index 0000000..c20a370
--- /dev/null
+++ b/aai-resources/src/main/java/org/onap/aai/rest/ExceptionHandler.java
@@ -0,0 +1,130 @@
+/**
+ * ============LICENSE_START=======================================================
+ * org.onap.aai
+ * ================================================================================
+ * Copyright © 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * 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=========================================================
+ *
+ * ECOMP is a trademark and service mark of AT&T Intellectual Property.
+ */
+package org.onap.aai.rest;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.ws.rs.WebApplicationException;
+import javax.ws.rs.core.Context;
+import javax.ws.rs.core.HttpHeaders;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+import javax.ws.rs.ext.ExceptionMapper;
+import javax.ws.rs.ext.Provider;
+
+import org.onap.aai.exceptions.AAIException;
+import org.onap.aai.logging.ErrorLogHelper;
+import com.fasterxml.jackson.core.JsonParseException;
+import com.fasterxml.jackson.databind.JsonMappingException;
+import com.sun.istack.SAXParseException2;
+
+/**
+ * The Class ExceptionHandler.
+ */
+@Provider
+public class ExceptionHandler implements ExceptionMapper<Exception> {
+
+ @Context
+ private HttpServletRequest request;
+
+ @Context
+ private HttpHeaders headers;
+
+ /**
+ * @{inheritDoc}
+ */
+ @Override
+ public Response toResponse(Exception exception) {
+
+ Response response = null;
+ ArrayList<String> templateVars = new ArrayList<String>();
+
+ //the general case is that cxf will give us a WebApplicationException
+ //with a linked exception
+ if (exception instanceof WebApplicationException) {
+ WebApplicationException e = (WebApplicationException) exception;
+ if (e.getCause() != null) {
+ if (e.getCause() instanceof SAXParseException2) {
+ templateVars.add("UnmarshalException");
+ AAIException ex = new AAIException("AAI_4007", exception);
+ response = Response
+ .status(400)
+ .entity(ErrorLogHelper.getRESTAPIErrorResponse(headers.getAcceptableMediaTypes(), ex, templateVars))
+ .build();
+ }
+ }
+ } else if (exception instanceof JsonParseException) {
+ //jackson does it differently so we get the direct JsonParseException
+ templateVars.add("JsonParseException");
+ AAIException ex = new AAIException("AAI_4007", exception);
+ response = Response
+ .status(400)
+ .entity(ErrorLogHelper.getRESTAPIErrorResponse(headers.getAcceptableMediaTypes(), ex, templateVars))
+ .build();
+ } else if (exception instanceof JsonMappingException) {
+ //jackson does it differently so we get the direct JsonParseException
+ templateVars.add("JsonMappingException");
+ AAIException ex = new AAIException("AAI_4007", exception);
+ response = Response
+ .status(400)
+ .entity(ErrorLogHelper.getRESTAPIErrorResponse(headers.getAcceptableMediaTypes(), ex, templateVars))
+ .build();
+ }
+
+ // it didn't get set above, we wrap a general fault here
+ if (response == null) {
+
+ Exception actual_e = exception;
+ if (exception instanceof WebApplicationException) {
+ WebApplicationException e = (WebApplicationException) exception;
+ response = e.getResponse();
+ } else {
+ templateVars.add(request.getMethod());
+ templateVars.add("unknown");
+ AAIException ex = new AAIException("AAI_4000", actual_e);
+ List<MediaType> mediaTypes = headers.getAcceptableMediaTypes();
+ int setError = 0;
+
+ for (MediaType mediaType : mediaTypes) {
+ if (MediaType.APPLICATION_XML_TYPE.isCompatible(mediaType)) {
+ response = Response
+ .status(400)
+ .type(MediaType.APPLICATION_XML_TYPE)
+ .entity(ErrorLogHelper.getRESTAPIErrorResponse(headers.getAcceptableMediaTypes(), ex, templateVars))
+ .build();
+ setError = 1;
+ }
+ }
+ if (setError == 0) {
+ response = Response
+ .status(400)
+ .type(MediaType.APPLICATION_JSON_TYPE)
+ .entity(ErrorLogHelper.getRESTAPIErrorResponse(headers.getAcceptableMediaTypes(), ex, templateVars))
+ .build();
+ }
+ }
+ }
+ return response;
+ }
+}
diff --git a/aai-resources/src/main/java/org/onap/aai/rest/LegacyMoxyConsumer.java b/aai-resources/src/main/java/org/onap/aai/rest/LegacyMoxyConsumer.java
new file mode 100644
index 0000000..a68d8f2
--- /dev/null
+++ b/aai-resources/src/main/java/org/onap/aai/rest/LegacyMoxyConsumer.java
@@ -0,0 +1,597 @@
+/**
+ * ============LICENSE_START=======================================================
+ * org.onap.aai
+ * ================================================================================
+ * Copyright © 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * 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=========================================================
+ *
+ * ECOMP is a trademark and service mark of AT&T Intellectual Property.
+ */
+package org.onap.aai.rest;
+
+import java.io.UnsupportedEncodingException;
+import java.net.URI;
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.ws.rs.Consumes;
+import javax.ws.rs.DELETE;
+import javax.ws.rs.DefaultValue;
+import javax.ws.rs.Encoded;
+import javax.ws.rs.GET;
+import javax.ws.rs.PUT;
+import javax.ws.rs.Path;
+import javax.ws.rs.PathParam;
+import javax.ws.rs.Produces;
+import javax.ws.rs.QueryParam;
+import javax.ws.rs.core.Context;
+import javax.ws.rs.core.HttpHeaders;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.MultivaluedMap;
+import javax.ws.rs.core.Response;
+import javax.ws.rs.core.UriBuilder;
+import javax.ws.rs.core.UriInfo;
+
+import org.apache.cxf.jaxrs.ext.PATCH;
+import org.javatuples.Pair;
+import org.onap.aai.dbmap.DBConnectionType;
+import org.onap.aai.exceptions.AAIException;
+import org.onap.aai.introspection.Introspector;
+import org.onap.aai.introspection.Loader;
+import org.onap.aai.introspection.ModelType;
+import org.onap.aai.introspection.Version;
+import org.onap.aai.parsers.query.QueryParser;
+import org.onap.aai.rest.db.DBRequest;
+import org.onap.aai.rest.db.HttpEntry;
+import org.onap.aai.rest.exceptions.AAIInvalidXMLNamespace;
+import org.onap.aai.rest.util.ValidateEncoding;
+import org.onap.aai.restcore.HttpMethod;
+import org.onap.aai.restcore.RESTAPI;
+import org.onap.aai.serialization.engines.QueryStyle;
+import org.onap.aai.serialization.engines.TransactionalGraphEngine;
+import org.onap.aai.workarounds.RemoveDME2QueryParams;
+
+import com.att.eelf.configuration.EELFLogger;
+import com.att.eelf.configuration.EELFManager;
+import com.google.common.base.Joiner;
+
+
+/**
+ * The Class LegacyMoxyConsumer.
+ */
+@Path("{version: v[2789]|v1[01]}")
+public class LegacyMoxyConsumer extends RESTAPI {
+
+ private static final EELFLogger LOGGER = EELFManager.getInstance().getLogger(LegacyMoxyConsumer.class.getName());
+ protected static String authPolicyFunctionName = "REST";
+ private ModelType introspectorFactoryType = ModelType.MOXY;
+ private QueryStyle queryStyle = QueryStyle.TRAVERSAL;
+
+ /**
+ * Update.
+ *
+ * @param content the content
+ * @param versionParam the version param
+ * @param uri the uri
+ * @param headers the headers
+ * @param info the info
+ * @param req the req
+ * @return the response
+ */
+ @PUT
+ @Path("/{uri: .+}")
+ @Consumes({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
+ @Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
+ public Response update (String content, @PathParam("version")String versionParam, @PathParam("uri") @Encoded String uri, @Context HttpHeaders headers, @Context UriInfo info, @Context HttpServletRequest req) {
+
+ MediaType mediaType = headers.getMediaType();
+
+ return this.handleWrites(mediaType, HttpMethod.PUT, content, versionParam, uri, headers, info);
+ }
+
+ /**
+ * Update relationship.
+ *
+ * @param content the content
+ * @param versionParam the version param
+ * @param uri the uri
+ * @param headers the headers
+ * @param info the info
+ * @param req the req
+ * @return the response
+ */
+ @PUT
+ @Path("/{uri: .+}/relationship-list/relationship")
+ @Consumes({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
+ @Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
+ public Response updateRelationship (String content, @PathParam("version")String versionParam, @PathParam("uri") @Encoded String uri, @Context HttpHeaders headers, @Context UriInfo info, @Context HttpServletRequest req) {
+
+ String sourceOfTruth = headers.getRequestHeaders().getFirst("X-FromAppId");
+ String transId = headers.getRequestHeaders().getFirst("X-TransactionId");
+ String realTime = headers.getRequestHeaders().getFirst("Real-Time");
+ MediaType inputMediaType = headers.getMediaType();
+ Response response = null;
+ Loader loader = null;
+ TransactionalGraphEngine dbEngine = null;
+ boolean success = true;
+
+ try {
+ validateRequest(info);
+ Version version = Version.valueOf(versionParam);
+ version = Version.valueOf(versionParam);
+ DBConnectionType type = this.determineConnectionType(sourceOfTruth, realTime);
+ HttpEntry httpEntry = new HttpEntry(version, introspectorFactoryType, queryStyle, type);
+ loader = httpEntry.getLoader();
+ dbEngine = httpEntry.getDbEngine();
+
+ URI uriObject = UriBuilder.fromPath(uri).build();
+ this.validateURI(uriObject);
+
+ QueryParser uriQuery = dbEngine.getQueryBuilder().createQueryFromURI(uriObject);
+
+ Introspector wrappedEntity = loader.unmarshal("relationship", content, org.onap.aai.restcore.MediaType.getEnum(this.getInputMediaType(inputMediaType)));
+
+ DBRequest request = new DBRequest.Builder(HttpMethod.PUT_EDGE, uriObject, uriQuery, wrappedEntity, headers, info, transId).build();
+ List<DBRequest> requests = new ArrayList<>();
+ requests.add(request);
+ Pair<Boolean, List<Pair<URI, Response>>> responsesTuple = httpEntry.process(requests, sourceOfTruth);
+
+ response = responsesTuple.getValue1().get(0).getValue1();
+ success = responsesTuple.getValue0();
+
+ } catch (AAIException e) {
+ response = consumerExceptionResponseGenerator(headers, info, HttpMethod.PUT, e);
+ success = false;
+ } catch (Exception e) {
+ AAIException aaiException = new AAIException("AAI_4000", e);
+ response = consumerExceptionResponseGenerator(headers, info, HttpMethod.PUT, aaiException);
+ success = false;
+ } finally {
+ if (dbEngine != null) {
+ if (success) {
+ dbEngine.commit();
+ } else {
+ LOGGER.warn("Rolling back Titan transaction");
+ dbEngine.rollback();
+ }
+ }
+
+ }
+
+ return response;
+ }
+
+ /**
+ * Patch.
+ *
+ * @param content the content
+ * @param versionParam the version param
+ * @param uri the uri
+ * @param headers the headers
+ * @param info the info
+ * @param req the req
+ * @return the response
+ */
+ @PATCH
+ @Path("/{uri: .+}")
+ @Consumes({ "application/merge-patch+json" })
+ @Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
+ public Response patch (String content, @PathParam("version")String versionParam, @PathParam("uri") @Encoded String uri, @Context HttpHeaders headers, @Context UriInfo info, @Context HttpServletRequest req) {
+
+ MediaType mediaType = MediaType.APPLICATION_JSON_TYPE;
+
+ return this.handleWrites(mediaType, HttpMethod.MERGE_PATCH, content, versionParam, uri, headers, info);
+
+ }
+
+ /**
+ * Gets the legacy.
+ *
+ * @param content the content
+ * @param versionParam the version param
+ * @param uri the uri
+ * @param depthParam the depth param
+ * @param cleanUp the clean up
+ * @param headers the headers
+ * @param info the info
+ * @param req the req
+ * @return the legacy
+ */
+ @GET
+ @Path("/{uri: .+}")
+ @Consumes({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
+ @Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
+ public Response getLegacy (String content, @PathParam("version")String versionParam, @PathParam("uri") @Encoded String uri, @DefaultValue("all") @QueryParam("depth") String depthParam, @DefaultValue("false") @QueryParam("cleanup") String cleanUp, @Context HttpHeaders headers, @Context UriInfo info, @Context HttpServletRequest req) {
+
+ return this.getLegacy(content, versionParam, uri, depthParam, cleanUp, headers, info, req, new HashSet<String>());
+ }
+
+ /**
+ * This method exists as a workaround for filtering out undesired query params while routing between REST consumers
+ *
+ * @param content
+ * @param versionParam
+ * @param uri
+ * @param depthParam
+ * @param cleanUp
+ * @param headers
+ * @param info
+ * @param req
+ * @param removeQueryParams
+ * @return
+ */
+ public Response getLegacy(String content, String versionParam, String uri, String depthParam, String cleanUp, HttpHeaders headers, UriInfo info, HttpServletRequest req, Set<String> removeQueryParams) {
+ String sourceOfTruth = headers.getRequestHeaders().getFirst("X-FromAppId");
+ String transId = headers.getRequestHeaders().getFirst("X-TransactionId");
+ String realTime = headers.getRequestHeaders().getFirst("Real-Time");
+ Response response = null;
+ TransactionalGraphEngine dbEngine = null;
+ Loader loader = null;
+
+ try {
+ validateRequest(info);
+ Version version = Version.valueOf(versionParam);
+ DBConnectionType type = this.determineConnectionType(sourceOfTruth, realTime);
+ final HttpEntry httpEntry = new HttpEntry(version, introspectorFactoryType, queryStyle, type);
+ dbEngine = httpEntry.getDbEngine();
+ loader = httpEntry.getLoader();
+ MultivaluedMap<String, String> params = info.getQueryParameters();
+
+ RemoveDME2QueryParams dme2Workaround = new RemoveDME2QueryParams();
+ //clear out all params not used for filtering
+ params.remove("depth");
+ params.remove("cleanup");
+ params.remove("nodes-only");
+ for (String queryParam : removeQueryParams) {
+ params.remove(queryParam);
+ }
+ if (dme2Workaround.shouldRemoveQueryParams(params)) {
+ dme2Workaround.removeQueryParams(params);
+ }
+
+ uri = uri.split("\\?")[0];
+
+ URI uriObject = UriBuilder.fromPath(uri).build();
+
+ QueryParser uriQuery = dbEngine.getQueryBuilder().createQueryFromURI(uriObject, params);
+
+ String objType = "";
+ if (!uriQuery.getContainerType().equals("")) {
+ objType = uriQuery.getContainerType();
+ } else {
+ objType = uriQuery.getResultType();
+ }
+ Introspector obj = loader.introspectorFromName(objType);
+ DBRequest request =
+ new DBRequest.Builder(HttpMethod.GET, uriObject, uriQuery, obj, headers, info, transId).build();
+ List<DBRequest> requests = new ArrayList<>();
+ requests.add(request);
+ Pair<Boolean, List<Pair<URI, Response>>> responsesTuple = httpEntry.process(requests, sourceOfTruth);
+
+ response = responsesTuple.getValue1().get(0).getValue1();
+
+ } catch (AAIException e) {
+ response = consumerExceptionResponseGenerator(headers, info, HttpMethod.GET, e);
+ } catch (Exception e ) {
+ AAIException ex = new AAIException("AAI_4000", e);
+
+ response = consumerExceptionResponseGenerator(headers, info, HttpMethod.GET, ex);
+ } finally {
+ if (dbEngine != null) {
+ if (cleanUp.equals("true")) {
+ dbEngine.commit();
+ } else {
+ dbEngine.rollback();
+ }
+ }
+ }
+
+ return response;
+ }
+ /**
+ * Delete.
+ *
+ * @param versionParam the version param
+ * @param uri the uri
+ * @param headers the headers
+ * @param info the info
+ * @param resourceVersion the resource version
+ * @param req the req
+ * @return the response
+ */
+ @DELETE
+ @Path("/{uri: .+}")
+ @Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
+ public Response delete (@PathParam("version")String versionParam, @PathParam("uri") @Encoded String uri, @Context HttpHeaders headers, @Context UriInfo info, @QueryParam("resource-version")String resourceVersion, @Context HttpServletRequest req) {
+
+
+ String outputMediaType = getMediaType(headers.getAcceptableMediaTypes());
+ String sourceOfTruth = headers.getRequestHeaders().getFirst("X-FromAppId");
+ String transId = headers.getRequestHeaders().getFirst("X-TransactionId");
+ String realTime = headers.getRequestHeaders().getFirst("Real-Time");
+
+ TransactionalGraphEngine dbEngine = null;
+ Response response = Response.status(404)
+ .type(outputMediaType).build();
+
+ boolean success = true;
+
+ try {
+
+ validateRequest(info);
+ Version version = Version.valueOf(versionParam);
+ DBConnectionType type = this.determineConnectionType(sourceOfTruth, realTime);
+ HttpEntry httpEntry = new HttpEntry(version, introspectorFactoryType, queryStyle, type);
+
+ dbEngine = httpEntry.getDbEngine();
+ Loader loader = httpEntry.getLoader();
+
+ URI uriObject = UriBuilder.fromPath(uri).build();
+
+ QueryParser uriQuery = dbEngine.getQueryBuilder().createQueryFromURI(uriObject);
+ String objType = uriQuery.getResultType();
+ Introspector obj = loader.introspectorFromName(objType);
+
+ DBRequest request = new DBRequest.Builder(HttpMethod.DELETE, uriObject, uriQuery, obj, headers, info, transId).build();
+ List<DBRequest> requests = new ArrayList<>();
+ requests.add(request);
+ Pair<Boolean, List<Pair<URI, Response>>> responsesTuple = httpEntry.process(requests, sourceOfTruth);
+
+ response = responsesTuple.getValue1().get(0).getValue1();
+ success = responsesTuple.getValue0();
+
+ } catch (AAIException e) {
+ response = consumerExceptionResponseGenerator(headers, info, HttpMethod.DELETE, e);
+ success = false;
+ } catch (Exception e) {
+ AAIException ex = new AAIException("AAI_4000", e);
+ response = consumerExceptionResponseGenerator(headers, info, HttpMethod.DELETE, ex);
+ success = false;
+ } finally {
+ if (dbEngine != null) {
+ if (success) {
+ dbEngine.commit();
+ } else {
+ LOGGER.warn("Rolling back Titan transaction");
+ dbEngine.rollback();
+ }
+ }
+ }
+
+ return response;
+ }
+
+ /**
+ * This whole method does nothing because the body is being dropped while fielding the request.
+ *
+ * @param content the content
+ * @param versionParam the version param
+ * @param uri the uri
+ * @param headers the headers
+ * @param info the info
+ * @param req the req
+ * @return the response
+ */
+ @DELETE
+ @Path("/{uri: .+}/relationship-list/relationship")
+ @Consumes({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
+ @Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
+ public Response deleteRelationship (String content, @PathParam("version")String versionParam, @PathParam("uri") @Encoded String uri, @Context HttpHeaders headers, @Context UriInfo info, @Context HttpServletRequest req) {
+
+ MediaType inputMediaType = headers.getMediaType();
+
+ String outputMediaType = getMediaType(headers.getAcceptableMediaTypes());
+ String sourceOfTruth = headers.getRequestHeaders().getFirst("X-FromAppId");
+ String transId = headers.getRequestHeaders().getFirst("X-TransactionId");
+ String realTime = headers.getRequestHeaders().getFirst("Real-Time");
+
+ Loader loader = null;
+ TransactionalGraphEngine dbEngine = null;
+ Response response = Response.status(404)
+ .type(outputMediaType).build();
+
+ boolean success = true;
+
+ try {
+ this.validateRequest(info);
+ Version version = Version.valueOf(versionParam);
+ DBConnectionType type = this.determineConnectionType(sourceOfTruth, realTime);
+ HttpEntry httpEntry = new HttpEntry(version, introspectorFactoryType, queryStyle, type);
+ loader = httpEntry.getLoader();
+ dbEngine = httpEntry.getDbEngine();
+
+ if (content.equals("")) {
+ throw new AAIException("AAI_3102", "You must supply a relationship");
+ }
+ URI uriObject = UriBuilder.fromPath(uri).build();
+ this.validateURI(uriObject);
+
+ QueryParser uriQuery = dbEngine.getQueryBuilder().createQueryFromURI(uriObject);
+
+ Introspector wrappedEntity = loader.unmarshal("relationship", content, org.onap.aai.restcore.MediaType.getEnum(this.getInputMediaType(inputMediaType)));
+
+ DBRequest request = new DBRequest.Builder(HttpMethod.DELETE_EDGE, uriObject, uriQuery, wrappedEntity, headers, info, transId).build();
+ List<DBRequest> requests = new ArrayList<>();
+ requests.add(request);
+ Pair<Boolean, List<Pair<URI, Response>>> responsesTuple = httpEntry.process(requests, sourceOfTruth);
+
+ response = responsesTuple.getValue1().get(0).getValue1();
+ success = responsesTuple.getValue0();
+ } catch (AAIException e) {
+ response = consumerExceptionResponseGenerator(headers, info, HttpMethod.DELETE, e);
+ success = false;
+ } catch (Exception e) {
+ AAIException ex = new AAIException("AAI_4000", e);
+ response = consumerExceptionResponseGenerator(headers, info, HttpMethod.DELETE, ex);
+ success = false;
+ } finally {
+ if (dbEngine != null) {
+ if (success) {
+ dbEngine.commit();
+ } else {
+ LOGGER.warn("Rolling back Titan transaction");
+ dbEngine.rollback();
+ }
+ }
+ }
+
+ return response;
+ }
+
+ /**
+ * Validate request.
+ *
+ * @param uri the uri
+ * @param headers the headers
+ * @param req the req
+ * @param action the action
+ * @param info the info
+ * @throws AAIException the AAI exception
+ * @throws UnsupportedEncodingException the unsupported encoding exception
+ */
+ private void validateRequest(UriInfo info) throws AAIException, UnsupportedEncodingException {
+
+ if (!ValidateEncoding.getInstance().validate(info)) {
+ throw new AAIException("AAI_3008", "uri=" + getPath(info));
+ }
+ }
+
+ /**
+ * Gets the path.
+ *
+ * @param info the info
+ * @return the path
+ */
+ private String getPath(UriInfo info) {
+ String path = info.getPath(false);
+ MultivaluedMap<String, String> map = info.getQueryParameters(false);
+ String params = "?";
+ List<String> parmList = new ArrayList<>();
+ for (String key : map.keySet()) {
+ for (String value : map.get(key)) {
+ parmList.add(key + "=" + value);
+ }
+ }
+ String queryParams = Joiner.on("&").join(parmList);
+ if (map.keySet().size() > 0) {
+ path += params + queryParams;
+ }
+
+ return path;
+
+ }
+
+ /**
+ * Handle writes.
+ *
+ * @param aaiAction the aai action
+ * @param mediaType the media type
+ * @param method the method
+ * @param content the content
+ * @param versionParam the version param
+ * @param uri the uri
+ * @param headers the headers
+ * @param info the info
+ * @param req the req
+ * @return the response
+ */
+ private Response handleWrites(MediaType mediaType, HttpMethod method, String content, String versionParam, String uri, HttpHeaders headers, UriInfo info) {
+
+ Response response = null;
+ TransactionalGraphEngine dbEngine = null;
+ Loader loader = null;
+ Version version = null;
+ String sourceOfTruth = headers.getRequestHeaders().getFirst("X-FromAppId");
+ String transId = headers.getRequestHeaders().getFirst("X-TransactionId");
+ String realTime = headers.getRequestHeaders().getFirst("Real-Time");
+ Boolean success = true;
+
+ try {
+ validateRequest(info);
+
+ version = Version.valueOf(versionParam);
+ DBConnectionType type = this.determineConnectionType(sourceOfTruth, realTime);
+ HttpEntry httpEntry = new HttpEntry(version, introspectorFactoryType, queryStyle, type);
+ loader = httpEntry.getLoader();
+ dbEngine = httpEntry.getDbEngine();
+ URI uriObject = UriBuilder.fromPath(uri).build();
+ this.validateURI(uriObject);
+ QueryParser uriQuery = dbEngine.getQueryBuilder().createQueryFromURI(uriObject);
+ String objName = uriQuery.getResultType();
+ if (content.length() == 0) {
+ if (mediaType.toString().contains(MediaType.APPLICATION_JSON)) {
+ content = "{}";
+ } else {
+ content = "<empty/>";
+ }
+ }
+ Introspector obj = loader.unmarshal(objName, content, org.onap.aai.restcore.MediaType.getEnum(this.getInputMediaType(mediaType)));
+ if (obj == null) {
+ throw new AAIException("AAI_3000", "object could not be unmarshalled:" + content);
+ }
+
+ if (mediaType.toString().contains(MediaType.APPLICATION_XML) && !content.equals("<empty/>") && isEmptyObject(obj)) {
+ throw new AAIInvalidXMLNamespace(content);
+ }
+
+ this.validateIntrospector(obj, loader, uriObject, method);
+
+ DBRequest request =
+ new DBRequest.Builder(method, uriObject, uriQuery, obj, headers, info, transId)
+ .rawRequestContent(content).build();
+ List<DBRequest> requests = new ArrayList<>();
+ requests.add(request);
+ Pair<Boolean, List<Pair<URI, Response>>> responsesTuple = httpEntry.process(requests, sourceOfTruth);
+
+ response = responsesTuple.getValue1().get(0).getValue1();
+ success = responsesTuple.getValue0();
+ } catch (AAIException e) {
+ response = consumerExceptionResponseGenerator(headers, info, method, e);
+ success = false;
+ } catch (Exception e ) {
+ AAIException ex = new AAIException("AAI_4000", e);
+ response = consumerExceptionResponseGenerator(headers, info, method, ex);
+ success = false;
+ } finally {
+ if (dbEngine != null) {
+ if (success) {
+ dbEngine.commit();
+ } else {
+ LOGGER.warn("Rolling back Titan transaction");
+ dbEngine.rollback();
+ }
+ }
+ }
+
+ return response;
+ }
+
+ private void validateURI(URI uri) throws AAIException {
+ if (hasRelatedTo(uri)) {
+ throw new AAIException("AAI_3010");
+ }
+ }
+ private boolean hasRelatedTo(URI uri) {
+
+ return uri.toString().contains("/" + RestTokens.COUSIN + "/");
+ }
+
+ protected boolean isEmptyObject(Introspector obj) {
+ return "{}".equals(obj.marshal(false));
+ }
+}
diff --git a/aai-resources/src/main/java/org/onap/aai/rest/URLFromVertexIdConsumer.java b/aai-resources/src/main/java/org/onap/aai/rest/URLFromVertexIdConsumer.java
new file mode 100644
index 0000000..aa67557
--- /dev/null
+++ b/aai-resources/src/main/java/org/onap/aai/rest/URLFromVertexIdConsumer.java
@@ -0,0 +1,121 @@
+/**
+ * ============LICENSE_START=======================================================
+ * org.onap.aai
+ * ================================================================================
+ * Copyright © 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * 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=========================================================
+ *
+ * ECOMP is a trademark and service mark of AT&T Intellectual Property.
+ */
+package org.onap.aai.rest;
+
+import java.net.URI;
+import java.net.URL;
+import java.util.Iterator;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.ws.rs.GET;
+import javax.ws.rs.Path;
+import javax.ws.rs.PathParam;
+import javax.ws.rs.Produces;
+import javax.ws.rs.core.Context;
+import javax.ws.rs.core.HttpHeaders;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+import javax.ws.rs.core.Response.Status;
+import javax.ws.rs.core.UriInfo;
+
+import org.apache.tinkerpop.gremlin.structure.Vertex;
+
+import org.onap.aai.dbmap.DBConnectionType;
+import org.onap.aai.exceptions.AAIException;
+import org.onap.aai.introspection.ModelType;
+import org.onap.aai.introspection.Version;
+import org.onap.aai.rest.db.HttpEntry;
+import org.onap.aai.restcore.HttpMethod;
+import org.onap.aai.restcore.RESTAPI;
+import org.onap.aai.serialization.db.DBSerializer;
+import org.onap.aai.serialization.engines.QueryStyle;
+import org.onap.aai.serialization.engines.TransactionalGraphEngine;
+import org.onap.aai.util.AAIConfig;
+import org.onap.aai.workarounds.LegacyURITransformer;
+
+/**
+ * The Class URLFromVertexIdConsumer.
+ */
+@Path("{version: v[2789]|v1[01]}/generateurl")
+public class URLFromVertexIdConsumer extends RESTAPI {
+ private ModelType introspectorFactoryType = ModelType.MOXY;
+ private QueryStyle queryStyle = QueryStyle.TRAVERSAL;
+
+ private final String ID_ENDPOINT = "/id/{vertexid: \\d+}";
+
+ /**
+ * Generate url from vertex id.
+ *
+ * @param content the content
+ * @param versionParam the version param
+ * @param vertexid the vertexid
+ * @param headers the headers
+ * @param info the info
+ * @param req the req
+ * @return the response
+ */
+ @Path(ID_ENDPOINT)
+ @Produces({ MediaType.TEXT_PLAIN })
+ public Response generateUrlFromVertexId(String content, @PathParam("version")String versionParam, @PathParam("vertexid")long vertexid, @Context HttpHeaders headers, @Context UriInfo info, @Context HttpServletRequest req) {
+
+ String sourceOfTruth = headers.getRequestHeaders().getFirst("X-FromAppId");
+ String realTime = headers.getRequestHeaders().getFirst("Real-Time");
+
+ Version version = Version.valueOf(versionParam);
+ StringBuilder result = new StringBuilder();
+ Response response = null;
+ TransactionalGraphEngine dbEngine = null;
+ try {
+ DBConnectionType type = this.determineConnectionType(sourceOfTruth, realTime);
+ HttpEntry httpEntry = new HttpEntry(version, introspectorFactoryType, queryStyle, type);
+ dbEngine = httpEntry.getDbEngine();
+
+ DBSerializer serializer = new DBSerializer(version, dbEngine, introspectorFactoryType, sourceOfTruth);
+
+ Iterator<Vertex> thisVertex = dbEngine.asAdmin().getTraversalSource().V(vertexid);
+
+ if (!thisVertex.hasNext()) {
+ throw new AAIException("AAI_6114", "no node at that vertex id");
+ }
+ URI uri = serializer.getURIForVertex(thisVertex.next());
+
+ result.append(uri.getRawPath());
+ result.insert(0, version);
+ result.insert(0, AAIConfig.get("aai.server.url.base"));
+ LegacyURITransformer urlTransformer = LegacyURITransformer.getInstance();
+ URI output = new URI(result.toString());
+
+ response = Response.ok().entity(result.toString()).status(Status.OK).type(MediaType.TEXT_PLAIN).build();
+ } catch (AAIException e) {
+ //TODO check that the details here are sensible
+ response = consumerExceptionResponseGenerator(headers, info, HttpMethod.GET, e);
+ } catch (Exception e) {
+ AAIException ex = new AAIException("AAI_4000", e);
+ response = consumerExceptionResponseGenerator(headers, info, HttpMethod.GET, ex);
+ } finally { //to close the titan transaction (I think)
+ if (dbEngine != null) {
+ dbEngine.rollback();
+ }
+ }
+ return response;
+ }
+}
diff --git a/aai-resources/src/main/java/org/onap/aai/rest/VertexIdConsumer.java b/aai-resources/src/main/java/org/onap/aai/rest/VertexIdConsumer.java
new file mode 100644
index 0000000..68a72e6
--- /dev/null
+++ b/aai-resources/src/main/java/org/onap/aai/rest/VertexIdConsumer.java
@@ -0,0 +1,146 @@
+/**
+ * ============LICENSE_START=======================================================
+ * org.onap.aai
+ * ================================================================================
+ * Copyright © 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * 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=========================================================
+ *
+ * ECOMP is a trademark and service mark of AT&T Intellectual Property.
+ */
+package org.onap.aai.rest;
+
+import java.net.URI;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.ws.rs.DefaultValue;
+import javax.ws.rs.GET;
+import javax.ws.rs.Path;
+import javax.ws.rs.PathParam;
+import javax.ws.rs.Produces;
+import javax.ws.rs.QueryParam;
+import javax.ws.rs.core.Context;
+import javax.ws.rs.core.HttpHeaders;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+import javax.ws.rs.core.Response.Status;
+import javax.ws.rs.core.UriBuilder;
+import javax.ws.rs.core.UriInfo;
+
+import org.apache.tinkerpop.gremlin.structure.Vertex;
+import org.javatuples.Pair;
+
+import org.onap.aai.db.props.AAIProperties;
+import org.onap.aai.dbmap.DBConnectionType;
+import org.onap.aai.exceptions.AAIException;
+import org.onap.aai.introspection.Introspector;
+import org.onap.aai.introspection.Loader;
+import org.onap.aai.introspection.MarshallerProperties;
+import org.onap.aai.introspection.ModelType;
+import org.onap.aai.introspection.Version;
+import org.onap.aai.parsers.query.QueryParser;
+import org.onap.aai.rest.db.DBRequest;
+import org.onap.aai.rest.db.HttpEntry;
+import org.onap.aai.restcore.HttpMethod;
+import org.onap.aai.restcore.RESTAPI;
+import org.onap.aai.serialization.db.DBSerializer;
+import org.onap.aai.serialization.engines.QueryStyle;
+import org.onap.aai.serialization.engines.TransactionalGraphEngine;
+
+/**
+ * The Class VertexIdConsumer.
+ */
+@Path("{version: v[2789]|v1[01]}/resources")
+public class VertexIdConsumer extends RESTAPI {
+
+ private ModelType introspectorFactoryType = ModelType.MOXY;
+ private QueryStyle queryStyle = QueryStyle.TRAVERSAL;
+
+ private final String ID_ENDPOINT = "/id/{vertexid: \\d+}";
+
+ /**
+ * Gets the by vertex id.
+ *
+ * @param content the content
+ * @param versionParam the version param
+ * @param vertexid the vertexid
+ * @param depthParam the depth param
+ * @param headers the headers
+ * @param info the info
+ * @param req the req
+ * @return the by vertex id
+ */
+ @GET
+ @Path(ID_ENDPOINT)
+ @Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
+ public Response getByVertexId(String content, @PathParam("version")String versionParam, @PathParam("vertexid")long vertexid, @DefaultValue("all") @QueryParam("depth") String depthParam, @Context HttpHeaders headers, @Context UriInfo info, @Context HttpServletRequest req) {
+
+ String outputMediaType = getMediaType(headers.getAcceptableMediaTypes());
+ String sourceOfTruth = headers.getRequestHeaders().getFirst("X-FromAppId");
+ String transId = headers.getRequestHeaders().getFirst("X-TransactionId");
+ String realTime = headers.getRequestHeaders().getFirst("Real-Time");
+ Version version = Version.valueOf(versionParam);
+ Status status = Status.NOT_FOUND;
+ String result = "";
+ Response response = null;
+ TransactionalGraphEngine dbEngine = null;
+ try {
+ int depth = setDepth(depthParam);
+ DBConnectionType type = this.determineConnectionType(sourceOfTruth, realTime);
+ HttpEntry httpEntry = new HttpEntry(version, introspectorFactoryType, queryStyle, type);
+ dbEngine = httpEntry.getDbEngine();
+ Loader loader = httpEntry.getLoader();
+
+ DBSerializer serializer = new DBSerializer(version, dbEngine, introspectorFactoryType, sourceOfTruth);
+
+ //get type of the object represented by the given id
+ Vertex thisVertex = null;
+ Iterator<Vertex> itr = dbEngine.asAdmin().getTraversalSource().V(vertexid);
+
+ if (!itr.hasNext()) {
+ throw new AAIException("AAI_6114", "no node at that vertex id");
+ }
+ thisVertex = itr.next();
+ String objName = thisVertex.<String>property(AAIProperties.NODE_TYPE).orElse(null);
+
+ QueryParser query = dbEngine.getQueryBuilder(thisVertex).createQueryFromObjectName(objName);
+
+ Introspector obj = loader.introspectorFromName(query.getResultType());
+
+ URI uriObject = UriBuilder.fromPath(info.getPath()).build();
+
+ DBRequest request =
+ new DBRequest.Builder(HttpMethod.GET, uriObject, query, obj, headers, info, transId)
+ .customMarshaller(new MarshallerProperties.Builder(org.onap.aai.restcore.MediaType.getEnum(outputMediaType)).includeRoot(true).build()).build();
+
+ List<DBRequest> requests = new ArrayList<>();
+ requests.add(request);
+ Pair<Boolean, List<Pair<URI, Response>>> responsesTuple = httpEntry.process(requests, sourceOfTruth);
+ response = responsesTuple.getValue1().get(0).getValue1();
+ } catch (AAIException e){
+ response = consumerExceptionResponseGenerator(headers, info, HttpMethod.GET, e);
+ } catch (Exception e) {
+ AAIException ex = new AAIException("AAI_4000", e);
+ response = consumerExceptionResponseGenerator(headers, info, HttpMethod.GET, ex);
+ } finally { //to close the titan transaction (I think)
+ if (dbEngine != null) {
+ dbEngine.rollback();
+ }
+ }
+ return response;
+ }
+}
diff --git a/aai-resources/src/main/java/org/onap/aai/rest/exceptions/AAIInvalidXMLNamespace.java b/aai-resources/src/main/java/org/onap/aai/rest/exceptions/AAIInvalidXMLNamespace.java
new file mode 100644
index 0000000..b9a8176
--- /dev/null
+++ b/aai-resources/src/main/java/org/onap/aai/rest/exceptions/AAIInvalidXMLNamespace.java
@@ -0,0 +1,41 @@
+/**
+ * ============LICENSE_START=======================================================
+ * org.onap.aai
+ * ================================================================================
+ * Copyright © 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * 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=========================================================
+ *
+ * ECOMP is a trademark and service mark of AT&T Intellectual Property.
+ */
+package org.onap.aai.rest.exceptions;
+
+import org.onap.aai.exceptions.AAIException;
+
+public class AAIInvalidXMLNamespace extends AAIException {
+
+ private static final long serialVersionUID = 7487333042291858169L;
+
+ public AAIInvalidXMLNamespace(String message) {
+ super("AAI_3011", message);
+ }
+
+ public AAIInvalidXMLNamespace(Throwable cause) {
+ super("AAI_3011",cause);
+ }
+
+ public AAIInvalidXMLNamespace(String message, Throwable cause) {
+ super("AAI_3011", cause, message);
+ }
+}
diff --git a/aai-resources/src/main/java/org/onap/aai/rest/retired/RetiredConsumer.java b/aai-resources/src/main/java/org/onap/aai/rest/retired/RetiredConsumer.java
new file mode 100644
index 0000000..0188142
--- /dev/null
+++ b/aai-resources/src/main/java/org/onap/aai/rest/retired/RetiredConsumer.java
@@ -0,0 +1,144 @@
+/**
+ * ============LICENSE_START=======================================================
+ * org.onap.aai
+ * ================================================================================
+ * Copyright © 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * 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=========================================================
+ *
+ * ECOMP is a trademark and service mark of AT&T Intellectual Property.
+ */
+package org.onap.aai.rest.retired;
+
+import java.util.ArrayList;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.ws.rs.DELETE;
+import javax.ws.rs.GET;
+import javax.ws.rs.POST;
+import javax.ws.rs.PUT;
+import javax.ws.rs.Path;
+import javax.ws.rs.PathParam;
+import javax.ws.rs.core.Context;
+import javax.ws.rs.core.HttpHeaders;
+import javax.ws.rs.core.Response;
+import javax.ws.rs.core.UriInfo;
+
+import org.apache.cxf.jaxrs.ext.PATCH;
+
+import org.onap.aai.exceptions.AAIException;
+import org.onap.aai.logging.ErrorLogHelper;
+import org.onap.aai.restcore.RESTAPI;
+import org.onap.aai.util.AAIConfig;
+
+/**
+ * The Class RetiredConsumer.
+ */
+public abstract class RetiredConsumer extends RESTAPI {
+
+ /**
+ * Creates the message get.
+ *
+ * @param versionParam the version param
+ * @param headers the headers
+ * @param info the info
+ * @param req the req
+ * @return the response
+ */
+ @GET
+ @Path("/{uri:.*}")
+ public Response createMessageGet(@PathParam("version")String versionParam, @Context HttpHeaders headers, @Context UriInfo info, @Context HttpServletRequest req) {
+ return createMessage(versionParam, headers, info, req);
+ }
+
+ /**
+ * Creates the message delete.
+ *
+ * @param versionParam the version param
+ * @param headers the headers
+ * @param info the info
+ * @param req the req
+ * @return the response
+ */
+ @DELETE
+ @Path("/{uri:.*}")
+ public Response createMessageDelete(@PathParam("version")String versionParam, @Context HttpHeaders headers, @Context UriInfo info, @Context HttpServletRequest req) {
+ return createMessage(versionParam, headers, info, req);
+ }
+
+ /**
+ * Creates the message post.
+ *
+ * @param versionParam the version param
+ * @param headers the headers
+ * @param info the info
+ * @param req the req
+ * @return the response
+ */
+ @POST
+ @Path("/{uri:.*}")
+ public Response createMessagePost(@PathParam("version")String versionParam, @Context HttpHeaders headers, @Context UriInfo info, @Context HttpServletRequest req) {
+ return createMessage(versionParam, headers, info, req);
+ }
+
+ @PATCH
+ @Path("/{uri:.*}")
+ public Response createMessagePatch(@PathParam("version")String versionParam, @Context HttpHeaders headers, @Context UriInfo info, @Context HttpServletRequest req) {
+ return createMessage(versionParam, headers, info, req);
+ }
+ /**
+ * Creates the message put.
+ *
+ * @param versionParam the version param
+ * @param headers the headers
+ * @param info the info
+ * @param req the req
+ * @return the response
+ */
+ @PUT
+ @Path("/{uri:.*}")
+ public Response createMessagePut(@PathParam("version")String versionParam, @Context HttpHeaders headers, @Context UriInfo info, @Context HttpServletRequest req) {
+ return createMessage(versionParam, headers, info, req);
+ }
+
+
+ /**
+ * Creates the message.
+ *
+ * @param versionParam the version param
+ * @param headers the headers
+ * @param info the info
+ * @param req the req
+ * @return the response
+ */
+ private Response createMessage(String versionParam, HttpHeaders headers, UriInfo info, HttpServletRequest req) {
+ AAIException e = new AAIException("AAI_3007");
+
+ ArrayList<String> templateVars = new ArrayList<String>();
+
+ if (templateVars.size() == 0) {
+ templateVars.add("PUT");
+ templateVars.add(info.getPath().toString());
+ templateVars.add(versionParam);
+ templateVars.add(AAIConfig.get("aai.default.api.version", ""));
+ }
+
+ Response response = Response
+ .status(e.getErrorObject().getHTTPResponseCode())
+ .entity(ErrorLogHelper.getRESTAPIErrorResponse(headers.getAcceptableMediaTypes(), e,
+ templateVars)).build();
+
+ return response;
+ }
+}
diff --git a/aai-resources/src/main/java/org/onap/aai/rest/retired/V3ThroughV7Consumer.java b/aai-resources/src/main/java/org/onap/aai/rest/retired/V3ThroughV7Consumer.java
new file mode 100644
index 0000000..a43e5c2
--- /dev/null
+++ b/aai-resources/src/main/java/org/onap/aai/rest/retired/V3ThroughV7Consumer.java
@@ -0,0 +1,29 @@
+/**
+ * ============LICENSE_START=======================================================
+ * org.onap.aai
+ * ================================================================================
+ * Copyright © 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * 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=========================================================
+ *
+ * ECOMP is a trademark and service mark of AT&T Intellectual Property.
+ */
+package org.onap.aai.rest.retired;
+
+import javax.ws.rs.Path;
+
+@Path("{version: v[3-6]}") //TODO re-add v7 when we fix our env issues AAI-8567
+public class V3ThroughV7Consumer extends RetiredConsumer {
+
+}
diff --git a/aai-resources/src/main/java/org/onap/aai/rest/retired/V7V8Models.java b/aai-resources/src/main/java/org/onap/aai/rest/retired/V7V8Models.java
new file mode 100644
index 0000000..26dea02
--- /dev/null
+++ b/aai-resources/src/main/java/org/onap/aai/rest/retired/V7V8Models.java
@@ -0,0 +1,29 @@
+/**
+ * ============LICENSE_START=======================================================
+ * org.onap.aai
+ * ================================================================================
+ * Copyright © 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * 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=========================================================
+ *
+ * ECOMP is a trademark and service mark of AT&T Intellectual Property.
+ */
+package org.onap.aai.rest.retired;
+
+import javax.ws.rs.Path;
+
+@Path("{version: v[78]}/service-design-and-creation/models")
+public class V7V8Models extends RetiredConsumer {
+
+}
diff --git a/aai-resources/src/main/java/org/onap/aai/rest/retired/V7V8NamedQueries.java b/aai-resources/src/main/java/org/onap/aai/rest/retired/V7V8NamedQueries.java
new file mode 100644
index 0000000..98be455
--- /dev/null
+++ b/aai-resources/src/main/java/org/onap/aai/rest/retired/V7V8NamedQueries.java
@@ -0,0 +1,29 @@
+/**
+ * ============LICENSE_START=======================================================
+ * org.onap.aai
+ * ================================================================================
+ * Copyright © 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * 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=========================================================
+ *
+ * ECOMP is a trademark and service mark of AT&T Intellectual Property.
+ */
+package org.onap.aai.rest.retired;
+
+import javax.ws.rs.Path;
+
+@Path("{version: v[78]}/service-design-and-creation/named-queries")
+public class V7V8NamedQueries extends RetiredConsumer {
+
+}
diff --git a/aai-resources/src/main/java/org/onap/aai/rest/tools/ModelVersionTransformer.java b/aai-resources/src/main/java/org/onap/aai/rest/tools/ModelVersionTransformer.java
new file mode 100644
index 0000000..eeaaf6a
--- /dev/null
+++ b/aai-resources/src/main/java/org/onap/aai/rest/tools/ModelVersionTransformer.java
@@ -0,0 +1,410 @@
+/**
+ * ============LICENSE_START=======================================================
+ * org.onap.aai
+ * ================================================================================
+ * Copyright © 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * 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=========================================================
+ *
+ * ECOMP is a trademark and service mark of AT&T Intellectual Property.
+ */
+package org.onap.aai.rest.tools;
+
+import java.io.UnsupportedEncodingException;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.NoSuchElementException;
+import java.util.Set;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.ws.rs.Consumes;
+import javax.ws.rs.Encoded;
+import javax.ws.rs.POST;
+import javax.ws.rs.Path;
+import javax.ws.rs.PathParam;
+import javax.ws.rs.Produces;
+import javax.ws.rs.core.Context;
+import javax.ws.rs.core.HttpHeaders;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.MultivaluedMap;
+import javax.ws.rs.core.Response;
+import javax.ws.rs.core.Response.Status;
+import javax.ws.rs.core.UriInfo;
+
+import org.apache.tinkerpop.gremlin.structure.Vertex;
+import org.onap.aai.db.props.AAIProperties;
+import org.onap.aai.dbmap.DBConnectionType;
+import org.onap.aai.exceptions.AAIException;
+import org.onap.aai.introspection.Introspector;
+import org.onap.aai.introspection.Loader;
+import org.onap.aai.introspection.MarshallerProperties;
+import org.onap.aai.introspection.ModelType;
+import org.onap.aai.introspection.Version;
+import org.onap.aai.introspection.exceptions.AAIUnknownObjectException;
+import org.onap.aai.logging.ErrorLogHelper;
+import org.onap.aai.rest.db.HttpEntry;
+import org.onap.aai.rest.exceptions.AAIInvalidXMLNamespace;
+import org.onap.aai.rest.util.ValidateEncoding;
+import org.onap.aai.restcore.RESTAPI;
+import org.onap.aai.serialization.db.EdgeType;
+import org.onap.aai.serialization.db.exceptions.NoEdgeRuleFoundException;
+import org.onap.aai.serialization.engines.QueryStyle;
+import org.onap.aai.serialization.engines.TransactionalGraphEngine;
+
+import com.att.eelf.configuration.EELFLogger;
+import com.att.eelf.configuration.EELFManager;
+import com.google.common.base.Joiner;
+
+
+/**
+ * The Class ModelVersionTransformer.
+ */
+@Path("tools")
+public class ModelVersionTransformer extends RESTAPI {
+
+ private static final EELFLogger LOGGER = EELFManager.getInstance().getLogger(ModelVersionTransformer.class.getName());
+ protected static String authPolicyFunctionName = "REST";
+ private ModelType introspectorFactoryType = ModelType.MOXY;
+ private QueryStyle queryStyle = QueryStyle.TRAVERSAL;
+
+
+ /**
+ * POST for model transformation.
+ *
+ * @param content the content
+ * @param uri the uri
+ * @param headers the headers
+ * @param info the info
+ * @param req the req
+ * @return the transformed model
+ * @Path("/{uri: modeltransform}")
+ * @throws UnsupportedEncodingException
+ */
+ @POST
+ @Path("/{uri: modeltransform}")
+ @Consumes({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
+ @Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
+ public Response modelTransform (String content, @PathParam("uri") @Encoded String uri, @Context HttpHeaders headers, @Context UriInfo info, @Context HttpServletRequest req) throws UnsupportedEncodingException {
+ Response response = null;
+ TransactionalGraphEngine dbEngine = null;
+ Loader loader = null;
+ MediaType mediaType = headers.getMediaType();
+ String sourceOfTruth = headers.getRequestHeaders().getFirst("X-FromAppId");
+ String transId = headers.getRequestHeaders().getFirst("X-TransactionId");
+ String realTime = headers.getRequestHeaders().getFirst("Real-Time");
+ Boolean success = true;
+ AAIException ex;
+
+ try {
+ validateRequest(info);
+
+ DBConnectionType type = this.determineConnectionType(sourceOfTruth, realTime);
+ HttpEntry httpEntry = new HttpEntry(Version.v8, introspectorFactoryType, queryStyle, type);
+ loader = httpEntry.getLoader();
+ dbEngine = httpEntry.getDbEngine();
+ if (content.length() == 0) {
+ if (mediaType.toString().contains(MediaType.APPLICATION_JSON)) {
+ content = "{}";
+ } else {
+ content = "<empty/>";
+ }
+ }
+
+ //Unmarshall the received model and store properties and values in a map.
+ Introspector obj = loader.unmarshal("Model", content, org.onap.aai.restcore.MediaType.getEnum(this.getInputMediaType(mediaType)));
+ if (obj == null) {
+ throw new AAIException("AAI_3000", "object could not be unmarshalled:" + content);
+ }
+
+ if (mediaType.toString().contains(MediaType.APPLICATION_XML) && !content.equals("<empty/>") && isEmptyObject(obj)) {
+ throw new AAIInvalidXMLNamespace(content);
+ }
+
+ Set<String> properties = obj.getProperties();
+ java.util.Iterator<String> propItr = properties.iterator();
+
+ Map<String, Object> v8PropMap = new HashMap<String, Object>();
+ while (propItr.hasNext()){
+ String property = propItr.next();
+ Object propertyValue = obj.getValue(property);
+ if (propertyValue != null) {
+ v8PropMap.put(propItr.next(), propertyValue);
+ }
+ }
+ // Get the current models and create a map of model-ver to model keys, this allows us
+ // to easily figure out and construct the relationships on the supplied v8 model
+ Map<String,String> modelVersionIdToModelInvariantIdMap = getCurrentModelsFromGraph(headers, transId, info);
+
+ // Build the v10 - TODO
+ HttpEntry newHttpEntry = new HttpEntry(Version.v10, introspectorFactoryType, queryStyle, type);
+ Loader newLoader = newHttpEntry.getLoader();
+ Introspector newModelObj = newLoader.introspectorFromName("Model");
+
+ // pull the attributes we need to apply to the model + model-ver objects
+ // model specific attrs
+ String oldModelInvariantId = obj.getValue("model-id");
+ String oldModelType = obj.getValue("model-type");
+ // model-ver specific
+ String oldModelName = obj.getValue("model-name");
+ String oldModelVersionId = obj.getValue("model-name-version-id");
+ String oldModelVersion = obj.getValue("model-version");
+
+ // copy attributes from the v8 model object to the v10 model object
+ newModelObj.setValue("model-invariant-id", oldModelInvariantId);
+ newModelObj.setValue("model-type", oldModelType);
+
+ Introspector modelVersObj = newModelObj.newIntrospectorInstanceOfProperty("model-vers");
+
+ newModelObj.setValue("model-vers", modelVersObj.getUnderlyingObject());
+
+ List<Object> modelVerList = (List<Object>)modelVersObj.getValue("model-ver");
+
+ //create a model-ver object
+ Introspector modelVerObj = newLoader.introspectorFromName("ModelVer");
+ // load attributes from the v8 model object into the v10 model-ver object
+ modelVerObj.setValue("model-version-id", oldModelVersionId);
+ modelVerObj.setValue("model-name", oldModelName);
+ modelVerObj.setValue("model-version", oldModelVersion);
+
+
+ if (obj.hasProperty("model-elements")) {
+ Introspector oldModelElements = obj.getWrappedValue("model-elements");
+ if (oldModelElements != null) {
+ Introspector newModelElements = modelVerObj.newIntrospectorInstanceOfProperty("model-elements");
+ modelVerObj.setValue("model-elements", newModelElements.getUnderlyingObject());
+ repackModelElements(oldModelElements, newModelElements, modelVersionIdToModelInvariantIdMap);
+ }
+ }
+
+ modelVerList.add(modelVerObj.getUnderlyingObject());
+
+ String outputMediaType = getMediaType(headers.getAcceptableMediaTypes());
+ MarshallerProperties marshallerProperties =
+ new MarshallerProperties.Builder(org.onap.aai.restcore.MediaType.getEnum(outputMediaType)).build();
+
+ String result = newModelObj.marshal(marshallerProperties);
+ response = Response.ok(result).build();
+
+ } catch (AAIException e) {
+
+ ArrayList<String> templateVars = new ArrayList<String>(2);
+ templateVars.add("POST modeltransform");
+ templateVars.add("model-ver.model-version-id");
+ response = Response
+ .status(e.getErrorObject().getHTTPResponseCode())
+ .entity(ErrorLogHelper.getRESTAPIErrorResponse(
+ headers.getAcceptableMediaTypes(), e,
+ templateVars)).build();
+ success = false;
+ } catch (Exception e) {
+ ArrayList<String> templateVars = new ArrayList<String>(2);
+ templateVars.add("POST modeltransform");
+ templateVars.add("model-ver.model-version-id");
+ ex = new AAIException("AAI_4000", e);
+ response = Response
+ .status(Status.INTERNAL_SERVER_ERROR)
+ .entity(ErrorLogHelper.getRESTAPIErrorResponse(headers.getAcceptableMediaTypes(), ex, templateVars))
+ .build();
+ e.printStackTrace();
+ success = false;
+ } finally {
+ if (dbEngine != null) {
+ if (success) {
+ dbEngine.commit();
+ } else {
+ dbEngine.rollback();
+ }
+ }
+ }
+ return response;
+ }
+
+
+ private void repackModelElements(Introspector oldModelElements, Introspector newModelElements, Map<String, String> modelVersionIdToModelInvariantIdMap)
+ throws AAIUnknownObjectException, AAIException {
+
+ List<Introspector> oldModelElementList = oldModelElements.getWrappedListValue("model-element");
+ List<Object> newModelElementList = (List<Object>)newModelElements.getValue("model-element");
+
+ for (Introspector oldModelElement : oldModelElementList) {
+ Introspector newModelElement = newModelElements.getLoader().introspectorFromName("model-element");
+
+ ArrayList<String> attrs = new ArrayList<String>();
+
+ attrs.add("model-element-uuid");
+ attrs.add("new-data-del-flag");
+ attrs.add("cardinality");
+ attrs.add("linkage-points");
+
+ for (String attr : attrs) {
+ if (oldModelElement.hasProperty(attr)) {
+ newModelElement.setValue(attr, oldModelElement.getValue(attr));
+ }
+ }
+
+ if (oldModelElement.hasProperty("relationship-list")) {
+
+ Introspector oldRelationshipList = oldModelElement.getWrappedValue("relationship-list");
+ Introspector newRelationshipList = newModelElements.getLoader().introspectorFromName("relationship-list");
+ newModelElement.setValue("relationship-list", newRelationshipList.getUnderlyingObject());
+
+ List<Introspector> oldRelationshipListList = oldRelationshipList.getWrappedListValue("relationship");
+ List<Object> newRelationshipListList = (List<Object>)newRelationshipList.getValue("relationship");
+
+ for (Introspector oldRelationship : oldRelationshipListList) {
+
+ Introspector newRelationship = newModelElements.getLoader().introspectorFromName("relationship");
+ newRelationshipListList.add(newRelationship.getUnderlyingObject());
+
+ List<Introspector> oldRelationshipData = oldRelationship.getWrappedListValue("relationship-data");
+ List<Object> newRelationshipData = (List<Object>)newRelationship.getValue("relationship-data");
+
+ newRelationship.setValue("related-to", "model-ver");
+
+ for (Introspector oldRelationshipDatum : oldRelationshipData) {
+
+ String oldProp = null;
+ String oldVal = null;
+
+ if (oldRelationshipDatum.hasProperty("relationship-key")) {
+ oldProp = oldRelationshipDatum.getValue("relationship-key");
+ }
+ if (oldRelationshipDatum.hasProperty("relationship-value")) {
+ oldVal = oldRelationshipDatum.getValue("relationship-value");
+ }
+
+ if ("model.model-name-version-id".equals(oldProp)) {
+ // make two new relationshipDatum for use w/ the new style model
+
+ // you should have the model in the list of models we collected earlier
+ if (modelVersionIdToModelInvariantIdMap.containsKey(oldVal)) {
+ Introspector newRelationshipDatum1 = newModelElements.getLoader().introspectorFromName("relationship-data");
+ Introspector newRelationshipDatum2 = newModelElements.getLoader().introspectorFromName("relationship-data");
+
+ String modelId = modelVersionIdToModelInvariantIdMap.get(oldVal);
+
+ // the first one points at the model-invariant-id of found model
+ newRelationshipDatum1.setValue("relationship-key", "model.model-invariant-id");
+ newRelationshipDatum1.setValue("relationship-value", modelId);
+
+ // the second one points at the model-version-id which corresponds to the old model-name-version-id
+ newRelationshipDatum2.setValue("relationship-key", "model-ver.model-version-id");
+ newRelationshipDatum2.setValue("relationship-value", oldVal);
+
+ newRelationshipData.add(newRelationshipDatum1.getUnderlyingObject());
+ newRelationshipData.add(newRelationshipDatum2.getUnderlyingObject());
+ } else {
+ throw new AAIException("AAI_6114", "No model-ver found using model-ver.model-version-id=" + oldVal);
+ }
+ }
+ }
+
+ }
+ }
+
+ if (oldModelElement.hasProperty("model-elements")) {
+ Introspector nextOldModelElements = oldModelElement.getWrappedValue("model-elements");
+ if (nextOldModelElements != null) {
+ Introspector nextNewModelElements = newModelElement.newIntrospectorInstanceOfProperty("model-elements");
+ newModelElement.setValue("model-elements", nextNewModelElements.getUnderlyingObject());
+ repackModelElements(nextOldModelElements, nextNewModelElements, modelVersionIdToModelInvariantIdMap);
+ }
+ }
+ newModelElementList.add(newModelElement.getUnderlyingObject());
+ }
+ return;
+
+ }
+
+ private Map<String, String> getCurrentModelsFromGraph(HttpHeaders headers, String transactionId, UriInfo info) throws NoEdgeRuleFoundException, AAIException {
+
+ TransactionalGraphEngine dbEngine = null;
+ Map<String, String> modelVerModelMap = new HashMap<String,String>() ;
+ try {
+
+ Version version = AAIProperties.LATEST;
+ DBConnectionType type = DBConnectionType.REALTIME;
+
+ final HttpEntry httpEntry = new HttpEntry(version, introspectorFactoryType, queryStyle, type);
+ dbEngine = httpEntry.getDbEngine();
+
+ List<Vertex> modelVertices = dbEngine.asAdmin().getTraversalSource().V().has(AAIProperties.NODE_TYPE,"model").toList();
+ for (Vertex modelVtx : modelVertices) {
+
+ List<Vertex> modelVerVerts = dbEngine.getQueryBuilder(modelVtx).createEdgeTraversal(EdgeType.TREE, "model", "model-ver").toList();
+ for (Vertex v : modelVerVerts) {
+ modelVerModelMap.put(v.value("model-version-id"), modelVtx.value("model-invariant-id"));
+ }
+ }
+ } catch (NoSuchElementException e) {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ } catch (Exception e1) {
+ e1.printStackTrace();
+ }
+ return modelVerModelMap;
+
+ }
+
+ /**
+ * Validate request.
+ *
+ * @param uri the uri
+ * @param headers the headers
+ * @param req the req
+ * @param action the action
+ * @param info the info
+ * @throws AAIException the AAI exception
+ * @throws UnsupportedEncodingException the unsupported encoding exception
+ */
+ private void validateRequest(UriInfo info) throws AAIException, UnsupportedEncodingException {
+
+ if (!ValidateEncoding.getInstance().validate(info)) {
+ throw new AAIException("AAI_3008", "uri=" + getPath(info));
+ }
+ }
+
+ /**
+ * Gets the path.
+ *
+ * @param info the info
+ * @return the path
+ */
+ private String getPath(UriInfo info) {
+ String path = info.getPath(false);
+ MultivaluedMap<String, String> map = info.getQueryParameters(false);
+ String params = "?";
+ List<String> parmList = new ArrayList<>();
+ for (String key : map.keySet()) {
+ for (String value : map.get(key)) {
+ parmList.add(key + "=" + value);
+ }
+ }
+ String queryParams = Joiner.on("&").join(parmList);
+ if (map.keySet().size() > 0) {
+ path += params + queryParams;
+ }
+
+ return path;
+
+ }
+
+ protected boolean isEmptyObject(Introspector obj) {
+ return "{}".equals(obj.marshal(false));
+ }
+
+
+}
diff --git a/aai-resources/src/main/java/org/onap/aai/rest/util/EchoResponse.java b/aai-resources/src/main/java/org/onap/aai/rest/util/EchoResponse.java
new file mode 100644
index 0000000..55a07e4
--- /dev/null
+++ b/aai-resources/src/main/java/org/onap/aai/rest/util/EchoResponse.java
@@ -0,0 +1,122 @@
+/**
+ * ============LICENSE_START=======================================================
+ * org.onap.aai
+ * ================================================================================
+ * Copyright © 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * 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=========================================================
+ *
+ * ECOMP is a trademark and service mark of AT&T Intellectual Property.
+ */
+package org.onap.aai.rest.util;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.ws.rs.GET;
+import javax.ws.rs.Path;
+import javax.ws.rs.Produces;
+import javax.ws.rs.QueryParam;
+import javax.ws.rs.core.Context;
+import javax.ws.rs.core.HttpHeaders;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+import javax.ws.rs.core.Response.Status;
+
+import org.onap.aai.exceptions.AAIException;
+import org.onap.aai.logging.ErrorLogHelper;
+import org.onap.aai.restcore.RESTAPI;
+
+/**
+ * The Class EchoResponse.
+ */
+public class EchoResponse extends RESTAPI {
+
+ protected static String authPolicyFunctionName = "util";
+
+ public static final String echoPath = "/util/echo";
+
+ /**
+ * Simple health-check API that echos back the X-FromAppId and X-TransactionId to clients.
+ * If there is a query string, a transaction gets logged into hbase, proving the application is connected to the data store.
+ * If there is no query string, no transacction logging is done to hbase.
+ *
+ * @param headers the headers
+ * @param req the req
+ * @param myAction if exists will cause transaction to be logged to hbase
+ * @return the response
+ */
+ @GET
+ @Produces( { MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
+ @Path(echoPath)
+ public Response echoResult(@Context HttpHeaders headers, @Context HttpServletRequest req,
+ @QueryParam("action") String myAction) {
+ Response response = null;
+
+ AAIException ex = null;
+ String fromAppId = null;
+ String transId = null;
+
+ try {
+ fromAppId = getFromAppId(headers );
+ transId = getTransId(headers);
+ } catch (AAIException e) {
+ ArrayList<String> templateVars = new ArrayList<String>();
+ templateVars.add("PUT uebProvider");
+ templateVars.add("addTopic");
+ return Response
+ .status(e.getErrorObject().getHTTPResponseCode())
+ .entity(ErrorLogHelper.getRESTAPIErrorResponse(headers.getAcceptableMediaTypes(), e, templateVars))
+ .build();
+ }
+
+ try {
+
+ HashMap<AAIException, ArrayList<String>> exceptionList = new HashMap<AAIException, ArrayList<String>>();
+
+ ArrayList<String> templateVars = new ArrayList<String>();
+ templateVars.add(fromAppId);
+ templateVars.add(transId);
+
+ exceptionList.put(new AAIException("AAI_0002", "OK"), templateVars);
+
+ response = Response.status(Status.OK)
+ .entity(ErrorLogHelper.getRESTAPIInfoResponse(
+ headers.getAcceptableMediaTypes(), exceptionList))
+ .build();
+
+ } catch (Exception e) {
+ ex = new AAIException("AAI_4000", e);
+ ArrayList<String> templateVars = new ArrayList<String>();
+ templateVars.add(Action.GET.name());
+ templateVars.add(fromAppId +" "+transId);
+
+ response = Response
+ .status(Status.INTERNAL_SERVER_ERROR)
+ .entity(ErrorLogHelper.getRESTAPIErrorResponse(
+ headers.getAcceptableMediaTypes(), ex,
+ templateVars)).build();
+
+ } finally {
+ if (ex != null) {
+ ErrorLogHelper.logException(ex);
+ }
+
+ }
+
+ return response;
+ }
+
+}
diff --git a/aai-resources/src/main/java/org/onap/aai/rest/util/LogFormatTools.java b/aai-resources/src/main/java/org/onap/aai/rest/util/LogFormatTools.java
new file mode 100644
index 0000000..cfda0c3
--- /dev/null
+++ b/aai-resources/src/main/java/org/onap/aai/rest/util/LogFormatTools.java
@@ -0,0 +1,37 @@
+/**
+ * ============LICENSE_START=======================================================
+ * org.onap.aai
+ * ================================================================================
+ * Copyright © 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * 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=========================================================
+ *
+ * ECOMP is a trademark and service mark of AT&T Intellectual Property.
+ */
+package org.onap.aai.rest.util;
+
+import java.time.ZoneOffset;
+import java.time.ZonedDateTime;
+import java.time.format.DateTimeFormatter;
+
+public class LogFormatTools {
+
+ private static final String DATE_FORMAT = "yyyy-MM-dd'T'HH:mm:ss.SSSZ";
+ private static final DateTimeFormatter DTF = DateTimeFormatter.ofPattern(DATE_FORMAT)
+ .withZone(ZoneOffset.UTC);
+
+ public static String getCurrentDateTime() {
+ return DTF.format(ZonedDateTime.now());
+ }
+}
diff --git a/aai-resources/src/main/java/org/onap/aai/rest/util/ValidateEncoding.java b/aai-resources/src/main/java/org/onap/aai/rest/util/ValidateEncoding.java
new file mode 100644
index 0000000..7d4b314
--- /dev/null
+++ b/aai-resources/src/main/java/org/onap/aai/rest/util/ValidateEncoding.java
@@ -0,0 +1,161 @@
+/**
+ * ============LICENSE_START=======================================================
+ * org.onap.aai
+ * ================================================================================
+ * Copyright © 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * 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=========================================================
+ *
+ * ECOMP is a trademark and service mark of AT&T Intellectual Property.
+ */
+package org.onap.aai.rest.util;
+
+import java.io.UnsupportedEncodingException;
+import java.net.URI;
+
+import javax.ws.rs.core.MultivaluedMap;
+import javax.ws.rs.core.UriInfo;
+
+import org.springframework.web.util.UriUtils;
+
+/**
+ * The Class ValidateEncoding.
+ */
+public class ValidateEncoding {
+
+ private final String encoding = "UTF-8";
+
+ /**
+ * Instantiates a new validate encoding.
+ */
+ private ValidateEncoding() {
+
+ }
+
+ /**
+ * The Class Helper.
+ */
+ private static class Helper {
+
+ /** The Constant INSTANCE. */
+ private static final ValidateEncoding INSTANCE = new ValidateEncoding();
+ }
+
+ /**
+ * Gets the single instance of ValidateEncoding.
+ *
+ * @return single instance of ValidateEncoding
+ */
+ public static ValidateEncoding getInstance() {
+ return Helper.INSTANCE;
+ }
+
+ /**
+ * Validate.
+ *
+ * @param uri the uri
+ * @return true, if successful
+ * @throws UnsupportedEncodingException the unsupported encoding exception
+ */
+ public boolean validate(URI uri) throws UnsupportedEncodingException {
+ boolean result = true;
+ if (!validatePath(uri.getRawPath())) {
+ result = false;
+ }
+ /*if (!validateQueryParams(uri.getRawQuery())) {
+ result = false;
+ } //TODO
+ */
+
+ return result;
+ }
+
+ /**
+ * Validate.
+ *
+ * @param info the info
+ * @return true, if successful
+ * @throws UnsupportedEncodingException the unsupported encoding exception
+ */
+ public boolean validate(UriInfo info) throws UnsupportedEncodingException {
+ boolean result = true;
+ if (!validatePath(info.getPath(false))) {
+ result = false;
+ }
+ if (!validateQueryParams(info.getQueryParameters(false))) {
+ result = false;
+ }
+
+ return result;
+ }
+
+ /**
+ * Validate path.
+ *
+ * @param path the path
+ * @return true, if successful
+ * @throws UnsupportedEncodingException the unsupported encoding exception
+ */
+ private boolean validatePath(String path) throws UnsupportedEncodingException {
+ String[] segments = path.split("/");
+ boolean valid = true;
+ for (String segment : segments) {
+ if (!this.checkEncoding(segment)) {
+ valid = false;
+ }
+ }
+
+ return valid;
+
+ }
+
+ /**
+ * Validate query params.
+ *
+ * @param params the params
+ * @return true, if successful
+ * @throws UnsupportedEncodingException the unsupported encoding exception
+ */
+ private boolean validateQueryParams(MultivaluedMap<String, String> params) throws UnsupportedEncodingException {
+ boolean valid = true;
+
+ for (String key : params.keySet()) {
+ if (!this.checkEncoding(key)) {
+ valid = false;
+ }
+ for (String item : params.get(key)) {
+ if (!this.checkEncoding(item)) {
+ valid = false;
+ }
+ }
+ }
+ return valid;
+ }
+
+ /**
+ * Check encoding.
+ *
+ * @param segment the segment
+ * @return true, if successful
+ * @throws UnsupportedEncodingException the unsupported encoding exception
+ */
+ private boolean checkEncoding(String segment) throws UnsupportedEncodingException {
+ boolean result = false;
+ String decode = UriUtils.decode(segment, encoding);
+ String encode = UriUtils.encode(decode, encoding);
+ result = segment.equals(encode);
+
+ return result;
+ }
+}