aboutsummaryrefslogtreecommitdiffstats
path: root/aai-traversal/src/main/java/org/openecomp
diff options
context:
space:
mode:
authorVenkata Harish K Kajur <vk250x@att.com>2017-05-12 17:36:59 -0400
committerVenkata Harish K Kajur <vk250x@att.com>2017-05-12 17:37:13 -0400
commitb5b99b72733ca5c064b46fdf4527ace28b8b545b (patch)
treeb1606e7d824e5d56b3530f724bf7bf326f9a7833 /aai-traversal/src/main/java/org/openecomp
parentb6a2b26886ac329dd0836270127c1b9d283c3659 (diff)
Add all of the traversal source files
Change-Id: Id31f4bdda9c86f782f86829f8b86dada959a9729 Signed-off-by: Venkata Harish K Kajur <vk250x@att.com>
Diffstat (limited to 'aai-traversal/src/main/java/org/openecomp')
-rw-r--r--aai-traversal/src/main/java/org/openecomp/aai/ajsc_aai/JaxrsErrorMessageLookupService.java98
-rw-r--r--aai-traversal/src/main/java/org/openecomp/aai/ajsc_aai/JaxrsUserService.java54
-rw-r--r--aai-traversal/src/main/java/org/openecomp/aai/ajsc_aai/filemonitor/ServicePropertiesListener.java19
-rw-r--r--aai-traversal/src/main/java/org/openecomp/aai/ajsc_aai/filemonitor/ServicePropertiesMap.java126
-rw-r--r--aai-traversal/src/main/java/org/openecomp/aai/ajsc_aai/filemonitor/ServicePropertyService.java19
-rw-r--r--aai-traversal/src/main/java/org/openecomp/aai/ajsc_aai/util/ServicePropertiesMapBean.java37
-rw-r--r--aai-traversal/src/main/java/org/openecomp/aai/db/DbMethHelper.java158
-rw-r--r--aai-traversal/src/main/java/org/openecomp/aai/dbgraphgen/DbEdgeGroup.java439
-rw-r--r--aai-traversal/src/main/java/org/openecomp/aai/dbgraphgen/DbMeth.java3643
-rw-r--r--aai-traversal/src/main/java/org/openecomp/aai/dbgraphgen/ModelBasedProcessing.java3718
-rw-r--r--aai-traversal/src/main/java/org/openecomp/aai/dbgraphgen/ResultSet.java168
-rw-r--r--aai-traversal/src/main/java/org/openecomp/aai/dbgraphmap/RelationshipGraph.java299
-rw-r--r--aai-traversal/src/main/java/org/openecomp/aai/dbgraphmap/SearchGraph.java1207
-rw-r--r--aai-traversal/src/main/java/org/openecomp/aai/dmaap/AAIDmaapEventJMSConsumer.java163
-rw-r--r--aai-traversal/src/main/java/org/openecomp/aai/dmaap/AAIDmaapEventJMSProducer.java44
-rw-r--r--aai-traversal/src/main/java/org/openecomp/aai/extensions/AAIExtensionMap.java827
-rw-r--r--aai-traversal/src/main/java/org/openecomp/aai/extensions/ExtensionController.java145
-rw-r--r--aai-traversal/src/main/java/org/openecomp/aai/interceptors/AAIHeaderProperties.java26
-rw-r--r--aai-traversal/src/main/java/org/openecomp/aai/interceptors/AAILogJAXRSInInterceptor.java283
-rw-r--r--aai-traversal/src/main/java/org/openecomp/aai/interceptors/AAILogJAXRSOutInterceptor.java323
-rw-r--r--aai-traversal/src/main/java/org/openecomp/aai/interceptors/PostAaiAjscInterceptor.java63
-rw-r--r--aai-traversal/src/main/java/org/openecomp/aai/interceptors/PreAaiAjscInterceptor.java54
-rw-r--r--aai-traversal/src/main/java/org/openecomp/aai/rest/ExceptionHandler.java129
-rw-r--r--aai-traversal/src/main/java/org/openecomp/aai/rest/QueryConsumer.java182
-rw-r--r--aai-traversal/src/main/java/org/openecomp/aai/rest/db/DBRequest.java251
-rw-r--r--aai-traversal/src/main/java/org/openecomp/aai/rest/db/HttpEntry.java672
-rw-r--r--aai-traversal/src/main/java/org/openecomp/aai/rest/retired/RetiredConsumer.java143
-rw-r--r--aai-traversal/src/main/java/org/openecomp/aai/rest/retired/V3ThroughV7Consumer.java28
-rw-r--r--aai-traversal/src/main/java/org/openecomp/aai/rest/retired/V7V8NamedQueries.java28
-rw-r--r--aai-traversal/src/main/java/org/openecomp/aai/rest/search/GenericQueryProcessor.java227
-rw-r--r--aai-traversal/src/main/java/org/openecomp/aai/rest/search/GremlinGroovyShellSingleton.java88
-rw-r--r--aai-traversal/src/main/java/org/openecomp/aai/rest/search/GremlinServerImpl.java76
-rw-r--r--aai-traversal/src/main/java/org/openecomp/aai/rest/search/GremlinServerSingleton.java130
-rw-r--r--aai-traversal/src/main/java/org/openecomp/aai/rest/search/GroovyShellImpl.java47
-rw-r--r--aai-traversal/src/main/java/org/openecomp/aai/rest/search/ModelAndNamedQueryRestProvider.java203
-rw-r--r--aai-traversal/src/main/java/org/openecomp/aai/rest/search/QueryProcessorType.java27
-rw-r--r--aai-traversal/src/main/java/org/openecomp/aai/rest/search/SearchProvider.java269
-rw-r--r--aai-traversal/src/main/java/org/openecomp/aai/rest/ueb/NotificationEvent.java96
-rw-r--r--aai-traversal/src/main/java/org/openecomp/aai/rest/ueb/UEBNotification.java178
-rw-r--r--aai-traversal/src/main/java/org/openecomp/aai/rest/util/EchoResponse.java121
-rw-r--r--aai-traversal/src/main/java/org/openecomp/aai/rest/util/LogFormatTools.java36
-rw-r--r--aai-traversal/src/main/java/org/openecomp/aai/rest/util/ValidateEncoding.java160
-rw-r--r--aai-traversal/src/main/java/org/openecomp/aai/transforms/Converter.java25
-rw-r--r--aai-traversal/src/main/java/org/openecomp/aai/transforms/LowerCamelToLowerHyphenConverter.java34
-rw-r--r--aai-traversal/src/main/java/org/openecomp/aai/transforms/LowerHyphenToLowerCamelConverter.java81
-rw-r--r--aai-traversal/src/main/java/org/openecomp/aai/transforms/MapTraverser.java87
-rw-r--r--aai-traversal/src/main/java/org/openecomp/aai/util/AAIAppServletContextListener.java104
-rw-r--r--aai-traversal/src/main/java/org/openecomp/aai/util/RestURL.java704
-rw-r--r--aai-traversal/src/main/java/org/openecomp/aai/util/StoreNotificationEvent.java358
49 files changed, 16397 insertions, 0 deletions
diff --git a/aai-traversal/src/main/java/org/openecomp/aai/ajsc_aai/JaxrsErrorMessageLookupService.java b/aai-traversal/src/main/java/org/openecomp/aai/ajsc_aai/JaxrsErrorMessageLookupService.java
new file mode 100644
index 0000000..ca78bac
--- /dev/null
+++ b/aai-traversal/src/main/java/org/openecomp/aai/ajsc_aai/JaxrsErrorMessageLookupService.java
@@ -0,0 +1,98 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * org.openecomp.aai
+ * ================================================================================
+ * Copyright (C) 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=========================================================
+ */
+
+package org.openecomp.aai.ajsc_aai;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import javax.ws.rs.GET;
+import javax.ws.rs.HeaderParam;
+import javax.ws.rs.Path;
+import javax.ws.rs.PathParam;
+import javax.ws.rs.Produces;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.web.context.ContextLoader;
+import org.springframework.web.context.WebApplicationContext;
+
+import ajsc.ErrorMessageLookupService;
+
+@Path("/errormessage")
+public class JaxrsErrorMessageLookupService {
+
+ private final static Logger logger = LoggerFactory
+ .getLogger(ErrorMessageLookupService.class);
+
+ /**
+ * Gets the message.
+ *
+ * @param input the input
+ * @param errorCode the error code
+ * @param appId the app id
+ * @param operation the operation
+ * @param messageText the message text
+ * @param isRESTService the is REST service
+ * @param faultEntity the fault entity
+ * @param ConvID the conv ID
+ * @return the message
+ */
+ @GET
+ @Path("/emls")
+ @Produces("text/plain")
+ public String getMessage(@PathParam("input") String input,
+ @HeaderParam("errorCode") String errorCode,
+ @HeaderParam("appId") String appId,
+ @HeaderParam("operation") String operation,
+ @HeaderParam("messageText") String messageText,
+ @HeaderParam("isRESTService") String isRESTService,
+ @HeaderParam("faultEntity") String faultEntity,
+ @HeaderParam("ConvID") String ConvID) {
+
+ Map<String, String> headers = new HashMap<String, String>();
+ headers.put(errorCode, errorCode);
+ headers.put(appId, appId);
+ headers.put(operation, operation);
+ headers.put(messageText, messageText);
+ headers.put(isRESTService, isRESTService);
+ headers.put(faultEntity, faultEntity);
+ headers.put(ConvID, ConvID);
+
+ WebApplicationContext applicationContext = ContextLoader
+ .getCurrentWebApplicationContext();
+
+ ErrorMessageLookupService e = (ErrorMessageLookupService) applicationContext
+ .getBean("errorMessageLookupService");
+
+ String message = e.getExceptionDetails(appId, operation, errorCode,
+ messageText,isRESTService, faultEntity, ConvID);
+
+ System.out.println("Error code = " + errorCode);
+ System.out.println("appId = " + appId);
+ System.out.println("operation = " + operation);
+ System.out.println("messageText = " + messageText);
+ System.out.println("isRESTService = " + isRESTService);
+ System.out.println("faultEntity = " + faultEntity);
+ System.out.println("ConvID = " + ConvID);
+ return "The exception message is:\n " + message;
+ }
+
+}
diff --git a/aai-traversal/src/main/java/org/openecomp/aai/ajsc_aai/JaxrsUserService.java b/aai-traversal/src/main/java/org/openecomp/aai/ajsc_aai/JaxrsUserService.java
new file mode 100644
index 0000000..39c78f6
--- /dev/null
+++ b/aai-traversal/src/main/java/org/openecomp/aai/ajsc_aai/JaxrsUserService.java
@@ -0,0 +1,54 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * org.openecomp.aai
+ * ================================================================================
+ * Copyright (C) 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=========================================================
+ */
+
+package org.openecomp.aai.ajsc_aai;
+
+import javax.ws.rs.GET;
+import javax.ws.rs.Path;
+import javax.ws.rs.PathParam;
+import javax.ws.rs.Produces;
+import java.util.Map;
+import java.util.HashMap;
+
+@Path("/user")
+public class JaxrsUserService {
+
+ private static final Map<String,String> userIdToNameMap;
+ static {
+ userIdToNameMap = new HashMap<String,String>();
+ userIdToNameMap.put("userID1","Name1");
+ userIdToNameMap.put("userID2","Name2");
+ }
+
+ /**
+ * Lookup user.
+ *
+ * @param userId the user id
+ * @return the string
+ */
+ @GET
+ @Path("/{userId}")
+ @Produces("text/plain")
+ public String lookupUser(@PathParam("userId") String userId) {
+ String name = userIdToNameMap.get(userId);
+ return name != null ? name : "unknown id";
+ }
+
+}
diff --git a/aai-traversal/src/main/java/org/openecomp/aai/ajsc_aai/filemonitor/ServicePropertiesListener.java b/aai-traversal/src/main/java/org/openecomp/aai/ajsc_aai/filemonitor/ServicePropertiesListener.java
new file mode 100644
index 0000000..22c1cb9
--- /dev/null
+++ b/aai-traversal/src/main/java/org/openecomp/aai/ajsc_aai/filemonitor/ServicePropertiesListener.java
@@ -0,0 +1,19 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * org.openecomp.aai
+ * ================================================================================
+ * Copyright (C) 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=========================================================
+ */
diff --git a/aai-traversal/src/main/java/org/openecomp/aai/ajsc_aai/filemonitor/ServicePropertiesMap.java b/aai-traversal/src/main/java/org/openecomp/aai/ajsc_aai/filemonitor/ServicePropertiesMap.java
new file mode 100644
index 0000000..656b290
--- /dev/null
+++ b/aai-traversal/src/main/java/org/openecomp/aai/ajsc_aai/filemonitor/ServicePropertiesMap.java
@@ -0,0 +1,126 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * org.openecomp.aai
+ * ================================================================================
+ * Copyright (C) 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=========================================================
+ */
+
+package org.openecomp.aai.ajsc_aai.filemonitor;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Properties;
+
+import com.att.eelf.configuration.EELFLogger;
+import com.att.eelf.configuration.EELFManager;
+import com.fasterxml.jackson.core.type.TypeReference;
+import com.fasterxml.jackson.databind.ObjectMapper;
+
+public class ServicePropertiesMap
+{
+ private static HashMap<String, HashMap<String, String>> mapOfMaps = new HashMap<String, HashMap<String, String>>();
+ private static final EELFLogger LOGGER = EELFManager.getInstance().getLogger(ServicePropertiesMap.class);
+
+ /**
+ * Refresh.
+ *
+ * @param file the file
+ * @throws Exception the exception
+ */
+ public static void refresh(File file) throws Exception
+ {
+ try
+ {
+ LOGGER.info("Loading properties - " + (file != null?file.getName():""));
+
+ //Store .json & .properties files into map of maps
+ String filePath = file.getPath();
+
+ if(filePath.lastIndexOf(".json")>0){
+
+ ObjectMapper om = new ObjectMapper();
+ TypeReference<HashMap<String, String>> typeRef = new TypeReference<HashMap<String, String>>() {};
+ HashMap<String, String> propMap = om.readValue(file, typeRef);
+ HashMap<String, String> lcasePropMap = new HashMap<String, String>();
+ for (String key : propMap.keySet() )
+ {
+ String lcaseKey = ifNullThenEmpty(key);
+ lcasePropMap.put(lcaseKey, propMap.get(key));
+ }
+
+ mapOfMaps.put(file.getName(), lcasePropMap);
+
+
+ }else if(filePath.lastIndexOf(".properties")>0){
+ Properties prop = new Properties();
+ FileInputStream fis = new FileInputStream(file);
+ prop.load(fis);
+
+ @SuppressWarnings("unchecked")
+ HashMap<String, String> propMap = new HashMap<String, String>((Map)prop);
+
+ mapOfMaps.put(file.getName(), propMap);
+ }
+
+ LOGGER.info("File - " + file.getName() + " is loaded into the map and the corresponding system properties have been refreshed");
+ }
+ catch (Exception e)
+ {
+ LOGGER.error("File " + (file != null?file.getName():"") + " cannot be loaded into the map ", e);
+ throw new Exception("Error reading map file " + (file != null?file.getName():""), e);
+ }
+ }
+
+ /**
+ * Gets the property.
+ *
+ * @param fileName the file name
+ * @param propertyKey the property key
+ * @return the property
+ */
+ public static String getProperty(String fileName, String propertyKey)
+ {
+ HashMap<String, String> propMap = mapOfMaps.get(fileName);
+ return propMap!=null?propMap.get(ifNullThenEmpty(propertyKey)):"";
+ }
+
+ /**
+ * Gets the properties.
+ *
+ * @param fileName the file name
+ * @return the properties
+ */
+ public static HashMap<String, String> getProperties(String fileName){
+ return mapOfMaps.get(fileName);
+ }
+
+ /**
+ * If null then empty.
+ *
+ * @param key the key
+ * @return the string
+ */
+ private static String ifNullThenEmpty(String key) {
+ if (key == null) {
+ return "";
+ } else {
+ return key;
+ }
+ }
+
+}
diff --git a/aai-traversal/src/main/java/org/openecomp/aai/ajsc_aai/filemonitor/ServicePropertyService.java b/aai-traversal/src/main/java/org/openecomp/aai/ajsc_aai/filemonitor/ServicePropertyService.java
new file mode 100644
index 0000000..22c1cb9
--- /dev/null
+++ b/aai-traversal/src/main/java/org/openecomp/aai/ajsc_aai/filemonitor/ServicePropertyService.java
@@ -0,0 +1,19 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * org.openecomp.aai
+ * ================================================================================
+ * Copyright (C) 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=========================================================
+ */
diff --git a/aai-traversal/src/main/java/org/openecomp/aai/ajsc_aai/util/ServicePropertiesMapBean.java b/aai-traversal/src/main/java/org/openecomp/aai/ajsc_aai/util/ServicePropertiesMapBean.java
new file mode 100644
index 0000000..7577de7
--- /dev/null
+++ b/aai-traversal/src/main/java/org/openecomp/aai/ajsc_aai/util/ServicePropertiesMapBean.java
@@ -0,0 +1,37 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * org.openecomp.aai
+ * ================================================================================
+ * Copyright (C) 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=========================================================
+ */
+
+package org.openecomp.aai.ajsc_aai.util;
+
+import org.openecomp.aai.ajsc_aai.filemonitor.ServicePropertiesMap;
+
+public class ServicePropertiesMapBean {
+
+ /**
+ * Gets the property.
+ *
+ * @param propFileName the prop file name
+ * @param propertyKey the property key
+ * @return the property
+ */
+ public static String getProperty(String propFileName, String propertyKey) {
+ return ServicePropertiesMap.getProperty(propFileName, propertyKey);
+ }
+}
diff --git a/aai-traversal/src/main/java/org/openecomp/aai/db/DbMethHelper.java b/aai-traversal/src/main/java/org/openecomp/aai/db/DbMethHelper.java
new file mode 100644
index 0000000..79172d9
--- /dev/null
+++ b/aai-traversal/src/main/java/org/openecomp/aai/db/DbMethHelper.java
@@ -0,0 +1,158 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * org.openecomp.aai
+ * ================================================================================
+ * Copyright (C) 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=========================================================
+ */
+
+package org.openecomp.aai.db;
+
+import java.io.UnsupportedEncodingException;
+import java.net.URI;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Optional;
+
+import org.apache.tinkerpop.gremlin.structure.Vertex;
+import org.apache.tinkerpop.gremlin.structure.VertexProperty;
+
+import org.openecomp.aai.exceptions.AAIException;
+import org.openecomp.aai.introspection.Introspector;
+import org.openecomp.aai.introspection.Loader;
+import org.openecomp.aai.introspection.exceptions.AAIUnknownObjectException;
+import org.openecomp.aai.parsers.query.QueryParser;
+import org.openecomp.aai.parsers.relationship.RelationshipToURI;
+import org.openecomp.aai.query.builder.QueryBuilder;
+import org.openecomp.aai.serialization.engines.TransactionalGraphEngine;
+
+public class DbMethHelper {
+
+ private final Loader loader;
+ private final TransactionalGraphEngine engine;
+
+ protected DbMethHelper() {
+ this.loader = null;
+ this.engine = null;
+ }
+ public DbMethHelper(Loader loader, TransactionalGraphEngine engine) {
+ this.loader = loader;
+ this.engine = engine;
+ }
+ /**
+ *
+ * @param type
+ * @param map - form [{type}.{propname}:{value}]
+ * @return
+ * @throws UnsupportedEncodingException
+ * @throws AAIException
+ */
+ public Optional<Vertex> searchVertexByIdentityMap(String type, Map<String, Object> map) throws AAIException {
+
+ Introspector relationship = constructRelationship(type, map);
+ RelationshipToURI parser;
+ URI uri;
+ QueryParser queryParser;
+ try {
+ parser = new RelationshipToURI(loader, relationship);
+ uri = parser.getUri();
+ queryParser = this.engine.getQueryBuilder().createQueryFromURI(uri);
+ } catch (UnsupportedEncodingException e) {
+ throw new AAIException("AAI_3000");
+ }
+
+ List<Vertex> results = queryParser.getQueryBuilder().toList();
+
+ return reduceToSingleVertex(results, map);
+ }
+
+ /**
+ * @param type
+ * @param map - form [{propname}:{value}]
+ * @return
+ * @throws AAIException
+ */
+ public Optional<Vertex> locateUniqueVertex(String type, Map<String, Object> map) throws AAIException {
+
+ return reduceToSingleVertex(locateUniqueVertices(type, map), map);
+ }
+
+ public List<Vertex> locateUniqueVertices(String type, Map<String, Object> map) throws AAIException {
+ Introspector obj = this.createIntrospectorFromMap(type, map);
+ QueryBuilder builder = this.engine.getQueryBuilder().exactMatchQuery(obj);
+
+ return builder.toList();
+ }
+ private Introspector constructRelationship(String type, Map<String, Object> map) throws AAIUnknownObjectException {
+ final Introspector relationship = loader.introspectorFromName("relationship");
+ relationship.setValue("related-to", type);
+ final List<Object> data = relationship.getValue("relationship-data");
+ for (Entry<String, Object> entry : map.entrySet()) {
+ final Introspector dataObj = loader.introspectorFromName("relationship-data");
+ dataObj.setValue("relationship-key", entry.getKey());
+ dataObj.setValue("relationship-value", entry.getValue());
+ data.add(dataObj.getUnderlyingObject());
+ }
+
+ return relationship;
+ }
+
+ private Introspector createIntrospectorFromMap(String targetNodeType, Map<String, Object> propHash) throws AAIUnknownObjectException {
+ final Introspector result = loader.introspectorFromName(targetNodeType);
+ for (Entry<String, Object> entry : propHash.entrySet()) {
+ result.setValue(entry.getKey(), entry.getValue());
+ }
+ return result;
+ }
+
+ private Optional<Vertex> reduceToSingleVertex(List<Vertex> vertices, Map<String, Object> map) throws AAIException {
+ if (vertices.isEmpty()){
+ return Optional.empty();
+ } else if (vertices.size() > 1) {
+ throw new AAIException("AAI_6112", "More than one Node found by getUniqueNode for params: " + map);
+ }
+
+ return Optional.of(vertices.get(0));
+ }
+ public List<String> getVertexProperties(Vertex v) {
+ List<String> retArr = new ArrayList<>();
+ if( v == null ){
+ retArr.add("null Node object passed to showPropertiesForNode()\n");
+ }
+ else {
+ String nodeType;
+ Object ob = v.<Object>property("aai-node-type").orElse(null);
+ if( ob == null ){
+ nodeType = "null";
+ }
+ else{
+ nodeType = ob.toString();
+ }
+
+ retArr.add(" AAINodeType/VtxID for this Node = [" + nodeType + "/" + v.id() + "]");
+ retArr.add(" Property Detail: ");
+ Iterator<VertexProperty<Object>> pI = v.properties();
+ while( pI.hasNext() ){
+ VertexProperty<Object> tp = pI.next();
+ Object val = tp.value();
+ retArr.add("Prop: [" + tp.key() + "], val = [" + val + "] ");
+ }
+ }
+ return retArr;
+ }
+}
diff --git a/aai-traversal/src/main/java/org/openecomp/aai/dbgraphgen/DbEdgeGroup.java b/aai-traversal/src/main/java/org/openecomp/aai/dbgraphgen/DbEdgeGroup.java
new file mode 100644
index 0000000..56a9a4b
--- /dev/null
+++ b/aai-traversal/src/main/java/org/openecomp/aai/dbgraphgen/DbEdgeGroup.java
@@ -0,0 +1,439 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * org.openecomp.aai
+ * ================================================================================
+ * Copyright (C) 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=========================================================
+ */
+
+package org.openecomp.aai.dbgraphgen;
+
+import java.io.UnsupportedEncodingException;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.Set;
+
+import org.apache.commons.collections.map.MultiValueMap;
+import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversal;
+import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversalSource;
+import org.apache.tinkerpop.gremlin.structure.Edge;
+import org.apache.tinkerpop.gremlin.structure.Vertex;
+
+import org.openecomp.aai.dbgen.DbMeth;
+import org.openecomp.aai.exceptions.AAIException;
+import org.openecomp.aai.exceptions.AAIExceptionWithInfo;
+import org.openecomp.aai.ingestModel.DbMaps;
+import org.openecomp.aai.ingestModel.IngestModelMoxyOxm;
+import org.openecomp.aai.serialization.db.EdgeRule;
+import org.openecomp.aai.serialization.db.EdgeRules;
+import org.openecomp.aai.serialization.db.EdgeType;
+import org.openecomp.aai.serialization.db.MultiplicityRule;
+import org.openecomp.aai.serialization.db.exceptions.NoEdgeRuleFoundException;
+import com.att.eelf.configuration.EELFLogger;
+import com.att.eelf.configuration.EELFManager;
+import com.thinkaurelius.titan.core.TitanEdge;
+import com.thinkaurelius.titan.core.TitanTransaction;
+import com.thinkaurelius.titan.core.TitanVertex;
+
+public class DbEdgeGroup {
+
+ private static final EELFLogger LOGGER = EELFManager.getInstance().getLogger(DbEdgeGroup.class);
+
+ /**
+ * Replace edge group.
+ *
+ * @param transId the trans id
+ * @param fromAppId the from app id
+ * @param graph the graph
+ * @param startVert the start vert
+ * @param scope the scope
+ * @param relatedNodesMultiMap the related nodes multi map
+ * @param apiVersion the api version
+ * @throws AAIException the AAI exception
+ */
+ public static void replaceEdgeGroup( String transId,
+ String fromAppId,
+ TitanTransaction graph,
+ TitanVertex startVert,
+ String scope,
+ MultiValueMap relatedNodesMultiMap, // supports multiple entries for same nodetype
+ String apiVersion ) throws AAIException{
+
+ // --------------------------------------------------------------------
+ // NOTE --- This routine is only used for "cousin" relationships.
+ // --------------------------------------------------------------------
+
+ /*
+ * scope can be one of these:
+ * a) "ALL_COUSIN_REL"
+ * b) "ONLY_PASSED_COUSINS_REL" (only look at the edge types that are
+ * represented in the passed list of relationships)
+ *
+ * Given a startNode and a list of relationshipInfo, we need to check the database and then,
+ * 1) Delete any in-scope db relationships which are not represented in the relationshipList.
+ * So, for ALL_COUSIN_REL, we would delete any db relationship that had an edge with
+ * parentOf = false if it was not represented in the passed Relationship List.
+ * For ONLY_PASSED_COUSINS_REL - we'd do the same as above, but only for edges that match the
+ * type in the passed relationshipList. We'd leave any others alone.
+ * 2) Then, Persist (add/update) all the remaining passed-in relationships.
+ */
+
+ if( !scope.equals("ALL_COUSIN_REL") && !scope.equals("ONLY_PASSED_COUSINS_REL") ){
+ throw new AAIException("AAI_6120", "Illegal scope parameter passed: [" + scope + "].");
+ }
+
+ HashMap <String,String> vidToNodeTypeInDbHash = new HashMap <String,String>();
+ HashMap <String,String> nodeTypeInReqHash = new HashMap <String,String>();
+ HashMap <String,TitanEdge> vidToEdgeInDbHash = new HashMap <String,TitanEdge>();
+ HashMap <String,TitanVertex> vidToTargetVertexHash = new HashMap <String,TitanVertex>();
+
+ //------------------------------------------------------------------------------------------------------------
+ // 1) First -- look what is currently in the db --
+ // "cousins" => grab all nodes connected to startVertex that have edges with param: isParent = false.
+ //------------------------------------------------------------------------------------------------------------
+ GraphTraversalSource conPipeTraversal = startVert.graph().traversal();
+ GraphTraversal<Vertex, Edge> conPipe = conPipeTraversal.V(startVert).bothE().has("isParent",false);
+ // Note - it's ok if nothing is found
+ if( conPipe != null ){
+ while( conPipe.hasNext() ){
+ TitanEdge ed = (TitanEdge) conPipe.next();
+ TitanVertex cousinV = ed.otherVertex(startVert);
+ String vid = cousinV.id().toString();
+ String noTy = cousinV.<String>property("aai-node-type").orElse(null);
+ vidToNodeTypeInDbHash.put(vid, noTy);
+ vidToEdgeInDbHash.put(vid, ed);
+
+ LOGGER.info("Found connected cousin vid(s) in db: [" + cousinV.id().toString() + "]");
+ }
+ }
+
+ //------------------------------------------------------------------------------------------------------------
+ //2) Get a List of the Titan nodes that the end-state list wants to be connected to
+ //------------------------------------------------------------------------------------------------------------
+ ArrayList <TitanVertex> targetConnectedToVertList = new ArrayList<TitanVertex>();
+ if( relatedNodesMultiMap != null ) {
+
+ Set entrySet = relatedNodesMultiMap.entrySet();
+ Iterator it = entrySet.iterator();
+ //System.out.println(" Object key Object value");
+ while (it.hasNext()) {
+ Map.Entry mapEntry = (Map.Entry) it.next();
+ String rel2Nt = (String) mapEntry.getKey();
+ int i = 0;
+ ArrayList <HashMap<String, Object>> propList = ((ArrayList<HashMap<String, Object>>)relatedNodesMultiMap.get(rel2Nt));
+ while (i < propList.size()) {
+ HashMap<String, Object> propFilterHash = (HashMap<String, Object>) propList.get(i++);
+
+ TitanVertex targetVert;
+
+ try {
+ targetVert = DbMeth.getUniqueNodeWithDepParams( transId,
+ fromAppId,
+ graph,
+ rel2Nt,
+ propFilterHash,
+ apiVersion );
+ } catch (AAIException e) {
+ if (e.getErrorObject().getErrorCode().equals("6114"))
+ throw new AAIExceptionWithInfo("AAI_6129",
+ e,
+ "Node of type " + rel2Nt + " not found for properties:" + propFilterHash.toString(),
+ propFilterHash,
+ rel2Nt);
+ else
+ throw e;
+ }
+
+ targetConnectedToVertList.add(targetVert);
+
+ String vid = targetVert.id().toString();
+ String noTy = targetVert.<String>property("aai-node-type").orElse(null);
+ nodeTypeInReqHash.put(noTy, "");
+ vidToTargetVertexHash.put(vid, targetVert);
+
+ LOGGER.info("They request edges to these vids:[" + targetVert.id().toString() + "]");
+ }
+ }
+ }
+
+ //-------------------------------------------------------------------------------------------------------------------
+ // 3) Compare what is in the DB with what they are requesting as an end-state.
+ // If any are found in the db-list but not the new-list, delete them from the db (conditionally - based on scope)
+ //-------------------------------------------------------------------------------------------------------------------
+ String startVtxNT = startVert.<String>property("aai-node-type").orElse(null);
+ for( Map.Entry<String, TitanEdge> entry : vidToEdgeInDbHash.entrySet() ){
+ String vertId = entry.getKey();
+ TitanEdge dbEd = entry.getValue();
+ if( ! vidToTargetVertexHash.containsKey(vertId) ){
+ if( scope.equals("ALL_COUSIN_REL") ){
+ LOGGER.info("We will DELETE existing DB-edge to vids = [" + entry.getKey() + "]");
+ DbMeth.removeAaiEdge(transId, fromAppId, graph, dbEd);
+ }
+ else if( scope.equals("ONLY_PASSED_COUSINS_REL") ){
+ // If they use "ONLY_PASSED_COUSINS_REL" scope, they want us to delete an edge ONLY if:
+ // a) this edge is the same type that they passed in (but goes to a different endpoint)
+ // AND b) this additional edge would break the multiplicity edge rule.
+ String ntInDb = vidToNodeTypeInDbHash.get(vertId);
+ if( nodeTypeInReqHash.containsKey(ntInDb) && additionalEdgeWouldBreakMultEdgeRule(startVtxNT, ntInDb) ){
+ LOGGER.info("We will DELETE existing DB-edge to vids = [" + entry.getKey() + "]");
+ DbMeth.removeAaiEdge(transId, fromAppId, graph, dbEd);
+ }
+ }
+ }
+ }
+
+ //---------------------------------------------------------------
+ // 4) add/update (persist) all the relations on the new-list
+ //---------------------------------------------------------------
+ for( Map.Entry<String, TitanVertex> entry : vidToTargetVertexHash.entrySet() ){
+ LOGGER.info("Call persistAaiEdge on edge(s) going to vids = " + "[" + entry.getKey() + "]");
+ TitanVertex targV = entry.getValue();
+ DbMeth.persistAaiEdge(transId, fromAppId, graph, startVert, targV, apiVersion, "cousin");
+ }
+
+ return;
+
+}// End replaceEdgeGroup()
+
+
+/**
+ * Additional edge would break mult edge rule.
+ *
+ * @param startNodeType the start node type
+ * @param endNodeType the end node type
+ * @return the boolean
+ * @throws AAIException the AAI exception
+ */
+private static Boolean additionalEdgeWouldBreakMultEdgeRule( String startNodeType, String endNodeType )
+ throws AAIException {
+ // Return true if a second edge from the startNodeType to the endNodeType would
+ // break a multiplicity edge rule.
+ // Ie. Adding an edge to a second tenant (endNode) from a vserver (startNode) node would be flagged by this
+ // if we have our multiplicity rule set up for the "vserver-tenant" edge set up as "Many2One" or if
+ // it was set up the other way, "tenant-vserver" as "One2Many" or even if it was "One2One". In any of
+ // those scenarios, the addition of an edge from a particular vserver to an additional tenant node
+ // would break the rule.
+
+ EdgeRule edgeRule = null;
+ boolean reversed = false;
+
+ if (EdgeRules.getInstance().hasEdgeRule(startNodeType, endNodeType)) {
+ } else if (EdgeRules.getInstance().hasEdgeRule(endNodeType, startNodeType)) {
+ reversed = true;
+ }
+
+ try {
+ edgeRule = EdgeRules.getInstance().getEdgeRule(EdgeType.COUSIN, startNodeType, endNodeType);
+ } catch (NoEdgeRuleFoundException e) {
+ return false;
+ }
+
+
+ if (edgeRule.getMultiplicityRule().equals(MultiplicityRule.ONE2ONE)) {
+ return true;
+ } else if (reversed && edgeRule.getMultiplicityRule().equals(MultiplicityRule.ONE2MANY)) {
+ return true;
+ } else if (!reversed && edgeRule.getMultiplicityRule().equals(MultiplicityRule.MANY2ONE)) {
+ return true;
+ } else {
+ return false;
+ }
+
+
+}// end of additionalEdgeWouldBreakMultEdgeRule()
+
+/**
+ * Delete edge group.
+ *
+ * @param transId the trans id
+ * @param fromAppId the from app id
+ * @param graph the graph
+ * @param startVert the start vert
+ * @param relatedNodesMultiMap the related nodes multi map
+ * @param apiVersion the api version
+ * @return void
+ * @throws AAIException the AAI exception
+ */
+public static void deleteEdgeGroup( String transId,
+ String fromAppId,
+ TitanTransaction graph,
+ TitanVertex startVert,
+ MultiValueMap relatedNodesMultiMap,
+ String apiVersion ) throws AAIException{
+ // --------------------------------------------------------------------
+ // NOTE - This routine is only used for "cousin" relationships.
+ // ALSO - an edge deletion will fail if that edge was needed by
+ // the node on one of the sides for uniqueness. We're just
+ // being careful here - so far, I don't think a cousin-edge
+ // is ever used for this kind of dependency.
+ // --------------------------------------------------------------------
+
+ HashMap <String,TitanEdge> cousinVidToEdgeInDbHash = new HashMap <String,TitanEdge>();
+ String startVertNT = startVert.<String>property("aai-node-type").orElse(null);
+ String startVertVid = startVert.id().toString();
+ DbMaps dbMaps = IngestModelMoxyOxm.dbMapsContainer.get(apiVersion);
+ Collection <String> startVertDepNTColl = dbMaps.NodeDependencies.get(startVertNT);
+
+ //-----------------------------------------------------------------------------------------------------
+ // Get a list of vertexes that are attached to the startVert as "cousins" and the connecting edges
+ //-----------------------------------------------------------------------------------------------------
+ GraphTraversalSource conPipeTraversal = startVert.graph().traversal();
+ GraphTraversal<Vertex, Edge> conPipe = conPipeTraversal.V(startVert).bothE().has("isParent",false);
+ if( conPipe != null ){
+ while( conPipe.hasNext() ){
+ TitanEdge ed = (TitanEdge) conPipe.next();
+ TitanVertex cousinV = ed.otherVertex(startVert);
+ String vid = cousinV.id().toString();
+ cousinVidToEdgeInDbHash.put(vid, ed);
+ }
+ }
+
+ //-------------------------------------------------------------
+ // Look through the Relationship info passed in.
+ // Delete edges as requested if they check-out as cousins.
+ //-------------------------------------------------------------
+ Boolean isFirst = true;
+ String msg = "Deleting edges from vid = " + startVertVid + "(" + startVertNT + "), to these: [";
+ if( relatedNodesMultiMap != null ) {
+ Set entrySet = relatedNodesMultiMap.entrySet();
+ Iterator it = entrySet.iterator();
+ //System.out.println(" Object key Object value");
+ while (it.hasNext()) {
+ Map.Entry mapEntry = (Map.Entry) it.next();
+ String rel2Nt = (String) mapEntry.getKey();
+ HashMap<String, Object> propFilterHash = (HashMap<String, Object>)((ArrayList) relatedNodesMultiMap.get(rel2Nt)).get(0);
+ TitanVertex otherEndVert = DbMeth.getUniqueNodeWithDepParams( transId, fromAppId, graph, rel2Nt, propFilterHash, apiVersion );
+ String otherNT = otherEndVert.<String>property("aai-node-type").orElse(null);
+ String reqDelConnectedVid = otherEndVert.id().toString();
+ if( !cousinVidToEdgeInDbHash.containsKey(reqDelConnectedVid) ){
+ throw new AAIException("AAI_6127", "COUSIN Edge between " + startVertVid + " (" + startVertNT + ") and " + reqDelConnectedVid +
+ "(" + otherNT + ") not found. ");
+ }
+ else {
+ // This was a cousin edge. But before we delete it, we will check to make
+ // sure it doesn't have a unique-dependency issue (need to check in two directions)
+ Iterator <String> ntItr1 = startVertDepNTColl.iterator();
+ if( ntItr1.hasNext() ){
+ while( ntItr1.hasNext() ){
+ if( ntItr1.next().equals(otherNT) ){
+ throw new AAIException("AAI_6126", "Edge between " + startVertVid + " and " + reqDelConnectedVid +
+ " cannot be deleted because of a uniqueness-dependancy between nodeTypes, " +
+ startVertNT + " and " + otherNT);
+ }
+ }
+ }
+
+ Collection <String> depNTColl = dbMaps.NodeDependencies.get(otherNT);
+ Iterator <String> ntItr2 = depNTColl.iterator();
+ if( ntItr2.hasNext() ){
+ while( ntItr2.hasNext() ){
+ if( ntItr2.next().equals(startVertNT) ){
+ throw new AAIException("AAI_6126", "Edge between " + startVertVid + " and " + reqDelConnectedVid +
+ " cannot be deleted because of a uniqueness-dependancy between nodeTypes: " +
+ otherNT + " and " + startVertNT);
+ }
+ }
+ }
+
+ // It's OK to delete this edge as requested.
+ if( ! isFirst ){
+ msg = msg + ", ";
+ }
+ isFirst = false;
+ msg = msg + reqDelConnectedVid + "(" + otherNT + ")";
+ TitanEdge targetDelEdge = cousinVidToEdgeInDbHash.get(reqDelConnectedVid);
+ DbMeth.removeAaiEdge(transId, fromAppId, graph, targetDelEdge);
+ }
+ }
+ }
+
+ msg = msg + "]";
+
+ LOGGER.info(msg);
+
+ return;
+
+}// End deleteEdgeGroup()
+
+
+/**
+ * Gets the edge group.
+ *
+ * @param transId the trans id
+ * @param fromAppId the from app id
+ * @param graph the graph
+ * @param startVert the start vert
+ * @param vidToNodeTypeHash the vid to node type hash
+ * @param vidToVertexHash the vid to vertex hash
+ * @param scope the scope
+ * @param apiVersion the api version
+ * @return void
+ * @throws AAIException the AAI exception
+ * @throws UnsupportedEncodingException the unsupported encoding exception
+ */
+public static void getEdgeGroup( String transId,
+ String fromAppId,
+ TitanTransaction graph,
+ TitanVertex startVert,
+ HashMap <String,String> vidToNodeTypeHash,
+ HashMap <String,TitanVertex> vidToVertexHash,
+ String scope,
+ String apiVersion ) throws AAIException, UnsupportedEncodingException{
+
+ LOGGER.debug("scope={}", scope);
+ LOGGER.debug("vid={}", startVert.id().toString());
+ LOGGER.debug("nodetype={}", startVert.property("aai-node-type").orElse(null).toString());
+
+ /*
+ * scope can be one of these:
+ * 1) "ONLY_COUSIN_REL" <-- This is the only one supported for now
+ * 2) "ALL_COUSIN_AND_CHILDREN_REL"
+ * 3) "ONLY_CHILDREN"
+ * 4) "USES_RESOURCE"
+ *
+ * Given a startNode and the scope, we need to return relationships that we find in the DB
+ */
+
+ if( !scope.equals("ONLY_COUSIN_REL") ){
+ throw new AAIException("AAI_6120", "Illegal scope parameter passed: [" + scope + "].");
+ }
+
+ //------------------------------------------------------------------------------------------------------------
+ // Grab "first-layer" vertexes from the in the db --
+ // "cousins" => grab all nodes connected to startVertex that have edges with param: isParent = false.
+ // "children" => grab nodes via out-edge with isParent = true (NOT YET SUPPORTED)
+ //------------------------------------------------------------------------------------------------------------
+ Iterable<Vertex> qResult = startVert.query().has("isParent",false).vertices();
+ Iterator <Vertex> resultI = qResult.iterator();
+
+ while( resultI.hasNext() ){
+ TitanVertex cousinV = (TitanVertex)resultI.next();
+ //showPropertiesForNode( transId, fromAppId, cousinV );
+
+ String vid = cousinV.id().toString();
+ String noTy = cousinV.<String>property("aai-node-type").orElse(null);
+ vidToNodeTypeHash.put(vid, noTy);
+ vidToVertexHash.put(vid, cousinV);
+
+ LOGGER.debug("Found connected cousin vid(s) in db: " + "[" + cousinV.id().toString() + "]");
+ }
+
+}// End getEdgeGroup()
+
+
+}
diff --git a/aai-traversal/src/main/java/org/openecomp/aai/dbgraphgen/DbMeth.java b/aai-traversal/src/main/java/org/openecomp/aai/dbgraphgen/DbMeth.java
new file mode 100644
index 0000000..5951a10
--- /dev/null
+++ b/aai-traversal/src/main/java/org/openecomp/aai/dbgraphgen/DbMeth.java
@@ -0,0 +1,3643 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * org.openecomp.aai
+ * ================================================================================
+ * Copyright (C) 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=========================================================
+ */
+
+package org.openecomp.aai.dbgraphgen;
+
+import java.net.Inet4Address;
+import java.net.Inet6Address;
+import java.net.InetAddress;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.__;
+import org.apache.tinkerpop.gremlin.structure.Direction;
+import org.apache.tinkerpop.gremlin.structure.Edge;
+import org.apache.tinkerpop.gremlin.structure.Vertex;
+import org.apache.tinkerpop.gremlin.structure.VertexProperty;
+
+import org.openecomp.aai.dbmodel.DbEdgeRules;
+import org.openecomp.aai.exceptions.AAIException;
+import org.openecomp.aai.ingestModel.DbMaps;
+import org.openecomp.aai.ingestModel.IngestModelMoxyOxm;
+import org.openecomp.aai.serialization.db.EdgeRule;
+import org.openecomp.aai.serialization.db.EdgeRules;
+import org.openecomp.aai.util.AAIConfig;
+import org.openecomp.aai.util.AAIConstants;
+import com.att.eelf.configuration.EELFLogger;
+import com.att.eelf.configuration.EELFManager;
+import com.google.common.net.InetAddresses;
+import com.thinkaurelius.titan.core.TitanEdge;
+import com.thinkaurelius.titan.core.TitanGraph;
+import com.thinkaurelius.titan.core.TitanTransaction;
+import com.thinkaurelius.titan.core.TitanVertex;
+
+
+/**
+ * General Database-level Utility class. These methods deal with the database one dataNode / Edge at a time.
+ * Transactions are managed at a higher level by the calling classes by passing in a TitanTransaction object.
+ */
+public class DbMeth{
+
+ private static final EELFLogger LOGGER = EELFManager.getInstance().getLogger(DbMeth.class);
+
+ /**
+ * Patch aai node.
+ *
+ * @param transId the trans id
+ * @param fromAppId the from app id
+ * @param graph the graph
+ * @param nodeType the node type
+ * @param propHash the prop hash
+ * @param depNodeVal the dep node val
+ * @param apiVersion the api version
+ * @return TitanVertex
+ * @throws AAIException the AAI exception
+ */
+ public static TitanVertex patchAaiNode(String transId, String fromAppId, TitanTransaction graph, String nodeType,
+ HashMap <String,Object> propHash, TitanVertex depNodeVal, String apiVersion ) throws AAIException{
+ // If they're calling patchAaiNode, then we only want to add/update the properties that they
+ // pass us in the propHash. If there are others already in the DB, we leave them alone.
+
+ // Note: to be really official, we'd throw an error if the node wasn't already in the db.
+ boolean[] objectExists = new boolean[1];
+ objectExists[0] = true;
+ Boolean patchOnly = true;
+ TitanVertex tv = persistAaiNodeBASE(transId, fromAppId, graph, nodeType, propHash, depNodeVal, patchOnly, apiVersion, objectExists);
+ return( tv );
+
+ } // end of patchAaiNode()
+
+ /**
+ * Patch aai node.
+ *
+ * @param transId the trans id
+ * @param fromAppId the from app id
+ * @param graph the graph
+ * @param nodeType the node type
+ * @param propHash the prop hash
+ * @param depNodeVal the dep node val
+ * @return the titan vertex
+ * @throws AAIException the AAI exception
+ */
+ @Deprecated
+ public static TitanVertex patchAaiNode(String transId, String fromAppId, TitanTransaction graph, String nodeType,
+ HashMap <String,Object> propHash, TitanVertex depNodeVal) throws AAIException{
+ return patchAaiNode( transId, fromAppId, graph, nodeType,
+ propHash, depNodeVal, null );
+ }
+
+ /**
+ * Persist aai node.
+ *
+ * @param transId the trans id
+ * @param fromAppId the from app id
+ * @param graph the graph
+ * @param nodeType the node type
+ * @param propHash the prop hash
+ * @param depNodeVal the dep node val
+ * @param patchOnly the patch only
+ * @param apiVersion the api version
+ * @return the titan vertex
+ * @throws AAIException the AAI exception
+ */
+ public static TitanVertex persistAaiNode(String transId, String fromAppId, TitanTransaction graph, String nodeType,
+ HashMap <String,Object> propHash, TitanVertex depNodeVal, Boolean patchOnly, String apiVersion) throws AAIException{
+ boolean[] objectExists = new boolean[1];
+ objectExists[0] = false;
+ return persistAaiNodeBASE( transId, fromAppId, graph, nodeType,
+ propHash, depNodeVal, patchOnly, apiVersion, objectExists);
+ }
+
+ /**
+ * Persist aai node.
+ *
+ * @param transId the trans id
+ * @param fromAppId the from app id
+ * @param graph the graph
+ * @param nodeType the node type
+ * @param propHash the prop hash
+ * @param addIfNotFound the add if not found
+ * @param depNodeVal the dep node val
+ * @param apiVersion the api version
+ * @return the titan vertex
+ * @throws AAIException the AAI exception
+ */
+ @Deprecated
+ public static TitanVertex persistAaiNode(String transId, String fromAppId, TitanTransaction graph, String nodeType,
+ HashMap <String,Object> propHash, Boolean addIfNotFound, TitanVertex depNodeVal, String apiVersion) throws AAIException{
+ // If they're calling persistAaiNode, then we want to make the Db look like whatever they pass us. That is, if
+ // there is already a record in the DB, but they do not pass some of the existing properties, they should
+ // be cleared from the DB. Since we want to take care of all properties, we pass patchOnly = false
+ Boolean patchOnly = false;
+ boolean[] objectExists = new boolean[1];
+ objectExists[0] = false;
+ TitanVertex tv = persistAaiNodeBASE(transId, fromAppId, graph, nodeType, propHash, depNodeVal, patchOnly, apiVersion, objectExists);
+ return( tv );
+ }
+
+ /**
+ * Persist aai node.
+ *
+ * @param transId the trans id
+ * @param fromAppId the from app id
+ * @param graph the graph
+ * @param nodeType the node type
+ * @param propHash the prop hash
+ * @param addIfNotFound the add if not found
+ * @param depNodeVal the dep node val
+ * @return the titan vertex
+ * @throws AAIException the AAI exception
+ */
+ @Deprecated
+ public static TitanVertex persistAaiNode(String transId, String fromAppId, TitanTransaction graph, String nodeType,
+ HashMap <String,Object> propHash, Boolean addIfNotFound, TitanVertex depNodeVal) throws AAIException{
+ // If they're calling persistAaiNode, then we want to make the Db look like whatever they pass us. That is, if
+ // there is already a record in the DB, but they do not pass some of the existing properties, they should
+ // be cleared from the DB. Since we want to take care of all properties, we pass patchOnly = false
+ Boolean patchOnly = false;
+ boolean[] objectExists = new boolean[1];
+ objectExists[0] = false;
+ TitanVertex tv = persistAaiNodeBASE(transId, fromAppId, graph, nodeType, propHash, depNodeVal, patchOnly, null, objectExists);
+ return( tv );
+ } // end of persistAaiNode()
+
+ /**
+ * Persist aai node.
+ *
+ * @param transId the trans id
+ * @param fromAppId the from app id
+ * @param graph the graph
+ * @param nodeType the node type
+ * @param propHash the prop hash
+ * @param addIfNotFound the add if not found
+ * @param depNodeVal the dep node val
+ * @param apiVersion the api version
+ * @param objectExists the object exists
+ * @return TitanVertex
+ * @throws AAIException the AAI exception
+ */
+ public static TitanVertex persistAaiNode(String transId, String fromAppId, TitanTransaction graph, String nodeType,
+ HashMap <String,Object> propHash, Boolean addIfNotFound, TitanVertex depNodeVal, String apiVersion, boolean[] objectExists) throws AAIException{
+ Boolean patchOnly = false;
+ // If they're calling persistAaiNode, then we want to make the Db look like whatever they pass us. That is, if
+ // there is already a record in the DB, but they do not pass some of the existing properties, they should
+ // be cleared from the DB. Since we want to take care of all properties, we pass patchOnly = false
+ TitanVertex tv = persistAaiNodeBASE(transId, fromAppId, graph, nodeType, propHash, depNodeVal, patchOnly, apiVersion, objectExists, null);
+ return( tv );
+ }
+
+ /**
+ * Persist aai node.
+ *
+ * @param transId the trans id
+ * @param fromAppId the from app id
+ * @param graph the graph
+ * @param nodeType the node type
+ * @param propHash the prop hash
+ * @param addIfNotFound the add if not found
+ * @param depNodeVal the dep node val
+ * @param apiVersion the api version
+ * @param objectExists the object exists
+ * @param thisNodeVertex the this node vertex
+ * @return the titan vertex
+ * @throws AAIException the AAI exception
+ */
+ public static TitanVertex persistAaiNode(String transId, String fromAppId, TitanTransaction graph, String nodeType,
+ HashMap <String,Object> propHash, Boolean addIfNotFound, TitanVertex depNodeVal, String apiVersion, boolean[] objectExists, TitanVertex thisNodeVertex) throws AAIException{
+ Boolean patchOnly = false;
+ // If they're calling persistAaiNode, then we want to make the Db look like whatever they pass us. That is, if
+ // there is already a record in the DB, but they do not pass some of the existing properties, they should
+ // be cleared from the DB. Since we want to take care of all properties, we pass patchOnly = false
+ TitanVertex tv = persistAaiNodeBASE(transId, fromAppId, graph, nodeType, propHash, depNodeVal, patchOnly, apiVersion, objectExists, thisNodeVertex);
+ return( tv );
+ }
+
+ /**
+ * Persist aai node BASE.
+ *
+ * @param transId the trans id
+ * @param fromAppId the from app id
+ * @param graph the graph
+ * @param nodeType the node type
+ * @param propHash the prop hash
+ * @param depNodeVal the dep node val
+ * @param patchOnly the patch only
+ * @param apiVersion the api version
+ * @param objectExists the object exists
+ * @return the titan vertex
+ * @throws AAIException the AAI exception
+ */
+ public static TitanVertex persistAaiNodeBASE(String transId, String fromAppId, TitanTransaction graph, String nodeType,
+ HashMap <String,Object> propHash, TitanVertex depNodeVal, Boolean patchOnly,
+ String apiVersion, boolean[] objectExists) throws AAIException{
+ return persistAaiNodeBASE(transId, fromAppId, graph, nodeType, propHash, depNodeVal, patchOnly, apiVersion, objectExists, null);
+ }
+
+ /**
+ * Persist aai node BASE.
+ *
+ * @param transId the trans id
+ * @param fromAppId the from app id
+ * @param graph the graph
+ * @param nodeType the node type
+ * @param propHash the prop hash
+ * @param depNodeVal the dep node val
+ * @param patchOnly the patch only
+ * @param apiVersion the api version
+ * @param objectExists the object exists
+ * @param thisNodeVertex the this node vertex
+ * @return the titan vertex
+ * @throws AAIException the AAI exception
+ */
+ public static TitanVertex persistAaiNodeBASE(String transId, String fromAppId, TitanTransaction graph, String nodeType,
+ HashMap <String,Object> propHash, TitanVertex depNodeVal, Boolean patchOnly,
+ String apiVersion, boolean[] objectExists, TitanVertex thisNodeVertex) throws AAIException{
+
+ if( graph == null ){
+ throw new AAIException("AAI_6101", "null graph object passed to persistAaiNodeBASE()");
+ }
+
+ DbMaps dbMaps = IngestModelMoxyOxm.dbMapsContainer.get(AAIConfig.get(AAIConstants.AAI_DEFAULT_API_VERSION_PROP));
+
+ boolean useDepNode = false;
+ String resourceVersion = null;
+ if( propHash.containsKey("resource-version") ){
+ resourceVersion = (String)(propHash.get("resource-version"));
+ }
+ String aaiUniqueKeyVal = null;
+ if( propHash.containsKey("aai-unique-key") ){
+ // Note -- we are assuming that nobody is monkeying with this. The 16-07 first-pass theory
+ // is that the REST layer is always gonna generate this or pass it through.
+ aaiUniqueKeyVal = (String)(propHash.get("aai-unique-key"));
+ propHash.remove("aai-unique-key");
+ }
+
+ if( needsADepNode4Uniqueness(transId, fromAppId, nodeType, apiVersion) ){
+ // This kind of node needs a dependent node (for uniqueness)
+ if( depNodeVal == null ){
+ // They should have passed in the node that this one depends on
+ throw new AAIException("AAI_6109", "null dependentNode object passed to persistAaiNodeBASE() but " + nodeType + " requires one.");
+ }
+ else if( ! nodeTypeACanDependOnB(transId, fromAppId, nodeType, depNodeVal.<String>property("aai-node-type").orElse(null), apiVersion) ){
+ // They should have passed in the right type of node as the dependent node
+ throw new AAIException("AAI_6109", "dependentNode of type " + depNodeVal.<String>property("aai-node-type").orElse(null) + " passed to persistAaiNodeBASE() for nodeType" + nodeType + ".");
+ }
+ useDepNode = true;
+ }
+ else {
+ depNodeVal = null;
+ }
+
+ // Note: as of 1607, we no longer validate property names since that's covered by the REST layer.
+ // Same goes for required fields (as of 1602)
+
+ // Special ip-address validation for ipAddr nodes only... This will go away when we go to YANG and
+ // do validations like this up at that layer.
+ if( nodeType.equals("ipaddress") ){
+ // Note - this will throw an exception if the ipAddress is using a bad format
+ ipAddressFormatOK( transId, fromAppId, (String)propHash.get("addr"), (String)propHash.get("version") );
+ }
+
+ // Use the key-fields/dependentNode to check if this is an add or an update
+ // We assume that all NodeTypes at least one key-property defined. A dependentNode is optional.
+ if( ! dbMaps.NodeKeyProps.containsKey(nodeType) ){
+ // Problem if no key Properties defined for this nodeType
+ String defVer = AAIConfig.get(AAIConstants.AAI_DEFAULT_API_VERSION_PROP);
+ throw new AAIException("AAI_6105", "No node-key-properties defined in dbMaps for nodeType = " + nodeType + " (ver=" + defVer + ")");
+ }
+
+ Boolean hasAltKey1 = false;
+ HashMap <String,Object>nodeAltKey1PropsHash = new HashMap<String,Object>();
+ Collection <String> altKey1Props = getNodeAltKey1PropNames(transId, fromAppId, nodeType, apiVersion);
+ if( altKey1Props != null ){
+ Iterator <String> altKey1PropI = altKey1Props.iterator();
+ while( altKey1PropI.hasNext() ){
+ String propName = altKey1PropI.next();
+ // NOTE: alt-keys are not always required fields. If it is null or blank, we won't
+ // do alt-key checks on it.
+ Object value = propHash.get(propName);
+ if( value != null && !value.toString().equals("") ){
+ hasAltKey1 = true;
+ nodeAltKey1PropsHash.put(propName, value);
+ }
+ }
+ }
+ HashMap <String,Object>nodeKeyPropsHash = new HashMap<String,Object>();
+ Collection <String> keyProps = getNodeKeyPropNames(transId, fromAppId, nodeType, apiVersion);
+ Iterator <String> keyPropI = keyProps.iterator();
+ while( keyPropI.hasNext() ){
+ String propName = keyPropI.next();
+
+ Object value = propHash.get(propName);
+ nodeKeyPropsHash.put(propName, value);
+ }
+
+ // Check if this node is already in the database based on the Primary Key Info
+ TitanVertex existingVert = thisNodeVertex;
+ boolean foundTheNodeInDb = true;
+
+ if (existingVert == null) {
+ try {
+ existingVert = getUniqueNode( transId, fromAppId, graph, nodeType, nodeKeyPropsHash, depNodeVal, apiVersion );
+ }
+ catch (AAIException e) {
+ if (e.getErrorObject().getErrorCode().equals("6114")) {
+ foundTheNodeInDb = false;
+ }
+ else {
+ throw e;
+ }
+ }
+ }
+
+ // this is so the notification knows whether or not the operation was an UPDATE or a CREATe
+ objectExists[0] = foundTheNodeInDb;
+ if( foundTheNodeInDb ){
+ // A record was found in the DB using the PK.
+ if( needToDoResourceVerCheck(apiVersion, patchOnly) ){
+ // Need to check that they knew what they were updating
+ String existingResVer = existingVert.<String>property("resource-version").orElse(null);
+ if( resourceVersion == null || resourceVersion.equals("") ){
+ throw new AAIException("AAI_6130", "Resource-version not passed for update of = " + nodeType + ", " + nodeKeyPropsHash.toString());
+ }
+ else if( (existingResVer != null) && !resourceVersion.equals(existingResVer) ){
+ throw new AAIException("AAI_6131", "Resource-version " + resourceVersion + " MISMATCH WITH EXISTING " + existingResVer + " for update of = " + nodeType + ", " + nodeKeyPropsHash.toString());
+ }
+ }
+
+ // Need to ensure that the Alternate key isn't changing to a value that points to a different existing node.
+ // It is ok if it points to nothing -- that would just be an update for this node. It's also ok if
+ // it points to this (existing) node - that just means that it wasn't being updated.
+ if( hasAltKey1 ){
+ try {
+ TitanVertex chkVert = getUniqueNode( transId, fromAppId, graph, nodeType, nodeAltKey1PropsHash, depNodeVal, apiVersion );
+ if( ! chkVert.id().toString().equals(existingVert.id().toString()) ){
+ throw new AAIException("AAI_6117", "In-Use AlternateKey value passed for update of nodeType = " + nodeType);
+ }
+ }
+ catch (AAIException e) {
+ if(! e.getErrorObject().getErrorCode().equals("6114") ){
+ throw e;
+ }
+ }
+ }
+ }
+ else {
+ // Note not in the DB -- This will be an ADD of a new node
+ // a) make sure they didn't say they were just doing "patchOnly" which cannot be an ADD.
+ // b) if there is an alternate key, we need to make sure the AK isn't already in use by somebody else.
+ if( patchOnly ){
+ String depMsg = "";
+ if( useDepNode ){
+ depMsg = " plus dependent node. ";
+ }
+ throw new AAIException("AAI_6114", "Patch Request, but no Node of type " + nodeType + " found for properties: [" + propHash + "] " + depMsg);
+ }
+
+ if( needToDoResourceVerCheck(apiVersion, patchOnly) && (resourceVersion != null) && !resourceVersion.equals("") ){
+ throw new AAIException("AAI_6131", "Resource-version was passed in, but this is an ADD of a " + nodeType + ", with these params: " + nodeKeyPropsHash.toString());
+ }
+ if( hasAltKey1 ){
+ try {
+ getUniqueNode( transId, fromAppId, graph, nodeType, nodeAltKey1PropsHash, depNodeVal, apiVersion );
+ // Since the Primary Key for this nodeType wasn't found in the DB yet, the fact that
+ // we are able to find a record (no "6114" exception thrown) using the Alternate-Key is an error.
+ // We can't create a new node that uses an AK that's already in use.
+ throw new AAIException("AAI_6117", "Conflicting Key and Alternate-Key values passed for add of nodeType = " + nodeType);
+ }
+ catch (AAIException e) {
+ if(! e.getErrorObject().getErrorCode().equals("6114") ){
+ throw e;
+ }
+ }
+ }
+ }
+
+ // ------------- Done with checking. Do the add or update to the dB -----------------------
+
+ if( foundTheNodeInDb ){
+ long unixTimeNow = System.currentTimeMillis() / 1000L;
+ // ----- This is an UPDATE ------
+
+
+ String existingSourceOfTruth = fromAppId; // default value if we can't get the old one
+ Object tmpOb = existingVert.<Object>property("source-of-truth").orElse(null);
+ if( tmpOb != null ){
+ existingSourceOfTruth = tmpOb.toString();
+ }
+ long existingCreateTs = unixTimeNow; // default value if we can't get the old one
+ tmpOb = existingVert.<Object>property("aai-created-ts").orElse(null);
+ if( tmpOb != null ){
+ existingCreateTs = (long) tmpOb;
+ }
+
+ String msg = "UPDATE vertex of type = [" + nodeType + "] ";
+ if( useDepNode ){
+ String depNType = depNodeVal.<String>property("aai-node-type").orElse(null);
+ HashMap <String, Object> depNodePropKeysHash = getNodeKeyPropHash(transId, fromAppId, graph, depNodeVal);
+ LOGGER.info("UPDATE existing node: type = " + nodeType + ", key(s) = [" + nodeKeyPropsHash +
+ "] which rides on dependent node: type = " + depNType + ", with key(s) = [" + depNodePropKeysHash + "].");
+ }
+ else {
+ LOGGER.info("UPDATE existing node: type = " + nodeType + ", key(s) = [" + nodeKeyPropsHash + "] (no dep. node).");
+ }
+ String removeList = "";
+ if( ! patchOnly ){
+ // They are updating an existing record, and they want us to "process all defined properties" (not just patch)
+ // So we will see if the node has any properties that were not passed-in. Those need to be removed.
+ Collection <String> propCol = dbMaps.NodeProps.get(nodeType);
+ Iterator <String> propIter = propCol.iterator();
+ while( propIter.hasNext() ){
+ String propName = propIter.next();
+ if( ! propHash.containsKey(propName) && !DbEdgeRules.ReservedPropNames.containsKey(propName)){
+ if( thisPropertyWasPutByNewerVersionOfCode(apiVersion, nodeType, propName) ){
+ // we must be using an older version of code here - but the property that
+ // has not been passed in this persist call is one that this older version of
+ // the database did not know about. So leave it alone.
+ }
+ else {
+ removeList = removeList + "," + propName;
+ existingVert.property(propName).remove();
+ }
+ }
+ }
+ }
+ if( !removeList.equals("") ){
+ LOGGER.info("Removed these props on update: [" + removeList + "]");
+ }
+ for( Map.Entry<String, Object> entry : propHash.entrySet() ){
+ // update the parameters that have been passed in (except the key-properties)
+ // taking away the key-property check. We will now allow this since
+ // the keys were used to identify this node, so they should be good and
+ // there are times when Titan resolves conflicts by only using the
+ // data set in an update - and was losing our key info...
+ // Similar to the change noted below.
+ //if( ! nodeKeyPropsHash.containsKey(entry.getKey()) ){
+ // existingVert.setProperty( entry.getKey(), entry.getValue() );
+ //}
+ if( ! entry.getKey().equals("resource-version") ){
+ boolean nonSingleCardinality = false;
+ boolean setSoNoDupes = false;
+ if( checkPropCardinality(entry.getKey(), "Set") ){
+ nonSingleCardinality = true;
+ setSoNoDupes = true;
+ }
+ else if( checkPropCardinality(entry.getKey(), "List") ){
+ nonSingleCardinality = true;
+ }
+
+ Iterator <Object> valIter = null;
+ if( nonSingleCardinality ){
+ String className = entry.getValue().getClass().getSimpleName();
+ if( className.equals("ArrayList") ){
+ valIter = ((ArrayList)(entry.getValue())).iterator();
+ }
+ else if( className.equals("List") ){
+ valIter = ((List)(entry.getValue())).iterator();
+ }
+ else if( className.equals("Set") ){
+ valIter = ((Set)(entry.getValue())).iterator();
+ }
+ }
+
+ if( nonSingleCardinality ){
+ // This property has Cardinality of List or Set - which need to be handled carefully
+ // Note -- for Lists or Sets, we assume they are of dataType String - that is all
+ // the Rest layer supports at the moment (16-02)
+ ArrayList <String> currentData = new ArrayList <String> ();
+ if( patchOnly ){
+ // When patching - gotta know what's already in the db
+ Iterator<VertexProperty<Object>> existingPropsIter = (existingVert.properties(entry.getKey()));
+ if( existingPropsIter != null ){
+ while( existingPropsIter.hasNext() ){
+ String existingVal = existingPropsIter.next().value().toString();
+ currentData.add( existingVal );
+ }
+ }
+ }
+ else {
+ // Since this is not a patch-update, we first have to clear out what is currently in the db.
+ existingVert.property(entry.getKey()).remove();
+ }
+
+ if( valIter != null ){
+ while( valIter.hasNext() ){
+ Object thisVal = valIter.next();
+ if( setSoNoDupes ){
+ // For Sets, we need to check that the data isn't already in the db or wasn't passed
+ // in to us twice in the propHash. Otherwise Titan throws an exception (instead of just ignoring it...)
+ if( !currentData.contains(thisVal) ){
+ // We don't have this data yet, so add it to the Set
+ existingVert.property( entry.getKey(), thisVal );
+ currentData.add( thisVal.toString() );
+ }
+ }
+ else {
+ // For List data types, it's ok to have duplicate values in the db (why would we want this?)
+ existingVert.property( entry.getKey(), thisVal );
+ }
+ }
+ }
+ }
+ else {
+ // This is a normal, "Cardinality = SINGLE" kind of property
+ // ResourceVersion is not populated based on passed-in data, it is set along with other internal properties below.
+ //Object cleanVal = convertTypeIfNeeded( entry.getKey(), entry.getValue() );
+ //existingVert.setProperty( entry.getKey(), cleanVal );
+ // ********************************
+ existingVert.property( entry.getKey(), entry.getValue() );
+ }
+ }
+ }
+
+ // DEBUG - trying to deal with the case where simultaneous PUTs
+ // cause our db to wind up with a vertex that does not have these three properties filled in.
+ existingVert.property( "aai-node-type", nodeType );
+ existingVert.property( "aai-created-ts", existingCreateTs );
+ existingVert.property( "source-of-truth", existingSourceOfTruth );
+
+ if( aaiUniqueKeyVal != null ){
+ existingVert.property( "aai-unique-key", aaiUniqueKeyVal );
+ }
+
+ existingVert.property( "aai-last-mod-ts", unixTimeNow );
+ String resVers = "" + unixTimeNow;
+ existingVert.property( "resource-version", resVers );
+ existingVert.property( "last-mod-source-of-truth", fromAppId );
+
+ LOGGER.info(msg + ", [aai-last-mod-ts]/[" + unixTimeNow + "]");
+
+ return( existingVert );
+ }
+ else{
+ // ----- Not found in the DB, This must be an ADD ------
+ if( DbEdgeRules.NodeTypeCategory.containsKey(nodeType) ){
+ throw new AAIException("AAI_6120", "nodeTypeCategory " + nodeType + " cannot be used to ADD a node. Need to pass a valid nodeType");
+ }
+
+ TitanVertex tiVnew = graph.addVertex( nodeType );
+
+ String msg = "ADD vertex of type = [" + nodeType + "] ";
+ if( depNodeVal != null ){
+ String depNType = depNodeVal.<String>property("aai-node-type").orElse(null);
+ HashMap <String, Object> depNodePropKeysHash = getNodeKeyPropHash(transId, fromAppId, graph, depNodeVal);
+ msg = msg + " onto dependent node: type = " + depNType + ", which has key(s) = [" + depNodePropKeysHash +
+ "]. New Node Prop/values = ";
+ }
+ else {
+ msg = msg + " Note: no dependent node. New Node Prop/values = ";
+ }
+ boolean first = true;
+ for( Map.Entry<String, Object> entry : propHash.entrySet() ){
+ if( ! entry.getKey().equals("resource-version") ){
+ if( first ){
+ msg = msg + " [" + entry.getKey() + "]/[" + entry.getValue() + "]";
+ first = false;
+ }
+ else {
+ msg = msg + ", [" + entry.getKey() + "]/[" + entry.getValue() + "]";
+ }
+
+ boolean nonSingleCardinality = false;
+ boolean setSoNoDupes = false;
+ if( checkPropCardinality(entry.getKey(), "Set") ){
+ nonSingleCardinality = true;
+ setSoNoDupes = true;
+ }
+ else if( checkPropCardinality(entry.getKey(), "List") ){
+ nonSingleCardinality = true;
+ }
+
+ Iterator <Object> valIter = null;
+ if( nonSingleCardinality ){
+ String className = entry.getValue().getClass().getSimpleName();
+ if( className.equals("ArrayList") ){
+ valIter = ((ArrayList)(entry.getValue())).iterator();
+ }
+ else if( className.equals("List") ){
+ valIter = ((List)(entry.getValue())).iterator();
+ }
+ else if( className.equals("Set") ){
+ valIter = ((Set)(entry.getValue())).iterator();
+ }
+ }
+
+ if( nonSingleCardinality ){
+ // This property has Cardinality of List or Set - which need to be handled carefully
+ ArrayList <String> currentData = new ArrayList <String> ();
+ if( valIter != null ){
+ while( valIter.hasNext() ){
+ Object thisVal = valIter.next();
+ if( setSoNoDupes ){
+ // For Sets, we need to check that they're not passing us duplicate data in propHash.
+ // Otherwise Titan throws an exception (instead of just ignoring it...)
+ if( !currentData.contains(thisVal) ){
+ // We don't have this data yet, so add it to the Set
+ tiVnew.property( entry.getKey(), thisVal );
+ currentData.add( thisVal.toString() );
+ }
+ }
+ else {
+ // For List data types, it's ok to have duplicate values in the db (why would we want this?)
+ tiVnew.property( entry.getKey(), thisVal );
+ }
+ }
+ }
+ }
+ else {
+ // This is a normal, "Cardinality = SINGLE" kind of property
+ // ResourceVersion is not populated based on passed-in data, it is set along with other internal properties below.
+ tiVnew.property( entry.getKey(), entry.getValue() );
+ }
+ }
+ }
+
+ tiVnew.property( "aai-node-type", nodeType );
+ //long unixTime = System.currentTimeMillis() / 1000L;
+ long unixTime = System.currentTimeMillis();
+ tiVnew.property( "aai-created-ts", unixTime );
+ tiVnew.property( "aai-last-mod-ts", unixTime );
+ String resVers = "" + unixTime;
+ tiVnew.property( "resource-version", resVers );
+ tiVnew.property( "source-of-truth", fromAppId );
+ tiVnew.property( "last-mod-source-of-truth", fromAppId );
+ if( aaiUniqueKeyVal != null ){
+ tiVnew.property( "aai-unique-key", aaiUniqueKeyVal );
+ }
+
+ LOGGER.info(msg + ", [aai-created-ts]/[" + unixTime + "]");
+ return( tiVnew );
+ }
+
+ } // end of persistAaiNodeBASE()
+
+
+ /**
+ * Need to do resource ver check.
+ *
+ * @param apiVersion the api version
+ * @param patchOnlyFlag the patch only flag
+ * @return the boolean
+ * @throws AAIException the AAI exception
+ */
+ public static Boolean needToDoResourceVerCheck(String apiVersion, Boolean patchOnlyFlag)
+ throws AAIException{
+
+ if( patchOnlyFlag ){
+ // we do not do resource checking for patch requests.
+ return false;
+ }
+
+ String resourceCheckOnFlag = AAIConfig.get(AAIConstants.AAI_RESVERSION_ENABLEFLAG);
+
+ int apiVerInt = cleanUpApiVersion(apiVersion);
+
+ if( (resourceCheckOnFlag != null) && resourceCheckOnFlag.equals("true") ){
+ // Only do the check if the resource enable flag is set to "true"
+ if( apiVerInt > 4 ){
+ // We're only doing the resource version checks for v5 and later
+ return true;
+ }
+ }
+
+ return false;
+ }// End needToDoResourceVerCheck()
+
+
+ /**
+ * Clean up api version.
+ *
+ * @param apiVersionString the api version string
+ * @return the int
+ * @throws AAIException the AAI exception
+ */
+ private static int cleanUpApiVersion( String apiVersionString ) throws AAIException {
+ // Note: we expect an apiVersion to start with the letter "v", followed by an integer.
+
+ int versionInt = 0;
+ String verStr = apiVersionString;
+ if( (apiVersionString == null) || (apiVersionString.length() < 2) ){
+ // Passed in version doesn't look right
+ verStr = org.openecomp.aai.util.AAIApiVersion.get();
+ }
+ versionInt = getVerNumFromVerString( verStr );
+
+ return versionInt;
+ }
+
+ /**
+ * Gets the ver num from ver string.
+ *
+ * @param versionString the version string
+ * @return the ver num from ver string
+ * @throws AAIException the AAI exception
+ */
+ private static int getVerNumFromVerString( String versionString )throws AAIException {
+ int versionInt = 0;
+ if( versionString == null || versionString.length() < 2 ){
+ throw new AAIException("AAI_6121", " Bad Version (format) passed to getVerNumFromVerString: [" + versionString + "].");
+ }
+
+ int strLen = versionString.length();
+ // We assume that a version looks like "v" followed by an integer
+ if( ! versionString.substring(0,1).equals("v") ){
+ String detail = " Bad Version (format) passed to getVerNumFromVerString: [" + versionString + "].";
+ throw new AAIException("AAI_6121", detail);
+ }
+ else {
+ String intPart = versionString.substring(1,strLen);
+ try {
+ versionInt = Integer.parseInt( intPart );
+ }
+ catch( Exception e ){
+ String detail = " Bad Version passed to getVerNumFromVerString: [" + versionString + "].";
+ throw new AAIException("AAI_6121", detail);
+ }
+ }
+ return versionInt;
+ }
+
+
+ /**
+ * Gets the node key prop names.
+ *
+ * @param transId the trans id
+ * @param fromAppId the from app id
+ * @param nodeType the node type
+ * @param apiVersion the api version
+ * @return HashMap of keyProperties
+ * @throws AAIException the AAI exception
+ */
+ public static Collection <String> getNodeKeyPropNames( String transId, String fromAppId, String nodeType, String apiVersion ) throws AAIException{
+
+ DbMaps dbMaps = IngestModelMoxyOxm.dbMapsContainer.get(AAIConfig.get(AAIConstants.AAI_DEFAULT_API_VERSION_PROP));
+
+ Collection <String> keyProps = new ArrayList <String>();
+ if( dbMaps.NodeKeyProps.containsKey(nodeType) ){
+ keyProps = dbMaps.NodeKeyProps.get(nodeType);
+ }
+ else if( DbEdgeRules.NodeTypeCategory.containsKey(nodeType) ){
+ // The passed-in nodeType was really a nodeCategory, so we need to look up the key params
+ Collection <String> nTypeCatCol = DbEdgeRules.NodeTypeCategory.get(nodeType);
+ Iterator <String> catItr = nTypeCatCol.iterator();
+ String catInfo = "";
+ if( catItr.hasNext() ){
+ // For now, we only look for one.
+ catInfo = catItr.next();
+ }
+ else {
+ String defVer = AAIConfig.get(AAIConstants.AAI_DEFAULT_API_VERSION_PROP);
+ throw new AAIException("AAI_6105", "Required Property name(s) not found for nodeType = " + nodeType+ " (ver=" + defVer + ")");
+ }
+
+ String [] flds = catInfo.split(",");
+ if( flds.length != 4 ){
+ throw new AAIException("AAI_6121", "Bad EdgeRule.NodeTypeCategory data for nodeType = [" + nodeType + "].");
+ }
+
+ String keyPropsString = flds[0];
+ String [] propNames = keyPropsString.split("\\|");
+ for( int i = 0; i < propNames.length; i++ ){
+ keyProps.add(propNames[i]);
+ }
+ }
+ else {
+ String defVer = AAIConfig.get(AAIConstants.AAI_DEFAULT_API_VERSION_PROP);
+ throw new AAIException("AAI_6105", "Required Property name(s) not found for nodeType = " + nodeType+ " (ver=" + defVer + ")");
+ }
+
+ return keyProps;
+
+ }// end of getNodeKeyPropNames
+
+ /**
+ * Gets the node key prop names.
+ *
+ * @param transId the trans id
+ * @param fromAppId the from app id
+ * @param nodeType the node type
+ * @return the node key prop names
+ * @throws AAIException the AAI exception
+ */
+ @Deprecated
+ public static Collection <String> getNodeKeyPropNames( String transId, String fromAppId, String nodeType ) throws AAIException{
+ return getNodeKeyPropNames( transId, fromAppId, nodeType, null);
+ }
+
+ /**
+ * Gets the node alt key 1 prop names.
+ *
+ * @param transId the trans id
+ * @param fromAppId the from app id
+ * @param nodeType the node type
+ * @param apiVersion the api version
+ * @return HashMap of keyProperties
+ * @throws AAIException the AAI exception
+ */
+ public static Collection <String> getNodeAltKey1PropNames( String transId, String fromAppId, String nodeType, String apiVersion ) throws AAIException{
+
+ DbMaps dbMaps = IngestModelMoxyOxm.dbMapsContainer.get(AAIConfig.get(AAIConstants.AAI_DEFAULT_API_VERSION_PROP));
+
+ Collection <String> altKey1Props = new ArrayList <String>();
+ if( dbMaps.NodeAltKey1Props.containsKey(nodeType) ){
+ altKey1Props = dbMaps.NodeAltKey1Props.get(nodeType);
+ }
+ else if( DbEdgeRules.NodeTypeCategory.containsKey(nodeType) ){
+ // The passed-in nodeType was really a nodeCategory, so we need to look up the key params
+ Collection <String> nTypeCatCol = DbEdgeRules.NodeTypeCategory.get(nodeType);
+ Iterator <String> catItr = nTypeCatCol.iterator();
+ String catInfo = "";
+ if( catItr.hasNext() ){
+ catInfo = catItr.next();
+ String [] flds = catInfo.split(",");
+ if( flds.length != 4 ){
+ throw new AAIException("AAI_6121", "Bad EdgeRule.NodeTypeCategory data (itemCount=" + flds.length + ") for nodeType = [" + nodeType + "].");
+ }
+
+ String altKeyPropsString = flds[1];
+ String [] propNames = altKeyPropsString.split("\\|");
+ for( int i = 0; i < propNames.length; i++ ){
+ altKey1Props.add(propNames[i]);
+ }
+ }
+ }
+
+ return altKey1Props;
+
+ }// end of getNodeAltKey1PropNames
+
+ /**
+ * Gets the node alt key 1 prop names.
+ *
+ * @param transId the trans id
+ * @param fromAppId the from app id
+ * @param nodeType the node type
+ * @return the node alt key 1 prop names
+ * @throws AAIException the AAI exception
+ */
+ @Deprecated
+ public static Collection <String> getNodeAltKey1PropNames( String transId, String fromAppId, String nodeType ) throws AAIException{
+ return getNodeAltKey1PropNames( transId, fromAppId, nodeType, null);
+ }
+
+
+ /**
+ * Gets the unique node.
+ *
+ * @param transId the trans id
+ * @param fromAppId the from app id
+ * @param graph the graph
+ * @param nodeType the node type
+ * @param keyPropsHash the key props hash
+ * @param depNodeVal the dep node val
+ * @param apiVersion the api version
+ * @return TitanVertex
+ * @throws AAIException the AAI exception
+ */
+ @Deprecated
+ public static TitanVertex getUniqueNode( String transId, String fromAppId, TitanTransaction graph, String nodeType,
+ HashMap<String,Object> keyPropsHash, TitanVertex depNodeVal, String apiVersion ) throws AAIException{
+
+ // NOTE - this is really for use by the PersistNode method -- it is looking to see if
+ // a node exists in the database given either Primary or Alternate Key data and dependent
+ // node data (if required for uniqueness).
+
+ // Note - the passed in nodeType could really be a nodeTypeCategory ---
+ Boolean nodeTypeIsCategory = DbEdgeRules.NodeTypeCategory.containsKey(nodeType);
+
+ Boolean useDepNode = false;
+ if( needsADepNode4Uniqueness(transId, fromAppId, nodeType, apiVersion) ){
+ // This kind of node depends on another node for uniqueness
+ if( depNodeVal == null ){
+ // They should have passed in the node that this one depends on
+ throw new AAIException("AAI_6109", "null dependentNode object passed to getUniqueNode() but " + nodeType + " requires one.");
+ }
+ else if( ! nodeTypeACanDependOnB(transId, fromAppId, nodeType, depNodeVal.<String>property("aai-node-type").orElse(null), apiVersion) ){
+ // They should have passed in the right type of node as the dependent node
+ throw new AAIException("AAI_6109", "dependentNode of type " + depNodeVal.<String>property("aai-node-type").orElse(null) + " passed to getUniqueNode() for nodeType" + nodeType + ".\n");
+ }
+ useDepNode = true;
+ }
+ else {
+ depNodeVal = null;
+ }
+
+ // We assume that all NodeTypes have at least one key-property defined. A dependentNode is optional.
+ // Note - instead of key-properties (the primary key properties), a user could pass
+ // alternate-key values if they are defined for the nodeType.
+ ArrayList<String> kName = new ArrayList<String>();
+ ArrayList<Object> kVal = new ArrayList<Object>();
+
+ Collection <String> keyProps = getNodeKeyPropNames(transId, fromAppId, nodeType, apiVersion);
+ Iterator <String> keyPropI = keyProps.iterator();
+ Boolean haveSomePrimKeyProps = false;
+ Boolean primaryKeyComplete = true;
+ while( keyPropI.hasNext() ){
+ haveSomePrimKeyProps = true;
+
+ String propName = keyPropI.next();
+ if( ! keyPropsHash.containsKey(propName) ){
+ primaryKeyComplete = false;
+ }
+ else {
+ Object valObj = keyPropsHash.get(propName);
+ if( valObj == null ){
+ primaryKeyComplete = false;
+ }
+ else {
+ String value = valObj.toString();
+ if( value == null || value.equals("") ){
+ // They passed the property name, but no value
+ primaryKeyComplete = false;
+ }
+ }
+ }
+ }
+
+ int i = -1;
+ if( haveSomePrimKeyProps && primaryKeyComplete ){
+ keyPropI = keyProps.iterator();
+ while( keyPropI.hasNext() ){
+ String propName = keyPropI.next();
+ String value = (keyPropsHash.get(propName)).toString();
+ i++;
+ kName.add(i, propName);
+ kVal.add(i, (Object)value);
+ }
+ }
+ else {
+ // See if they're using the alternate key
+ Collection <String> altKey1Props = getNodeAltKey1PropNames(transId, fromAppId, nodeType, apiVersion);
+ Iterator <String> altKey1PropI = altKey1Props.iterator();
+ Boolean haveSomeAltKey1Props = false;
+ Boolean altKey1Complete = true;
+ while( altKey1PropI.hasNext() ){
+ haveSomeAltKey1Props = true;
+ String propName = altKey1PropI.next();
+ if( ! keyPropsHash.containsKey(propName) ){
+ altKey1Complete = false;
+ }
+ else {
+ Object valObj = keyPropsHash.get(propName);
+ if( valObj == null ){
+ altKey1Complete = false;
+ }
+ else {
+ String value = valObj.toString();
+ if( value == null || value.equals("") ){
+ // They passed the property name, but no value
+ altKey1Complete = false;
+ }
+ }
+ }
+ }
+ if( haveSomeAltKey1Props && altKey1Complete ){
+ altKey1PropI = altKey1Props.iterator();
+ while( altKey1PropI.hasNext() ){
+ String propName = altKey1PropI.next();
+ String value = (keyPropsHash.get(propName)).toString();
+ i++;
+ kName.add(i, propName);
+ kVal.add(i, (Object)value);
+ }
+ }
+ }
+
+ int topPropIndex = i;
+ TitanVertex tiV = null;
+ String propsAndValuesForMsg = "";
+ if( !useDepNode ){
+ // There is no node that this type of node depends on, so we can look for it based
+ // solely on the Aai-defined key fields.
+ Iterable <?> verts = null;
+
+ if( topPropIndex == -1 ){
+ // Problem if no key Properties defined for this nodeType
+ String defVer = AAIConfig.get(AAIConstants.AAI_DEFAULT_API_VERSION_PROP);
+ throw new AAIException("AAI_6105", "Bad or Incomplete Key Property params: (" + keyPropsHash.toString() +
+ ") for nodeType: " + nodeType + " (ver=" + defVer + ")");
+ }
+ else if( topPropIndex == 0 ){
+ if (nodeTypeIsCategory) // dont know real type
+ verts= graph.query().has(kName.get(0),kVal.get(0)).vertices();
+ else // need this to find dvs switch: dvs.switch-name and port-group.switch-name issue
+ verts= graph.query().has(kName.get(0),kVal.get(0)).has("aai-node-type",nodeType).vertices();
+ propsAndValuesForMsg = " (" + kName.get(0) + " = " + kVal.get(0) + ") ";
+ }
+ else if( topPropIndex == 1 ){
+ verts = graph.query().has(kName.get(0),kVal.get(0)).has(kName.get(1),kVal.get(1)).vertices();
+ propsAndValuesForMsg = " (" + kName.get(0) + " = " + kVal.get(0) + ", "
+ + kName.get(1) + " = " + kVal.get(1) + ") ";
+ }
+ else if( topPropIndex == 2 ){
+ verts= graph.query().has(kName.get(0),kVal.get(0)).has(kName.get(1),kVal.get(1)).has(kName.get(2),kVal.get(2)).vertices();
+ propsAndValuesForMsg = " (" + kName.get(0) + " = " + kVal.get(0) + ", "
+ + kName.get(1) + " = " + kVal.get(1) + ", "
+ + kName.get(2) + " = " + kVal.get(2) + ") ";
+ }
+ else if( topPropIndex == 3 ){
+ verts= graph.query().has(kName.get(0),kVal.get(0)).has(kName.get(1),kVal.get(1)).has(kName.get(2),kVal.get(2)).has(kName.get(3),kVal.get(3)).vertices();
+ propsAndValuesForMsg = " (" + kName.get(0) + " = " + kVal.get(0) + ", "
+ + kName.get(1) + " = " + kVal.get(1) + ", "
+ + kName.get(2) + " = " + kVal.get(2) + ", "
+ + kName.get(3) + " = " + kVal.get(3) + ") ";
+ }
+ else {
+ String emsg = " We only support 4 keys per nodeType for now \n";
+ throw new AAIException("AAI_6114", emsg);
+ }
+
+ Iterator <?> vertI = verts.iterator();
+ if( vertI != null && vertI.hasNext()) {
+ // We found a vertex that meets the input criteria.
+ tiV = (TitanVertex) vertI.next();
+
+ if( vertI.hasNext() ){
+ // Since this routine is looking for a unique node for the given input values, if
+ // more than one is found - it's a problem.
+ throw new AAIException("AAI_6112", "More than one Node found by getUniqueNode for params: " + propsAndValuesForMsg);
+ }
+ }
+ else {
+ // No Vertex was found for this key - throw a not-found exception
+ throw new AAIException("AAI_6114", "No Node of type " + nodeType + " found for properties: " + propsAndValuesForMsg);
+ }
+ }
+ else {
+ // Need to use the dependent vertex to look for this one.
+ // filter this to the actual keys because
+ HashMap<String,Object> onlyKeysHash = new HashMap<String,Object>();
+
+ Collection <String> onlyKeyProps = getNodeKeyPropNames(transId, fromAppId, nodeType, apiVersion);
+
+ Iterator <String> onlyKeyPropsI = onlyKeyProps.iterator();
+
+ while( onlyKeyPropsI.hasNext() ){
+ String keyName = onlyKeyPropsI.next();
+ onlyKeysHash.put(keyName, keyPropsHash.get(keyName));
+ }
+
+ propsAndValuesForMsg = onlyKeysHash.toString() + " combined with a Dependent [" + depNodeVal.<String>property("aai-node-type").orElse(null) + "] node.";
+ ArrayList<TitanVertex> resultList = DbMeth.getConnectedNodes(transId, fromAppId, graph, nodeType, onlyKeysHash,
+ depNodeVal, apiVersion, false);
+ if( resultList.size() > 1 ){
+ // More than one vertex found when we thought there should only be one.
+ throw new AAIException("AAI_6112", "More than one Node found by getUniqueNode for params: " + propsAndValuesForMsg);
+ }
+ else if( resultList.size() == 1 ){
+ tiV = resultList.get(0);
+ }
+ }
+
+ if( tiV == null ){
+ // No Vertex was found for this key - throw a not-found exception
+ throw new AAIException("AAI_6114", "No Node of type " + nodeType + " found for properties: " + propsAndValuesForMsg);
+ }
+ else {
+ if( !DbEdgeRules.NodeTypeCategory.containsKey(nodeType) ){
+ // The nodeType passed in was a real one, not a nodeTypeCategory, so we will
+ // use it as part of the query to make sure we find the right type of node.
+ // This can be an issue if they're using nodeTypes covered by a nodeTypeCategory but
+ // pass in the wrong nodeType. We don't want them to ask for one thing and get the other.
+ String foundNodeType = tiV.<String>property("aai-node-type").orElse(null);
+ if( foundNodeType != null && !foundNodeType.equals(nodeType) ){
+ throw new AAIException("AAI_6114", "No Node of type " + nodeType + " found for properties: " + propsAndValuesForMsg + " (did find a " + foundNodeType + " though.)");
+ }
+ }
+
+ return tiV;
+ }
+
+ }// End of getUniqueNode()
+
+ /**
+ * Gets the unique node.
+ *
+ * @param transId the trans id
+ * @param fromAppId the from app id
+ * @param graph the graph
+ * @param nodeType the node type
+ * @param keyPropsHash the key props hash
+ * @param depNodeVal the dep node val
+ * @return the unique node
+ * @throws AAIException the AAI exception
+ */
+ @Deprecated
+ public static TitanVertex getUniqueNode( String transId, String fromAppId, TitanTransaction graph, String nodeType,
+ HashMap<String,Object> keyPropsHash, TitanVertex depNodeVal) throws AAIException {
+ return getUniqueNode( transId, fromAppId, graph, nodeType,
+ keyPropsHash, depNodeVal, null );
+ }
+ // End getUniqueNode()
+
+
+ /**
+ * Gets the unique node with dep params.
+ *
+ * @param transId the trans id
+ * @param fromAppId the from app id
+ * @param graph the graph
+ * @param nodeType the node type
+ * @param nodePropsHash the node props hash
+ * @param apiVersion the api version
+ * @return TitanVertex
+ * @throws AAIException the AAI exception
+ */
+ @Deprecated
+ public static TitanVertex getUniqueNodeWithDepParams( String transId, String fromAppId, TitanTransaction graph, String nodeType,
+ HashMap<String,Object> nodePropsHash, String apiVersion )
+ throws AAIException{
+ /*
+ * This method uses the nodePropsHash to walk back over dependent nodes until it finds one that
+ * does not depend on any other for uniqueness. It uses the getUniqueNode() method as it finds
+ * dependent nodes. NOTE -- it is passed a hash of all the nodeProperties -- for itself and
+ * for any dependent nodes that it will need to find. There are some types of nodes that can
+ * depend on more than one node, we assume that there wouldn't be a case where BOTH types of
+ * dependent nodes are in the trail that we need to traverse. Ie. an ipaddress can depend on
+ * either a vserver or pserver. NOTE this case can now happen -- nodePropsHash
+ * should now be sent as a LinkedHashMap in this case so we can search in order.
+ */
+
+ // NOTE ALSO -- We're currently supporting 6 layers of dependency. We never thought there would be this
+ // many layers before hitting a node-type that would be uniquely identifiable on it's own. So the
+ // code is a little ugly with all these nested if-then-else's. Since we're supporting so many
+ // layers, it should be re-written so we can support "n" layers instead of having to go in hear
+ // and adding code... But as of 15-07, we really don't NEED more than 5.
+
+ // NOTE: The passed in nodeType could really be a nodeTypeCategory --
+ // The calls to figureDepNodeTypeForRequest() below will deal with it for the dep nodes, the
+ // call to getUniqueNode() takes care of it for the node itself.
+
+ TitanVertex nullVert = null;
+ String depNodeType = figureDepNodeTypeForRequest( transId, fromAppId, nodeType, nodePropsHash, apiVersion );
+ if( depNodeType.equals("")){
+ // This kind of node does not depend on another node for uniqueness, so
+ // we can just use the "getUniqueNode()" method to get it.
+ HashMap <String,Object> thisNodeTypeParamHash = getThisNodeTypeParams(transId, fromAppId, nodeType, nodePropsHash, apiVersion);
+ return( getUniqueNode(transId, fromAppId, graph, nodeType, thisNodeTypeParamHash, nullVert, apiVersion) );
+ }
+ else {
+ // Will need to find the second-layer dependent node
+ String secondLayerDepNodeType = figureDepNodeTypeForRequest( transId, fromAppId, depNodeType, nodePropsHash, apiVersion );
+ if( secondLayerDepNodeType.equals("")){
+ // This second-layer kind of node does not depend on another node for uniqueness.
+ // So once we find the second-layer node, we can use it to get the top-layer guy.
+ HashMap <String,Object> thisNodeTypeParamHash = getThisNodeTypeParams(transId, fromAppId, depNodeType, nodePropsHash, apiVersion);
+ TitanVertex secLayerDepVert = getUniqueNode(transId, fromAppId, graph, depNodeType, thisNodeTypeParamHash, nullVert, apiVersion);
+
+ thisNodeTypeParamHash = getThisNodeTypeParams(transId, fromAppId, nodeType, nodePropsHash, apiVersion);
+ return( getUniqueNode(transId, fromAppId, graph, nodeType, thisNodeTypeParamHash, secLayerDepVert, apiVersion) );
+ }
+ else {
+ // Will need to find the third-layer dependent node
+ /// String thirdLayerDepNodeType = dbMaps.NodeDependencies.get(secondLayerDepNodeType);
+ String thirdLayerDepNodeType = figureDepNodeTypeForRequest( transId, fromAppId, secondLayerDepNodeType, nodePropsHash, apiVersion );
+
+ if( thirdLayerDepNodeType.equals("")){
+ // This third-layer kind of node does not depend on another node for uniqueness.
+ // So we can find it, and then use it to find the second-layer and then use that to find the top guy.
+ HashMap <String,Object> thisNodeTypeParamHash = getThisNodeTypeParams(transId, fromAppId, secondLayerDepNodeType, nodePropsHash, apiVersion);
+ TitanVertex thirdLayerDepVert = getUniqueNode(transId, fromAppId, graph, secondLayerDepNodeType, thisNodeTypeParamHash, nullVert, apiVersion);
+
+ thisNodeTypeParamHash = getThisNodeTypeParams(transId, fromAppId, depNodeType, nodePropsHash, apiVersion);
+ TitanVertex secLayerDepVert = getUniqueNode(transId, fromAppId, graph, depNodeType, thisNodeTypeParamHash, thirdLayerDepVert, apiVersion);
+
+ thisNodeTypeParamHash = getThisNodeTypeParams(transId, fromAppId, nodeType, nodePropsHash, apiVersion);
+
+ return( getUniqueNode(transId, fromAppId, graph, nodeType, thisNodeTypeParamHash, secLayerDepVert, apiVersion) );
+ }
+ else {
+ // Will need to find the third-layer dependent node
+ String forthLayerDepNodeType = figureDepNodeTypeForRequest( transId, fromAppId, thirdLayerDepNodeType, nodePropsHash, apiVersion );
+ if( forthLayerDepNodeType == null || forthLayerDepNodeType.equals("")){
+ // This forth-layer kind of node does not depend on another node for uniqueness.
+ // So we can find it, and then use it to find the third, then second-layer and then use that to find the top guy.
+ HashMap <String,Object> thisNodeTypeParamHash = getThisNodeTypeParams(transId, fromAppId, thirdLayerDepNodeType, nodePropsHash, apiVersion);
+ TitanVertex forthLayerDepVert = getUniqueNode(transId, fromAppId, graph, thirdLayerDepNodeType, thisNodeTypeParamHash, nullVert, apiVersion);
+
+ thisNodeTypeParamHash = getThisNodeTypeParams(transId, fromAppId, secondLayerDepNodeType, nodePropsHash, apiVersion);
+ TitanVertex thirdLayerDepVert = getUniqueNode(transId, fromAppId, graph, secondLayerDepNodeType, thisNodeTypeParamHash, forthLayerDepVert, apiVersion);
+
+ thisNodeTypeParamHash = getThisNodeTypeParams(transId, fromAppId, depNodeType, nodePropsHash, apiVersion);
+ TitanVertex secLayerDepVert = getUniqueNode(transId, fromAppId, graph, depNodeType, thisNodeTypeParamHash, thirdLayerDepVert, apiVersion);
+
+ thisNodeTypeParamHash = getThisNodeTypeParams(transId, fromAppId, nodeType, nodePropsHash, apiVersion);
+ return( getUniqueNode(transId, fromAppId, graph, nodeType, thisNodeTypeParamHash, secLayerDepVert, apiVersion) );
+ }
+ else {
+ // Will need to find the forth-layer dependent node
+ String fifthLayerDepNodeType = figureDepNodeTypeForRequest( transId, fromAppId, forthLayerDepNodeType, nodePropsHash, apiVersion );
+ if( fifthLayerDepNodeType == null || fifthLayerDepNodeType.equals("")){
+ // This fifth-layer kind of node does not depend on another node for uniqueness.
+ // So we can find it, and then use it to find the forth, third, then second-layer and then use that to find the top guy.
+ HashMap <String,Object> thisNodeTypeParamHash = getThisNodeTypeParams(transId, fromAppId, forthLayerDepNodeType, nodePropsHash, apiVersion);
+ TitanVertex fifthLayerDepVert = getUniqueNode(transId, fromAppId, graph, forthLayerDepNodeType, thisNodeTypeParamHash, nullVert, apiVersion);
+
+ thisNodeTypeParamHash = getThisNodeTypeParams(transId, fromAppId, thirdLayerDepNodeType, nodePropsHash, apiVersion);
+ TitanVertex forthLayerDepVert = getUniqueNode(transId, fromAppId, graph, thirdLayerDepNodeType, thisNodeTypeParamHash, fifthLayerDepVert, apiVersion);
+
+ thisNodeTypeParamHash = getThisNodeTypeParams(transId, fromAppId, secondLayerDepNodeType, nodePropsHash, apiVersion);
+ TitanVertex thirdLayerDepVert = getUniqueNode(transId, fromAppId, graph, secondLayerDepNodeType, thisNodeTypeParamHash, forthLayerDepVert, apiVersion);
+
+ thisNodeTypeParamHash = getThisNodeTypeParams(transId, fromAppId, depNodeType, nodePropsHash, apiVersion);
+ TitanVertex secLayerDepVert = getUniqueNode(transId, fromAppId, graph, depNodeType, thisNodeTypeParamHash, thirdLayerDepVert, apiVersion);
+
+ thisNodeTypeParamHash = getThisNodeTypeParams(transId, fromAppId, nodeType, nodePropsHash, apiVersion);
+ return( getUniqueNode(transId, fromAppId, graph, nodeType, thisNodeTypeParamHash, secLayerDepVert, apiVersion) );
+ }
+ else {
+ // Will need to find the fifth-layer dependent node
+ String sixthLayerDepNodeType = figureDepNodeTypeForRequest( transId, fromAppId, fifthLayerDepNodeType, nodePropsHash, apiVersion );
+ if( sixthLayerDepNodeType == null || sixthLayerDepNodeType.equals("")){
+ // This six-layer kind of node does not depend on another node for uniqueness.
+ // So we can find it, and then use it to find the fifth, forth, third, then second-layer and then use that to find the top guy.
+ HashMap <String,Object> thisNodeTypeParamHash = getThisNodeTypeParams(transId, fromAppId, fifthLayerDepNodeType, nodePropsHash, apiVersion);
+ TitanVertex sixthLayerDepVert = getUniqueNode(transId, fromAppId, graph, fifthLayerDepNodeType, thisNodeTypeParamHash, nullVert, apiVersion);
+
+ thisNodeTypeParamHash = getThisNodeTypeParams(transId, fromAppId, forthLayerDepNodeType, nodePropsHash, apiVersion);
+ TitanVertex fifthLayerDepVert = getUniqueNode(transId, fromAppId, graph, forthLayerDepNodeType, thisNodeTypeParamHash, sixthLayerDepVert, apiVersion);
+
+ thisNodeTypeParamHash = getThisNodeTypeParams(transId, fromAppId, thirdLayerDepNodeType, nodePropsHash, apiVersion);
+ TitanVertex forthLayerDepVert = getUniqueNode(transId, fromAppId, graph, thirdLayerDepNodeType, thisNodeTypeParamHash, fifthLayerDepVert, apiVersion);
+
+ thisNodeTypeParamHash = getThisNodeTypeParams(transId, fromAppId, secondLayerDepNodeType, nodePropsHash, apiVersion);
+ TitanVertex thirdLayerDepVert = getUniqueNode(transId, fromAppId, graph, secondLayerDepNodeType, thisNodeTypeParamHash, forthLayerDepVert, apiVersion);
+
+ thisNodeTypeParamHash = getThisNodeTypeParams(transId, fromAppId, depNodeType, nodePropsHash, apiVersion);
+ TitanVertex secLayerDepVert = getUniqueNode(transId, fromAppId, graph, depNodeType, thisNodeTypeParamHash, thirdLayerDepVert, apiVersion);
+
+ thisNodeTypeParamHash = getThisNodeTypeParams(transId, fromAppId, nodeType, nodePropsHash, apiVersion);
+ return( getUniqueNode(transId, fromAppId, graph, nodeType, thisNodeTypeParamHash, secLayerDepVert, apiVersion) );
+ }
+ else {
+ // We don't currently support more layers. We can later if we need to.
+ // Hopefully, we'll never need to go this deep -- there should be unique keys in there somewhere!
+ throw new AAIException("AAI_6114", "CODE-LIMITATION - Can't resolve dependant node layers for nodeType = " + nodeType);
+ }
+ }
+ }
+ }
+ }
+ }
+ } // End getUniqueNodeWithDepParams()
+
+ /**
+ * Gets the unique node with dep params.
+ *
+ * @param transId the trans id
+ * @param fromAppId the from app id
+ * @param graph the graph
+ * @param nodeType the node type
+ * @param nodePropsHash the node props hash
+ * @return the unique node with dep params
+ * @throws AAIException the AAI exception
+ */
+ @Deprecated
+ public static TitanVertex getUniqueNodeWithDepParams( String transId, String fromAppId, TitanTransaction graph, String nodeType,
+ HashMap<String,Object> nodePropsHash ) throws AAIException {
+ return getUniqueNodeWithDepParams(transId, fromAppId, graph, nodeType, nodePropsHash, null);
+ }
+
+
+ /**
+ * Gets the this node type params.
+ *
+ * @param transId the trans id
+ * @param fromAppId the from app id
+ * @param targetNodeType the target node type
+ * @param passedHash the passed hash
+ * @param apiVersion the api version
+ * @return the this node type params
+ * @throws AAIException the AAI exception
+ */
+ private static HashMap <String, Object> getThisNodeTypeParams(String transId, String fromAppId, String targetNodeType,
+ HashMap<String,Object> passedHash, String apiVersion )throws AAIException{
+ /*
+ * For the passed-in hash, each key is assumed to look like, "nodeType.paramName". We want to
+ * pick out the entries that match the targetNodeType and return those with the values they go with. The
+ * returned keys will have the "nodeType." stripped off.
+ *
+ * NOTE - the nodeType passed to this method could actually be a nodeTypeCategory. Just keepin it ugly.
+ */
+
+ if( passedHash == null ){
+ throw new AAIException("AAI_6120", "Bad param: null passedHash ");
+ }
+
+ String targetNodeTypeCat = "";
+ if( DbEdgeRules.NodeTypeCatMap.containsKey(targetNodeType) ){
+ targetNodeTypeCat = DbEdgeRules.NodeTypeCatMap.get(targetNodeType);
+ }
+
+ HashMap <String,Object> returnHash = new HashMap <String,Object> ();
+ Iterator <Map.Entry<String,Object>>it = passedHash.entrySet().iterator();
+ while( it.hasNext() ){
+ Map.Entry <String,Object>pairs = (Map.Entry<String,Object>)it.next();
+ String k = (pairs.getKey()).toString();
+ int periodLoc = k.indexOf(".");
+ if( periodLoc <= 0 ){
+ throw new AAIException("AAI_6120", "Bad filter param key passed in: [" + k + "]. Expected format = [nodeName.paramName]\n");
+ }
+ else {
+ String nty = k.substring(0,periodLoc);
+ String paramName = k.substring(periodLoc + 1);
+ if( nty.equals(targetNodeType) || (!targetNodeTypeCat.equals("") && nty.equals(targetNodeTypeCat)) ){
+ String newK = paramName;
+ returnHash.put( newK,pairs.getValue() );
+ }
+ }
+ }
+
+ //aaiLogger.debug(logline, " - end ");
+ return returnHash;
+
+ }// End of getThisNodeTypeParams()
+
+ /**
+ * Gets the this node type params.
+ *
+ * @param transId the trans id
+ * @param fromAppId the from app id
+ * @param targetNodeType the target node type
+ * @param passedHash the passed hash
+ * @return the this node type params
+ * @throws AAIException the AAI exception
+ */
+ @Deprecated
+ private static HashMap <String, Object> getThisNodeTypeParams(String transId, String fromAppId, String targetNodeType,
+ HashMap<String,Object> passedHash )throws AAIException{
+ return getThisNodeTypeParams( transId, fromAppId, targetNodeType,
+ passedHash, null);
+
+ }
+
+ /**
+ * Gets the dep node types.
+ *
+ * @param transId the trans id
+ * @param fromAppId the from app id
+ * @param nodeType the node type
+ * @param apiVersion the api version
+ * @return the dep node types
+ * @throws AAIException the AAI exception
+ */
+ public static ArrayList <String> getDepNodeTypes(String transId, String fromAppId, String nodeType, String apiVersion)throws AAIException{
+ /*
+ * This returns any nodeTypes that this nodeType can be dependent on. A particular instance of a node will only
+ * depend on one other node - we don't currently support dependence on multiple nodes.
+ */
+
+ DbMaps dbMaps = IngestModelMoxyOxm.dbMapsContainer.get(AAIConfig.get(AAIConstants.AAI_DEFAULT_API_VERSION_PROP));
+
+ ArrayList <String> depNodeTypeL = new ArrayList <String> ();
+ if( !DbEdgeRules.NodeTypeCategory.containsKey(nodeType) ){
+ // This is a good-ole nodeType
+ Collection <String> depNTColl = dbMaps.NodeDependencies.get(nodeType);
+ Iterator <String> ntItr = depNTColl.iterator();
+ while( ntItr.hasNext() ){
+ depNodeTypeL.add(ntItr.next());
+ }
+ }
+ else {
+ // The passed-in nodeType must really be a nodeTypeCategory
+ Collection <String> nTypeCatCol = DbEdgeRules.NodeTypeCategory.get(nodeType);
+ Iterator <String> catItr = nTypeCatCol.iterator();
+ String catInfo = "";
+ if( catItr.hasNext() ){
+ // For now, we only look for one.
+ catInfo = catItr.next();
+ }
+ else {
+ throw new AAIException("AAI_6121", "Error getting DbEdgeRules.NodeTypeCategory info for nodeTypeCat = " + nodeType);
+ }
+
+ String [] flds = catInfo.split(",");
+ if( flds.length != 4 ){
+ throw new AAIException("AAI_6121", "Bad EdgeRule.NodeTypeCategory data (itemCount=" + flds.length + ") for nodeType = [" + nodeType + "].");
+ }
+
+ String nodeTypesString = flds[0];
+ String hasDepNodes = flds[3];
+ if( hasDepNodes.equals("true") ){
+ String [] ntNames = nodeTypesString.split("\\|");
+ for( int i = 0; i < ntNames.length; i++ ){
+ Collection <String> depNTColl = dbMaps.NodeDependencies.get(nodeType);
+ Iterator <String> ntItr = depNTColl.iterator();
+ while( ntItr.hasNext() ){
+ String depNode = ntItr.next();
+ if( !depNodeTypeL.contains(depNode) ){
+ depNodeTypeL.add(depNode);
+ }
+ }
+ }
+ }
+ }
+
+
+ return depNodeTypeL;
+
+ }// End getDepNodeTypes()
+
+ /**
+ * Gets the dep node types.
+ *
+ * @param transId the trans id
+ * @param fromAppId the from app id
+ * @param nodeType the node type
+ * @return the dep node types
+ * @throws AAIException the AAI exception
+ */
+ @Deprecated
+ public static ArrayList <String> getDepNodeTypes(String transId, String fromAppId, String nodeType)throws AAIException{
+ return getDepNodeTypes( transId, fromAppId, nodeType, null);
+ }
+
+ /**
+ * Gets the default delete scope.
+ *
+ * @param transId the trans id
+ * @param fromAppId the from app id
+ * @param nodeType the node type
+ * @param apiVersion the api version
+ * @return the default delete scope
+ * @throws AAIException the AAI exception
+ */
+ private static String getDefaultDeleteScope(String transId, String fromAppId, String nodeType, String apiVersion)throws AAIException{
+
+ // At some point we may have different delete rules for different services, so this is
+ // a list for now even thought there's only one scope per nodeType.
+ Collection <String> scopeList = DbEdgeRules.DefaultDeleteScope.get(nodeType);
+ if( scopeList.isEmpty() ){
+ throw new AAIException("AAI_6121", "No default deleteScope found for nodeType = [" + nodeType + "] ");
+ }
+ else {
+ Iterator <String> ito = scopeList.iterator();
+ return ito.next();
+ }
+
+ }// End getDefaultDeleteScope()
+
+ /**
+ * Gets the default delete scope.
+ *
+ * @param transId the trans id
+ * @param fromAppId the from app id
+ * @param nodeType the node type
+ * @return the default delete scope
+ * @throws AAIException the AAI exception
+ */
+ @Deprecated
+ private static String getDefaultDeleteScope(String transId, String fromAppId, String nodeType)throws AAIException{
+ return getDefaultDeleteScope( transId, fromAppId, nodeType, null);
+ }
+
+ /**
+ * Needs A dep node 4 uniqueness.
+ *
+ * @param transId the trans id
+ * @param fromAppId the from app id
+ * @param nodeType the node type
+ * @param apiVersion the api version
+ * @return the boolean
+ * @throws AAIException the AAI exception
+ */
+ public static Boolean needsADepNode4Uniqueness(String transId, String fromAppId, String nodeType, String apiVersion)throws AAIException{
+ // Note: the passed in nodeType could really be a nodeTypeCategory. That is handled by getDepNodeTypes()
+
+ ArrayList <String> depList = getDepNodeTypes(transId, fromAppId, nodeType, apiVersion);
+ if( depList.isEmpty() ){
+ return false;
+ }
+ else {
+ return true;
+ }
+
+ }// End needsADepNode4Uniqueness()
+
+ /**
+ * Needs A dep node 4 uniqueness.
+ *
+ * @param transId the trans id
+ * @param fromAppId the from app id
+ * @param nodeType the node type
+ * @return the boolean
+ * @throws AAIException the AAI exception
+ */
+ @Deprecated
+ private static Boolean needsADepNode4Uniqueness(String transId, String fromAppId, String nodeType)throws AAIException{
+ return needsADepNode4Uniqueness( transId, fromAppId, nodeType, null);
+ }
+
+ /**
+ * Node type A can depend on B.
+ *
+ * @param transId the trans id
+ * @param fromAppId the from app id
+ * @param nodeTypeA the node type A
+ * @param nodeTypeB the node type B
+ * @param apiVersion the api version
+ * @return the boolean
+ * @throws AAIException the AAI exception
+ */
+ public static Boolean nodeTypeACanDependOnB(String transId, String fromAppId, String nodeTypeA, String nodeTypeB, String apiVersion)
+ throws AAIException{
+ // Note: the passed in nodeType could really be a nodeTypeCategory. That is handled by getDepNodeTypes()
+
+ ArrayList <String> depList = getDepNodeTypes(transId, fromAppId, nodeTypeA, apiVersion);
+ if( depList.isEmpty() ){
+ return false;
+ }
+ else if( depList.contains(nodeTypeB) ){
+ return true;
+ }
+ else {
+ return false;
+ }
+
+ }// End nodeTypeACanDependOnB()
+
+ /**
+ * Node type A can depend on B.
+ *
+ * @param transId the trans id
+ * @param fromAppId the from app id
+ * @param nodeTypeA the node type A
+ * @param nodeTypeB the node type B
+ * @return the boolean
+ * @throws AAIException the AAI exception
+ */
+ @Deprecated
+ private static Boolean nodeTypeACanDependOnB(String transId, String fromAppId, String nodeTypeA, String nodeTypeB)
+ throws AAIException{
+ return nodeTypeACanDependOnB( transId, fromAppId, nodeTypeA, nodeTypeB, null);
+ }
+
+ /**
+ * Figure dep node type for request.
+ *
+ * @param transId the trans id
+ * @param fromAppId the from app id
+ * @param nodeType the node type
+ * @param requestParamHash the request param hash
+ * @param apiVersion the api version
+ * @return the string
+ * @throws AAIException the AAI exception
+ */
+ public static String figureDepNodeTypeForRequest(String transId, String fromAppId, String nodeType,
+ HashMap<String,Object> requestParamHash, String apiVersion )throws AAIException{
+ /*
+ * This is ugly. But if the passed-in nodeType is dependent on another nodeType for
+ * uniqueness, we need to return what that dependent node-type is. The ugly comes in
+ * because a node can be dependent on more than one type of node. So, to tell which one
+ * is going to apply, we root through the passed request parameters to see which of
+ * the possible dependent node types is being used.
+ * Note -- if there comes a day when there are so many dependencies that the request could
+ * have more than one that match -- Then we need to think up something new. But for now,
+ * we have to assume that if there are more than one legal dep-node-types, only one will
+ * be represented in the requestHash data. >>> NOTE >>> That day has come. For
+ * the upstreamers will send in a LinkedHashMap instead of just an unordered
+ * HashMap so we can look in order for the dependent node.
+ *
+ */
+
+ if( requestParamHash == null ){
+ throw new AAIException("AAI_6120", "Bad param: null requestParamHash ");
+ }
+
+ ArrayList <String> depNodeTypes = getDepNodeTypes(transId, fromAppId, nodeType, apiVersion);
+ if( depNodeTypes.isEmpty() ){
+ // This kind of node is not dependent on any other
+ //aaiLogger.debug(logline, " (not dependent) - end ");
+ return "";
+ }
+ else if( depNodeTypes.size() == 1 ){
+ // This kind of node can only depend on one other nodeType - so return that.
+ //aaiLogger.debug(logline, " (depends on " + depNodeTypes.get(0) + " - end ");
+ return depNodeTypes.get(0);
+ }
+ else {
+ // We need to look to find the first of the dep-node types that is represented in the passed-in
+ // request data. That will be the one we need to use.
+
+ // first find out what node-types are represented in the requestHash
+
+ Iterator <Map.Entry<String,Object>>it = requestParamHash.entrySet().iterator();
+ while( it.hasNext() ){
+ Map.Entry <String,Object>pairs = (Map.Entry<String,Object>)it.next();
+ String k = (pairs.getKey()).toString();
+ int periodLoc = k.indexOf(".");
+ if( periodLoc <= 0 ){
+ throw new AAIException("AAI_6120", "Bad filter param key passed in: [" + k + "]. Expected format = [nodeName.paramName]\n");
+ }
+ else {
+ String nty = k.substring(0,periodLoc);
+ if( depNodeTypes.contains(nty) ){
+ // This is the first possible dep. node type we've found for the passed in data set
+ return nty;
+ }
+ }
+ }
+
+ }
+
+ // It's not an error if none is found - the caller needs to deal with cases where there
+ // should be a dep. node identified but isn't.
+ //aaiLogger.debug(logline, " no dep NT found - end ");
+ return "";
+
+ }// End of figureDepNodeTypeForRequest()
+
+ /**
+ * Figure dep node type for request.
+ *
+ * @param transId the trans id
+ * @param fromAppId the from app id
+ * @param nodeType the node type
+ * @param requestParamHash the request param hash
+ * @return the string
+ * @throws AAIException the AAI exception
+ */
+ @Deprecated
+ public static String figureDepNodeTypeForRequest(String transId, String fromAppId, String nodeType,
+ HashMap<String,Object> requestParamHash )throws AAIException{
+ return figureDepNodeTypeForRequest( transId, fromAppId, nodeType, requestParamHash, null);
+ }
+
+ /**
+ * Detach connected nodes.
+ *
+ * @param transId the trans id
+ * @param fromAppId the from app id
+ * @param graph the graph
+ * @param nodeType the node type
+ * @param propFilterHash the prop filter hash
+ * @param startNodeVal the start node val
+ * @param autoDeleteOrphans the auto delete orphans
+ * @param apiVersion the api version
+ * @return deletedNodeCount
+ * @throws AAIException the AAI exception
+ */
+ public static int detachConnectedNodes( String transId, String fromAppId, TitanTransaction graph, String nodeType,
+ HashMap<String,Object> propFilterHash, TitanVertex startNodeVal, boolean autoDeleteOrphans, String apiVersion ) throws AAIException{
+
+ /* Find nodes that are attached to this node which meet the nodeType/filterParams criteria.
+ * Remove the edges that go to those nodes.
+ * If that turns any of the nodes into an orphan, then delete it if the autoDeleteOrphans flag is set.
+ * Return a count of how many nodes were actually deleted (not just detached).
+ */
+
+ int deletedCount = 0;
+
+ if( startNodeVal == null ){
+ // They should have passed in the node that this query starts from
+ throw new AAIException("AAI_6109", "null startNode object passed to detachConnectedNodes().");
+ }
+
+ // We want to loop through the connected Nodes that we found.
+ // For each connected Node, we'll get the all edges that start from that node and look for the one
+ // that connects back to our startNode.
+ // Only delete the edge that connects back to our startNode.
+ // then autoDeleteOrphans flag is set, then delete the connectedNode if it's now orphaned.
+ //
+
+ String startNodeVId = startNodeVal.id().toString();
+ ArrayList<TitanVertex> conNodeList = getConnectedNodes( transId, fromAppId, graph, nodeType, propFilterHash, startNodeVal, apiVersion, false );
+ Iterator<TitanVertex> conVIter = conNodeList.iterator();
+ while( conVIter.hasNext() ){
+ TitanVertex connectedVert = conVIter.next();
+ boolean isFirstOne = true;
+ Iterator<Edge> eI = connectedVert.edges(Direction.BOTH);
+ while( eI.hasNext() ){
+ TitanEdge ed = (TitanEdge) eI.next();
+ TitanVertex otherVtx = (TitanVertex) ed.otherVertex(connectedVert);
+ String otherSideLookingBackVId = otherVtx.id().toString();
+ if( startNodeVId.equals(otherSideLookingBackVId) ){
+ // This is an edge from the connected node back to our starting node
+ if( isFirstOne && !eI.hasNext() && autoDeleteOrphans ){
+ // This was the one and only edge for this connectedNode, so
+ // delete the node and edge since flag was set
+ String resVers = connectedVert.<String>property("resource-version").orElse(null);
+ removeAaiNode( transId, fromAppId, graph, connectedVert, "USE_DEFAULT", apiVersion, resVers);
+ deletedCount = deletedCount + 1;
+ }
+ else {
+ removeAaiEdge( transId, fromAppId, graph, ed );
+ }
+ }
+ isFirstOne = false;
+ }
+ }
+ return deletedCount;
+
+ } // end of detachConnectedNodes()
+
+
+
+ /**
+ * Detach connected nodes.
+ *
+ * @param transId the trans id
+ * @param fromAppId the from app id
+ * @param graph the graph
+ * @param nodeType the node type
+ * @param propFilterHash the prop filter hash
+ * @param startNodeVal the start node val
+ * @param autoDeleteOrphans the auto delete orphans
+ * @return the int
+ * @throws AAIException the AAI exception
+ */
+ @Deprecated
+ public static int detachConnectedNodes( String transId, String fromAppId, TitanTransaction graph, String nodeType,
+ HashMap<String,Object> propFilterHash, TitanVertex startNodeVal, boolean autoDeleteOrphans ) throws AAIException{
+ return detachConnectedNodes( transId, fromAppId, graph, nodeType,
+ propFilterHash, startNodeVal, autoDeleteOrphans, null);
+ }
+
+ /**
+ * Gets the nodes.
+ *
+ * @param transId the trans id
+ * @param fromAppId the from app id
+ * @param graph the graph
+ * @param nodeType the node type
+ * @param propFilterHash the prop filter hash
+ * @param noFilterOnPurpose the no filter on purpose
+ * @param apiVersion the api version
+ * @return ArrayList<TitanVertex>
+ * @throws AAIException the AAI exception
+ */
+ @Deprecated
+ public static ArrayList<TitanVertex> getNodes( String transId, String fromAppId, TitanTransaction graph, String nodeType,
+ HashMap<String,Object> propFilterHash, Boolean noFilterOnPurpose, String apiVersion ) throws AAIException{
+ boolean skipGroomingFlag = true;
+ // we will only do real-time grooming if a system variable is set, telling us not to skip it.
+ String skipGroomingStr = AAIConstants.AAI_SKIPREALTIME_GROOMING;
+ if( skipGroomingStr.equals("false") ){
+ skipGroomingFlag = false;
+ }
+ return( getNodes(transId, fromAppId, graph, nodeType, propFilterHash, noFilterOnPurpose, apiVersion, skipGroomingFlag) );
+ }
+
+ /**
+ * Gets the nodes.
+ *
+ * @param transId the trans id
+ * @param fromAppId the from app id
+ * @param graph the graph
+ * @param nodeType the node type
+ * @param propFilterHash the prop filter hash
+ * @param noFilterOnPurpose the no filter on purpose
+ * @param apiVersion the api version
+ * @param skipGroomCheck the skip groom check
+ * @return ArrayList<TitanVertex>
+ * @throws AAIException the AAI exception
+ */
+ @Deprecated
+ public static ArrayList<TitanVertex> getNodes( String transId, String fromAppId, TitanTransaction graph, String nodeType,
+ HashMap<String,Object> propFilterHash, Boolean noFilterOnPurpose, String apiVersion, boolean skipGroomCheck )
+ throws AAIException{
+ // Note - the skipGroomCheck flag is set to true when the DataGrooming tool is using this method to collect
+ // node data. When the grooming tool is collecting data, we don't want any nodes skipped, because we
+ // want details about what nodes/edges are bad - more detail than the check in this method does
+ // as it checks if a node is ok to return to a caller.
+
+ /* Use the nodeType + filterParams to find nodes.
+ */
+ DbMaps dbMaps = IngestModelMoxyOxm.dbMapsContainer.get(AAIConfig.get(AAIConstants.AAI_DEFAULT_API_VERSION_PROP));
+
+ ArrayList<TitanVertex> returnVertList = new ArrayList<TitanVertex>();
+ if( nodeType == null || nodeType.equals("") ){
+ // They should have passed in a nodeType
+ throw new AAIException("AAI_6118", "Required field: nodeType not passed to getNodes().");
+ }
+
+ if( !noFilterOnPurpose && (propFilterHash == null || propFilterHash.isEmpty()) ){
+ // They should have passed at least one property to filter on
+ throw new AAIException("AAI_6118", "Required field: propFilterHash not passed to getNodes().");
+ }
+
+ ArrayList<String> kName = new ArrayList<String>();
+ ArrayList<Object> kVal = new ArrayList<Object>();
+ int i = -1;
+ Collection <String> indexedProps = dbMaps.NodeMapIndexedProps.get(nodeType);
+ // First loop through to pick up the indexed-properties if there are any being used
+
+ if( propFilterHash != null ){
+ Iterator <?> it = propFilterHash.entrySet().iterator();
+ while( it.hasNext() ){
+ Map.Entry<?,?> propEntry = (Map.Entry<?,?>) it.next();
+ String propName = (propEntry.getKey()).toString();
+ // Don't allow search on properties that do not have SINGLE cardinality
+ if( !checkPropCardinality(propName, "Set") && !checkPropCardinality(propName, "List") ){
+ if( indexedProps.contains(propName) ){
+ i++;
+ kName.add(i, propName);
+ kVal.add(i, (Object)propEntry.getValue());
+ }
+ }
+ }
+
+ // Now go through again and pick up the non-indexed properties
+ it = propFilterHash.entrySet().iterator();
+ while( it.hasNext() ){
+ Map.Entry <?,?> propEntry = (Map.Entry<?,?>)it.next();
+ String propName = (propEntry.getKey()).toString();
+ // Don't allow search on properties that do not have SINGLE cardinality
+ if( !checkPropCardinality(propName, "Set") && !checkPropCardinality(propName, "List") ){
+ if( ! indexedProps.contains(propName) ){
+ i++;
+ kName.add(i, propName);
+ kVal.add(i, (Object)propEntry.getValue());
+ }
+ }
+ }
+ }
+
+ Iterable <?> verts = null;
+ String propsAndValuesForMsg = "";
+ int topPropIndex = i;
+ if( topPropIndex == -1 ){
+ // No Filtering -- just go get them all
+ verts= graph.query().has("aai-node-type",nodeType).vertices();
+ propsAndValuesForMsg = " ( no filter props ) ";
+ }
+ else if( topPropIndex == 0 ){
+ verts= graph.query().has(kName.get(0),kVal.get(0)).has("aai-node-type",nodeType).vertices();
+ propsAndValuesForMsg = " (" + kName.get(0) + " = " + kVal.get(0) + ") ";
+ }
+ else if( topPropIndex == 1 ){
+ verts= graph.query().has(kName.get(0),kVal.get(0)).has(kName.get(1),kVal.get(1)).has("aai-node-type",nodeType).vertices();
+ propsAndValuesForMsg = " (" + kName.get(0) + " = " + kVal.get(0) + ", "
+ + kName.get(1) + " = " + kVal.get(1) + ") ";
+ }
+ else if( topPropIndex == 2 ){
+ verts= graph.query().has(kName.get(0),kVal.get(0)).has(kName.get(1),kVal.get(1)).has(kName.get(2),kVal.get(2)).has("aai-node-type",nodeType).vertices();
+ propsAndValuesForMsg = " (" + kName.get(0) + " = " + kVal.get(0) + ", "
+ + kName.get(1) + " = " + kVal.get(1) + ", "
+ + kName.get(2) + " = " + kVal.get(2) + ") ";
+ }
+ else if( topPropIndex == 3 ){
+ verts= graph.query().has(kName.get(0),kVal.get(0)).has(kName.get(1),kVal.get(1)).has(kName.get(2),kVal.get(2)).has(kName.get(3),kVal.get(3)).has("aai-node-type",nodeType).vertices();
+ propsAndValuesForMsg = " (" + kName.get(0) + " = " + kVal.get(0) + ", "
+ + kName.get(1) + " = " + kVal.get(1) + ", "
+ + kName.get(2) + " = " + kVal.get(2) + ", "
+ + kName.get(3) + " = " + kVal.get(3) + ") ";
+ }
+ else {
+ String emsg = " -- Sorry -- we only support 4 filter properties in getNodes() for now... \n";
+ throw new AAIException("AAI_6114", emsg);
+ }
+ if( verts != null ){
+ // We did find some matching vertices
+ Iterator <?> it = verts.iterator();
+ while( it.hasNext() ){
+ TitanVertex v = (TitanVertex)it.next();
+
+ if( skipGroomCheck ){
+ // Good or bad, just return everything we find
+ returnVertList.add( v );
+ }
+ else {
+ // Weed out any bad vertices we find
+ if( thisVertexNotReachable(transId, fromAppId, graph, v, apiVersion) ){
+ LOGGER.info("IN-LINE GROOMING - Unreachable Node DETECTED > skipping it. ");
+ }
+ else if( thisVertexHasBadEdges(transId, fromAppId, graph, v, apiVersion) ){
+ LOGGER.info("IN-LINE GROOMING - BAD EDGE DETECTED > skipping vtxId = [" + v.id() + "] ");
+ }
+ else if( thisVertexIsAPhantom(transId, fromAppId, graph, v, apiVersion) ){
+ LOGGER.info("IN-LINE GROOMING - BAD NODE DETECTED > skipping vtxId = [" + v.id() + "] ");
+ }
+ else {
+ returnVertList.add( v );
+ }
+ }
+ }
+ }
+
+ return returnVertList;
+ }
+
+ /**
+ * Gets the nodes.
+ *
+ * @param transId the trans id
+ * @param fromAppId the from app id
+ * @param graph the graph
+ * @param nodeType the node type
+ * @param propFilterHash the prop filter hash
+ * @param noFilterOnPurpose the no filter on purpose
+ * @return the nodes
+ * @throws AAIException the AAI exception
+ */
+ @Deprecated
+ public static ArrayList<TitanVertex> getNodes( String transId, String fromAppId, TitanTransaction graph, String nodeType,
+ HashMap<String,Object> propFilterHash, Boolean noFilterOnPurpose ) throws AAIException{
+ return getNodes(transId, fromAppId, graph, nodeType,
+ propFilterHash, noFilterOnPurpose, null );
+ }
+ // End of getNodes()
+
+
+ /**
+ * Gets the connected children.
+ *
+ * @param transId the trans id
+ * @param fromAppId the from app id
+ * @param graph the graph
+ * @param startVtx the start vtx
+ * @param limitToThisNodeType the limit to this node type
+ * @return ArrayList <TitanVertex>
+ * @throws AAIException the AAI exception
+ */
+ public static ArrayList<TitanVertex> getConnectedChildren( String transId, String fromAppId, TitanTransaction graph,
+ TitanVertex startVtx, String limitToThisNodeType ) throws AAIException{
+
+ // Just get child nodes (ie. other end of an OUT edge that is tagged as a parent/Child edge)
+
+ ArrayList <TitanVertex> childList = new ArrayList <TitanVertex> ();
+ Boolean doNodeTypeCheck = false;
+ if( limitToThisNodeType != null && ! limitToThisNodeType.equals("") ){
+ doNodeTypeCheck = true;
+ }
+
+
+ List<Vertex> verts = graph.traversal().V(startVtx).union(__.outE().has("isParent-REV", true).inV(), __.inE().has("isParent", true).outV()).toList();
+ TitanVertex tmpVtx = null;
+ int vertsSize = verts.size();
+ for (int i = 0; i < vertsSize; i++){
+ tmpVtx = (TitanVertex) verts.get(i);
+ if( ! doNodeTypeCheck ){
+ childList.add(tmpVtx);
+ }
+ else {
+ String tmpNT = tmpVtx.<String>property("aai-node-type").orElse(null);
+ if( tmpNT != null && tmpNT.equals(limitToThisNodeType) ){
+ childList.add(tmpVtx);
+ }
+ }
+ }
+
+ return childList;
+
+ }// End of getConnectedChildren()
+
+
+
+ /**
+ * Gets the connected nodes.
+ *
+ * @param transId the trans id
+ * @param fromAppId the from app id
+ * @param graph the graph
+ * @param nodeType the node type
+ * @param propFilterHash the prop filter hash
+ * @param startNodeVal the start node val
+ * @param apiVersion the api version
+ * @param excludeRecurComingIn the exclude recur coming in
+ * @return ArrayList <TitanVertex>
+ * @throws AAIException the AAI exception
+ */
+ public static ArrayList<TitanVertex> getConnectedNodes( String transId, String fromAppId, TitanTransaction graph, String nodeType,
+ HashMap<String,Object> propFilterHash, TitanVertex startNodeVal, String apiVersion, Boolean excludeRecurComingIn ) throws AAIException{
+
+ DbMaps dbMaps = IngestModelMoxyOxm.dbMapsContainer.get(AAIConfig.get(AAIConstants.AAI_DEFAULT_API_VERSION_PROP));
+ /* Get (almost) all the nodes that are connected to this vertex.
+ * Narrow down what is returned using optional filter parameters nodeType and propFilterHash
+ * NOTE - the default behavior has changed slightly. For start-Nodes that
+ * can be recursivly connected, this method will only bring back the same kind of
+ * connected node by following an OUT edge. Ie. if the start node is an "model-element",
+ * then this method will only follow OUT edges to get to other "model-element" type nodes.
+ */
+
+ String startNodeNT = "";
+ if( startNodeVal == null ){
+ // They should have passed in the node that this query starts from
+ throw new AAIException("AAI_6109", "null startNode object passed to getConnectedNodes().");
+ }
+ else {
+ startNodeNT = startNodeVal.<String>property("aai-node-type").orElse(null);
+ }
+
+ boolean nodeTypeFilter = false;
+ if( nodeType != null && !nodeType.equals("") ){
+ // They want to filter using nodeType
+ if( ! dbMaps.NodeProps.containsKey(nodeType) ){
+ throw new AAIException("AAI_6115", "Unrecognized nodeType [" + nodeType + "] passed to getConnectedNodes().");
+ }
+ nodeTypeFilter = true;
+ }
+
+ ArrayList <String> excludeVidList = new <String> ArrayList ();
+ if( DbEdgeRules.CanBeRecursiveNT.containsKey(startNodeNT) && excludeRecurComingIn ){
+ // If we're starting on a nodeType that supports recursion, then find any connected
+ // nodes that are coming from IN edges so we can exclude them later.
+
+ Iterable <?> vertsR = startNodeVal.query().direction(Direction.IN).vertices();
+ Iterator <?> vertIR = vertsR.iterator();
+ while( vertIR != null && vertIR.hasNext() ){
+ TitanVertex tmpVertIN = (TitanVertex) vertIR.next();
+ String tmpNT = tmpVertIN.<String>property("aai-node-type").orElse(null);
+ if( tmpNT != null && tmpNT.equals(startNodeNT) ){
+ // We're on a nodetype that supports recursion (like model-element) and we've
+ // found an connected Node of this same type on an IN edge - put this
+ // on our excludeList.
+ excludeVidList.add( tmpVertIN.id().toString() );
+ }
+ }
+ }
+
+ boolean propertyFilter = false;
+ if( propFilterHash != null && !propFilterHash.isEmpty() ){
+ // They want to filter using some properties
+ Iterator <?> it = propFilterHash.entrySet().iterator();
+ while( it.hasNext() ){
+ Map.Entry<?,?> propEntry = (Map.Entry<?,?>)it.next();
+ String propName = (propEntry.getKey()).toString();
+ if( ! dbMaps.NodeProps.containsValue(propName) ){
+ throw new AAIException("AAI_6116", "Unrecognized property name [" + propName + "] passed to getConnectedNodes().");
+ }
+ // Don't allow search on properties that do not have SINGLE cardinality
+ if( !checkPropCardinality(propName, "Set") && !checkPropCardinality(propName, "List") ){
+ propertyFilter = true;
+ }
+ }
+ }
+ // If filter-properties were passed in, then look for nodes that have those values.
+ ArrayList<TitanVertex> returnVertList = new ArrayList<TitanVertex>();
+ Iterable<TitanVertex> qResult = null;
+ Iterator<TitanVertex> resultI = null;
+ try {
+ qResult = startNodeVal.query().vertices();
+ resultI = qResult.iterator();
+ }
+ catch( NullPointerException npe ){
+ throw new AAIException("AAI_6125", "Titan null pointer exception trying to get nodes connected to vertexId = " +
+ startNodeVal.id() + ", aai-node-type = [" + startNodeVal.property("aai-node-type") + "].");
+ }
+
+ while( resultI != null && resultI.hasNext() ){
+ boolean addThisOne = true;
+ TitanVertex tmpV = (TitanVertex)resultI.next();
+ if( tmpV == null ){
+ LOGGER.info("Titan gave a null vertex when looking for nodes connected to vertexId = " +
+ startNodeVal.id() + ", aai-node-type = [" + startNodeVal.property("aai-node-type") + "].");
+ // Note - we will skip this one, but try to return any others that we find.
+ addThisOne = false;
+ }
+
+ else {
+ String tmpVid = tmpV.id().toString();
+ if( nodeTypeFilter ){
+ Object nto = tmpV.<Object>property("aai-node-type").orElse(null);
+ if( nto == null || !nto.toString().equals(nodeType) ){
+ //LOGGER.info("Found a connected vertex (vertexId = " +
+ // tmpVid + "), but we will not collect it. It had aai-node-type [" +
+ // nto + "], we are looking for [" + nodeType + "]. ");
+ // Note - we will skip this one, but try to return any others that we find.
+ addThisOne = false;
+ }
+ }
+
+ if( excludeVidList.contains(tmpVid) ){
+ LOGGER.info("Found a connected vertex (vertexId = " +
+ tmpVid + "), but will exclude it since it is on an IN edge and this nodeType " +
+ startNodeNT + " can be recursively attached.");
+ // Note - we will skip this one, but try to return any others that we find.
+ addThisOne = false;
+ }
+
+ if( propertyFilter ){
+ Iterator <?> it = propFilterHash.entrySet().iterator();
+ while( it.hasNext() ){
+ Map.Entry <?,?>propEntry = (Map.Entry<?,?>)it.next();
+ String propName = (propEntry.getKey()).toString();
+ if( checkPropCardinality(propName, "Set") || checkPropCardinality(propName, "List") ){
+ // Don't allow search on properties that do not have SINGLE cardinality
+ continue;
+ }
+ Object propVal = propEntry.getValue();
+ Object foundVal = tmpV.<Object>property(propName).orElse(null);
+ if( foundVal != null && propVal != null && !foundVal.toString().equals(propVal.toString()) ){
+ addThisOne = false;
+ break;
+ }
+ else if( (foundVal == null && propVal != null) || (foundVal != null && propVal == null) ){
+ addThisOne = false;
+ break;
+ }
+ }
+ }
+ }
+ if( addThisOne ){
+ // This node passed the tests -- put it on the return List
+ returnVertList.add( (TitanVertex)tmpV );
+ }
+ }
+ //aaiLogger.debug(logline, " end ");
+ return returnVertList;
+
+ }// End of getConnectedNodes()
+
+
+ /**
+ * Gets the connected nodes.
+ *
+ * @param transId the trans id
+ * @param fromAppId the from app id
+ * @param graph the graph
+ * @param nodeType the node type
+ * @param propFilterHash the prop filter hash
+ * @param startNodeVal the start node val
+ * @param apiVersion the api version
+ * @return the connected nodes
+ * @throws AAIException the AAI exception
+ */
+ @Deprecated
+ public static ArrayList<TitanVertex> getConnectedNodes(String transId, String fromAppId, TitanTransaction graph, String nodeType,
+ HashMap<String,Object> propFilterHash, TitanVertex startNodeVal, String apiVersion ) throws AAIException {
+ return getConnectedNodes( transId, fromAppId, graph, nodeType,
+ propFilterHash, startNodeVal, apiVersion, true );
+ }
+
+ /**
+ * Gets the connected nodes.
+ *
+ * @param transId the trans id
+ * @param fromAppId the from app id
+ * @param graph the graph
+ * @param nodeType the node type
+ * @param propFilterHash the prop filter hash
+ * @param startNodeVal the start node val
+ * @return the connected nodes
+ * @throws AAIException the AAI exception
+ */
+ @Deprecated
+ public static ArrayList<TitanVertex> getConnectedNodes(String transId, String fromAppId, TitanTransaction graph, String nodeType,
+ HashMap<String,Object> propFilterHash, TitanVertex startNodeVal ) throws AAIException {
+ return getConnectedNodes( transId, fromAppId, graph, nodeType,
+ propFilterHash, startNodeVal, null, true );
+
+ }
+
+ /**
+ * Ip address format OK.
+ *
+ * @param transId the trans id
+ * @param fromAppId the from app id
+ * @param addrVal the addr val
+ * @param addrVer the addr ver
+ * @param apiVersion the api version
+ * @return Boolean
+ * @throws AAIException the AAI exception
+ */
+ public static Boolean ipAddressFormatOK(String transId, String fromAppId, String addrVal, String addrVer, String apiVersion) throws AAIException{
+
+ /* NOTE -- the google methods we use do not allow leading zeros in ipV4 addresses.
+ * So it will reject, "22.33.44.001"
+ */
+
+ if( addrVal == null ){
+ throw new AAIException("AAI_6120", "Bad data (addrVal = null) passed to ipAddressFormatOK()");
+ }
+ else if( addrVer == null ){
+ throw new AAIException("AAI_6120", "Bad data (addrType = null) passed to ipAddressFormatOK()");
+ }
+
+ Boolean retVal = false;
+ Boolean lookingForV4 = false;
+ Boolean lookingForV6 = false;
+ InetAddress inetAddr = null;
+
+ if( addrVer.equalsIgnoreCase("v4") || addrVer.equals("ipv4") || addrVer.equals("4")){
+ lookingForV4 = true;
+ }
+ else if( addrVer.equalsIgnoreCase("v6") || addrVer.equals("ipv6") || addrVer.equals("6")){
+ lookingForV6 = true;
+ }
+ else {
+ throw new AAIException("AAI_6120", " Bad data for addressVersion [" + addrVer + "] passed to ipAddressFormatOK()");
+ }
+
+ try {
+ inetAddr = InetAddresses.forString(addrVal);
+ if( inetAddr instanceof Inet4Address ){
+ if( lookingForV4 ){
+ retVal = true;
+ }
+ else {
+ throw new AAIException("AAI_6120", "Bad data. Address is a V4, but addressType said it should be V6. ["
+ + addrVal + "], [" + addrVer + "] passed to ipAddressFormatOK()");
+ }
+ }
+ else if( inetAddr instanceof Inet6Address ){
+ if( lookingForV6 ){
+ retVal = true;
+ }
+ else {
+ throw new AAIException("AAI_6120", "Bad data. Address is a V6, but addressType said it should be V4. ["
+ + addrVal + "], [" + addrVer + "] passed to ipAddressFormatOK().");
+ }
+ }
+ }
+ catch (IllegalArgumentException e) {
+ throw new AAIException("AAI_6120", "Badly formed ip-address: [" + addrVal + "] passed to ipAddressFormatOK()");
+ }
+
+ return retVal;
+
+ }//end of ipAddressFormatOk()
+
+ /**
+ * Ip address format OK.
+ *
+ * @param transId the trans id
+ * @param fromAppId the from app id
+ * @param addrVal the addr val
+ * @param addrVer the addr ver
+ * @return the boolean
+ * @throws AAIException the AAI exception
+ */
+ public static Boolean ipAddressFormatOK(String transId, String fromAppId, String addrVal, String addrVer) throws AAIException{
+ return ipAddressFormatOK( transId, fromAppId, addrVal, addrVer, null);
+ }
+
+ /**
+ * Save aai edge to db.
+ *
+ * @param transId the trans id
+ * @param fromAppId the from app id
+ * @param graph the graph
+ * @param edgeLabel the edge label
+ * @param outV the out V
+ * @param inV the in V
+ * @param propHash the prop hash
+ * @param apiVersion the api version
+ * @return TitanEdge
+ * @throws AAIException the AAI exception
+ */
+ private static TitanEdge saveAaiEdgeToDb(String transId, String fromAppId, TitanTransaction graph, String edgeLabel,
+ TitanVertex outV, TitanVertex inV, HashMap <String,Object> propHash, String apiVersion) throws AAIException{
+
+ // If this edge doesn't exist yet, then create it.
+
+ // NOTE - the Titan javaDoc says that there might not always be an id for a node.
+ // This is the internal-titan-unique-id, not any of our data.
+ // Not sure how to know when it might be there and when it might not?!
+ // So far, it has worked for all my testing, but this might warrant some
+ // further investigation.
+
+ TitanEdge existingEdge = null;
+ String inVId = inV.id().toString();
+ Iterator <Edge> eI = outV.edges(Direction.BOTH, edgeLabel);
+ while( eI.hasNext() ){
+ TitanEdge ed = (TitanEdge) eI.next();
+ TitanVertex otherVtx = (TitanVertex) ed.otherVertex(outV);
+ if( (otherVtx.id().toString()).equals(inVId) ){
+ // NOTE -?- Not sure -- at some point we might want to check the edgeLabels also since we might
+ // want to allow two different-type edges between the same two vertexes? (or maybe not.)
+ existingEdge = ed;
+ break;
+ }
+ }
+
+ if( existingEdge != null ){
+ // This is just an UPDATE
+ for( Map.Entry<String, Object> entry : propHash.entrySet() ){
+ LOGGER.debug("update edge property/val = [" + entry.getKey() + "]/[" + entry.getValue() + "]");
+ existingEdge.property( entry.getKey(), entry.getValue() );
+ }
+
+ return( existingEdge );
+ }
+ else {
+ // This is an ADD
+
+ // Uniqueness double-check. This is just to catch the possibility that at the transaction layer,
+ // if data came in for two identical nodes that point to the same dependant node (for uniqueness),
+ // we would only be able to catch the problem at the time the edge to the second node is added.
+ // For example - if they had a VM and then got a request to add two ipAddress nodes, but some
+ // bad data was passed and those two ipAddress nodes were identical -- we'd want to catch it.
+ String outV_NType = outV.<String>property("aai-node-type").orElse(null);
+ String inV_NType = inV.<String>property("aai-node-type").orElse(null);
+ if( needsADepNode4Uniqueness(transId, fromAppId, outV_NType, apiVersion)
+ && nodeTypeACanDependOnB(transId, fromAppId, outV_NType, inV_NType, apiVersion) ){
+ // The out-Vertex has a uniqueness dependency on the in-vertex
+ // Make sure we haven't already added an node/edge like this in this transaction
+ HashMap <String, Object> nodeKeyPropsHash = getNodeKeyPropHash(transId, fromAppId, graph, outV);
+ ArrayList<TitanVertex> resultList = new ArrayList<TitanVertex>();
+ resultList = DbMeth.getConnectedNodes("transId", "fromAppId", graph, outV_NType, nodeKeyPropsHash, inV, apiVersion, false);
+ if( resultList.size() > 0 ){
+ String propInfo = "";
+ if( nodeKeyPropsHash != null ){
+ propInfo = nodeKeyPropsHash.toString();
+ }
+ throw new AAIException("AAI_6117", "Failed to add edge. This node (" + inV_NType + ") already has an edge to a " + outV_NType +
+ " node with kepProps [" + propInfo + "]");
+ }
+ }
+ else if( needsADepNode4Uniqueness(transId, fromAppId, inV_NType, apiVersion)
+ && nodeTypeACanDependOnB(transId, fromAppId, inV_NType, outV_NType, apiVersion) ){
+ // The in-Vertex has a uniqueness dependency on the out-vertex
+ // Make sure we haven't already added an node/edge like this in this transaction
+ HashMap <String, Object> nodeKeyPropsHash = getNodeKeyPropHash(transId, fromAppId, graph, inV);
+ ArrayList<TitanVertex> resultList = new ArrayList<TitanVertex>();
+ resultList = DbMeth.getConnectedNodes("transId", "fromAppId", graph, inV_NType, nodeKeyPropsHash, outV, apiVersion, false);
+ if( resultList.size() > 0 ){
+ String propInfo = "";
+ if( nodeKeyPropsHash != null ){
+ propInfo = nodeKeyPropsHash.toString();
+ }
+ throw new AAIException("AAI_6117", "Failed to add edge. This node (" + outV_NType + ") already has an edge to a " + inV_NType +
+ " node with kepProps [" + propInfo + "]");
+ }
+ }
+
+
+ // We're good to go to add this edge
+
+ TitanEdge tEdge = outV.addEdge( edgeLabel, inV );
+ // Add the properties to the new Edge
+ for( Map.Entry<String, Object> entry : propHash.entrySet() ){
+ tEdge.property( entry.getKey(), entry.getValue() );
+ }
+
+ // For (resource-id updates) we need to "touch" the vertices on each side of the edge so
+ // anybody working on one of those vertices will know that something (ADDing this edge) has happened.
+ touchVertex( transId, fromAppId, inV );
+ touchVertex( transId, fromAppId, outV );
+
+ return tEdge;
+ }
+
+ }// End saveAaiEdgeToDb()
+
+
+
+ /**
+ * Derive edge rule key for this edge.
+ *
+ * @param transId the trans id
+ * @param fromAppId the from app id
+ * @param graph the graph
+ * @param tEdge the t edge
+ * @return String - key to look up edgeRule (fromNodeType|toNodeType)
+ * @throws AAIException the AAI exception
+ */
+ public static String deriveEdgeRuleKeyForThisEdge( String transId, String fromAppId, TitanTransaction graph,
+ TitanEdge tEdge ) throws AAIException{
+
+ TitanVertex fromVtx = tEdge.outVertex();
+ TitanVertex toVtx = tEdge.inVertex();
+ String startNodeType = fromVtx.<String>property("aai-node-type").orElse(null);
+ String targetNodeType = toVtx.<String>property("aai-node-type").orElse(null);
+ String key = startNodeType + "|" + targetNodeType;
+ if( EdgeRules.getInstance().hasEdgeRule(startNodeType, targetNodeType) ){
+ // We can use the node info in the order they were given
+ return( key );
+ }
+ else {
+ key = targetNodeType + "|" + startNodeType;
+ if( EdgeRules.getInstance().hasEdgeRule(targetNodeType, startNodeType) ){
+ return( key );
+ }
+ else {
+ // Couldn't find a rule for this edge
+ throw new AAIException("AAI_6120", "No EdgeRule found for passed nodeTypes: " + startNodeType + ", "
+ + targetNodeType);
+ }
+ }
+ }// end of deriveEdgeRuleKeyForThisEdge()
+
+
+
+ /**
+ * Save aai edge to db.
+ *
+ * @param transId the trans id
+ * @param fromAppId the from app id
+ * @param graph the graph
+ * @param edgeLabel the edge label
+ * @param outV the out V
+ * @param inV the in V
+ * @param propHash the prop hash
+ * @return the titan edge
+ * @throws AAIException the AAI exception
+ */
+ @Deprecated
+ private static TitanEdge saveAaiEdgeToDb(String transId, String fromAppId, TitanTransaction graph, String edgeLabel,
+ TitanVertex outV, TitanVertex inV, HashMap <String,Object> propHash) throws AAIException{
+ return saveAaiEdgeToDb( transId, fromAppId, graph, edgeLabel,
+ outV, inV, propHash, null);
+ }
+
+ /**
+ * Persist aai edge.
+ *
+ * @param transId the trans id
+ * @param fromAppId the from app id
+ * @param graph the graph
+ * @param startVert the start vert
+ * @param targetVert the target vert
+ * @param apiVersion the api version
+ * @return the titan edge
+ * @throws AAIException the AAI exception
+ */
+ public static TitanEdge persistAaiEdge( String transId, String fromAppId, TitanTransaction graph,
+ TitanVertex startVert, TitanVertex targetVert, String apiVersion ) throws AAIException{
+ TitanEdge returnEdge = persistAaiEdge(transId, fromAppId, graph, startVert, targetVert, apiVersion, "");
+ return returnEdge;
+ }
+
+ /**
+ * Persist aai edge.
+ *
+ * @param transId the trans id
+ * @param fromAppId the from app id
+ * @param graph the graph
+ * @param startVert the start vert
+ * @param targetVert the target vert
+ * @param apiVersion the api version
+ * @param edgeType the edge type
+ * @return TitanEdge
+ * @throws AAIException the AAI exception
+ */
+ public static TitanEdge persistAaiEdge( String transId, String fromAppId, TitanTransaction graph,
+ TitanVertex startVert, TitanVertex targetVert, String apiVersion, String edgeType ) throws AAIException{
+
+ TitanVertex fromVtx = null;
+ TitanVertex toVtx = null;
+ String startNodeType = startVert.<String>property("aai-node-type").orElse(null);
+ String targetNodeType = targetVert.<String>property("aai-node-type").orElse(null);
+ String fwdRuleKey = startNodeType + "|" + targetNodeType;
+ int fwdRuleCount = 0;
+ String fwdRule = "";
+ String fwdLabel = "";
+ String revRuleKey = targetNodeType + "|" + startNodeType;
+ int revRuleCount = 0;
+ String revRule = "";
+ String revLabel = "";
+ String edRule = "";
+ String edLabel = "";
+
+ Boolean checkType = false;
+ if( (edgeType != null) && edgeType != "" ){
+ checkType = true;
+ }
+
+ // As of 16-07, it is possible to have more than one kind of edge defined between a given
+ // pair of nodeTypes. So we need to check to see if there is only one possibility, or if
+ // we need to look at the edgeType to determine which to use.
+ // NOTE -- we're only supporting having 2 edges between a given pair of nodeTypes and
+ // one and only one of them would have to be a parent-child edge.
+
+ if( DbEdgeRules.EdgeRules.containsKey(fwdRuleKey) ){
+ Collection <String> edRuleColl = DbEdgeRules.EdgeRules.get(fwdRuleKey);
+ Iterator <String> ruleItr = edRuleColl.iterator();
+ while( ruleItr.hasNext() ){
+ String tmpRule = ruleItr.next();
+ String [] rules = tmpRule.split(",");
+ String tmpLabel = rules[0];
+ String tmpParChild = rules[3];
+ if( !checkType
+ || (checkType && tmpParChild.equals("true") && edgeType.equals("parentChild"))
+ || (checkType && tmpParChild.equals("false") && edgeType.equals("cousin")) ){
+ // Either they didn't want us to check the edgeType or it is a match
+ fwdRuleCount++;
+ if( fwdRuleCount > 1 ){
+ // We found more than one with the given info
+ throw new AAIException("AAI_6120", "Multiple EdgeRules found for nodeTypes: [" + startNodeType + "], ["
+ + targetNodeType + "], edgeType = [" + edgeType + "].");
+ }
+ else {
+ fwdRule = tmpRule;
+ fwdLabel = tmpLabel;
+ }
+ }
+ }
+ }
+
+ // Try it the other way also (unless this is the case of a nodeType recursively pointing to itself
+ // Ie. the edge rule: "model-element|model-element"
+ if( !revRuleKey.equals(fwdRuleKey) && DbEdgeRules.EdgeRules.containsKey(revRuleKey) ){
+ Collection <String> edRuleColl = DbEdgeRules.EdgeRules.get(revRuleKey);
+ Iterator <String> ruleItr = edRuleColl.iterator();
+ while( ruleItr.hasNext() ){
+ String tmpRule = ruleItr.next();
+ String [] rules = tmpRule.split(",");
+ String tmpLabel = rules[0];
+ String tmpParChild = rules[3];
+ if( !checkType
+ || (checkType && tmpParChild.equals("true") && edgeType.equals("parentChild"))
+ || (checkType && tmpParChild.equals("false") && edgeType.equals("cousin")) ){
+ // Either they didn't want us to check the edgeType or it is a match
+ revRuleCount++;
+ if( revRuleCount > 1 ){
+ // We found more than one with the given info
+ throw new AAIException("AAI_6120", "Multiple EdgeRules found for nodeTypes: [" + targetNodeType + "], ["
+ + startNodeType + "], edgeType = [" + edgeType + "].");
+ }
+ else {
+ revRule = tmpRule;
+ revLabel = tmpLabel;
+ }
+ }
+ }
+ }
+
+ if( (fwdRuleCount == 1) && (revRuleCount == 0) ){
+ // We can use the node info in the order they were given
+ fromVtx = startVert;
+ toVtx = targetVert;
+ edRule = fwdRule;
+ edLabel = fwdLabel;
+ }
+ else if( (fwdRuleCount == 0) && (revRuleCount == 1) ){
+ // We need to switch the vertex order so the edge-direction is correct
+ toVtx = startVert;
+ fromVtx = targetVert;
+ edRule = revRule;
+ edLabel = revLabel;
+ }
+ else if( (fwdRuleCount == 0) && (revRuleCount == 0) ){
+ // No edge rule found for this
+ throw new AAIException("AAI_6120", "No EdgeRule found for passed nodeTypes: " + startNodeType + ", " + targetNodeType
+ + "], checkLabelType = [" + edgeType + "].");
+ }
+ else if( (fwdRuleCount > 0) && (revRuleCount > 0) ){
+ // We found more than one with the given info
+ throw new AAIException("AAI_6120", "Multiple EdgeRules (fwd and rev) found for nodeTypes: [" + startNodeType + "], ["
+ + targetNodeType + "], checkLabelType = [" + edgeType + "].");
+ }
+
+ // If we got to this point, we now have a single edge label and we know to and from Vtx.
+
+ HashMap <String,Object> edgeParamHash = getEdgeTagPropPutHash4Rule(transId, fromAppId, edRule);
+ // We do "source-of-truth" for all edges
+ edgeParamHash.put("source-of-truth", fromAppId );
+
+ TitanEdge returnEdge = saveAaiEdgeToDb(transId, fromAppId, graph, edLabel, fromVtx, toVtx, edgeParamHash, apiVersion);
+
+ return returnEdge;
+
+ }
+
+ /**
+ * Persist aai edge.
+ *
+ * @param transId the trans id
+ * @param fromAppId the from app id
+ * @param graph the graph
+ * @param startVert the start vert
+ * @param targetVert the target vert
+ * @return the titan edge
+ * @throws AAIException the AAI exception
+ */
+ @Deprecated
+ public static TitanEdge persistAaiEdge( String transId, String fromAppId, TitanTransaction graph,
+ TitanVertex startVert, TitanVertex targetVert ) throws AAIException{
+ return persistAaiEdge( transId, fromAppId, graph,
+ startVert, targetVert, null);
+ }
+ // End persistAaiEdge()
+
+
+ /**
+ * Persist aai edge.
+ *
+ * @param transId the trans id
+ * @param fromAppId the from app id
+ * @param graph the graph
+ * @param edgeLabel the edge label
+ * @param startVert the start vert
+ * @param targetVert the target vert
+ * @param propHash the prop hash
+ * @param addIfNotFound the add if not found
+ * @return the titan edge
+ * @throws AAIException the AAI exception
+ */
+ @Deprecated
+ public static TitanEdge persistAaiEdge( String transId, String fromAppId, TitanTransaction graph,
+ String edgeLabel, TitanVertex startVert, TitanVertex targetVert,
+ HashMap <String,Object> propHash, Boolean addIfNotFound ) throws AAIException{
+
+ /*----- This method is depricated ------
+ * We will ignore the parameters: edgeLabel, propHash and addIfNotFound
+ * We will use the remaining params to call the newer version of this method
+ */
+ TitanEdge returnEdge = persistAaiEdge(transId, fromAppId, graph, startVert, targetVert, null);
+
+ return returnEdge;
+
+ }// End depricated version of persistAaiEdge()
+
+
+ /**
+ * Persist aai edge with dep params.
+ *
+ * @param transId the trans id
+ * @param fromAppId the from app id
+ * @param graph the graph
+ * @param startVert the start vert
+ * @param targetNodeType the target node type
+ * @param targetNodeParamHash the target node param hash
+ * @param apiVersion the api version
+ * @return TitanEdge
+ * @throws AAIException the AAI exception
+ */
+ public static TitanEdge persistAaiEdgeWithDepParams( String transId, String fromAppId, TitanTransaction graph,
+ TitanVertex startVert, String targetNodeType, HashMap <String,Object> targetNodeParamHash, String apiVersion) throws AAIException{
+
+ TitanVertex targetVert = getUniqueNodeWithDepParams( transId, fromAppId, graph, targetNodeType, targetNodeParamHash, apiVersion );
+ TitanEdge returnEdge = persistAaiEdge(transId, fromAppId, graph, startVert, targetVert, apiVersion);
+
+ return returnEdge;
+
+ }// End persistAaiEdgeWithDepParams()
+
+ // Version that lets you pass in an edgeType ("parentChild" or "cousin" since it sometimes cannot be determined
+ /**
+ * Persist aai edge with dep params.
+ *
+ * @param transId the trans id
+ * @param fromAppId the from app id
+ * @param graph the graph
+ * @param startVert the start vert
+ * @param targetNodeType the target node type
+ * @param targetNodeParamHash the target node param hash
+ * @param apiVersion the api version
+ * @param edgeType the edge type
+ * @return the titan edge
+ * @throws AAIException the AAI exception
+ */
+ // from the two nodeTypes anymore (16-07)
+ public static TitanEdge persistAaiEdgeWithDepParams( String transId, String fromAppId, TitanTransaction graph,
+ TitanVertex startVert, String targetNodeType, HashMap <String,Object> targetNodeParamHash,
+ String apiVersion, String edgeType) throws AAIException{
+ TitanVertex targetVert = getUniqueNodeWithDepParams( transId, fromAppId, graph, targetNodeType, targetNodeParamHash, apiVersion );
+ TitanEdge returnEdge = persistAaiEdge(transId, fromAppId, graph, startVert, targetVert, apiVersion, edgeType);
+
+ return returnEdge;
+
+ }// End persistAaiEdgeWithDepParams()
+
+ /**
+ * Persist aai edge with dep params.
+ *
+ * @param transId the trans id
+ * @param fromAppId the from app id
+ * @param graph the graph
+ * @param startVert the start vert
+ * @param targetNodeType the target node type
+ * @param targetNodeParamHash the target node param hash
+ * @return the titan edge
+ * @throws AAIException the AAI exception
+ */
+ @Deprecated
+ public static TitanEdge persistAaiEdgeWithDepParams( String transId, String fromAppId, TitanTransaction graph,
+ TitanVertex startVert, String targetNodeType, HashMap <String,Object> targetNodeParamHash) throws AAIException{
+ return persistAaiEdgeWithDepParams( transId, fromAppId, graph,
+ startVert, targetNodeType, targetNodeParamHash, null);
+ }
+
+ /**
+ * Gets the node key prop hash.
+ *
+ * @param transId the trans id
+ * @param fromAppId the from app id
+ * @param graph the graph
+ * @param vtx the vtx
+ * @return nodeKeyPropHash
+ * @throws AAIException the AAI exception
+ */
+ public static HashMap <String, Object> getNodeKeyPropHash( String transId, String fromAppId, TitanTransaction graph, TitanVertex vtx) throws AAIException{
+
+ if( vtx == null ){
+ throw new AAIException("AAI_6109", "null node object passed to getNodeKeyPropHash().");
+ }
+
+ DbMaps dbMaps = IngestModelMoxyOxm.dbMapsContainer.get(AAIConfig.get(AAIConstants.AAI_DEFAULT_API_VERSION_PROP));
+
+ String nType = vtx.<String>property("aai-node-type").orElse(null);
+ if( ! dbMaps.NodeKeyProps.containsKey(nType) ){
+ // Problem if no key Properties defined for this nodeType
+ String defVer = AAIConfig.get(AAIConstants.AAI_DEFAULT_API_VERSION_PROP);
+ throw new AAIException("AAI_6105", "No node-key-properties defined in dbMaps for nodeType = " + nType + " (ver=" + defVer + ")");
+ }
+
+ HashMap <String,Object>nodeKeyPropsHash = new HashMap<String,Object>();
+ Collection <String> keyProps = dbMaps.NodeKeyProps.get(nType);
+ Iterator <String> keyPropI = keyProps.iterator();
+ while( keyPropI.hasNext() ){
+ String propName = keyPropI.next();
+ Object value = (Object) vtx.<Object>property(propName).orElse(null);
+ nodeKeyPropsHash.put(propName, value);
+ }
+
+ return nodeKeyPropsHash;
+
+ }// End of getNodeKeyPropHash()
+
+ /**
+ * Gets the node name prop hash.
+ *
+ * @param transId the trans id
+ * @param fromAppId the from app id
+ * @param graph the graph
+ * @param vtx the vtx
+ * @param apiVersion the api version
+ * @return nodeKeyPropHash
+ * @throws AAIException the AAI exception
+ */
+ public static HashMap <String, Object> getNodeNamePropHash( String transId, String fromAppId, TitanTransaction graph, TitanVertex vtx, String apiVersion) throws AAIException{
+
+ if( vtx == null ){
+ throw new AAIException("AAI_6109", "null node object passed to getNodeNamePropHash()." );
+ }
+
+ String nType = vtx.<String>property("aai-node-type").orElse(null);
+ HashMap <String,Object>nodeNamePropsHash = new HashMap<String,Object>();
+ Collection <String> keyProps = DbMeth.getNodeNameProps(transId, fromAppId, nType, apiVersion);
+ Iterator <String> keyPropI = keyProps.iterator();
+ while( keyPropI.hasNext() ){
+ String propName = keyPropI.next();
+ Object value = (Object) vtx.<Object>property(propName).orElse(null);
+ nodeNamePropsHash.put(propName, value);
+ }
+
+ return nodeNamePropsHash;
+
+ }// End of getNodeNamePropHash()
+
+
+ /**
+ * Removes the aai edge.
+ *
+ * @param transId the trans id
+ * @param fromAppId the from app id
+ * @param graph the graph
+ * @param tEdge the t edge
+ * @return void
+ */
+ public static void removeAaiEdge( String transId, String fromAppId, TitanTransaction graph, TitanEdge tEdge){
+ // Before removing the edge, touch the vertices on each side so their resource-versions will get updated
+ TitanVertex tmpVIn = tEdge.inVertex();
+ touchVertex( transId, fromAppId, tmpVIn );
+
+ TitanVertex tmpVOut = tEdge.outVertex();
+ touchVertex( transId, fromAppId, tmpVOut );
+
+ // Remove the passed in edge.
+ tEdge.remove();
+
+ }// end of removeAaiEdge()
+
+
+ /**
+ * Removes the aai node.
+ *
+ * @param transId the trans id
+ * @param fromAppId the from app id
+ * @param graph the graph
+ * @param thisVtx the this vtx
+ * @param scopeParam the scope param
+ * @param apiVersion the api version
+ * @param resourceVersion the resource version
+ * @throws AAIException the AAI exception
+ */
+ public static void removeAaiNode( String transId, String fromAppId, TitanTransaction graph, TitanVertex thisVtx, String scopeParam,
+ String apiVersion, String resourceVersion ) throws AAIException{
+ // Note: the resource Version Override flag is only set to true when called by the Model Delete code which
+ // has no way to know the resource-versions of nodes at lower-levels of it's model topology.
+ Boolean resVersionOverrideFlag = false;
+ removeAaiNode( transId, fromAppId, graph, thisVtx, scopeParam, apiVersion, resourceVersion, resVersionOverrideFlag );
+ }
+
+
+ /**
+ * <pre>
+ * Possible values for deleteScope can be:
+ * USE_DEFAULT - Get the scope from ref data for this node
+ * THIS_NODE_ONLY (but should fail if it there are nodes that depend on it for uniqueness)
+ * CASCADE_TO_CHILDREN - will look for OUT-Edges that have parentOf/hasDelTarget = true and follow those down
+ * ERROR_4_IN_EDGES_OR_CASCADE - combo of error-if-any-IN-edges + CascadeToChildren
+ * ERROR_IF_ANY_IN_EDGES - Fail if this node has any existing IN edges
+ * ERROR_IF_ANY_EDGES - Fail if this node has any existing edges at all!
+ * </pre>.
+ *
+ * @param transId the trans id
+ * @param fromAppId the from app id
+ * @param graph the graph
+ * @param thisVtx the this vtx
+ * @param scopeParam the scope param
+ * @param apiVersion the api version
+ * @param resourceVersion the resource version
+ * @param resVerOverride the res ver override
+ * @return void
+ * @throws AAIException the AAI exception
+ */
+ public static void removeAaiNode( String transId, String fromAppId, TitanTransaction graph, TitanVertex thisVtx, String scopeParam,
+ String apiVersion, String resourceVersion, Boolean resVerOverride ) throws AAIException{
+ String nodeType2Del = thisVtx.<String>property("aai-node-type").orElse(null);
+ String deleteScope = scopeParam;
+ if( scopeParam.equals("USE_DEFAULT") ){
+ deleteScope = getDefaultDeleteScope(transId, fromAppId, nodeType2Del, apiVersion);
+ }
+
+ if( !resVerOverride && needToDoResourceVerCheck(apiVersion, false) ){
+ // Need to check that they knew what they were deleting
+ String existingResVer = thisVtx.<String>property("resource-version").orElse(null);
+ if( resourceVersion == null || resourceVersion.equals("") ){
+ throw new AAIException("AAI_6130", "Resource-version not passed for delete of = " + nodeType2Del);
+ }
+ else if( (existingResVer != null) && !resourceVersion.equals(existingResVer) ){
+ throw new AAIException("AAI_6131", "Resource-version MISMATCH for delete of = " + nodeType2Del);
+ }
+ }
+
+ if( !deleteScope.equals("THIS_NODE_ONLY")
+ && !deleteScope.equals("CASCADE_TO_CHILDREN")
+ && !deleteScope.equals("ERROR_4_IN_EDGES_OR_CASCADE")
+ && !deleteScope.equals("ERROR_IF_ANY_EDGES")
+ && !deleteScope.equals("ERROR_IF_ANY_IN_EDGES") ){
+ throw new AAIException("AAI_6120", "Unrecognized value in deleteScope: [" + deleteScope + "].");
+ }
+
+ if( deleteScope.equals("ERROR_IF_ANY_EDGES") ){
+ if ( thisVtx.edges(Direction.BOTH).hasNext() ) {
+ throw new AAIException("AAI_6110", "Node cannot be deleted because it still has Edges and the ERROR_IF_ANY_EDGES scope was used.");
+ }
+ }
+ else if( deleteScope.equals("ERROR_IF_ANY_IN_EDGES") || deleteScope.equals("ERROR_4_IN_EDGES_OR_CASCADE") ){
+ Iterator <Edge> eI = thisVtx.edges(Direction.IN);
+ boolean onlyHasParent = false;
+ Edge temp = null;
+ if( eI != null && eI.hasNext() ){
+ temp = eI.next();
+ Boolean isParent = temp.<Boolean>property("isParent").orElse(null);
+ if (isParent != null && isParent && !eI.hasNext()) {
+ onlyHasParent = true;
+ }
+
+ if (!onlyHasParent) {
+ throw new AAIException("AAI_6110", "Node cannot be deleted because it still has Edges and the " + deleteScope + " scope was used.");
+ }
+ }
+ }
+ else if( deleteScope.equals("THIS_NODE_ONLY")){
+ // Make sure nobody depends on this node.
+ Iterator<Edge> eI = thisVtx.edges(Direction.BOTH);
+ while( eI.hasNext() ){
+ TitanEdge ed = (TitanEdge) eI.next();
+ TitanVertex otherVtx = (TitanVertex) ed.otherVertex(thisVtx);
+ String nodeTypeA = otherVtx.<String>property("aai-node-type").orElse(null);
+ if( nodeTypeACanDependOnB(transId, fromAppId, nodeTypeA, nodeType2Del, apiVersion)){
+ // We're only supposed to delete this node - but another node is dependant on it,
+ // so we shouldn't delete this one.
+ throw new AAIException("AAI_6110", "Node cannot be deleted using scope = " + deleteScope +
+ " another node (type = " + nodeTypeA + ") depends on it for uniqueness.");
+ }
+ }
+ }
+
+ // We've passed our checks - so do some deleting of edges and maybe pass
+ // the delete request down to children or delete-targets.
+
+ // First we deal with the "IN"-Edges which can't have children/delete-targets which
+ // by definition (of "IN") on the other end
+ Iterator <Edge> eI_In = thisVtx.edges(Direction.IN);
+ while( eI_In.hasNext() ){
+ TitanEdge ed = (TitanEdge) eI_In.next();
+
+ //- "touch" vertex on other side of this edge so it gets a fresh resource-version
+ TitanVertex tmpVOther = ed.otherVertex(thisVtx);
+ touchVertex( transId, fromAppId, tmpVOther );
+
+ ed.remove();
+ }
+
+ // Now look at the "OUT"-edges which might include children or delete-targets
+ String cascadeMsg = "This nt = " + nodeType2Del + ", Cascading del to: ";
+ Iterator <Edge> eI_Out = thisVtx.edges(Direction.OUT);
+ if( !eI_Out.hasNext() ){
+ cascadeMsg = cascadeMsg + "[no children for this node]";
+ }
+ while( eI_Out.hasNext() ){
+ TitanEdge ed = (TitanEdge) eI_Out.next();
+
+ // "touch" vertex on other side of this edge so it gets a fresh resource-version
+ TitanVertex tmpVOther = ed.otherVertex(thisVtx);
+ touchVertex( transId, fromAppId, tmpVOther );
+
+ Boolean otherVtxAChild = ed.<Boolean>property("isParent").orElse(null);
+ if( otherVtxAChild == null ){
+ otherVtxAChild = false;
+ }
+
+ Boolean otherVtxADeleteTarget = ed.<Boolean>property("hasDelTarget").orElse(null);
+ if( otherVtxADeleteTarget == null ){
+ otherVtxADeleteTarget = false;
+ }
+
+ if( (otherVtxAChild || otherVtxADeleteTarget) &&
+ (deleteScope.equals("CASCADE_TO_CHILDREN") || deleteScope.equals("ERROR_4_IN_EDGES_OR_CASCADE")) ){
+ // Delete the edge to the child and Pass the delete down to it.
+ ed.remove();
+ TitanVertex otherVtx = (TitanVertex) ed.otherVertex(thisVtx);
+ String vid = otherVtx.id().toString();
+ String nty = otherVtx.<String>property("aai-node-type").orElse(null);
+ String resVers = otherVtx.<String>property("resource-version").orElse(null);
+ cascadeMsg = cascadeMsg + "[" + nty + ":" + vid + "]";
+ removeAaiNode(transId, fromAppId, graph, otherVtx, "CASCADE_TO_CHILDREN", apiVersion, resVers);
+ }
+ else {
+ // The other node is not a child or deleteTarget. Delete the edge to it if it is not
+ // dependent (Should never be dependent since it's not a child/delTarget... but
+ // someone could create a node that was dependent for Uniqueness without
+ // being a child/target.
+
+ // DEBUG -- eventually add the check for dependancy that isn't on a parent-type or delTarget-type edge
+ ed.remove();
+ }
+ }
+
+ LOGGER.info(cascadeMsg);
+
+ Iterator<Edge> eI = thisVtx.edges(Direction.BOTH);
+ if( ! eI.hasNext() ){
+ // By this point, either there were no edges to deal with, or we have dealt with them.
+ thisVtx.remove();
+ }
+ else {
+ // Something went wrong and we couldn't delete all the edges for this guy.
+ throw new AAIException("AAI_6110", "Node could be deleted because it unexpectedly still has Edges.\n");
+ }
+ }
+
+
+ /**
+ * Removes the aai node.
+ *
+ * @param transId the trans id
+ * @param fromAppId the from app id
+ * @param graph the graph
+ * @param thisVtx the this vtx
+ * @param scopeParam the scope param
+ * @return void
+ * @throws AAIException the AAI exception
+ */
+ @Deprecated
+ public static void removeAaiNode( String transId, String fromAppId, TitanTransaction graph, TitanVertex thisVtx, String scopeParam) throws AAIException{
+ removeAaiNode(transId, fromAppId, graph, thisVtx, scopeParam, null, null);
+ }
+
+ /**
+ * Removes the aai node.
+ *
+ * @param transId the trans id
+ * @param fromAppId the from app id
+ * @param graph the graph
+ * @param thisVtx the this vtx
+ * @param scopeParam the scope param
+ * @param apiVersion the api version
+ * @throws AAIException the AAI exception
+ */
+ @Deprecated
+ public static void removeAaiNode( String transId, String fromAppId, TitanTransaction graph, TitanVertex thisVtx, String scopeParam,
+ String apiVersion ) throws AAIException{
+ removeAaiNode(transId, fromAppId, graph, thisVtx, scopeParam, apiVersion, null);
+ }
+ // end of removeAaiNode()
+
+
+ /**
+ * Delete all graph data.
+ *
+ * @param transId the trans id
+ * @param fromAppId the from app id
+ * @param graph the graph
+ * @return void
+ */
+ public static void deleteAllGraphData( String transId, String fromAppId, TitanGraph graph ){
+ /** ======================================================================
+ * WARNING -- this removes ALL the data that is currently in the graph.
+ * ======================================================================
+ **/
+ LOGGER.warn("deleteAllGraphData called! Run for the hills!");
+ Iterator<Edge> edges = graph.edges(Direction.BOTH);
+ graph.tx().commit();
+ Edge edge = null;
+ while (edges.hasNext()) {
+ edge = edges.next();
+ edges.remove();
+ }
+ graph.tx().commit();
+ Iterator<Vertex> vertices = graph.vertices();
+ graph.tx().commit();
+ Vertex vertex = null;
+ while (vertices.hasNext()) {
+ vertex = vertices.next();
+ vertex.remove();
+ }
+ graph.tx().commit();
+ }
+
+
+ /**
+ * Show all edges for node.
+ *
+ * @param transId the trans id
+ * @param fromAppId the from app id
+ * @param tVert the t vert
+ * @return the array list
+ */
+ public static ArrayList <String> showAllEdgesForNode( String transId, String fromAppId, TitanVertex tVert ){
+
+ ArrayList <String> retArr = new ArrayList <String> ();
+ Iterator <Edge> eI = tVert.edges(Direction.IN);
+ if( ! eI.hasNext() ){
+ retArr.add("No IN edges were found for this vertex. ");
+ }
+ while( eI.hasNext() ){
+ TitanEdge ed = (TitanEdge) eI.next();
+ String lab = ed.label();
+ TitanVertex vtx = (TitanVertex) ed.otherVertex(tVert);
+ if( vtx == null ){
+ retArr.add(" >>> COULD NOT FIND VERTEX on the other side of this edge edgeId = " + ed.id() + " <<< ");
+ }
+ else {
+ String nType = vtx.<String>property("aai-node-type").orElse(null);
+ String vid = vtx.id().toString();
+ retArr.add("Found an IN edge (" + lab + ") to this vertex from a [" + nType + "] node with VtxId = " + vid );
+ //DEBUG ---
+ //showPropertiesForEdge( transId, fromAppId, ed );
+ }
+ }
+
+ eI = tVert.edges(Direction.OUT);
+ if( ! eI.hasNext() ){
+ retArr.add("No OUT edges were found for this vertex. ");
+ }
+ while( eI.hasNext() ){
+ TitanEdge ed = (TitanEdge) eI.next();
+ String lab = ed.label();
+ TitanVertex vtx = (TitanVertex) ed.otherVertex(tVert);
+ if( vtx == null ){
+ retArr.add(" >>> COULD NOT FIND VERTEX on the other side of this edge edgeId = " + ed.id() + " <<< ");
+ }
+ else {
+ String nType = vtx.<String>property("aai-node-type").orElse(null);
+ String vid = vtx.id().toString();
+ retArr.add("Found an OUT edge (" + lab + ") from this vertex to a [" + nType + "] node with VtxId = " + vid );
+ //DEBUG ---
+ //showPropertiesForEdge( transId, fromAppId, ed );
+ }
+ }
+ return retArr;
+ }
+
+
+ /**
+ * Show properties for node.
+ *
+ * @param transId the trans id
+ * @param fromAppId the from app id
+ * @param tVert the t vert
+ * @return the array list
+ */
+ public static ArrayList <String> showPropertiesForNode( String transId, String fromAppId, TitanVertex tVert ){
+
+ ArrayList <String> retArr = new ArrayList <String> ();
+ if( tVert == null ){
+ retArr.add("null Node object passed to showPropertiesForNode()\n");
+ }
+ else {
+ String nodeType = "";
+ //String datType = "";
+ Object ob = tVert.<Object>property("aai-node-type").orElse(null);
+ if( ob == null ){
+ nodeType = "null";
+ }
+ else{
+ nodeType = ob.toString();
+ //datType = ob.getClass().getSimpleName();
+ }
+
+ retArr.add(" AAINodeType/VtxID for this Node = [" + nodeType + "/" + tVert.id() + "]");
+ retArr.add(" Property Detail: ");
+ Iterator<VertexProperty<Object>> pI = tVert.properties();
+ while( pI.hasNext() ){
+ VertexProperty<Object> tp = pI.next();
+ Object val = tp.value();
+ //retArr.add("Prop: [" + tp.getPropertyKey() + "], val = [" + val + "], dataType = " + val.getClass() );
+ retArr.add("Prop: [" + tp.key() + "], val = [" + val + "] ");
+ }
+ }
+ return retArr;
+ }
+
+
+ /**
+ * Gets the node name props.
+ *
+ * @param transId the trans id
+ * @param fromAppId the from app id
+ * @param nodeType the node type
+ * @param apiVersion the api version
+ * @return HashMap of keyProperties
+ * @throws AAIException the AAI exception
+ */
+ public static Collection <String> getNodeNameProps( String transId, String fromAppId, String nodeType, String apiVersion ) throws AAIException{
+
+ DbMaps dbMaps = IngestModelMoxyOxm.dbMapsContainer.get(AAIConfig.get(AAIConstants.AAI_DEFAULT_API_VERSION_PROP));
+
+ Collection <String> nameProps = new ArrayList <String>();
+ if( dbMaps.NodeNameProps.containsKey(nodeType) ){
+ nameProps = dbMaps.NodeNameProps.get(nodeType);
+ }
+ else if( DbEdgeRules.NodeTypeCategory.containsKey(nodeType) ){
+ // The passed-in nodeType was really a nodeCategory, theoretically, all the guys in the same
+ // category should have the same name property -- so if they just give us the category, we will
+ // just give the name info from the first nodeType we encounter of that category.
+ Collection <String> nTypeCatCol = DbEdgeRules.NodeTypeCategory.get(nodeType);
+ Iterator <String> catItr = nTypeCatCol.iterator();
+ String catInfo = "";
+ if( catItr.hasNext() ){
+ // For now, we only look for one.
+ catInfo = catItr.next();
+ }
+ else {
+ throw new AAIException("AAI_6105", "Required Property name(s) not found for nodeType = " + nodeType);
+ }
+
+ String [] flds = catInfo.split(",");
+ if( flds.length != 4 ){
+ throw new AAIException("AAI_6121", "Bad EdgeRule.NodeTypeCategory data (itemCount=" + flds.length + ") for nodeType = [" + nodeType + "].");
+ }
+
+ String nodeTypesString = flds[0];
+ String [] nodeTypeNames = nodeTypesString.split("\\|");
+ if( nodeTypeNames != null && nodeTypeNames.length > 0 ){
+ // We'll just use the first one
+ String nt = nodeTypeNames[0];
+ nameProps = dbMaps.NodeNameProps.get(nt);
+ }
+ }
+
+
+ // Note - it's ok if there was no defined name property for this nodeType.
+
+ return nameProps;
+
+ }// end of getNodeKeyPropNames
+
+
+ /**
+ * Gets the edge tag prop put hash 4 rule.
+ *
+ * @param transId the trans id
+ * @param fromAppId the from app id
+ * @param edRule the ed rule
+ * @return the edge tag prop put hash 4 rule
+ * @throws AAIException the AAI exception
+ */
+ public static HashMap <String,Object> getEdgeTagPropPutHash4Rule( String transId, String fromAppId, String edRule )
+ throws AAIException{
+ // For a given edgeRule - already pulled out of DbEdgeRules.EdgeRules -- parse out the "tags" that
+ // need to be set for this kind of edge.
+ // These are the Boolean properties like, "isParent", "usesResource" etc.
+ HashMap <String,Object> retEdgePropPutMap = new HashMap <String,Object>();
+
+ if( (edRule == null) || edRule.equals("") ){
+ // No edge rule found for this
+ throw new AAIException("AAI_6120", "blank edRule passed to getEdgeTagPropPutHash4Rule()");
+ }
+
+ int tagCount = DbEdgeRules.EdgeInfoMap.size();
+ String [] rules = edRule.split(",");
+ if( rules.length != tagCount ){
+ throw new AAIException("AAI_6121", "Bad EdgeRule data (itemCount =" + rules.length + ") for rule = [" + edRule + "].");
+ }
+
+ // In DbEdgeRules.EdgeRules -- What we have as "edRule" is a comma-delimited set of strings.
+ // The first item is the edgeLabel.
+ // The second in the list is always "direction" which is always OUT for the way we've implemented it.
+ // Items starting at "firstTagIndex" and up are all assumed to be booleans that map according to
+ // tags as defined in EdgeInfoMap.
+ // Note - if they are tagged as 'reverse', that means they get the tag name with "-REV" on it
+ for( int i = DbEdgeRules.firstTagIndex; i < tagCount; i++ ){
+ String booleanStr = rules[i];
+ Integer mapKey = new Integer(i);
+ String propName = DbEdgeRules.EdgeInfoMap.get(mapKey);
+ String revPropName = propName + "-REV";
+
+ if( booleanStr.equals("true") ){
+ retEdgePropPutMap.put(propName, true);
+ retEdgePropPutMap.put(revPropName,false);
+ }
+ else if( booleanStr.equals("false") ){
+ retEdgePropPutMap.put(propName, false);
+ retEdgePropPutMap.put(revPropName,false);
+ }
+ else if( booleanStr.equals("reverse") ){
+ retEdgePropPutMap.put(propName, false);
+ retEdgePropPutMap.put(revPropName,true);
+ }
+ else {
+ throw new AAIException("AAI_6121", "Bad EdgeRule data for rule = [" + edRule + "], val = [" + booleanStr + "].");
+ }
+
+ }
+
+ return retEdgePropPutMap;
+
+ } // End of getEdgeTagPropPutHash()
+
+
+
+ /**
+ * Gets the edge tag prop put hash.
+ *
+ * @param transId the trans id
+ * @param fromAppId the from app id
+ * @param edgeRuleKey the edge rule key
+ * @return the edge tag prop put hash
+ * @throws AAIException the AAI exception
+ */
+ public static Map<String, EdgeRule> getEdgeTagPropPutHash( String transId, String fromAppId, String edgeRuleKey )
+ throws AAIException{
+ // For a given edgeRuleKey (nodeTypeA|nodeTypeB), look up the rule that goes with it in
+ // DbEdgeRules.EdgeRules and parse out the "tags" that need to be set on each edge.
+ // These are the Boolean properties like, "isParent", "usesResource" etc.
+ // Note - this code is also used by the updateEdgeTags.java code
+
+ String[] edgeRuleKeys = edgeRuleKey.split("\\|");
+
+ if (edgeRuleKeys.length < 2 || ! EdgeRules.getInstance().hasEdgeRule(edgeRuleKeys[0], edgeRuleKeys[1])) {
+ throw new AAIException("AAI_6120", "Could not find an DbEdgeRule entry for passed edgeRuleKey (nodeTypeA|nodeTypeB): " + edgeRuleKey + ".");
+ }
+
+ Map<String, EdgeRule> edgeRules = EdgeRules.getInstance().getEdgeRules(edgeRuleKeys[0], edgeRuleKeys[1]);
+
+ return edgeRules;
+
+ } // End of getEdgeTagPropPutHash()
+
+
+ /**
+ * This property was put by newer version of code.
+ *
+ * @param apiVersionStr the api version str
+ * @param nodeType the node type
+ * @param propName the prop name
+ * @return true, if successful
+ * @throws AAIException the AAI exception
+ */
+ private static boolean thisPropertyWasPutByNewerVersionOfCode( String apiVersionStr,
+ String nodeType, String propName) throws AAIException{
+ // We want to return True if the nodeType + property-name combo was introduced AFTER the apiVersion passed.
+
+ int apiVerInt = 0;
+ int propIntroVerInt = 0;
+
+ if( apiVersionStr == null || apiVersionStr.equals("") ){
+ apiVersionStr = org.openecomp.aai.util.AAIApiVersion.get();
+ }
+ apiVerInt = getVerNumFromVerString(apiVersionStr);
+ DbMaps dbMaps = IngestModelMoxyOxm.dbMapsContainer.get(AAIConfig.get(AAIConstants.AAI_DEFAULT_API_VERSION_PROP));
+ String propIntroKey = nodeType + "|" + propName;
+ if( propName.equals("prov-status") ){
+ // This is a special case -- The dbMaps from v2 has it in there, but it was introduced half way through. So
+ // it needs to be catogorized as v3.
+ propIntroVerInt = 3;
+ }
+ else if( ! dbMaps.PropertyVersionInfoMap.containsKey(propIntroKey) ){
+ String detail = propIntroKey + " [" + propIntroKey + "] not found in dbMaps.PropertyVersionInfoMap.";
+ throw new AAIException("AAI_6121", detail);
+ }
+ else {
+ String propIntroVerString = dbMaps.PropertyVersionInfoMap.get(propIntroKey);
+ propIntroVerInt = getVerNumFromVerString( propIntroVerString );
+ }
+
+ if( propIntroVerInt > apiVerInt ){
+ return true;
+ }
+ else {
+ return false;
+ }
+
+ } // End of thisPropertyWasPutByNewerVersionOfCode()
+
+
+ /**
+ * Touch vertex.
+ *
+ * @param transId the trans id
+ * @param fromAppId the from app id
+ * @param v the v
+ * @return void
+ */
+ public static void touchVertex( String transId, String fromAppId, TitanVertex v ){
+ // We want to "touch" the vertex -- Ie. update it's last-mod-date, last-mod- resource-version to the current date/time
+ if( v != null ){
+ long unixTimeNow = System.currentTimeMillis() / 1000L;
+ String timeNowInSec = "" + unixTimeNow;
+ v.property( "aai-last-mod-ts", timeNowInSec );
+ v.property( "resource-version", timeNowInSec );
+ v.property( "last-mod-source-of-truth", fromAppId );
+ }
+ } // End of touchVertex()
+
+
+ /**
+ * Check prop cardinality.
+ *
+ * @param propName the prop name
+ * @param cardinalityType the cardinality type
+ * @return boolean
+ * @throws AAIException the AAI exception
+ */
+ public static boolean checkPropCardinality( String propName, String cardinalityType ) throws AAIException {
+
+ // Return true if the named property is tagged in our dbMaps PropetyDataTypeMap as
+ // having the passed in cardinality type.
+ // NOTE: supported cardinality types in dbMaps = "Set" or "List"
+ // In Titan (and ex5.json), those go in as "SET" and "LIST"
+ DbMaps dbMaps = IngestModelMoxyOxm.dbMapsContainer.get(AAIConfig.get(AAIConstants.AAI_DEFAULT_API_VERSION_PROP));
+
+ if( dbMaps.PropertyDataTypeMap.containsKey(propName) ){
+ String propDataType = dbMaps.PropertyDataTypeMap.get(propName);
+ if( propDataType != null && propDataType.startsWith(cardinalityType) ){
+ return true;
+ }
+ }
+ return false;
+
+ } // End of checkPropCardinality()
+
+ /**
+ * Convert type if needed.
+ *
+ * @param propName the prop name
+ * @param val the val
+ * @return convertedValue (if it was a String but needed to be a Boolean)
+ * @throws AAIException the AAI exception
+ */
+ public static Object convertTypeIfNeeded( String propName, Object val )
+ throws AAIException {
+ // Make sure the dataType of the passed-in Object matches what the DB expects
+
+ // NOTE: since this is a fix very late in our dev cycle, we'll just fix the scenarios that
+ // we're having trouble with which is Strings getting into the db which should be going in as
+ // Booleans or Integers.
+ DbMaps dbMaps = IngestModelMoxyOxm.dbMapsContainer.get(AAIConfig.get(AAIConstants.AAI_DEFAULT_API_VERSION_PROP));
+
+ if( dbMaps.PropertyDataTypeMap.containsKey(propName) ){
+ String dbExpectedDataType = dbMaps.PropertyDataTypeMap.get(propName);
+ if( dbExpectedDataType != null
+ && dbExpectedDataType.equals("Boolean")
+ && val != null
+ && !(val instanceof Boolean) ){
+ String valStr = val.toString().trim();
+ if( valStr.equals("true") || valStr.equals("True") || valStr.equals("TRUE") ){
+ return Boolean.valueOf("true");
+ }
+ else if( valStr.equals("false") || valStr.equals("False") || valStr.equals("FALSE") ){
+ return Boolean.valueOf("false");
+ }
+ else {
+ String emsg = "Error trying to convert value: [" + valStr + "] to a Boolean for property + " + propName + "\n";
+ throw new AAIException("AAI_6120", emsg);
+ }
+ }
+ else if( dbExpectedDataType != null
+ && dbExpectedDataType.equals("Integer")
+ && val != null
+ && !(val.toString().trim().equals(""))
+ && !(val instanceof Integer) ){
+ String valStr = val.toString().trim();
+ Integer newInt;
+ try {
+ newInt = Integer.valueOf(valStr);
+ return newInt;
+ }
+ catch( Exception e ){
+ String emsg = "Error trying to convert value: [" + valStr + "] to an Integer for property + " + propName + "\n";
+ throw new AAIException("AAI_6120", emsg);
+ }
+ }
+ }
+
+ // If it didn't need to be converted, just return it.
+ return val;
+
+ } // End of convertTypeIfNeeded()
+
+
+
+ /**
+ * This vertex not reachable.
+ *
+ * @param transId the trans id
+ * @param fromAppId the from app id
+ * @param graph the graph
+ * @param v the v
+ * @param version the version
+ * @return boolean
+ */
+ public static boolean thisVertexNotReachable( String transId, String fromAppId, TitanTransaction graph, TitanVertex v, String version){
+ if( v == null ){
+ return true;
+ }
+ else {
+ try {
+ v.id().toString();
+ }
+ catch( Exception ex ){
+ // Could not get this -- sometimes we're holding a vertex object that has gotten deleted, so
+ // when we try to get stuff from it, we get an "Element Has Been Removed" error from Titan
+ return true;
+ }
+ }
+
+ return false;
+
+ } // End of thisVertexNotReachable()
+
+ /**
+ * This vertex has bad edges.
+ *
+ * @param transId the trans id
+ * @param fromAppId the from app id
+ * @param graph the graph
+ * @param v the v
+ * @param version the version
+ * @return boolean
+ */
+ public static boolean thisVertexHasBadEdges( String transId, String fromAppId, TitanTransaction graph, TitanVertex v, String version){
+
+ Iterator <Edge> eItor = v.edges(Direction.BOTH);
+ while( eItor.hasNext() ){
+ Edge e = null;
+ e = eItor.next();
+ if( e == null ){
+ return true;
+ }
+ Vertex vIn = e.inVertex();
+ if( (vIn == null) || (vIn.<String>property("aai-node-type").orElse(null) == null) ){
+ // this is a bad edge because it points to a vertex that isn't there anymore
+ return true;
+ }
+
+ Vertex vOut = e.outVertex();
+ if( (vOut == null) || (vOut.<String>property("aai-node-type").orElse(null) == null) ){
+ // this is a bad edge because it points to a vertex that isn't there anymore
+ return true;
+ }
+ }
+
+ // If we made it to here, the vertex's edges must be ok.
+ return false;
+
+ } // End of thisVertexHasBadEdges()
+
+
+ /**
+ * This vertex is A phantom.
+ *
+ * @param transId the trans id
+ * @param fromAppId the from app id
+ * @param graph the graph
+ * @param v the v
+ * @param version the version
+ * @return boolean
+ * @throws AAIException the AAI exception
+ */
+ public static boolean thisVertexIsAPhantom( String transId, String fromAppId, TitanTransaction graph, TitanVertex v, String version )
+ throws AAIException {
+
+
+ // The kind of Phantom we're looking for is the kind that we sometimes get when we do a select without
+ // using key properties. They can be in the database as a vertex, but the indexes that should point to
+ // them are not working -- so they cannot be used by normal interfaces (like the REST API) which means
+ // that if we return it, it can mess up a caller who tries to use it.
+ if( v == null ){
+ return true;
+ }
+ String thisVid = v.id().toString();
+
+ DbMaps dbMaps = IngestModelMoxyOxm.dbMapsContainer.get(AAIConfig.get(AAIConstants.AAI_DEFAULT_API_VERSION_PROP));
+
+ Object propOb = v.<Object>property("aai-node-type").orElse(null);
+ if( propOb == null ){
+ // This vertex does not have an aai-node-type ---> it is messed up
+ return true;
+ }
+ String nType = propOb.toString();
+ if( ! dbMaps.NodeKeyProps.containsKey(nType) ){
+ // This node Type does not have keys defined
+ // This could just be bad reference data, so we will not flag this guy, but we
+ // can't really do our test...
+ return false;
+ }
+
+ HashMap <String,Object> propHashWithKeys = new HashMap<String, Object>();
+ Collection <String> keyProps = null;
+ try {
+ keyProps = getNodeKeyPropNames(transId, fromAppId, nType, version);
+ }
+ catch (AAIException ex) {
+ // something wrong with getting this guy's key property names - we'll abandon this test...
+ return false;
+ }
+
+ Iterator <String> keyPropI = keyProps.iterator();
+ while( keyPropI.hasNext() ){
+ String propName = keyPropI.next();
+ String propVal = "";
+ Object ob = v.<Object>property(propName).orElse(null);
+ if( ob != null ){
+ propVal = ob.toString();
+ }
+ propHashWithKeys.put(propName, propVal);
+ }
+ try {
+ // Note - We can get more than one back since some nodes need a dep. node for uniqueness.
+ // We don't care about that -- we just want to make sure we can get this vertex back when
+ // we're searching with it's indexed fields.
+ // NOTE - we're passing the skipGroomCheck to getNodes so we don't wind up in an infinite loop
+ ArrayList <TitanVertex> vertList2 = getNodes( transId, fromAppId, graph, nType, propHashWithKeys, false, version, true );
+ Iterator<TitanVertex> iter2 = vertList2.iterator();
+ while( iter2.hasNext() ){
+ TitanVertex tvx2 = iter2.next();
+ String foundId = tvx2.id().toString();
+ if( foundId.equals( thisVid ) ){
+ // We could get back the vertex by looking it up using key properties... That's good.
+ return false;
+ }
+ }
+ }
+ catch (Exception e2) {
+ //String msg = " Error encountered for this vertex id: [" + thisVid +
+ // "]. Caught this exception: " + e2.toString();
+ // Something messed up - but that doesn't prove that this is a phantom.
+ return false;
+ }
+
+ // If we dropped down to here, we have looked but could not pull the vertex out of the
+ // db using it's key fields, so it gets flagged as a Phantom.
+ return true;
+
+ } // End of thisVertexIsAPhantom()
+
+
+ /**
+ * Gets the node by unique key.
+ *
+ * @param transId the trans id
+ * @param fromAppId the from app id
+ * @param graph the graph
+ * @param aaiUniquekey the aai uniquekey
+ * @return the node by unique key
+ */
+ public TitanVertex getNodeByUniqueKey(String transId, String fromAppId, TitanTransaction graph, String aaiUniquekey) {
+
+ TitanVertex vert = null;
+
+ Iterator<?> vertI = graph.query().has("aai-unique-key", aaiUniquekey).vertices().iterator();
+
+ if( vertI != null && vertI.hasNext()) {
+ // We found a vertex that meets the input criteria.
+ vert = (TitanVertex) vertI.next();
+ }
+
+ return vert;
+ }
+
+
+
+}
+
diff --git a/aai-traversal/src/main/java/org/openecomp/aai/dbgraphgen/ModelBasedProcessing.java b/aai-traversal/src/main/java/org/openecomp/aai/dbgraphgen/ModelBasedProcessing.java
new file mode 100644
index 0000000..f51e67b
--- /dev/null
+++ b/aai-traversal/src/main/java/org/openecomp/aai/dbgraphgen/ModelBasedProcessing.java
@@ -0,0 +1,3718 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * org.openecomp.aai
+ * ================================================================================
+ * Copyright (C) 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=========================================================
+ */
+
+package org.openecomp.aai.dbgraphgen;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.ListIterator;
+import java.util.Map;
+import java.util.Optional;
+import java.util.Set;
+import java.util.concurrent.Callable;
+import java.util.concurrent.TimeUnit;
+
+import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversal;
+import org.apache.tinkerpop.gremlin.structure.Vertex;
+import org.apache.tinkerpop.gremlin.structure.VertexProperty;
+
+import org.openecomp.aai.db.DbMethHelper;
+import org.openecomp.aai.db.props.AAIProperties;
+import org.openecomp.aai.dbgen.PropertyLimitDesc;
+import org.openecomp.aai.exceptions.AAIException;
+import org.openecomp.aai.ingestModel.DbMaps;
+import org.openecomp.aai.ingestModel.IngestModelMoxyOxm;
+import org.openecomp.aai.introspection.Introspector;
+import org.openecomp.aai.introspection.Loader;
+import org.openecomp.aai.introspection.exceptions.AAIUnknownObjectException;
+import org.openecomp.aai.query.builder.QueryBuilder;
+import org.openecomp.aai.serialization.db.DBSerializer;
+import org.openecomp.aai.serialization.db.EdgeRules;
+import org.openecomp.aai.serialization.db.EdgeType;
+import org.openecomp.aai.serialization.engines.TransactionalGraphEngine;
+import org.openecomp.aai.util.AAIConfig;
+import org.openecomp.aai.util.AAIConstants;
+import com.att.eelf.configuration.EELFLogger;
+import com.att.eelf.configuration.EELFManager;
+import com.google.common.collect.ArrayListMultimap;
+import com.google.common.collect.Multimap;
+import com.google.common.util.concurrent.SimpleTimeLimiter;
+import com.google.common.util.concurrent.TimeLimiter;
+import com.google.common.util.concurrent.UncheckedTimeoutException;
+import com.thinkaurelius.titan.core.TitanVertex;
+
+/**
+ * Utility class that uses Model/Named-Query definitions to navigate the graph.
+ */
+public class ModelBasedProcessing{
+
+ private EELFLogger LOGGER = EELFManager.getInstance().getLogger(ModelBasedProcessing.class);
+ private final int MAX_LEVELS = 50; // max depth allowed for our model - to protect against infinite loop problems
+
+ private TransactionalGraphEngine engine;
+ private Loader loader;
+ private DBSerializer serializer;
+ private DbMethHelper dbMethHelper;
+
+ protected ModelBasedProcessing() {
+
+ }
+ public ModelBasedProcessing(Loader loader, TransactionalGraphEngine engine, DBSerializer serializer) {
+ this.loader = loader;
+ this.engine = engine;
+ this.serializer = serializer;
+ dbMethHelper = new DbMethHelper(loader, engine);
+ }
+ /**
+ * Gets the start nodes and model-ver's.
+ *
+ * @param transId the trans id
+ * @param fromAppId the from app id
+ * @param passedModelVersionId the passed model-version-id -- optional (unique id for a model-ver)
+ * @param passedModelId the passed model-invariant-id -- optional
+ * @param passedModelName the passed model-name -- optional
+ * @param passedTopNodeType the passed top node type -- optional (needed if neither model=invariant-id nor model-version-id is passed)
+ * @param startNodeFilterArrayOfHashes the start node filter array of hashes -- optional (used to locate the first node(s) of instance data)
+ * @param apiVer the api ver
+ * @return HashMap of startNodes and their corresponding model-version-id's
+ * @throws AAIException the AAI exception
+ */
+ public Map<String,String> getStartNodesAndModVersionIds( String transId, String fromAppId,
+ String passedModelVersionId,
+ String passedModelInvId,
+ String passedModelName,
+ String passedTopNodeType,
+ List<Map<String,Object>> startNodeFilterArrayOfHashes,
+ String apiVer )
+ throws AAIException{
+ // ----------------------------------------------------------------------------------------------------
+ // Get a hash for all start-nodes (key = vtxId, val = modelVersionId that applies)
+ // If no start-node-key info is passed, then use either the passed modelVersion or
+ // the passed model-invariant-id or model-name to collect them.
+ // If start-node-key info is given, use it instead to look for start-nodes.
+ // Note: if ONLY start-node-key info is given, then it would have to map to nodes which
+ // have persona data. Otherwise we'd have no way to know what model to collect data with.
+ // ----------------------------------------------------------------------------------------------------
+
+ Iterator<Vertex> startVerts = null;
+ Map<String, String> startVertInfo = new HashMap<>();
+
+ if( startNodeFilterArrayOfHashes.isEmpty() ){
+ // Since they did not give any data to find start instances, we will have to find them
+ // using whatever model-info they provided so we can use it to map to persona-data in the db.
+ if( (passedModelVersionId == null || passedModelVersionId.equals(""))
+ && (passedModelInvId == null || passedModelInvId.equals(""))
+ && (passedModelName == null || passedModelName.equals(""))){
+ throw new AAIException("AAI_6118", "ModelInvariantId or ModelName or ModelVersionId required if no startNodeFilter data passed.");
+ }
+ else {
+ // Use whatever model info they pass to find start-node instances
+ // Get the first/top named-query-element used by this query
+ if( passedModelVersionId != null && !passedModelVersionId.equals("") ){
+ // Need to look up the model-invariant-id and model-version to check against persona data
+ Vertex modVerVtx = getNodeUsingUniqueId(transId, fromAppId, "model-ver",
+ "model-version-id", passedModelVersionId);
+ Vertex modVtx = getModelGivenModelVer( modVerVtx, "" );
+ String calcModId = modVtx.<String>property("model-invariant-id").orElse(null);
+ // Now we can look up instances that match this model's info
+ if( calcModId != null ){
+ startVerts = this.engine.asAdmin().getReadOnlyTraversalSource().V().has("model-invariant-id-local",calcModId).has("model-version-id-local",passedModelVersionId);
+ }
+ }
+ else if( passedModelInvId != null && !passedModelInvId.equals("") ){
+ // They gave us the model-invariant-id
+ startVerts = this.engine.asAdmin().getReadOnlyTraversalSource().V().has("model-invariant-id-local",passedModelInvId);
+ }
+ else if( passedModelName != null && !passedModelName.equals("") ){
+ List<Vertex> modelVerVtxList = getModelVersUsingName(transId, fromAppId, passedModelName);
+ List<Vertex> startVtxList = new ArrayList<>();
+ // Need to look up the model-inv-ids and model-versions to check against persona data
+ if( !modelVerVtxList.isEmpty() ){
+ for( int i = 0; i < modelVerVtxList.size(); i++ ){
+ String calcModVerId = (modelVerVtxList.get(i)).<String>property("model-version-id").orElse(null);
+ Vertex modVtx = getModelGivenModelVer(modelVerVtxList.get(i),"");
+ String calcModInvId = modVtx.<String>property("model-invariant-id").orElse(null);
+ // Now we can look up instances that match this model's info
+ Iterator<Vertex> tmpStartIter = this.engine.asAdmin().getReadOnlyTraversalSource().V().has("model-invariant-id-local",calcModInvId).has("model-version-id-local",calcModVerId);
+ while( tmpStartIter.hasNext() ){
+ Vertex tmpStartVert = (Vertex) tmpStartIter.next();
+ startVtxList.add(tmpStartVert);
+ }
+ }
+ }
+ if( !startVtxList.isEmpty() ){
+ startVerts = startVtxList.iterator();
+ }
+ }
+ }
+
+ if( startVerts != null ){
+ while( startVerts.hasNext() ){
+ Vertex tmpStartVert = (Vertex) startVerts.next();
+ String vid = tmpStartVert.id().toString();
+ String tmpModId = tmpStartVert.<String>property("model-invariant-id-local").orElse(null);
+ String tmpModVerId = tmpStartVert.<String>property("model-version-id-local").orElse(null);
+ startVertInfo.put(vid, tmpModVerId);
+ }
+ }
+ if( startVertInfo.isEmpty() ){
+ throw new AAIException("AAI_6114", "Start Node(s) could not be found for model data passed. " +
+ "(modelVersionId = [" + passedModelVersionId +
+ "], modelInvariantId = [" + passedModelInvId +
+ "], modelName = [" + passedModelName +
+ "])");
+ }
+
+ return startVertInfo;
+ }
+ else {
+ // Use start-node filter info to find start-node(s) - Note - there could also be model info passed that we'll need
+ // to use to trim down the set of start-nodes that we find based on the startNodeFilter data.
+ String modTopNodeType ="";
+ String modInfoStr = "";
+ if( passedModelVersionId != null && !passedModelVersionId.equals("") ){
+ modTopNodeType = getModelVerTopWidgetType( transId, fromAppId, passedModelVersionId, "", "" );
+ modInfoStr = "modelVersionId = (" + passedModelVersionId + ")";
+ }
+ else if( passedModelInvId != null && !passedModelInvId.equals("") ){
+ modTopNodeType = getModelVerTopWidgetType( transId, fromAppId,"", passedModelInvId, "" );
+ modInfoStr = "modelId = (" + passedModelInvId + ")";
+ }
+ else if( passedModelName != null && !passedModelName.equals("") ){
+ modTopNodeType = getModelVerTopWidgetType( transId, fromAppId,"", "", passedModelName );
+ modInfoStr = "modelName = (" + passedModelName + ")";
+ }
+
+ if( modTopNodeType.equals("") ){
+ if( (passedTopNodeType == null) || passedTopNodeType.equals("") ){
+ String msg = "Could not determine the top-node nodeType for this request. modelInfo: [" + modInfoStr + "]";
+ throw new AAIException("AAI_6118", msg);
+ }
+ else {
+ // We couldn't find a top-model-type based on passed in model info, but they
+ // gave us a type to use -- so use it.
+ modTopNodeType = passedTopNodeType;
+ }
+ }
+ else {
+ // we did get a topNode type based on model info - make sure it doesn't contradict
+ // the passsed-in one (if there is one)
+ if( passedTopNodeType != null && !passedTopNodeType.equals("")
+ && !passedTopNodeType.equals(modTopNodeType) ){
+ throw new AAIException("AAI_6120", "topNodeType passed in [" + passedTopNodeType
+ + "] does not match nodeType derived for model info passed in: ["
+ + modTopNodeType + "]");
+ }
+ }
+
+ List<String> modelVersionIds2Check = new ArrayList<>();
+ if( (passedModelName != null && !passedModelName.equals("")) ){
+ // They passed a modelName, so find all the model UUIDs (model-version-id's) that map to this
+ modelVersionIds2Check = getModelVerIdsUsingName(transId, fromAppId, passedModelName);
+ }
+ if( (passedModelVersionId != null && !passedModelVersionId.equals("")) ){
+ // They passed in a modelNameVersionId
+ if( modelVersionIds2Check.isEmpty() ){
+ // There was no modelName passed, so we can use the passed modelNameVersionId
+ modelVersionIds2Check.add(passedModelVersionId);
+ }
+ else if( modelVersionIds2Check.contains(passedModelVersionId) ){
+ // The passed in uuid does not conflict with what we got using the passed-in modelName.
+ // We'll just use the passed in uuid in this case.
+ // Hopefully they would not be passing strange combinations like this, but we'll try to deal with it.
+ modelVersionIds2Check = new ArrayList<>(); // Clear out what we had
+ modelVersionIds2Check.add(passedModelVersionId);
+ }
+ }
+
+ // We should now be OK with our topNodeType for this request, so we can look for the actual startNodes
+ for( int i=0; i < startNodeFilterArrayOfHashes.size(); i++ ){
+ // Locate the starting node which will be used to look which corresponds to this set of filter data
+ Vertex startVtx = null;
+ try {
+ Optional<Vertex> result = dbMethHelper.searchVertexByIdentityMap(modTopNodeType, startNodeFilterArrayOfHashes.get(i));
+ if (!result.isPresent()) {
+ throw new AAIException("AAI_6114", "No Node of type " + modTopNodeType + " found for properties");
+ }
+ startVtx = result.get();
+ }
+ catch( AAIException e ){
+ String msg = "Could not find startNode of type = [" + modTopNodeType + "], given these params: "
+ + startNodeFilterArrayOfHashes.get(i) + ". msg # from getUniqueNode() = " + e.getMessage();
+ throw new AAIException("AAI_6114", msg);
+ }
+
+ String vid = startVtx.id().toString();
+ String personaModInvId = startVtx.<String>property("model-invariant-id-local").orElse(null);
+ String personaModVerId = startVtx.<String>property("model-version-id-local").orElse(null);
+
+ // Either this start-node has persona info (which should not contradict any passed-in model info)
+ // or they should have passed in the model to use - so we'd just use that.
+ if( personaModVerId != null && !personaModVerId.equals("") ){
+ // There is persona data in this start-node. So make sure it doesn't contradict any "passed" stuff
+ if( modelVersionIds2Check.isEmpty()
+ && (passedModelInvId == null || passedModelInvId.equals("")) ){
+ // They didn't pass any model info, so use the persona one.
+ startVertInfo.put(vid, personaModVerId);
+ }
+ else if( modelVersionIds2Check.isEmpty()
+ && (passedModelInvId != null && !passedModelInvId.equals("")) ){
+ // They passed in just the modelId - so check it
+ if( passedModelInvId.equals(personaModInvId) ){
+ startVertInfo.put(vid, personaModVerId);
+ }
+ }
+ else if( !modelVersionIds2Check.isEmpty()
+ && (passedModelInvId == null || passedModelInvId.equals("")) ){
+ // They passed in just modelVersionId - so check
+ if( modelVersionIds2Check.contains(personaModVerId) ){
+ startVertInfo.put(vid, personaModVerId);
+ }
+ }
+ else if( !modelVersionIds2Check.isEmpty()
+ && (passedModelInvId != null && !passedModelInvId.equals("")) ){
+ // We have BOTH a modelVersionIds and a modelId to check
+ if( passedModelInvId.equals(personaModInvId)
+ && modelVersionIds2Check.contains(personaModVerId) ){
+ startVertInfo.put(vid, personaModVerId);
+ }
+ }
+ }
+ else {
+ // This start node did not have persona info -- so we will use the passed in model info if they passed one
+ if( passedModelVersionId!= null && !passedModelVersionId.equals("") ){
+ // The model-version-id uniquely identifies a model-ver, so we can use it.
+ startVertInfo.put(vid, passedModelVersionId);
+ }
+ else {
+ throw new AAIException("AAI_6118", "Found startNode but since it does not have persona data, the " +
+ " model-version-id is required. ");
+ }
+ }
+ }
+ }
+
+ return startVertInfo;
+
+ }//end of getStartNodesAndModVersionIds()
+
+
+ /**
+ * Query by model. (really model-ver)
+ *
+ * @param transId the trans id
+ * @param fromAppId the from app id
+ * @param modelVersionId the model-version-id (unique id in model-ver)
+ * @param modelInvariantId the model-invariant-id (unique id in model)
+ * @param modelName the model name
+ * @param topNodeType - optional (needed if neither model-invariant-id nor model-version-id is passed)
+ * @param startNodeFilterArrayOfHashes the start node filter array of hashes -- optional (used to locate the first node(s) of instance data)
+ * @param apiVer the api ver
+ * @return resultSet
+ * @throws AAIException the AAI exception
+ */
+ public List<ResultSet> queryByModel( String transId, String fromAppId,
+ String modelVersionId,
+ String modelInvariantId,
+ String modelName,
+ String topNodeType,
+ List<Map<String,Object>> startNodeFilterArrayOfHashes,
+ String apiVer )
+ throws AAIException{
+
+ final String transId_f = transId;
+ final String fromAppId_f = fromAppId;
+ final String modelVersionId_f = modelVersionId;
+ final String modelInvId_f = modelInvariantId;
+ final String modelName_f = modelName;
+ final String topNodeType_f = topNodeType;
+ final List<Map<String,Object>> startNodeFilterArrayOfHashes_f = startNodeFilterArrayOfHashes;
+ final String apiVer_f = apiVer;
+
+ // Find out what our time-limit should be
+ int timeLimitSec = 0;
+ String timeLimitString = AAIConfig.get("aai.model.query.timeout.sec");
+ if( timeLimitString != null && !timeLimitString.equals("") ){
+ try {
+ timeLimitSec = Integer.parseInt(timeLimitString);
+ }
+ catch ( Exception nfe ){
+ // Don't worry, we will leave the limit as zero - which tells us not to use it.
+ }
+ }
+
+ if( timeLimitSec <= 0 ){
+ // We will NOT be using a timer
+ return queryByModel_Timed( transId, fromAppId,
+ modelVersionId,
+ modelInvariantId,
+ modelName,
+ topNodeType,
+ startNodeFilterArrayOfHashes,
+ apiVer );
+ }
+
+ List<ResultSet> resultList = new ArrayList<>();
+ TimeLimiter limiter = new SimpleTimeLimiter();
+ try {
+ resultList = limiter.callWithTimeout(new Callable <List<ResultSet>>() {
+ public List<ResultSet> call() throws AAIException {
+ return queryByModel_Timed( transId_f, fromAppId_f,
+ modelVersionId_f,
+ modelInvId_f,
+ modelName_f,
+ topNodeType_f,
+ startNodeFilterArrayOfHashes_f,
+ apiVer_f );
+ }
+ }, timeLimitSec, TimeUnit.SECONDS, true);
+ }
+ catch (AAIException ae) {
+ // Re-throw AAIException so we get can tell what happened internally
+ throw ae;
+ }
+ catch (UncheckedTimeoutException ute) {
+ throw new AAIException("AAI_6140", "Query Processing Limit exceeded. (limit = " + timeLimitSec + " seconds)");
+ }
+ catch (Exception e) {
+ throw new AAIException("AAI_6128", "Unexpected exception in queryByModel(): " + e.getMessage() );
+ }
+
+ return resultList;
+ }
+
+
+ /**
+ * Query by model (model-ver) timed.
+ *
+ * @param transId the trans id
+ * @param fromAppId the from app id
+ * @param modelVersionId the model-version-id (unique id in model-ver)
+ * @param modelInvariantId the model-invariant-id (unique id in model)
+ * @param modelName the model name
+ * @param topNodeType the top node type
+ * @param startNodeFilterArrayOfHashes the start node filter array of hashes
+ * @param apiVer the api ver
+ * @return the array list
+ * @throws AAIException the AAI exception
+ */
+ public List<ResultSet> queryByModel_Timed( String transId, String fromAppId,
+ String modelVersionId,
+ String modelInvariantId,
+ String modelName,
+ String topNodeType,
+ List<Map<String,Object>> startNodeFilterArrayOfHashesVal,
+ String apiVer )
+ throws AAIException{
+
+ DbMaps dbMaps = IngestModelMoxyOxm.dbMapsContainer.get(AAIConfig.get(AAIConstants.AAI_DEFAULT_API_VERSION_PROP));
+
+ List<ResultSet> resultArray = new ArrayList<>();
+
+ // NOTE: this method can be used for different styles of queries:
+ // a) They could pass neither a modelVersionId or a modelInvariantId but just pass a set of data defining start-nodes.
+ // Note - with no model info, we need them to pass the startNodeType for us to be able to use the
+ // start-node-filter data. We would look at each start node and ensure that each has persona-model info.
+ // Then use whatever model corresponds to each instance to pull that instance's data.
+ // b) They could pass a modelInvariantId, but no modelVersionId and no startNode info. In this case, we
+ // Would look in the database for all nodes that have a model-invariant-id-local that matches what was
+ // passed, and then for each of those instances, pull the data based on the corresponding model.
+ // c) They could pass a model-version-id, but no startNode info. We'd make sure that if a
+ // model-invariant-id was also passed, that it does not conflict - but it really should be null if they
+ // are passing a full model-version-id. Like case -b-, we'd do a query for all nodes
+ // that have persona info that corresponds to the model-version-id passed and then
+ // collect data for each one.
+ // d) They could pass either modelVersionId or modelInvariantId AND startNodeFilter info. In this case we
+ // would look at the model info to figure out what the top-node-type is, then look at the
+ // top-node instances based on the startNodeFilter. We'd only collect data for each instance if
+ // it's persona model info matches what was passed in.
+
+
+ // Sorry to do this, but code that gets called with an empty hash as the first array element was causing errors
+ List<Map<String,Object>> startNodeFilterArrayOfHashes = new ArrayList <Map<String,Object>>();
+ if( !startNodeFilterArrayOfHashesVal.isEmpty() ){
+ Map<String,Object> tmpH = startNodeFilterArrayOfHashesVal.get(0);
+ if( !tmpH.isEmpty() ){
+ for( int i=0; i < startNodeFilterArrayOfHashesVal.size(); i++ ){
+ startNodeFilterArrayOfHashes.add( startNodeFilterArrayOfHashesVal.get(i) );
+ }
+ }
+ }
+
+ // ----------------------------------------------------------------------------------------------------------
+ // Get a Hash of all the start-nodes (top instance-data node for a model-ver where we will
+ // start collecting data) for startNode2ModelVerHash:
+ // key = vertex-id for the startNode,
+ // value = model-version-id for the corresponding model-ver
+ // ----------------------------------------------------------------------------------------------------------
+ Map<String, String> startNode2ModelVerHash = getStartNodesAndModVersionIds( transId, fromAppId,
+ modelVersionId, modelInvariantId, modelName, topNodeType,
+ startNodeFilterArrayOfHashes, apiVer );
+
+ //System.out.println("\nDEBUG -- Here's a dump of the startnodes/model-vers: " + startNode2ModelVerHash.toString());
+
+ // --------------------------------------------------------------------------------------------------------
+ // Figure out what-all models (model-ver nodes) we will be dealing with
+ // Note - Instances must all use the same type of start-node, but do not have to all use the same model-ver.
+ // --------------------------------------------------------------------------------------------------------
+ Map<String, Vertex> distinctModelVersHash = new HashMap<>();
+ // For distinctModelVersHash: key = modelVersionId, val= modelVerVertex
+ String startNodeType = "";
+ if( topNodeType != null && !topNodeType.equals("") ){
+ startNodeType = topNodeType;
+ }
+
+ List<String> skipModelVerIdList = new ArrayList<>();
+ List<String> skipStartVertVerIdList = new ArrayList<>();
+ Set <String> snKeySet = startNode2ModelVerHash.keySet();
+ Iterator<String> startNodeIterator = snKeySet.iterator();
+ while( startNodeIterator.hasNext() ){
+ String modVerIdKey = (String) startNodeIterator.next();
+ String modVerId = startNode2ModelVerHash.get(modVerIdKey);
+ if( !distinctModelVersHash.containsKey(modVerId) ){
+ // First time seeing this model-version-id
+ Vertex modVerVtx = getNodeUsingUniqueId(transId, fromAppId, "model-ver",
+ "model-version-id", modVerId);
+ String tmpNodeType = "";
+ try {
+ tmpNodeType = getModelVerTopWidgetType( modVerVtx, "" );
+ }
+ catch( AAIException ae ){
+ // There must be some old bad data in the db - we will skip over this model-ver since its
+ // model is not good anymore - but will log that this is happening.
+ skipModelVerIdList.add(modVerId);
+ skipStartVertVerIdList.add(modVerIdKey);
+ System.out.println(">>> WARNING - will not collect model data for this vertex since " +
+ "it uses an inconsistant model-ver model. Model-version-id = " + modVerId );
+ }
+
+ if( tmpNodeType != null && !tmpNodeType.equals("") ){
+ if( startNodeType.equals("") ){
+ startNodeType = tmpNodeType;
+ }
+ else if( !startNodeType.equals(tmpNodeType) ){
+ String msg = "Conflict between startNode types for models involved: [" + startNodeType
+ + "], [" + tmpNodeType + "]";
+ throw new AAIException("AAI_6125", msg);
+ }
+ distinctModelVersHash.put(modVerId, modVerVtx);
+ }
+ }
+ }
+
+ //System.out.println("\nDEBUG -- Here's a dump of the DISTINCT model-ver hash: " + distinctModelVersHash.toString() );
+
+ // ------------------------------------------------------------------------------------------------------
+ // Get the "valid-next-step" hash for each distinct model-ver
+ // While we're at it, get a mapping of model-invariant-id|model-version to model-version-id for
+ // the model-vers being used
+ // ------------------------------------------------------------------------------------------------------
+ Map<String, Multimap<String, String>> validNextStepHash = new HashMap<>();
+ // validNextStepHash: key = modelVerId, value = nextStepMap
+ Set <String> keySet = distinctModelVersHash.keySet();
+ Iterator<String> modelVerIterator = keySet.iterator();
+ while( modelVerIterator.hasNext() ){
+ String modVerKey = (String) modelVerIterator.next();
+ if( ! skipModelVerIdList.contains(modVerKey) ){
+ Vertex modelVerVtx = (Vertex)distinctModelVersHash.get(modVerKey);
+ Multimap<String, String> tmpTopoMap = genTopoMap4ModelVer( transId, fromAppId,
+ modelVerVtx, modVerKey, dbMaps );
+ validNextStepHash.put(modVerKey, tmpTopoMap);
+ }
+ }
+
+ // -------------------------------------------------------------------------------------------------
+ // Figure out what the "start-node" for each instance will be (plus the info we will use to
+ // represent that in our topology)
+ // -------------------------------------------------------------------------------------------------
+ List<String> failedPersonaCheckVids = new ArrayList<>();
+ Map<String, String> firstStepInfoHash = new HashMap<>();
+ // For firstStepInfoHash: key = startNodeVtxId, val=topNodeType plus personaData if applicable
+ // ie. the value is what we'd use as the "first-step" for this model.
+ if( !nodeTypeSupportsPersona( startNodeType, dbMaps) ){
+ // This node type doesn't have persona info, so we just use startNodeType for the first-step-info
+ snKeySet = startNode2ModelVerHash.keySet();
+ startNodeIterator = snKeySet.iterator();
+ while( startNodeIterator.hasNext() ){
+ String vtxKey = (String) startNodeIterator.next();
+ firstStepInfoHash.put(vtxKey,startNodeType);
+ }
+ }
+ else {
+ // Need to check that this node's persona data is good and if it is - use it for the first step info
+ snKeySet = startNode2ModelVerHash.keySet();
+ startNodeIterator = snKeySet.iterator();
+ while( startNodeIterator.hasNext() ){
+ String vtxKey = (String) startNodeIterator.next();
+ Iterator<Vertex> vtxIterator = this.engine.asAdmin().getReadOnlyTraversalSource().V(vtxKey);
+ Vertex tmpVtx = (Vertex)vtxIterator.next();
+ String thisVtxModelVerId = startNode2ModelVerHash.get(vtxKey);
+ if( skipModelVerIdList.contains(thisVtxModelVerId) ){
+ // Skip this vertex because it uses a model-ver that is bad
+ continue;
+ }
+ Vertex modelVerVtx = (Vertex)distinctModelVersHash.get(thisVtxModelVerId);
+ Vertex modelVtx = getModelGivenModelVer( modelVerVtx, "" );
+ String modInvId = modelVtx.<String>property("model-invariant-id").orElse(null);
+ String personaModInvId = tmpVtx.<String>property("model-invariant-id-local").orElse(null);
+ String personaModVerId = tmpVtx.<String>property("model-version-id-local").orElse(null);
+ if( modInvId.equals(personaModInvId) && thisVtxModelVerId.equals(personaModVerId) ){
+ String tmpPersonaInfoStr = startNodeType + "," + personaModInvId + "," + personaModVerId;
+ firstStepInfoHash.put(vtxKey, tmpPersonaInfoStr );
+ }
+ else {
+ // we won't use this start node below when we collect data because it should have
+ // had persona data that matched it's model - but it did not.
+ failedPersonaCheckVids.add(vtxKey);
+ }
+ }
+ }
+
+ //System.out.println("\nDEBUG -- Here's a dump of the firstStepInfoHash hash: " + firstStepInfoHash.toString() );
+
+ // ------------------------------------------------------------------------------------------------
+ // Loop through each start-node, collect it's data using collectInstanceData() and put the
+ // resultSet onto the resultArray.
+ // ------------------------------------------------------------------------------------------------
+
+ // Make sure they're not bringing back too much data
+ String maxString = AAIConfig.get("aai.model.query.resultset.maxcount");
+ if( maxString != null && !maxString.equals("") ){
+ int maxSets = 0;
+ try {
+ maxSets = Integer.parseInt(maxString);
+ }
+ catch ( Exception nfe ){
+ // Don't worry, we will leave the max as zero - which tells us not to use it.
+ }
+
+ if( maxSets > 0 && (startNode2ModelVerHash.size() > maxSets) ){
+ String msg = " Query returns " + startNode2ModelVerHash.size() + " resultSets. Max allowed is: " + maxSets;
+ throw new AAIException("AAI_6141", msg);
+ }
+ }
+
+ snKeySet = startNode2ModelVerHash.keySet();
+ startNodeIterator = snKeySet.iterator();
+ while( startNodeIterator.hasNext() ){
+ String topNodeVtxId = (String) startNodeIterator.next();
+ if( failedPersonaCheckVids.contains(topNodeVtxId) ){
+ // Skip this vertex because it failed it's persona-data check above
+ continue;
+ }
+ if( skipStartVertVerIdList.contains(topNodeVtxId) ){
+ // Skip this vertex because it uses a model-ver that is bad
+ continue;
+ }
+
+ Iterator<Vertex> vtxIterator = this.engine.asAdmin().getReadOnlyTraversalSource().V(topNodeVtxId);
+ Vertex tmpStartVtx = (Vertex)vtxIterator.next();
+ String elementLocationTrail = firstStepInfoHash.get(topNodeVtxId);
+ String modelVerId = startNode2ModelVerHash.get(topNodeVtxId);
+ Multimap<String, String> validNextStepMap = validNextStepHash.get(modelVerId);
+
+ List<String> vidsTraversed = new ArrayList<>();
+ Map<String,String> emptyDelKeyHash = new HashMap<>();
+ Map<String,String> emptyNQElementHash = new HashMap<>(); // Only applies to Named Queries
+ ResultSet tmpResSet = collectInstanceData( transId, fromAppId,
+ tmpStartVtx, elementLocationTrail,
+ validNextStepMap, vidsTraversed, 0, emptyDelKeyHash, emptyNQElementHash, apiVer );
+
+ resultArray.add(tmpResSet);
+ }
+
+ return resultArray;
+
+ }// queryByModel_Timed()
+
+
+
+ /**
+ * Run delete by model-ver.
+ *
+ * @param transId the trans id
+ * @param fromAppId the from app id
+ * @param modelVersionId the model version id -- unique id for a model-ver node
+ * @param topNodeTypeVal the top node type val -- required if no model-version-id is passed
+ * @param startNodeFilterHash the start node filter hash -- used to locate the first node of instance data
+ * @param apiVer the api ver
+ * @param resVersion the res version -- resourceVersion of the top/first widget in the model instance
+ * @return HashMap (keys = vertexIds that were deleted)
+ * @throws AAIException the AAI exception
+ */
+ public Map<String,String> runDeleteByModel( String transId, String fromAppId,
+ String modelVersionId, String topNodeTypeVal, Map<String,Object> startNodeFilterHash, String apiVer, String resVersion )
+ throws AAIException{
+
+ Map<String,String> retHash = new HashMap<>();
+
+ DbMaps dbMaps = IngestModelMoxyOxm.dbMapsContainer.get(AAIConfig.get(AAIConstants.AAI_DEFAULT_API_VERSION_PROP));
+
+ // Locate the Model-ver node to be used
+ Vertex modelVerVtx = null;
+ if( modelVersionId != null && !modelVersionId.equals("") ){
+ modelVerVtx = getNodeUsingUniqueId(transId, fromAppId, "model-ver",
+ "model-version-id", modelVersionId);
+ }
+ else {
+ // if they didn't pass the modelVersionId, then we need to use the startNode to figure it out
+ // Locate the starting node based on the start node params
+ if( topNodeTypeVal == null || topNodeTypeVal.equals("") ){
+ throw new AAIException("AAI_6118", "If no model info is passed, then topNodeType is required. ");
+ }
+
+ Optional<Vertex> result = dbMethHelper.searchVertexByIdentityMap(topNodeTypeVal, startNodeFilterHash);
+ if (!result.isPresent()) {
+ throw new AAIException("AAI_6114", "No Node of type " + topNodeTypeVal + " found for properties");
+ }
+ Vertex startVtx = result.get();
+
+ String startVertModVerId = startVtx.<String>property("model-version-id-local").orElse(null);
+ modelVerVtx = getNodeUsingUniqueId(transId, fromAppId, "model-ver",
+ "model-version-id", startVertModVerId);
+ }
+
+ if( modelVerVtx == null ){
+ throw new AAIException("AAI_6114", "Could not determine the model-ver for the given input parameters. ");
+ }
+
+ String topNType = "unknown";
+ String modelType = getModelTypeFromModelVer( modelVerVtx, "" );
+
+ if( modelType.equals("widget") ){
+ // If they want to delete using a widget-level model.. That is just a delete of the one
+ // instance of one of our nodes.
+ String widgModNodeType = modelVerVtx.<String>property("model-name").orElse(null);
+ if( (widgModNodeType == null) || widgModNodeType.equals("") ){
+ String msg = "Could not find model-name for the widget model [" + modelVersionId + "].";
+ throw new AAIException("AAI_6132", msg);
+ }
+ Optional<Vertex> result = dbMethHelper.locateUniqueVertex(widgModNodeType, startNodeFilterHash);
+ if (!result.isPresent()) {
+ throw new AAIException("AAI_6114", "No Node of type " + topNType + " found for properties");
+ }
+ Vertex widgetVtx = result.get();
+ String widgId = widgetVtx.id().toString();
+ serializer.delete(widgetVtx, resVersion, true);
+ retHash.put(widgId, widgModNodeType);
+ return retHash;
+ }
+
+ // ---------------------------------------------------------------------------------
+ // If we got to here, this must be either a service or resource model.
+ // So, we'll need to get a Hash of which parts of the model to delete.
+ // NOTE- deleteByModel is deleting data based on one specific version of a model.
+ // ---------------------------------------------------------------------------------
+ String chkFirstNodePersonaModInvId = "";
+ String chkFirstNodePersonaModVerId = "";
+ String personaData = "";
+ Vertex firstModElementVertex = getTopElementForSvcOrResModelVer( modelVerVtx, "" );
+ topNType = getModElementWidgetType( firstModElementVertex, "" );
+ if( (topNType == null) || topNType.equals("") ){
+ String msg = "Could not determine the top-node nodeType for model-version-id: [" + modelVersionId + "]";
+ throw new AAIException("AAI_6132", msg);
+ }
+ if( nodeTypeSupportsPersona(topNType, dbMaps) ){
+ Vertex modelVtx = getModelGivenModelVer(modelVerVtx,"");
+ chkFirstNodePersonaModInvId = modelVtx.<String>property("model-invariant-id").orElse(null);
+ chkFirstNodePersonaModVerId = modelVerVtx.<String>property("model-version-id").orElse(null);
+ personaData = "," + chkFirstNodePersonaModInvId + "," + chkFirstNodePersonaModVerId;
+ }
+
+ // Get the deleteKeyHash for this model
+ String incomingTrail = "";
+ Map<String, String> currentHash = new HashMap<>();
+ Map<String, Vertex> modConHash = new HashMap<>();
+ ArrayList <String> vidsTraversed = new ArrayList<>();
+ Map<String, String> delKeyHash = collectDeleteKeyHash( transId, fromAppId,
+ firstModElementVertex, incomingTrail, currentHash, vidsTraversed,
+ 0, dbMaps, modConHash,
+ chkFirstNodePersonaModInvId, chkFirstNodePersonaModVerId );
+
+
+ System.out.println("\n ----DEBUG -----: Delete Hash for model: [" + modelVersionId + "] looks like: ");
+ for( Map.Entry<String, String> entry : delKeyHash.entrySet() ){
+ System.out.println("key = [" + entry.getKey() + "], val = [" + entry.getValue() + "]");
+ }
+ System.out.println("\n -----");
+ // Locate the starting node that we'll use to start looking for instance data
+ Optional<Vertex> result = dbMethHelper.searchVertexByIdentityMap(topNType, startNodeFilterHash);
+ if (!result.isPresent()) {
+ throw new AAIException("AAI_6114", "No Node of type " + topNType + " found for properties");
+ }
+ Vertex startVtx = result.get();
+ if( !chkFirstNodePersonaModInvId.equals("") ){
+ // NOTE: For Service or Resource models, if this is a nodeType that supports persona's, then
+ // we need to make sure that the start node matches the persona values.
+ String startVertPersonaModInvId = startVtx.<String>property("model-invariant-id-local").orElse(null);
+ String startVertPersonaModVerId = startVtx.<String>property("model-version-id-local").orElse(null);
+ if( !chkFirstNodePersonaModInvId.equals(startVertPersonaModInvId)
+ || !chkFirstNodePersonaModVerId.equals(startVertPersonaModVerId) ){
+ String msg = "Persona-Model data mismatch for start node (" + topNType + "), " +
+ startNodeFilterHash ;
+ throw new AAIException("AAI_6114", msg);
+ }
+ }
+ String topVid = startVtx.id().toString();
+
+ // Read the model-ver into a Map for processing
+ Multimap <String, String> validNextStepMap = genTopoMap4ModelVer(transId, fromAppId,
+ modelVerVtx, modelVersionId, dbMaps );
+
+ // Collect the data
+ String elementLocationTrail = topNType + personaData;
+ vidsTraversed = new ArrayList<>();
+ Map<String,String> emptyHash = new HashMap<>();
+
+ // Pass emptyHash for the NQElement hash since that parameter only applies to Named Queries
+ ResultSet retResSet = collectInstanceData( transId, fromAppId,
+ startVtx, elementLocationTrail,
+ validNextStepMap, vidsTraversed, 0, delKeyHash, emptyHash, apiVer );
+
+ // Note: the new ResultSet will have each element tagged with the del flag so we'll know if it
+ // should be deleted or not - so loop through the results in a try-block since some things
+ // will get auto-deleted by parents before we get to them --- and try to remove each one.
+ String vidToResCheck = topVid;
+
+ retHash = deleteAsNeededFromResultSet( transId, fromAppId, retResSet,
+ vidToResCheck, apiVer, resVersion, emptyHash );
+ //String msgStr = "processed deletes for these vids: (\n"+ retHash.keySet().toString() + ").";
+
+ return retHash;
+
+ }// End of runDeleteByModel()
+
+
+
+ /**
+ * Delete as needed from result set.
+ *
+ * @param transId the trans id
+ * @param fromAppId the from app id
+ * @param resSet the res set
+ * @param vidToResCheck -- this vertex will need to have its resource-version checked
+ * @param apiVer the api ver
+ * @param resVersion the res version
+ * @param hashSoFar the hash so far -- hash of what's been deleted so far
+ * @return String
+ * @throws AAIException the AAI exception
+ */
+ public Map<String,String> deleteAsNeededFromResultSet( String transId, String fromAppId,
+ ResultSet resSet, String vidToResCheck, String apiVer, String resVersion, Map<String,String> hashSoFar )
+ throws AAIException
+ {
+ Map<String,String> retHash = new HashMap<>();
+ retHash.putAll( hashSoFar );
+ Boolean deleteIt = false;
+
+ if( resSet.getVert() == null ){
+ return retHash;
+ }
+
+ TitanVertex thisVtx = resSet.getVert();
+ String thisGuyId = "";
+ String thisNT = "";
+ String thisGuyStr = "";
+
+ try {
+ if( thisVtx != null && !thisVtx.isRemoved() ){
+ thisGuyId = thisVtx.id().toString();
+ thisNT = thisVtx.<String>property(AAIProperties.NODE_TYPE).orElse(null);
+ thisGuyStr = thisGuyId + "[" + thisNT + " found at:" + resSet.getLocationInModelSubGraph() + "]";
+ }
+ }
+ catch (Exception ex) {
+ // Sometimes things have already been deleted by the time we get to them - just log it.
+ LOGGER.warn("Exception when deleting " + thisGuyStr + ". msg = " + ex.getMessage(), ex);
+ }
+
+ if( thisGuyId.equals("") ){
+ // The vertex must have already been removed. Just return.
+ return retHash;
+ }
+ else {
+ if( resSet.getNewDataDelFlag() != null && resSet.getNewDataDelFlag().equals("T") ){
+ LOGGER.info(">> will try to delete this one >> " + thisGuyStr);
+
+ try {
+ Boolean requireResourceVersion = false;
+ if( thisGuyId.equals(vidToResCheck) ){
+ // This is the one vertex that we want to check the resourceId before deleting
+ requireResourceVersion = true;
+ }
+ this.serializer.delete(thisVtx, resVersion, requireResourceVersion);
+ }
+ catch (AAIException ae) {
+ String errorCode = ae.getErrorObject().getErrorCode();
+ if ( errorCode.equals("6130") || errorCode.equals("6131") ) {
+ // They didn't pass the correct resource-version for the top node.
+ throw ae;
+ }
+ else {
+ String errText = ae.getErrorObject().getErrorText();
+ String errDetail = ae.getMessage();
+ LOGGER.warn("Exception when deleting " + thisGuyStr + ". ErrorCode = " + errorCode +
+ ", errorText = " + errText + ", details = " + errDetail);
+ }
+ }
+ catch( Exception e ){
+ // We'd expect to get a "node not found" here sometimes depending on the order that
+ // the model has us finding / deleting nodes.
+ // Ignore the exception - but log it so we can see what happened.
+ LOGGER.warn("Exception when deleting " + thisGuyStr + e.getMessage(), e);
+ }
+
+ // We can't depend on a thrown exception to tell us if a node was deleted since it may
+ // have been auto=deleted before this removeAaiNode() call.
+ // --- Not sure if we would want to check anything here -- because the graph.commit() is done outside of this call.
+
+ deleteIt = true;
+ }
+ else {
+ // --- DEBUG ----
+ System.out.println(">>>>>>> NOT DELETING THIS ONE >>>> " + thisGuyStr );
+ List<String> retArr = dbMethHelper.getVertexProperties(thisVtx);
+ for( String info : retArr ){ System.out.println(info); }
+ // --- DEBUG ----
+ }
+ }
+
+ // Now call this routine for the sub-resultSets
+ List <ResultSet> subResultSetList = resSet.getSubResultSet();
+ Iterator <ResultSet> subResSetIter = subResultSetList.iterator();
+ while( subResSetIter.hasNext() ){
+ ResultSet tmpSubResSet = subResSetIter.next();
+ retHash = deleteAsNeededFromResultSet( transId, fromAppId, tmpSubResSet,
+ vidToResCheck, apiVer, resVersion, retHash );
+ }
+
+ if( deleteIt ){
+ retHash.put(thisGuyId, thisGuyStr);
+ }
+
+ return retHash;
+
+ }// deleteAsNeededFromResultSet()
+
+
+
+ /**
+ * Query by named query (old version).
+ *
+ * @param transId the trans id
+ * @param fromAppId the from app id
+ * @param namedQueryUuid the named query uuid
+ * @param startNodeFilterArrayOfHashes the start node filter array of hashes --used to locate the first nodes of instance data
+ * @param apiVer the api ver
+ * @return resultSet
+ * @throws AAIException the AAI exception
+ */
+ public List<ResultSet> queryByNamedQuery( String transId, String fromAppId,
+ String namedQueryUuid,
+ ArrayList <Map<String,Object>> startNodeFilterArrayOfHashes,
+ String apiVer )
+ throws AAIException{
+
+ String dummyCutPoint = null;
+ Map<String,Object> dummySecondaryFilterHash = null;
+
+ return queryByNamedQuery( transId, fromAppId,
+ namedQueryUuid,
+ startNodeFilterArrayOfHashes,
+ apiVer,
+ dummyCutPoint,
+ dummySecondaryFilterHash );
+ }
+
+
+ /**
+ * Query by named query.
+ *
+ * @param transId the trans id
+ * @param fromAppId the from app id
+ * @param namedQueryUuid the named query uuid
+ * @param startNodeFilterArrayOfHashes the start node filter array of hashes --used to locate the first nodes of instance data
+ * @param apiVer the api ver
+ * @param secondaryCutPoint nodeType where we will prune if secondary filter is not met
+ * @param secondaryFilterHash secondary filter params
+ * @return resultSet
+ * @throws AAIException the AAI exception
+ */
+ public List<ResultSet> queryByNamedQuery( String transId, String fromAppId,
+ String namedQueryUuid,
+ List<Map<String,Object>> startNodeFilterArrayOfHashes,
+ String apiVer,
+ String secondaryFilterCutPoint,
+ Map<String,Object> secondaryFilterHash )
+ throws AAIException{
+
+ final String transId_f = transId;
+ final String fromAppId_f = fromAppId;
+ final String namedQueryUuid_f = namedQueryUuid;
+ final List<Map<String,Object>> startNodeFilterArrayOfHashes_f = startNodeFilterArrayOfHashes;
+ final String apiVer_f = apiVer;
+ final String secondaryFilterCutPoint_f = secondaryFilterCutPoint;
+ final Map<String,Object> secondaryFilterHash_f = secondaryFilterHash;
+
+ // Find out what our time-limit should be
+ int timeLimitSec = 0;
+ String timeLimitString = AAIConfig.get("aai.model.query.timeout.sec");
+ if( timeLimitString != null && !timeLimitString.equals("") ){
+ try {
+ timeLimitSec = Integer.parseInt(timeLimitString);
+ }
+ catch ( Exception nfe ){
+ // Don't worry, we will leave the limit as zero - which tells us not to use it.
+ }
+ }
+
+ if( timeLimitSec <= 0 ){
+ // We will NOT be using a timer
+ return queryByNamedQuery_Timed( transId, fromAppId,
+ namedQueryUuid,
+ startNodeFilterArrayOfHashes,
+ apiVer,
+ secondaryFilterCutPoint_f,
+ secondaryFilterHash_f );
+ }
+
+ List<ResultSet> resultList = new ArrayList<>();
+ TimeLimiter limiter = new SimpleTimeLimiter();
+ try {
+ resultList = limiter.callWithTimeout(new Callable <List<ResultSet>>() {
+ public List<ResultSet> call() throws AAIException {
+ return queryByNamedQuery_Timed( transId_f, fromAppId_f,
+ namedQueryUuid_f,
+ startNodeFilterArrayOfHashes_f,
+ apiVer_f,
+ secondaryFilterCutPoint_f,
+ secondaryFilterHash_f );
+ }
+ }, timeLimitSec, TimeUnit.SECONDS, true);
+
+ }
+ catch (AAIException ae) {
+ // Re-throw AAIException so we get can tell what happened internally
+ throw ae;
+ }
+ catch (UncheckedTimeoutException ute) {
+ throw new AAIException("AAI_6140", "Query Processing Limit exceeded. (limit = " + timeLimitSec + " seconds)");
+ }
+ catch (Exception e) {
+ throw new AAIException("AAI_6128", "Unexpected exception in queryByNamedQuery(): " + e.getMessage() );
+ }
+
+ return resultList;
+ }
+
+
+ /**
+ * Query by named query timed.
+ *
+ * @param transId the trans id
+ * @param fromAppId the from app id
+ * @param namedQueryUuid the named query uuid
+ * @param startNodeFilterArrayOfHashes the start node filter array of hashes --used to locate the first nodes of instance data
+ * @param apiVer the api ver
+ * @param secondaryFilterCutPoint the nodeType where we will parse for the secondary Filter
+ * @param secondaryFilterHash the secondary filter hash
+ * @return resultSet
+ * @throws AAIException the AAI exception
+ */
+ public List<ResultSet> queryByNamedQuery_Timed( String transId, String fromAppId,
+ String namedQueryUuid,
+ List<Map<String,Object>> startNodeFilterArrayOfHashes,
+ String apiVer,
+ String secondaryFilterCutPoint,
+ Map<String,Object> secondaryFilterHash
+ )
+ throws AAIException{
+
+ // Locate the Query to be used
+ Vertex queryVtx = getNodeUsingUniqueId(transId, fromAppId, "named-query",
+ "named-query-uuid", namedQueryUuid);
+
+ // Get the first/top named-query-element used by this query
+ Iterator<Vertex> vertI = this.traverseIncidentEdges(EdgeType.TREE, queryVtx, "named-query-element");
+ Vertex firstNqElementVert = null;
+ int count = 0;
+ String topNType = "";
+ while( vertI != null && vertI.hasNext() ){
+ firstNqElementVert = vertI.next();
+ count++;
+ topNType = getNqElementWidgetType( transId, fromAppId, firstNqElementVert, "" );
+ }
+
+ if( count < 1 ){
+ // A named query must start with a single top element
+ throw new AAIException("AAI_6133", "No top-node defined for named-query-uuid = [" + namedQueryUuid + "]");
+ }
+ else if( count > 1 ){
+ // A named query should start with a single top element
+ throw new AAIException("AAI_6133", "More than one top-node defined for named-query-uuid = [" + namedQueryUuid + "]");
+ }
+ if( (topNType == null) || topNType.equals("") ){
+ String msg = "Could not determine the top-node nodeType for Named Query: [" + namedQueryUuid + "]";
+ throw new AAIException("AAI_6133", msg);
+ }
+
+ // Read the topology into a hash for processing
+ Multimap <String, String> validNextStepMap = genTopoMap4NamedQ(transId, fromAppId, queryVtx, namedQueryUuid);
+
+ List<Vertex> startVertList = new ArrayList<>();
+ if( startNodeFilterArrayOfHashes.size() == 1 ){
+ // If there is only one set of startFilter info given, then allow it to possibly not be
+ // defining just one start node.
+ Map<String, Object> cleanHash = new HashMap<>();
+ Map<String, Object> tmpHash = startNodeFilterArrayOfHashes.get(0);
+ Set <String> propKeySet = tmpHash.keySet();
+ Iterator<String> propIter = propKeySet.iterator();
+ Introspector obj = loader.introspectorFromName(topNType);
+ Set<String> keys = obj.getKeys();
+ boolean foundIndexedField = false;
+ int propertiesSet = 0;
+ while( propIter.hasNext() ){
+ String oldVtxKey = (String) propIter.next();
+ String newKey = oldVtxKey;
+ String [] parts = oldVtxKey.split("\\.");
+ if( parts.length == 2 ){
+ newKey = parts[1];
+ }
+ Object obVal = tmpHash.get(oldVtxKey);
+ if (obj.hasProperty(newKey)) {
+ if (keys.contains(newKey)) {
+ foundIndexedField = true;
+ }
+ obj.setValue(newKey, obVal);
+ propertiesSet++;
+ }
+ }
+ //we found all the properties in the startNodeType
+ if (propertiesSet == propKeySet.size()) {
+ if (foundIndexedField) {
+ QueryBuilder builder = this.engine.getQueryBuilder().exactMatchQuery(obj);
+ startVertList = builder.toList();
+ } else {
+ //force a filter from aai-node-type
+ QueryBuilder builder = this.engine.getQueryBuilder().createContainerQuery(obj).exactMatchQuery(obj);
+ startVertList = builder.toList();
+ }
+ } else {
+ Optional<Vertex> tmpVtx = dbMethHelper.searchVertexByIdentityMap(topNType, startNodeFilterArrayOfHashes.get(0));
+ // Only found one, so just use it.
+ if (tmpVtx.isPresent()) {
+ startVertList.add(tmpVtx.get());
+ }
+ }
+ }
+ else {
+ // Since they give an array of startNodeFilterHash info, we expect each one
+ // to just point to one node.
+ for( int i = 0; i < startNodeFilterArrayOfHashes.size(); i++ ){
+ // Locate the starting node for each set of data
+ Optional<Vertex> tmpVtx = dbMethHelper.searchVertexByIdentityMap(topNType, startNodeFilterArrayOfHashes.get(i));
+ if (tmpVtx.isPresent()) {
+ startVertList.add(tmpVtx.get());
+ }
+ }
+ }
+
+ if (startVertList.isEmpty()) {
+ throw new AAIException("AAI_6114", "No Node of type " + topNType + " found for properties");
+ }
+ // Make sure they're not bringing back too much data
+ String maxString = AAIConfig.get("aai.model.query.resultset.maxcount");
+ if( maxString != null && !maxString.equals("") ){
+ int maxSets = Integer.parseInt(maxString);
+ if( startVertList.size() > maxSets ){
+ String msg = " Query returns " + startVertList.size() + " resultSets. Max allowed is: " + maxSets;
+ throw new AAIException("AAI_6141", msg);
+ }
+ }
+
+ // Loop through each start node and get its data
+ List<ResultSet> resSetList = new ArrayList<>();
+ for( int i = 0; i < startVertList.size(); i++ ){
+ Vertex startVtx = startVertList.get(i);
+ // Collect the data
+ String elementLocationTrail = topNType;
+ ArrayList <String> vidsTraversed = new ArrayList<>();
+ Map<String,String> emptyDelKeyHash = new HashMap<>(); // Does not apply to Named Queries
+
+ // Get the mapping of namedQuery elements to our widget topology for this namedQuery
+ String incomingTrail = "";
+ Map<String, String> currentHash = new HashMap<>();
+
+ Map<String,String> namedQueryElementHash = collectNQElementHash( transId, fromAppId,
+ firstNqElementVert, incomingTrail, currentHash, vidsTraversed, 0 );
+
+ vidsTraversed = new ArrayList<>();
+ ResultSet tmpResSet = collectInstanceData( transId, fromAppId,
+ startVtx, elementLocationTrail,
+ validNextStepMap, vidsTraversed, 0, emptyDelKeyHash, namedQueryElementHash, apiVer );
+ resSetList.add(tmpResSet);
+ }
+
+ // If a secondary filter was defined, we will prune the collected instance data result set(s) based on it.
+ List<ResultSet> prunedResSetList = new ArrayList<>();
+ if( resSetList != null && !resSetList.isEmpty() ){
+ for( int i = 0; i < resSetList.size(); i++ ){
+ if( secondaryFilterCutPoint == null || secondaryFilterCutPoint.equals("") || secondaryFilterHash == null ){
+ // They didn't want to do any pruning, so just use the results we already had
+ prunedResSetList.add(resSetList.get(i));
+ }
+ else {
+ ResultSet tmpResSet = pruneResultSet(resSetList.get(i), secondaryFilterCutPoint, secondaryFilterHash);
+ if( tmpResSet != null ){
+ prunedResSetList.add(tmpResSet);
+ }
+ }
+ }
+ }
+
+ // Since a NamedQuery can mark some nodes as "do-not-display", we need to collapse our resultSet so
+ // does not display those nodes.
+ List<ResultSet> collapsedResSetList = new ArrayList<>();
+ if( prunedResSetList != null && !prunedResSetList.isEmpty() ){
+ for( int i = 0; i < prunedResSetList.size(); i++ ){
+ // Note - a single resultSet could be collapsed into many smaller ones if they
+ // marked all the "top" node-elements as do-not-output. Ie. the query may
+ // have had a top-node of "generic-vnf" which joins down to different l-interfaces.
+ // If they only want to see the l-interfaces, then a single result set
+ // would be "collapsed" into many separate resultSets - each of which is
+ // just a single l-interface.
+ List<ResultSet> tmpResSetList = collapseForDoNotOutput(prunedResSetList.get(i));
+ if( tmpResSetList != null && !tmpResSetList.isEmpty() ){
+ for( int x = 0; x < tmpResSetList.size(); x++ ){
+ //showResultSet( tmpResSetList.get(x), 0 ); //DEBUG-- this was just for testing
+ collapsedResSetList.add(tmpResSetList.get(x));
+ }
+ }
+ }
+ }
+
+ return collapsedResSetList;
+
+ }// End of queryByNamedQuery()
+
+
+ /**
+ * Prune a result set as per a secondary filter.
+ *
+ * @param resSetVal the res set val
+ * @param cutPoint the nodeType where the trim will happen
+ * @param secFilterHash hash of properties and values to use as the secondary filter
+ * @return pruned result set
+ * @throws AAIException the AAI exception
+ */
+ public ResultSet pruneResultSet( ResultSet resSetVal, String cutPointType, Map<String,Object> secFilterHash )
+ throws AAIException {
+
+ // Given a ResultSet and some secondary filter info, do pruning as needed
+ ResultSet pResSet = new ResultSet();
+
+ // For this ResultSet, we will see if we are on a node of the type that is our cutPoint;
+ // then only keep it if we peek "below" and see a match for our filter.
+
+ String nt = resSetVal.getVert().<String>property(AAIProperties.NODE_TYPE).orElse(null);
+ if( nt != null && nt.equals(cutPointType) ){
+ // We are on the type of node that may need to be "pruned" along with it's sub-results
+ if( ! satisfiesFilters(resSetVal, secFilterHash) ){
+ // Return an empty result set since we are pruning at this level.
+ return pResSet;
+ }
+ }
+
+ // If we made it to here, we will not be pruning at this level, so we will
+ // be returning a copy of this resultSet that has it's subResults pruned (as needed).
+ pResSet.setVert(resSetVal.getVert());
+ pResSet.setDoNotOutputFlag(resSetVal.getDoNotOutputFlag());
+ pResSet.setExtraPropertyHash(resSetVal.getExtraPropertyHash());
+ pResSet.setLocationInModelSubGraph(resSetVal.getLocationInModelSubGraph());
+ pResSet.setNewDataDelFlag(resSetVal.getNewDataDelFlag());
+ pResSet.setPropertyLimitDesc(resSetVal.getPropertyLimitDesc());
+ pResSet.setPropertyOverRideHash(resSetVal.getPropertyOverRideHash());
+
+ if( !resSetVal.getSubResultSet().isEmpty() ){
+ ListIterator<ResultSet> listItr = resSetVal.getSubResultSet().listIterator();
+ List<ResultSet> newSubSetList = new ArrayList<>();
+ while( listItr.hasNext() ){
+ ResultSet tmpSubResSet = pruneResultSet( listItr.next(), cutPointType, secFilterHash );
+ if( tmpSubResSet.getVert() != null ){
+ // This one wasn't pruned - so keep it.
+ newSubSetList.add(tmpSubResSet);
+ }
+ }
+ pResSet.setSubResultSet(newSubSetList);
+ }
+
+ return pResSet;
+
+ }// End pruneResultSet()
+
+
+ /**
+ * Satisfies hash of filters.
+ *
+ * @param resSet the res set
+ * @param filterHash the filter hash
+ * @return true, if successful
+ * @throws AAIException the AAI exception
+ */
+ public boolean satisfiesFilters( ResultSet resSet, Map<String,Object> filterHash )
+ throws AAIException {
+
+ if( filterHash.isEmpty() ){
+ // Nothing to look for, so no, we didn't find it.
+ return false;
+ }
+
+ Iterator <?> it = filterHash.entrySet().iterator();
+ while( it.hasNext() ){
+ Map.Entry<?,?> filtEntry = (Map.Entry<?,?>) it.next();
+ String propNodeTypeDotName = (filtEntry.getKey()).toString();
+ String fpv = (filtEntry.getValue()).toString();
+
+ int periodLoc = propNodeTypeDotName.indexOf(".");
+ if( periodLoc <= 0 ){
+ String emsg = "Bad filter param key passed in: [" + propNodeTypeDotName + "]. Expected format = [nodeName.paramName]\n";
+ throw new AAIException("AAI_6120", emsg);
+ }
+ else {
+ String fnt = propNodeTypeDotName.substring(0,periodLoc);
+ String fpn = propNodeTypeDotName.substring(periodLoc + 1);
+ if( filterMetByThisSet( resSet, fnt, fpn, fpv ) ){
+ //System.out.println(" DEBUG -- satisfied/matched filter: [" + fnt + "|" + fpn + "|" + fpv + "].");
+ }
+ else {
+ //System.out.println(" DEBUG -- NOT satisfied/matched filter: [" + fnt + "|" + fpn + "|" + fpv + "].");
+ return false;
+ }
+ }
+ }
+
+ // Made it through all the filters -- it found what we were looking for.
+ return true;
+
+ }// end of satisfiesFilters()
+
+
+ /**
+ * Filter met by this set.
+ *
+ * @param resSet the res set
+ * @param filtNodeType the filt node type
+ * @param filtPropName the filt prop name
+ * @param filtPropVal the filt prop val
+ * @return true, if successful
+ */
+ public boolean filterMetByThisSet( ResultSet resSet, String filtNodeType, String filtPropName, String filtPropVal ) {
+ // Note - we are just looking for a positive match for one filter for this resultSet
+ // NOTE: we're expecting the filter to have a format like this: "nodeType.parameterName:parameterValue"
+
+ Vertex vert = resSet.getVert();
+ if( vert == null ){
+ return false;
+ }
+ else {
+ String nt = resSet.getVert().<String>property(AAIProperties.NODE_TYPE).orElse(null);
+ if( nt.equals( filtNodeType ) ){
+ if( filtPropName.equals("vertex-id") ){
+ // vertex-id can't be gotten the same way as other properties
+ String thisVtxId = vert.id().toString();
+ if( thisVtxId.equals(filtPropVal) ){
+ return true;
+ }
+ }
+ else {
+ Object thisValObj = vert.property(filtPropName).orElse(null);
+ if( thisValObj != null ){
+ String thisVal = thisValObj.toString();
+ if( thisVal.equals(filtPropVal) ){
+ return true;
+ }
+ }
+ }
+ }
+ }
+
+ // Didn't find a match at the this level, so check the sets below it meet the criteria
+ if( resSet.getSubResultSet() != null ){
+ ListIterator<ResultSet> listItr = resSet.getSubResultSet().listIterator();
+ while( listItr.hasNext() ){
+ if( filterMetByThisSet(listItr.next(), filtNodeType, filtPropName, filtPropVal) ){
+ return true;
+ }
+ }
+ }
+
+ return false;
+
+ }// end of filterMetByThisSet()
+
+
+
+ /**
+ * Collapse for do not output.
+ *
+ * @param resSetVal the res set val
+ * @return the array list
+ * @throws AAIException the AAI exception
+ */
+ public List<ResultSet> collapseForDoNotOutput( ResultSet resSetVal )
+ throws AAIException {
+
+ // Given a ResultSet -- if it is tagged to NOT be output, then replace it with
+ // it's sub-ResultSets if it has any.
+ List<ResultSet> colResultSet = new ArrayList<>();
+
+ if( resSetVal.getDoNotOutputFlag().equals("true") ){
+ // This ResultSet isn't to be displayed, so replace it with it's sub-ResultSets
+ List<ResultSet> subResList = (ArrayList<ResultSet>) resSetVal.getSubResultSet();
+ for( int k = 0; k < subResList.size(); k++ ){
+ List<ResultSet> newSubResList = collapseForDoNotOutput(subResList.get(k));
+ colResultSet.addAll(newSubResList);
+ }
+ }
+ else {
+ // This set will be displayed
+ colResultSet.add(resSetVal);
+ }
+
+ // For each result set now at this level, call this same routine to collapse their sub-resultSets
+ for( int i = 0; i < colResultSet.size(); i++ ){
+ List<ResultSet> newSubSet = new ArrayList<>();
+ List<ResultSet> subResList = (ArrayList<ResultSet>) colResultSet.get(i).getSubResultSet();
+ for( int n = 0; n < subResList.size(); n++ ){
+ List<ResultSet> newSubResList = collapseForDoNotOutput(subResList.get(n));
+ newSubSet.addAll(newSubResList);
+ }
+ // Replace the old subResultSet with the collapsed set
+ colResultSet.get(i).setSubResultSet(newSubSet);
+ }
+
+ return colResultSet;
+
+ }// End collapseForDoNotOutput()
+
+
+
+ /**
+ * Collect instance data.
+ *
+ * @param transId the trans id
+ * @param fromAppId the from app id
+ * @param thisLevelElemVtx the element vtx at this level
+ * @param thisVertsTrail the this verts trail
+ * @param elementLocationTrail -- trail of nodeTypes that got us here (this element vertex) from the top
+ * @param validNextStepMap the valid next step map -- hash of valid next steps (node types) for this model
+ * @param vidsTraversed the vids traversed -- ArrayList of vertexId's that we traversed to get to this point
+ * @param levelCounter the level counter
+ * @param delKeyHash -- hashMap of which spots on our topology should be deleted during a modelDelete
+ * @param namedQueryElementHash - hashMap which maps each spot in our widget topology to the NamedQueryElemment that it maps to
+ * @param apiVer the api ver
+ * @return resultSet
+ * @throws AAIException the AAI exception
+ */
+ public ResultSet collectInstanceData( String transId, String fromAppId,
+ Vertex thisLevelElemVtx,
+ String thisVertsTrail,
+ Multimap <String,String> validNextStepMap,
+ List<String> vidsTraversed,
+ int levelCounter,
+ Map<String,String> delKeyHash, // only applies when collecting data using the default model for delete
+ Map<String,String> namedQueryElementHash, // only applies to named-query data collecting
+ String apiVer
+ ) throws AAIException {
+
+ levelCounter++;
+
+ String thisElemVid = thisLevelElemVtx.id().toString();
+
+ if( levelCounter > MAX_LEVELS ) {
+ throw new AAIException("AAI_6125", "collectInstanceData() has looped across more levels than allowed: " + MAX_LEVELS + ". ");
+ }
+
+ ResultSet rs = new ResultSet();
+ if( namedQueryElementHash.containsKey(thisVertsTrail) ){
+ // We're collecting data for a named-query, so need to see if we need to do anything special
+ String nqElUuid = namedQueryElementHash.get(thisVertsTrail);
+ Vertex nqElementVtx = getNodeUsingUniqueId(transId, fromAppId, "named-query-element",
+ "named-query-element-uuid", nqElUuid);
+
+ String tmpDoNotShow = nqElementVtx.<String>property("do-not-output").orElse(null);
+ if( tmpDoNotShow != null && tmpDoNotShow.equals("true") ){
+ rs.setDoNotOutputFlag("true");
+ }
+
+ if( namedQueryConstraintSaysStop(transId, fromAppId, nqElementVtx, thisLevelElemVtx, apiVer) ){
+ // There was a property constraint which says they do not want to collect this vertex or whatever
+ // might be below it. Just return the empty rs here.
+ return rs;
+ }
+
+ String propLimDesc = nqElementVtx.<String>property("property-limit-desc").orElse(null);
+ if( (propLimDesc != null) && !propLimDesc.equals("") ){
+ if (propLimDesc.equalsIgnoreCase("show-all")) {
+ rs.setPropertyLimitDesc(PropertyLimitDesc.SHOW_ALL);
+ } else if (propLimDesc.equalsIgnoreCase("show-none")) {
+ rs.setPropertyLimitDesc(PropertyLimitDesc.SHOW_NONE);
+ }else if (propLimDesc.equalsIgnoreCase("name-and-keys-only")) {
+ rs.setPropertyLimitDesc(PropertyLimitDesc.SHOW_NAME_AND_KEYS_ONLY);
+ }
+ }
+
+ // Look to see if we need to use an Override of the normal properties
+ Map<String,Object> tmpPropertyOverRideHash = getNamedQueryPropOverRide(transId, fromAppId, nqElementVtx, thisLevelElemVtx, apiVer);
+ //System.out.println(" DEBUG --- USING this propertyOverride data set on ResSet [" + tmpPropertyOverRideHash.toString() + "]");
+ rs.setPropertyOverRideHash(tmpPropertyOverRideHash);
+
+ // See if we need to look up any "unconnected" data that needs to be associated with this result set
+ Map<String,Object> tmpExtraPropHash = getNamedQueryExtraDataLookup(transId, fromAppId, nqElementVtx, thisLevelElemVtx, apiVer);
+ //System.out.println(" DEBUG --- ADDING this EXTRA Lookup data to the ResSet [" + tmpExtraPropHash.toString() + "]");
+ rs.setExtraPropertyHash(tmpExtraPropHash);
+ }
+
+ rs.setVert((TitanVertex)thisLevelElemVtx);
+ rs.setLocationInModelSubGraph(thisVertsTrail);
+ if( delKeyHash.containsKey(thisVertsTrail) && delKeyHash.get(thisVertsTrail).equals("T") ){
+ rs.setNewDataDelFlag("T");
+ }
+ else {
+ rs.setNewDataDelFlag("F");
+ }
+
+ // Use Gremlin-pipeline to just look for edges that go to a valid "next-steps"
+ Collection <String> validNextStepColl = validNextStepMap.get(thisVertsTrail);
+
+ // Because of how we process linkage-points, we may have duplicate node-types in our next-stepMap (for one step)
+ // So, to keep from looking (and bringing back) the same data twice, we need to make sure our next-steps are unique
+ Set<String> validNextStepHashSet = new HashSet<>();
+ Iterator <String> ntcItr = validNextStepColl.iterator();
+ while( ntcItr.hasNext() ){
+ String targetStepStr = ntcItr.next();
+ validNextStepHashSet.add(targetStepStr);
+ }
+
+ List<String> tmpVidsTraversedList = new ArrayList<>();
+ tmpVidsTraversedList.addAll(vidsTraversed);
+ tmpVidsTraversedList.add(thisElemVid);
+
+ Iterator <String> ntItr = validNextStepHashSet.iterator();
+ while( ntItr.hasNext() ){
+ String targetStep = ntItr.next();
+ // NOTE: NextSteps can either be just a nodeType, or can be a nodeType plus
+ // model-invariant-id-local and model-version-id-local (the two persona properties)
+ // if those need to be checked also.
+ // When the persona stuff is part of the step, it is a comma separated string.
+ // Ie. "nodeType,model-inv-id-local,model-version-id-local" (the two "persona" props)
+ //
+ String targetNodeType = "";
+ String pmid = "";
+ String pmv = "";
+ Boolean stepIsJustNT = true;
+ if( targetStep.contains(",") ){
+ stepIsJustNT = false;
+ String[] pieces = targetStep.split(",");
+ if( pieces.length != 3 ){
+ throw new AAIException("AAI_6128", "Unexpected format for nextStep in model processing = ["
+ + targetStep + "]. ");
+ }
+ else {
+ targetNodeType = pieces[0];
+ pmid = pieces[1];
+ pmv = pieces[2];
+ }
+ }
+ else {
+ // It's just the nodeType with no other info
+ targetNodeType = targetStep;
+ }
+
+ GraphTraversal<Vertex, Vertex> modPipe = null;
+ if( stepIsJustNT ){
+ modPipe = this.engine.asAdmin().getReadOnlyTraversalSource().V(thisLevelElemVtx).both().has(AAIProperties.NODE_TYPE, targetNodeType);
+ }
+ else {
+ modPipe = this.engine.asAdmin().getReadOnlyTraversalSource().V(thisLevelElemVtx).both().has(AAIProperties.NODE_TYPE, targetNodeType).has("model-invariant-id-local",pmid).has("model-version-id-local",pmv);
+ }
+
+ if( modPipe == null || !modPipe.hasNext() ){
+ //System.out.println("DEBUG - didn't find any [" + targetStep + "] connected to this guy (which is ok)");
+ }
+ else {
+ while( modPipe.hasNext() ){
+ Vertex tmpVert = (Vertex) modPipe.next();
+ String tmpVid = tmpVert.id().toString();
+ String tmpTrail = thisVertsTrail + "|" + targetStep;
+ if( !vidsTraversed.contains(tmpVid) ){
+ // This is one we would like to use - so we'll include the result set we get for it
+ ResultSet tmpResSet = collectInstanceData( transId, fromAppId,
+ tmpVert, tmpTrail,
+ validNextStepMap, tmpVidsTraversedList,
+ levelCounter, delKeyHash, namedQueryElementHash, apiVer );
+
+ rs.getSubResultSet().add(tmpResSet);
+ }
+ }
+ }
+ }
+
+ return rs;
+
+ } // End of collectInstanceData()
+
+
+ /**
+ * Gen topo map 4 model.
+ *
+ * @param transId the trans id
+ * @param fromAppId the from app id
+ * @param modelVerVertex the model-ver vertex
+ * @param modelVerId the model-version-id
+ * @param dbMaps the db maps
+ * @return MultiMap of valid next steps for each potential model-element
+ * @throws AAIException the AAI exception
+ */
+ public Multimap<String, String> genTopoMap4ModelVer( String transId, String fromAppId,
+ Vertex modelVerVertex, String modelVerId, DbMaps dbMaps )
+ throws AAIException {
+
+ if( modelVerVertex == null ){
+ throw new AAIException("AAI_6114", "null modelVerVertex passed to genTopoMap4ModelVer()");
+ }
+
+ Multimap <String, String> initialEmptyMap = ArrayListMultimap.create();
+ List<String> vidsTraversed = new ArrayList<>();
+ String modelType = getModelTypeFromModelVer( modelVerVertex, "" );
+ if( modelType.equals("widget") ){
+ // A widget model by itself does not have a topoplogy. That is - it has no "model-elements" which
+ // define how it is connected to other things. All it has is a name which ties it to
+ // an aai-node-type
+ Iterator<Vertex> vertI= this.traverseIncidentEdges(EdgeType.TREE, modelVerVertex, "model-element");
+ if( vertI != null && vertI.hasNext() ){
+ throw new AAIException("AAI_6132", "Bad Model Definition: Widget Model has a startsWith edge to a model-element. "
+ + " model-version-id = " + modelVerId);
+ }
+ else {
+ return initialEmptyMap;
+ }
+ }
+
+ String firstModelVerId = modelVerVertex.<String>property("model-version-id").orElse(null);
+ String firstModelVersion = modelVerVertex.<String>property("model-version").orElse(null);
+ if( firstModelVerId == null || firstModelVerId.equals("") || firstModelVersion == null || firstModelVersion.equals("") ){
+ throw new AAIException("AAI_6132", "Bad Model Definition: Bad model-version-id or model-version. model-version-id = "
+ + modelVerId);
+ }
+
+ Vertex firstElementVertex = getTopElementForSvcOrResModelVer( modelVerVertex, "" );
+ Vertex firstEleModVerVtx = getModelVerThatElementRepresents( firstElementVertex, "" );
+ String firstElemModelType = getModelTypeFromModelVer( firstEleModVerVtx, "" );
+ if( ! firstElemModelType.equals("widget") ){
+ throw new AAIException("AAI_6132", "Bad Model Definition: First element must correspond to a widget type model. Model UUID = "
+ + modelVerId);
+ }
+
+ Vertex firstModVtx = getModelGivenModelVer( modelVerVertex, "" );
+ String firstModelInvId = firstModVtx.<String>property("model-invariant-id").orElse(null);
+ if( firstModelInvId == null || firstModelInvId.equals("") ){
+ throw new AAIException("AAI_6132", "Bad Model Definition: Could not find model.model-invariant-id given model-ver.model-version-id = "
+ + modelVerId);
+ }
+
+ Multimap <String, String> collectedMap = collectTopology4ModelVer( transId, fromAppId,
+ firstElementVertex, "", initialEmptyMap, vidsTraversed, 0, dbMaps, null, firstModelInvId, firstModelVersion );
+
+ return collectedMap;
+
+ } // End of genTopoMap4ModelVer()
+
+
+ public List<String> makeSureItsAnArrayList( String listStringVal ){
+ // We're sometimes getting a String back on db properties that should be ArrayList<String>
+ // Seems to be how they're defined in OXM - whether they use a "xml-wrapper" or not
+ // Need to translate them into ArrayLists sometimes...
+
+ List<String> retArrList = new ArrayList<String>();
+ String listString = listStringVal;
+ listString = listString.replace(" ", "");
+ listString = listString.replace("\"", "");
+ listString = listString.replace("[", "");
+ listString = listString.replace("]", "");
+ String [] pieces = listString.split(",");
+ if( pieces != null && pieces.length > 0 ){
+ for( int i = 0; i < pieces.length; i++ ){
+ retArrList.add(pieces[i]);
+ }
+ }
+
+ return retArrList;
+ }
+
+
+ /**
+ * Gets the mod constraint hash.
+ *
+ * @param modelElementVtx the model element vtx
+ * @param currentHash -- the current ModelConstraint's that this routine will add to if it finds any.
+ * @return HashMap of model-constraints that will be looked at for this model-element and what's "below" it.
+ * @throws AAIException the AAI exception
+ */
+ public Map<String, Vertex> getModConstraintHash( Vertex modelElementVtx, Map<String, Vertex> currentHash )
+ throws AAIException {
+
+ // For a given model-element vertex, look to see if there are any "model-constraint" elements that is has
+ // an OUT "uses" edge to. If it does, then get any "constrained-element-set" nodes that are pointed to
+ // by the "model-constraint". That will be the replacement "constrained-element-set". The UUID of the
+ // "constrained-element-set" that it is supposed to replace is found in the property:
+ // model-constraint.constrained-element-set-uuid-to-replace
+ //
+ // For now, that is the only type of model-constraint allowed, so that is all we will look for.
+ // Pass back any of these "constrained-element-set" nodes along with any that were passed in by
+ // the "currentHash" parameter.
+
+ if( modelElementVtx == null ){
+ String msg = " null modelElementVtx passed to getModConstraintHash() ";
+ throw new AAIException("AAI_6114", msg);
+ }
+
+ String modelType = modelElementVtx.<String>property(AAIProperties.NODE_TYPE).orElse(null);
+ if( modelType == null || (!modelType.equals("model-element")) ){
+ String msg = " getModConstraintHash() called with wrong type model: [" + modelType + "]. ";
+ throw new AAIException("AAI_6114", msg);
+ }
+
+ Map<String, Vertex> thisHash = new HashMap<>();
+ if( currentHash != null ){
+ thisHash.putAll(currentHash);
+ }
+
+ int count = 0;
+ List<Vertex> modelConstraintArray = new ArrayList<>();
+ Iterator<Vertex> vertI = this.traverseIncidentEdges(EdgeType.TREE, modelElementVtx, "model-constraint");
+ while( vertI != null && vertI.hasNext() ){
+ Vertex tmpVert = vertI.next();
+ String connectToType = tmpVert.<String>property(AAIProperties.NODE_TYPE).orElse(null);
+ if( (connectToType != null) && connectToType.equals("model-constraint") ){
+ // We need to find the constrained element set pointed to by this and add it to the Hash to return
+ modelConstraintArray.add(tmpVert);
+ count++;
+ }
+ }
+
+ if( count > 0 ) {
+ for( int i = 0; i < count; i++ ){
+ Vertex vtxOfModelConstraint = modelConstraintArray.get(i);
+ String uuidOfTheOneToBeReplaced = vtxOfModelConstraint.<String>property("constrained-element-set-uuid-2-replace").orElse(null);
+ // We have the UUID of the constrained-element-set that will be superseded, now find the
+ // constrained-element-set to use in its place
+ Iterator<Vertex> mvertI = this.traverseIncidentEdges(EdgeType.TREE, vtxOfModelConstraint, "constrained-element-set");
+ while( mvertI != null && mvertI.hasNext() ){
+ // There better only be one...
+ Vertex tmpVert = mvertI.next();
+ String connectToType = tmpVert.<String>property(AAIProperties.NODE_TYPE).orElse(null);
+ if( (connectToType != null) && connectToType.equals("constrained-element-set") ){
+ // This is the "constrained-element-set" that we want to use as the Replacement
+ thisHash.put(uuidOfTheOneToBeReplaced, tmpVert );
+ }
+ }
+ }
+ return thisHash;
+ }
+ else {
+ // Didn't find anything to add, so just return what they passed in.
+ return currentHash;
+ }
+
+ } // End of getModConstraintHash()
+
+
+ /**
+ * Gets the top element vertex for service or resource model.
+ *
+ * @param modelVerVtx the model-ver vertex
+ * @return first element pointed to by this model-ver
+ * @throws AAIException the AAI exception
+ */
+ public Vertex getTopElementForSvcOrResModelVer( Vertex modelVerVtx, String trail )
+ throws AAIException {
+
+ // For a "resource" or "service" type model, return the "top" element in that model
+ if( modelVerVtx == null ){
+ String msg = " null modelVertex passed to getTopoElementForSvcOrResModelVer() at [" + trail + "]. ";
+ throw new AAIException("AAI_6114", msg);
+ }
+
+ String modelVerId = modelVerVtx.<String>property("model-version-id").orElse(null);
+ if( modelVerId == null ){
+ String nt = modelVerVtx.<String>property(AAIProperties.NODE_TYPE).orElse(null);
+ if( nt != null && !nt.equals("model-ver") ){
+ String msg = "Illegal model defined: model element pointing to nodeType: ["
+ + nt + "], should be pointing to: [model-ver] at [" + trail + "]. ";
+ throw new AAIException("AAI_6132", msg);
+ }
+ }
+
+ Vertex firstElementVertex = null;
+
+ Iterator<Vertex> vertI = this.traverseIncidentEdges(EdgeType.TREE, modelVerVtx, "model-element");
+ int elCount = 0;
+ while( vertI != null && vertI.hasNext() ){
+ elCount++;
+ firstElementVertex = vertI.next();
+ }
+
+ if( elCount > 1 ){
+ String msg = "Illegal model defined: More than one first element defined for model-ver-id = " +
+ modelVerId + " at [" + trail + "]. ";
+ throw new AAIException("AAI_6132", msg);
+ }
+
+ if( firstElementVertex == null ){
+ String msg = "Could not find first model element for model-ver-id = "
+ + modelVerId + " at [" + trail + "]. ";
+ throw new AAIException("AAI_6132", msg);
+ }
+
+ return firstElementVertex;
+
+ } // End of getTopElementForSvcOrResModelVer()
+
+
+
+ /**
+ * Gets the named query prop over ride.
+ *
+ * @param transId the trans id
+ * @param fromAppId the from app id
+ * @param namedQueryElementVertex the named query element vertex
+ * @param instanceVertex the instance vertex
+ * @param apiVer the api ver
+ * @return HashMap of alternate properties to return for this element
+ * @throws AAIException the AAI exception
+ */
+ public Map<String,Object> getNamedQueryPropOverRide( String transId, String fromAppId,
+ Vertex namedQueryElementVertex, Vertex instanceVertex, String apiVer )
+ throws AAIException {
+
+ // If this model-element says that they want an alternative set of properties returned, then pull that
+ // data out of the instance vertex.
+
+ Map<String,Object> altPropHash = new HashMap<>();
+
+ if( namedQueryElementVertex == null ){
+ String msg = " null namedQueryElementVertex passed to getNamedQueryPropOverRide() ";
+ throw new AAIException("AAI_6114", msg);
+ }
+
+ List<String> propCollectList = new ArrayList<>();
+ Iterator <VertexProperty<Object>> vpI = namedQueryElementVertex.properties("property-collect-list");
+ while( vpI.hasNext() ){
+ propCollectList.add((String)vpI.next().value());
+ }
+
+ for( int i = 0; i < propCollectList.size(); i++ ){
+ String thisPropName = propCollectList.get(i);
+ Object instanceVal = instanceVertex.<Object>property(thisPropName).orElse(null);
+ altPropHash.put(thisPropName, instanceVal);
+ }
+
+ return altPropHash;
+
+ } // End of getNamedQueryPropOverRide()
+
+
+ /**
+ * Named query constraint says stop.
+ *
+ * @param transId the trans id
+ * @param fromAppId the from app id
+ * @param namedQueryElementVertex the named query element vertex
+ * @param instanceVertex the instance vertex
+ * @param apiVer the api ver
+ * @return true - if a constraint was defined that has not been met by the passed instanceVertex
+ * @throws AAIException the AAI exception
+ */
+ public Boolean namedQueryConstraintSaysStop( String transId, String fromAppId,
+ Vertex namedQueryElementVertex, Vertex instanceVertex, String apiVer )
+ throws AAIException {
+
+ // For each (if any) property-constraint defined for this named-query-element, we will evaluate if
+ // the constraint is met or not-met. if there are constraints and any are not-met, then
+ // we return "true".
+
+ if( namedQueryElementVertex == null ){
+ String msg = " null namedQueryElementVertex passed to namedQueryConstraintSaysStop() ";
+ throw new AAIException("AAI_6114", msg);
+ }
+ if( instanceVertex == null ){
+ String msg = " null instanceVertex passed to namedQueryConstraintSaysStop() ";
+ throw new AAIException("AAI_6114", msg);
+ }
+
+ Iterator<Vertex> constrPipe = this.traverseIncidentEdges(EdgeType.TREE, namedQueryElementVertex, "property-constraint");
+ if( constrPipe == null || !constrPipe.hasNext() ){
+ // There's no "property-constraint" defined for this named-query-element. No problem.
+ return false;
+ }
+
+ while( constrPipe.hasNext() ){
+ Vertex constrVtx = (Vertex) constrPipe.next();
+ // We found a property constraint that we will need to check
+ String conType = constrVtx.<String>property("constraint-type").orElse(null);
+ if( (conType == null) || conType.equals("")){
+ String msg = " Bad property-constraint (constraint-type) found in Named Query definition. ";
+ throw new AAIException("AAI_6133", msg);
+ }
+ String propName = constrVtx.<String>property("property-name").orElse(null);
+ if( (propName == null) || propName.equals("")){
+ String msg = " Bad property-constraint (property-name) found in Named Query definition. ";
+ throw new AAIException("AAI_6133", msg);
+ }
+ String propVal = constrVtx.<String>property("property-value").orElse(null);
+ if( (propVal == null) || propVal.equals("")){
+ String msg = " Bad property-constraint (propVal) found in Named Query definition. ";
+ throw new AAIException("AAI_6133", msg);
+ }
+
+ // See if that constraint is met or not
+ String val = instanceVertex.<String>property(propName).orElse(null);
+ if( val == null ){
+ val = "";
+ }
+
+ if( conType.equals("EQUALS") ){
+ if( !val.equals(propVal) ){
+ // This constraint was not met
+ return true;
+ }
+ }
+ else if( conType.equals("NOT-EQUALS") ){
+ if( val.equals(propVal) ){
+ // This constraint was not met
+ return true;
+ }
+ }
+ else {
+ String msg = " Bad property-constraint (constraint-type) found in Named Query definition. ";
+ throw new AAIException("AAI_6133", msg);
+ }
+ }
+
+ return false;
+
+ } // End of namedQueryConstraintSaysStop()
+
+
+ /**
+ * Gets the named query extra data lookup.
+ *
+ * @param transId the trans id
+ * @param fromAppId the from app id
+ * @param namedQueryElementVertex the named query element vertex
+ * @param instanceVertex the instance vertex
+ * @param apiVer the api ver
+ * @return HashMap of alternate properties to return for this element
+ * @throws AAIException the AAI exception
+ */
+ public Map<String,Object> getNamedQueryExtraDataLookup( String transId, String fromAppId,
+ Vertex namedQueryElementVertex, Vertex instanceVertex, String apiVer )
+ throws AAIException {
+
+ // For each (if any) related-lookup defined for this named-query-element, we will go and
+ // and try to find it. All the related-lookup data will get put in a hash and returned.
+
+ if( namedQueryElementVertex == null ){
+ String msg = " null namedQueryElementVertex passed to getNamedQueryExtraDataLookup() ";
+ throw new AAIException("AAI_6114", msg);
+ }
+ if( instanceVertex == null ){
+ String msg = " null instanceVertex passed to getNamedQueryExtraDataLookup() ";
+ throw new AAIException("AAI_6114", msg);
+ }
+
+ Map<String,Object> retHash = new HashMap<>();
+
+ Iterator<Vertex> lookPipe = this.traverseIncidentEdges(EdgeType.TREE, namedQueryElementVertex, "related-lookup");
+ if( lookPipe == null || !lookPipe.hasNext() ){
+ // There's no "related-lookup" defined for this named-query-element. No problem.
+ return retHash;
+ }
+
+ while( lookPipe.hasNext() ){
+ Vertex relLookupVtx = (Vertex) lookPipe.next();
+ // We found a related-lookup record to try and use
+ String srcProp = relLookupVtx.<String>property("source-node-property").orElse(null);
+ if( (srcProp == null) || srcProp.equals("")){
+ String msg = " Bad related-lookup (source-node-property) found in Named Query definition. ";
+ throw new AAIException("AAI_6133", msg);
+ }
+ String targetNodeType = relLookupVtx.<String>property("target-node-type").orElse(null);
+ if( (targetNodeType == null) || targetNodeType.equals("")){
+ String msg = " Bad related-lookup (targetNodeType) found in Named Query definition. ";
+ throw new AAIException("AAI_6133", msg);
+ }
+ String targetProp = relLookupVtx.<String>property("target-node-property").orElse(null);
+ if( (targetProp == null) || targetProp.equals("")){
+ String msg = " Bad related-lookup (target-node-property) found in Named Query definition. ";
+ throw new AAIException("AAI_6133", msg);
+ }
+
+ List<String> propCollectList = new ArrayList<>();
+ Iterator <VertexProperty<Object>> vpI = relLookupVtx.properties("property-collect-list");
+ while( vpI.hasNext() ){
+ propCollectList.add((String)vpI.next().value());
+ }
+
+ // Use the value from the source to see if we can find ONE target record using the value from the source
+ String valFromInstance = instanceVertex.<String>property(srcProp).orElse(null);
+ if( valFromInstance == null ){
+ valFromInstance = "";
+ }
+
+ Map<String,Object> propHash = new HashMap<String,Object>();
+ propHash.put(targetProp, valFromInstance);
+
+ Optional<Vertex> result = dbMethHelper.locateUniqueVertex(targetNodeType, propHash);
+ if (!result.isPresent()) {
+ throw new AAIException("AAI_6114", "No Node of type " + targetNodeType + " found for properties");
+ }
+ Vertex tmpVtx = result.get();
+ // Pick up the properties from the target vertex that they wanted us to get
+ for( int j = 0; j < propCollectList.size(); j++ ){
+ String tmpPropName = propCollectList.get(j);
+ Object valObj = tmpVtx.<Object>property(tmpPropName).orElse(null);
+ String lookupKey = targetNodeType + "." + tmpPropName;
+ retHash.put(lookupKey, valObj);
+
+ }
+ }
+
+ return retHash;
+
+ } // End of getNamedQueryExtraDataLookup()
+
+ /**
+ * Collect NQ element hash.
+ *
+ * @param transId the trans id
+ * @param fromAppId the from app id
+ * @param thisLevelElemVtx the element verrtx for this level
+ * @param incomingTrail the incoming trail -- trail of nodeTypes that got us here (this nq-element vertex) from the top
+ * @param currentHash the current hash
+ * @param Map that got us to this point (that we will use as the base of the map we will return)
+ * @param vidsTraversed the vids traversed -- ArrayList of vertexId's that we traversed to get to this point
+ * @param levelCounter the level counter
+ * @return HashMap of all widget-points on a namedQuery topology with the value being the "named-query-element-uuid" for that spot.
+ * @throws AAIException the AAI exception
+ */
+ public Map<String, String> collectNQElementHash( String transId, String fromAppId,
+ Vertex thisLevelElemVtx, String incomingTrail,
+ Map<String,String> currentHash, ArrayList <String> vidsTraversed,
+ int levelCounter ) throws AAIException {
+
+ levelCounter++;
+
+ Map<String, String> thisHash = new HashMap<>();
+ thisHash.putAll(currentHash);
+
+ if( levelCounter > MAX_LEVELS ) {
+ throw new AAIException("AAI_6125", "collectNQElementHash() has looped across more levels than allowed: " + MAX_LEVELS + ". ");
+ }
+ String thisGuysTrail = "";
+ String thisElemVid = thisLevelElemVtx.id().toString();
+
+ // Find out what widget (and thereby what aai-node-type) this element represents.
+ String thisElementNodeType = getNqElementWidgetType( transId, fromAppId, thisLevelElemVtx, incomingTrail );
+
+ if( incomingTrail == null || incomingTrail.equals("") ){
+ // This is the first one
+ thisGuysTrail = thisElementNodeType;
+ }
+ else {
+ thisGuysTrail = incomingTrail + "|" + thisElementNodeType;
+ }
+ vidsTraversed.add(thisElemVid);
+
+ String nqElementUuid = thisLevelElemVtx.<String>property("named-query-element-uuid").orElse(null);
+ if( nqElementUuid == null || nqElementUuid.equals("") ){
+ String msg = " named-query element UUID not found at trail = [" + incomingTrail + "].";
+ throw new AAIException("AAI_6133", msg);
+ }
+ thisHash.put(thisGuysTrail, nqElementUuid );
+
+ // Now go "down" and look at the sub-elements pointed to so we can get their data.
+ Iterator<Vertex> vertI = this.traverseIncidentEdges(EdgeType.TREE, thisLevelElemVtx, "named-query-element");
+ while( vertI != null && vertI.hasNext() ){
+ Vertex tmpVert = vertI.next();
+ String vid = tmpVert.id().toString();
+ Map<String,Object> elementHash = new HashMap<String, Object>();
+
+ String connectToType = tmpVert.<String>property(AAIProperties.NODE_TYPE).orElse(null);
+ if( connectToType != null && connectToType.equals("named-query-element") ){
+ // This is what we would expect
+ elementHash.put(vid, tmpVert);
+ }
+ else {
+ String msg = " named query element has [connectedTo] edge to improper nodeType= ["
+ + connectToType + "] trail = [" + incomingTrail + "].";
+ throw new AAIException("AAI_6133", msg);
+ }
+ for( Map.Entry<String, Object> entry : elementHash.entrySet() ){
+ Vertex elVert = (Vertex)(entry.getValue());
+ String tmpElVid = elVert.id().toString();
+ if( !vidsTraversed.contains(tmpElVid) ){
+ // This is one we would like to use - so we'll recursively get it's result set to add to ours
+ Map<String, String> tmpHash = collectNQElementHash( transId, fromAppId,
+ elVert, thisGuysTrail, currentHash, vidsTraversed, levelCounter);
+ thisHash.putAll(tmpHash);
+ }
+ }
+ }
+ return thisHash;
+
+ } // End of collectNQElementHash()
+
+
+ /**
+ * Collect delete key hash.
+ *
+ * @param transId the trans id
+ * @param fromAppId the from app id
+ * @param thisLevelElemVtx the element vertex at this level
+ * @param incomingTrail the incoming trail -- trail of nodeTypes that got us here (this vertex) from the top
+ * @param currentHash the current hash
+ * @param Map that got us to this point (that we will use as the base of the map we will return)
+ * @param vidsTraversed the vids traversed ---- ArrayList of vertexId's that we traversed to get to this point
+ * @param levelCounter the level counter
+ * @param dbMaps the db maps
+ * @param modConstraintHash the mod constraint hash
+ * @param overRideModelId the over ride model id
+ * @param overRideModelVersionId the over ride model version id
+ * @return HashMap of all widget-points on a model topology with the value being the "newDataDelFlag" for that spot.
+ * @throws AAIException the AAI exception
+ */
+ public Map<String, String> collectDeleteKeyHash( String transId, String fromAppId,
+ Vertex thisLevelElemVtx, String incomingTrail,
+ Map<String,String> currentHash, ArrayList <String> vidsTraversed,
+ int levelCounter, DbMaps dbMaps, Map<String, Vertex> modConstraintHash,
+ String overRideModelId, String overRideModelVersionId )
+ throws AAIException {
+
+ levelCounter++;
+
+ Map<String, String> thisHash = new HashMap<>();
+ thisHash.putAll(currentHash);
+
+ if( levelCounter > MAX_LEVELS ) {
+ throw new AAIException("AAI_6125", "collectDeleteKeyHash() has looped across more levels than allowed: " + MAX_LEVELS + ". ");
+ }
+ String thisGuysTrail = "";
+ String thisElemVid = thisLevelElemVtx.id().toString();
+ Map<String, Vertex> modConstraintHash2Use = null;
+
+ // If this element represents a resource or service model, then we will replace this element with
+ // the "top" element of that resource or service model. That model-element already points to its
+ // topology, so it will graft in that model's topology.
+ // EXCEPT - if this element has "linkage-points" defined, then we need to do some extra
+ // processing for how we join to that model and will not try to go any "deeper".
+ List<String> linkagePtList = new ArrayList<>();
+ Iterator <VertexProperty<Object>> vpI = thisLevelElemVtx.properties("linkage-points");
+ //DEBUG -- AAI-8002
+ // I am not sure why, but since "linkage-points" is an xml-element-wrapper in the OXM definition,
+ // we get back the whole array of Strings in one String - but still use the "vtx.properties()" to
+ // get it - but only look at the first thing returned by the iterator.
+ if( vpI.hasNext() ){
+ String tmpLinkageThing = (String)vpI.next().value();
+ linkagePtList = makeSureItsAnArrayList( tmpLinkageThing );
+ }
+
+ if( linkagePtList != null && !linkagePtList.isEmpty() ){
+ // Whatever this element is - we are connecting to it via a linkage-point
+ // We will figure out what to do and then return without going any deeper
+ String elemFlag = thisLevelElemVtx.<String>property("new-data-del-flag").orElse(null);
+
+ Set<String> linkageConnectNodeTypes = getLinkageConnectNodeTypes( linkagePtList );
+ Iterator <?> linkNtIter = linkageConnectNodeTypes.iterator();
+ String incTrail = "";
+ if( incomingTrail != null && !incomingTrail.equals("") ){
+ incTrail = incomingTrail + "|";
+ }
+
+ while( linkNtIter.hasNext() ){
+ // The 'trail' (or trails) for this element should just be the to the first-contact on the linkage point
+ String linkTrail = incTrail + linkNtIter.next();
+ Boolean alreadyTaggedFalse = false;
+ if( thisHash.containsKey(linkTrail) && thisHash.get(linkTrail).equals("F") ){
+ // some other path with a matching trail has the deleteFlag set to "F", so we do not want
+ // to override that since our model code only uses nodeTypes to know where it is - and we
+ // would rather do less deleting than needed instead of too much deleting.
+ alreadyTaggedFalse = true;
+ }
+ if( elemFlag != null && elemFlag.equals("T") && !alreadyTaggedFalse ){
+ // This trail should be marked with an "T"
+ thisHash.put(linkTrail, "T");
+ }
+ else {
+ thisHash.put(linkTrail, "F");
+ }
+ }
+ return thisHash;
+ }
+
+ // ----------------------------------------------------------------------------
+ // If we got to here, then this was not an element that used a linkage-point
+ // ----------------------------------------------------------------------------
+
+ // Find out what widget-model (and thereby what aai-node-type) this element represents.
+ // Even if this element is pointing to a service or resource model, it must have a
+ // first element which is a single widget-type model.
+ String thisElementNodeType = getModElementWidgetType( thisLevelElemVtx, incomingTrail );
+ String firstElementModelInfo = "";
+
+ vidsTraversed.add(thisElemVid);
+ Vertex elementVtxForThisLevel = null;
+ Vertex thisElementsModelVerVtx = getModelVerThatElementRepresents( thisLevelElemVtx, incomingTrail );
+ Vertex thisElementsModelVtx = getModelGivenModelVer( thisElementsModelVerVtx, incomingTrail );
+ String modType = getModelTypeFromModel( thisElementsModelVtx, incomingTrail );
+ String subModelFirstModInvId = thisElementsModelVtx.<String>property("model-invariant-id").orElse(null);
+ String subModelFirstVerId = thisElementsModelVerVtx.<String>property("model-version-id").orElse(null);
+ if( modType.equals("widget") ){
+ if( overRideModelId != null && !overRideModelId.equals("") ){
+ // Note - this is just to catch the correct model for the TOP node in a model since
+ // it will have an element which will always be a widget even though the model
+ // could be a resource or service model.
+ firstElementModelInfo = "," + overRideModelId + "," + overRideModelVersionId;
+ }
+ }
+ else if( nodeTypeSupportsPersona(thisElementNodeType, dbMaps) ){
+ firstElementModelInfo = "," + subModelFirstModInvId + "," + subModelFirstVerId;
+ }
+
+ if( incomingTrail.equals("") ){
+ // This is the first one
+ thisGuysTrail = thisElementNodeType + firstElementModelInfo;
+ }
+ else {
+ thisGuysTrail = incomingTrail + "|" + thisElementNodeType + firstElementModelInfo;
+ }
+
+ String tmpFlag = "F";
+ Boolean stoppedByASvcOrResourceModelElement = false;
+ if( modType.equals("widget") ){
+ elementVtxForThisLevel = thisLevelElemVtx;
+ // For the element-model for the widget at this level, record it's delete flag
+ tmpFlag = elementVtxForThisLevel.<String>property("new-data-del-flag").orElse(null);
+ }
+ else {
+ // For an element that is referring to a resource or service model, we replace
+ // this element with the "top" element for that resource/service model so that the
+ // topology of that resource/service model will be included in this topology.
+ String modelVerId = thisElementsModelVerVtx.<String>property("model-version-id").orElse(null);
+ if( subModelFirstModInvId == null || subModelFirstModInvId.equals("")
+ || subModelFirstVerId == null || subModelFirstVerId.equals("") ){
+ throw new AAIException("AAI_6132", "Bad Model Definition: Bad model-invariant-id or model-version-id. Model-version-id = " +
+ modelVerId + ", at [" + incomingTrail + "]");
+ }
+
+ // BUT -- if the model-element HERE at the resource/service level does NOT have
+ // it's new-data-del-flag set to "T", then we do not need to go down into the
+ // sub-model looking for delete-able things.
+
+ tmpFlag = thisLevelElemVtx.<String>property("new-data-del-flag").orElse(null);
+ elementVtxForThisLevel = getTopElementForSvcOrResModelVer(thisElementsModelVerVtx, thisGuysTrail);
+ if( tmpFlag != null && tmpFlag.equals("T") ){
+ modConstraintHash2Use = getModConstraintHash( thisLevelElemVtx, modConstraintHash );
+ }
+ else {
+ stoppedByASvcOrResourceModelElement = true;
+ }
+ // For the element-model for the widget at this level, record it's delete flag
+ tmpFlag = elementVtxForThisLevel.<String>property("new-data-del-flag").orElse(null);
+ }
+
+ String flag2Use = "F"; // by default we'll use "F" for the delete flag
+ if( ! stoppedByASvcOrResourceModelElement ){
+ // Since we haven't been stopped by a resource/service level "F", we can look at the lower level flag
+ if( thisHash.containsKey(thisGuysTrail) ){
+ // We've seen this spot in the topology before - do not override the delete flag if the older one is "F"
+ // We will only over-ride it if the old one was "T" and the new one is "F" (anything but "T")
+ String oldFlag = thisHash.get(thisGuysTrail);
+ if( oldFlag.equals("T") && (tmpFlag != null) && tmpFlag.equals("T") ){
+ // The old flag was "T" and the new flag is also "T"
+ flag2Use = "T";
+ }
+ else {
+ // the old flag was not "F" - so don't override it
+ flag2Use = "F";
+ }
+ }
+ else if( (tmpFlag != null) && tmpFlag.equals("T") ){
+ // We have not seen this one, so we can set it to "T" if that's what it is.
+ flag2Use = "T";
+ }
+ }
+
+ thisHash.put(thisGuysTrail, flag2Use);
+ if( ! stoppedByASvcOrResourceModelElement ){
+ // Since we haven't been stopped by a resource/service level "F", we will continue to
+ // go "down" and look at the elements pointed to so we can get their data.
+ Iterator<Vertex> vertI = this.traverseIncidentEdges(EdgeType.TREE, elementVtxForThisLevel, "model-element", "constrained-element-set");
+ while( vertI != null && vertI.hasNext() ){
+ Vertex tmpVert = vertI.next();
+ String vid = tmpVert.id().toString();
+ Map<String,Object> elementHash = new HashMap<String, Object>();
+
+ String connectToType = tmpVert.<String>property(AAIProperties.NODE_TYPE).orElse(null);
+ if( connectToType != null && connectToType.equals("model-element") ){
+ // A nice, regular old model-element
+ elementHash.put(vid, tmpVert);
+ }
+ else if( (connectToType != null) && connectToType.equals("constrained-element-set") ){
+ // translate the constrained-element-set into a hash of model-element Vertex's
+ String constrainedElementSetUuid = tmpVert.<String>property("constrained-element-set-uuid").orElse(null);
+ if( (modConstraintHash2Use != null) && modConstraintHash2Use.containsKey(constrainedElementSetUuid) ){
+ // This constrained-element-set is being superseded by a different one
+ Vertex replacementConstraintVert = modConstraintHash.get(constrainedElementSetUuid);
+ elementHash = getNextStepElementsFromSet( replacementConstraintVert );
+ // Now that we've found and used the replacement constraint, we don't need to carry it along any farther
+ modConstraintHash.remove(constrainedElementSetUuid);
+ }
+ else {
+ elementHash = getNextStepElementsFromSet( tmpVert );
+ }
+ }
+ else {
+ String msg = " model-element has [connectedTo] edge to improper nodeType= ["
+ + connectToType + "] trail = [" + incomingTrail + "].";
+ throw new AAIException("AAI_6132", msg);
+ }
+
+ for( Map.Entry<String, Object> entry : elementHash.entrySet() ){
+ Vertex elVert = (Vertex)(entry.getValue());
+ String tmpElVid = elVert.id().toString();
+ String tmpElNT = getModElementWidgetType( elVert, thisGuysTrail );
+ check4EdgeRule(tmpElNT, thisElementNodeType, dbMaps);
+ if( !vidsTraversed.contains(tmpElVid) ){
+ // This is one we would like to use - so we'll recursively get it's result set to add to ours
+ Map<String, String> tmpHash = collectDeleteKeyHash( transId, fromAppId,
+ elVert, thisGuysTrail,
+ currentHash, vidsTraversed, levelCounter, dbMaps, modConstraintHash2Use,
+ "", "" );
+ thisHash.putAll(tmpHash);
+ }
+ }
+ }
+ }
+ return thisHash;
+
+ } // End of collectDeleteKeyHash()
+
+
+ /**
+ * Gets the linkage connect node types.
+ *
+ * @param linkagePtList the linkage pt list
+ * @return the linkage connect node types
+ * @throws AAIException the AAI exception
+ */
+ public Set<String> getLinkageConnectNodeTypes(List<String> linkagePtList )
+ throws AAIException {
+ // linkage points are a path from the top of a model to where we link in.
+ // This method wants to just bring back a list of distinct last items.
+ // Ie: for the input with these two: "pserver|lag-link|l-interface" and "pserver|p-interface|l-interface"
+ // it would just return a single item, "l-interface" since both linkage points end in that same node-type.
+
+ Set<String> linkPtSet = new HashSet<>();
+
+ if( linkagePtList == null ){
+ String detail = " Bad (null) linkagePtList passed to getLinkageConnectNodeTypes() ";
+ throw new AAIException("AAI_6125", detail);
+ }
+
+ for( int i = 0; i < linkagePtList.size(); i++ ){
+ String [] trailSteps = linkagePtList.get(i).split("\\|");
+ if( trailSteps == null || trailSteps.length == 0 ){
+ String detail = " Bad incomingTrail passed to getLinkageConnectNodeTypes(): [" + linkagePtList + "] ";
+ throw new AAIException("AAI_6125", detail);
+ }
+ String lastStepNT = trailSteps[trailSteps.length - 1];
+ linkPtSet.add(lastStepNT);
+ }
+
+ return linkPtSet;
+
+ }// End getLinkageConnectNodeTypes()
+
+
+ /**
+ * Collect topology for model-ver.
+ *
+ * @param transId the trans id
+ * @param fromAppId the from app id
+ * @param modelElement vertex to collect for
+ * @param incomingTrail the incoming trail -- trail of nodeTypes/personaInfo that got us here (this vertex) from the top
+ * @param currentMap the current map -- map that got us to this point (that we will use as the base of the map we will return)
+ * @param vidsTraversed the vids traversed -- ArrayList of vertexId's that we traversed to get to this point
+ * @param levelCounter the level counter
+ * @param dbMaps the db maps
+ * @param modConstraintHash the mod constraint hash
+ * @param overRideModelInvId the override model-invariant-id
+ * @param overRideModelVersionId the override model-version-id
+ * @return Map of the topology
+ * @throws AAIException the AAI exception
+ */
+ public Multimap<String, String> collectTopology4ModelVer( String transId, String fromAppId,
+ Vertex thisLevelElemVtx, String incomingTrail,
+ Multimap <String,String> currentMap, List<String> vidsTraversed,
+ int levelCounter, DbMaps dbMaps, Map<String, Vertex> modConstraintHash,
+ String overRideModelInvId, String overRideModelVersionId )
+ throws AAIException {
+
+ levelCounter++;
+
+ Multimap <String, String> thisMap = ArrayListMultimap.create();
+ thisMap.putAll(currentMap);
+
+ if( levelCounter > MAX_LEVELS ) {
+ throw new AAIException("AAI_6125", "collectTopology4ModelVer() has looped across more levels than allowed: " + MAX_LEVELS + ". ");
+ }
+ String thisGuysTrail = "";
+ String thisElemVid = thisLevelElemVtx.id().toString();
+ Map<String, Vertex> modConstraintHash2Use = null;
+
+ // If this element represents a resource or service model, then we will replace this element with
+ // the "top" element of that resource or service model. That model-element already points to its
+ // topology, so it will graft in that model's topology.
+ // EXCEPT - if this element defines "linkage-points" defined, then we need to do some extra
+ // processing for how we join to that model.
+
+ // Find out what widget-model (and thereby what aai-node-type) this element represents.
+ // Even if this element is pointing to a service or resource model, it must have a
+ // first element which is a single widget-type model.
+ String firstElementModelInfo = "";
+ String thisElementNodeType = getModElementWidgetType( thisLevelElemVtx, incomingTrail );
+ if( nodeTypeSupportsPersona(thisElementNodeType, dbMaps) && overRideModelInvId != null && !overRideModelInvId.equals("") ){
+ firstElementModelInfo = "," + overRideModelInvId + "," + overRideModelVersionId;
+ }
+
+ Vertex elementVtxForThisLevel = null;
+ Vertex thisElementsModelVerVtx = getModelVerThatElementRepresents( thisLevelElemVtx, incomingTrail );
+ String subModelFirstModInvId = "";
+ String subModelFirstModVerId = "";
+ String modInfo4Trail = "";
+ String modType = getModelTypeFromModelVer( thisElementsModelVerVtx, incomingTrail );
+ if( modType.equals("resource") || modType.equals("service") ){
+ // For an element that is referring to a resource or service model, we replace this
+ // this element with the "top" element for that resource/service model so that the
+ // topology of that resource/service model gets included in this topology.
+ // -- Note - since that top element of a service or resource model will point to a widget model,
+ // we have to track what modelId/version it really maps so we can make our recursive call
+ Vertex thisElementsModelVtx = getModelGivenModelVer(thisElementsModelVerVtx, incomingTrail);
+ subModelFirstModInvId = thisElementsModelVtx.<String>property("model-invariant-id").orElse(null);
+ subModelFirstModVerId = thisElementsModelVerVtx.<String>property("model-version-id").orElse(null);
+
+ if( nodeTypeSupportsPersona(thisElementNodeType, dbMaps) ){
+ modInfo4Trail = "," + subModelFirstModInvId + "," + subModelFirstModVerId;
+ }
+ String modelVerId = thisElementsModelVerVtx.<String>property("model-version-id").orElse(null);
+ if( subModelFirstModInvId == null || subModelFirstModInvId.equals("") || subModelFirstModVerId == null || subModelFirstModVerId.equals("") ){
+ throw new AAIException("AAI_6132", "Bad Model Definition: Bad model-invariant-id or model-version-id. Model-ver-id = " + modelVerId);
+ }
+
+ elementVtxForThisLevel = getTopElementForSvcOrResModelVer(thisElementsModelVerVtx, incomingTrail);
+ modConstraintHash2Use = getModConstraintHash( thisLevelElemVtx, modConstraintHash );
+ }
+ else {
+ elementVtxForThisLevel = thisLevelElemVtx;
+ }
+
+ if( incomingTrail.equals("") ){
+ // This is the first one
+ thisGuysTrail = thisElementNodeType + firstElementModelInfo;
+ }
+ else {
+ thisGuysTrail = incomingTrail + "|" + thisElementNodeType + modInfo4Trail;
+ }
+
+ // We only want to ensure that a particular element does not repeat on a single "branch".
+ // It could show up on other branches in the case where it is a sub-model which is being
+ // used in more than one place.
+ //
+ List<String> thisTrailsVidsTraversed = new ArrayList <String>();
+ thisTrailsVidsTraversed.addAll(vidsTraversed);
+ thisTrailsVidsTraversed.add(thisElemVid);
+
+ // Look at the elements pointed to at this level and add on their data
+ Iterator<Vertex> vertI = this.traverseIncidentEdges(EdgeType.TREE, elementVtxForThisLevel, "model-element", "constrained-element-set");
+
+ while( vertI != null && vertI.hasNext() ){
+ Vertex tmpVert = vertI.next();
+ String vid = tmpVert.id().toString();
+ Map<String,Object> elementHash = new HashMap<String, Object>();
+ String connectToType = tmpVert.<String>property(AAIProperties.NODE_TYPE).orElse(null);
+ if( connectToType != null && connectToType.equals("model-element") ){
+ // A nice, regular old model-element
+ elementHash.put(vid, tmpVert);
+ }
+ else if( (connectToType != null) && connectToType.equals("constrained-element-set") ){
+ // translate the constrained-element-set into a hash of model-element Vertex's
+ String constrainedElementSetUuid = tmpVert.<String>property("constrained-element-set-uuid").orElse(null);
+ if( (modConstraintHash2Use != null) && modConstraintHash2Use.containsKey(constrainedElementSetUuid) ){
+ // This constrained-element-set is being superseded by a different one
+ Vertex replacementConstraintVert = modConstraintHash.get(constrainedElementSetUuid);
+ elementHash = getNextStepElementsFromSet( replacementConstraintVert );
+ // Now that we've found and used the replacement constraint, we don't need to carry it along any farther
+ modConstraintHash.remove(constrainedElementSetUuid);
+ }
+ else {
+ elementHash = getNextStepElementsFromSet( tmpVert );
+ }
+ }
+ else {
+ String msg = " model element has [connectedTo] edge to improper nodeType= ["
+ + connectToType + "] trail = [" + incomingTrail + "].";
+ throw new AAIException("AAI_6132", msg);
+ }
+
+ for( Map.Entry<String, Object> entry : elementHash.entrySet() ){
+ Vertex elVert = (Vertex)(entry.getValue());
+ String tmpElVid = elVert.id().toString();
+ String tmpElNT = getModElementWidgetType( elVert, thisGuysTrail );
+ String tmpElStepName = getModelElementStepName( elVert, thisGuysTrail, dbMaps );
+
+ List<String> linkagePtList = new ArrayList <String>();
+ Iterator <VertexProperty<Object>> vpI = elVert.properties("linkage-points");
+ //DEBUG -- AAI-8002
+ // I am not sure why, but since "linkage-points" is an xml-element-wrapper in the OXM definition,
+ // we get back the whole array of Strings in one String - but still use the "vtx.properties()" to
+ // get it - but only look at the first thing returned by the iterator.
+ if( vpI.hasNext() ){
+ String tmpLinkageThing = (String)vpI.next().value();
+ linkagePtList = makeSureItsAnArrayList( tmpLinkageThing );
+ }
+
+ if( linkagePtList != null && !linkagePtList.isEmpty() ){
+ // This is as far as we can go, we will use the linkage point info to define the
+ // rest of this "trail"
+ for( int i = 0; i < linkagePtList.size(); i++ ){
+ Multimap<String, String> tmpMap = collectTopology4LinkagePoint( transId, fromAppId,
+ linkagePtList.get(i), thisGuysTrail, currentMap, dbMaps);
+ thisMap.putAll(tmpMap);
+ }
+ }
+ else {
+ check4EdgeRule(tmpElNT, thisElementNodeType, dbMaps);
+ thisMap.put(thisGuysTrail, tmpElStepName);
+ if( !thisTrailsVidsTraversed.contains(tmpElVid) ){
+ // This is one we would like to use - so we'll recursively get it's result set to add to ours
+ Multimap<String, String> tmpMap = collectTopology4ModelVer( transId, fromAppId,
+ elVert, thisGuysTrail,
+ currentMap, thisTrailsVidsTraversed, levelCounter,
+ dbMaps, modConstraintHash2Use, subModelFirstModInvId, subModelFirstModVerId );
+ thisMap.putAll(tmpMap);
+ }
+ else {
+ String modelElementUuid = elVert.<String>property("model-element-uuid").orElse(null);
+ String msg = "Bad Model Definition: looping model-element (model-element-uuid = [" +
+ modelElementUuid + "]) found trying to add step: [" + tmpElStepName + "], " +
+ " on trail = [" + thisGuysTrail + "]. ";
+ System.out.println( msg );
+ throw new AAIException("AAI_6132", msg);
+ }
+ }
+ }
+ }
+
+ return thisMap;
+
+ } // End of collectTopology4ModelVer()
+
+
+ /**
+ * Check 4 edge rule.
+ *
+ * @param nodeTypeA the node type A
+ * @param nodeTypeB the node type B
+ * @param dbMaps the db maps
+ * @throws AAIException the AAI exception
+ */
+ public void check4EdgeRule( String nodeTypeA, String nodeTypeB, DbMaps dbMaps ) throws AAIException {
+ // Throw an exception if there is no defined edge rule for this combination of nodeTypes in DbEdgeRules.
+
+ final EdgeRules edgeRules = EdgeRules.getInstance();
+
+ if( !edgeRules.hasEdgeRule(nodeTypeA, nodeTypeB)
+ && !edgeRules.hasEdgeRule(nodeTypeB, nodeTypeA) ){
+ // There's no EdgeRule for this -- find out if one of the nodeTypes is invalid or if
+ // they are valid, but there's just no edgeRule for them.
+ if( ! dbMaps.NodeProps.containsKey(nodeTypeA) ){
+ String emsg = " Unrecognized nodeType aa [" + nodeTypeA + "]\n";
+ throw new AAIException("AAI_6115", emsg);
+ }
+ else if( ! dbMaps.NodeProps.containsKey(nodeTypeB) ){
+ String emsg = " Unrecognized nodeType bb [" + nodeTypeB + "]\n";
+ throw new AAIException("AAI_6115", emsg);
+ }
+ else {
+ String msg = " No Edge Rule found for this pair of nodeTypes (order does not matter) ["
+ + nodeTypeA + "], [" + nodeTypeB + "].";
+ throw new AAIException("AAI_6120", msg);
+ }
+ }
+
+ }
+
+
+ /**
+ * Collect topology 4 linkage point.
+ *
+ * @param transId the trans id
+ * @param fromAppId the from app id
+ * @param linkagePointStr -- Note it is in reverse order from where we connect to it.
+ * @param incomingTrail -- trail of nodeTypes that got us here (this vertex) from the top
+ * @param currentMap the current map -- that got us to this point (that we will use as the base of the map we will return)
+ * @param dbMaps the db maps
+ * @return Map of the topology
+ * @throws AAIException the AAI exception
+ */
+ public Multimap<String, String> collectTopology4LinkagePoint( String transId, String fromAppId,
+ String linkagePointStrVal, String incomingTrail, Multimap <String,String> currentMap, DbMaps dbMaps )
+ throws AAIException {
+
+ Multimap <String, String> thisMap = ArrayListMultimap.create();
+ thisMap.putAll(currentMap);
+ String thisGuysTrail = incomingTrail;
+
+ // NOTE - "trails" can have multiple parts now since we track persona info for some.
+ // We just want to look at the node type info - which would be the piece
+ // before any commas (if there are any).
+
+ String [] trailSteps = thisGuysTrail.split("\\|");
+ if( trailSteps == null || trailSteps.length == 0 ){
+ throw new AAIException("AAI_6125", "Bad incomingTrail passed to collectTopology4LinkagePoint(): [" + incomingTrail + "] ");
+ }
+ String lastStepString = trailSteps[trailSteps.length - 1];
+ String [] stepPieces = lastStepString.split(",");
+ String lastStepNT = stepPieces[0];
+
+ // It is assumed that the linkagePoint string will be a pipe-delimited string where each
+ // piece is an AAIProperties.NODE_TYPE. For now, the first thing to connect to is what is on the farthest right.
+ // Example: linkagePoint = "pserver|p-interface|l-interface" would mean that we're connecting to the l-interface
+ // but that after that, we connect to a p-interface followed by a pserver.
+ // It might have been more clear to define it in the other direction, but for now, that is it. (16-07)
+ String linkagePointStr = linkagePointStrVal;
+ // --- DEBUG For AAI-8002
+ // We are getting these with more than linkage thing in one string.
+ // Ie. "pserver|lag-interface|l-interface, pserver|p-interface|l-interface, vlan|l-interface"
+ linkagePointStr = linkagePointStr.replace("[", "");
+ linkagePointStr = linkagePointStr.replace("]", "");
+ linkagePointStr = linkagePointStr.replace(" ", "");
+
+ String [] linkage = linkagePointStr.split("\\,");
+ for( int x = 0; x < linkage.length; x++ ){
+ lastStepNT = stepPieces[0];
+ String thisStepNT = "";
+ String [] linkageSteps = linkage[x].split("\\|");
+ if( linkageSteps == null || linkageSteps.length == 0 ){
+ throw new AAIException("AAI_6125", "Bad linkagePointStr passed to collectTopology4LinkagePoint(): [" + linkagePointStr + "] ");
+ }
+ for( int i=(linkageSteps.length - 1); i >= 0; i-- ){
+ thisStepNT = linkageSteps[i];
+ check4EdgeRule(lastStepNT, thisStepNT, dbMaps);
+ thisMap.put(thisGuysTrail, thisStepNT);
+ thisGuysTrail = thisGuysTrail + "|" + thisStepNT;
+ lastStepNT = thisStepNT;
+ }
+ }
+ return thisMap;
+
+ } // End of collectTopology4LinkagePoint()
+
+
+ /**
+ * Gets the next step elements from set.
+ *
+ * @param constrElemSetVtx the constr elem set vtx
+ * @return Hash of the set of model-elements this set represents
+ * @throws AAIException the AAI exception
+ */
+ public Map<String,Object> getNextStepElementsFromSet( Vertex constrElemSetVtx )
+ throws AAIException {
+ // Take a constrained-element-set and figure out the total set of all the possible elements that it
+ // represents and return them as a Hash.
+
+ Map<String,Object> retElementHash = new HashMap<String, Object>();
+
+ if( constrElemSetVtx == null ){
+ String msg = " getNextStepElementsFromSet() called with null constrElemSetVtx ";
+ throw new AAIException("AAI_6125", msg);
+ }
+
+ String constrNodeType = constrElemSetVtx.<String>property(AAIProperties.NODE_TYPE).orElse(null);
+ String constrElemSetUuid = constrElemSetVtx.<String>property("constrained-element-set-uuid").orElse(null);
+ if( constrNodeType == null || !constrNodeType.equals("constrained-element-set") ){
+ String msg = " getNextStepElementsFromSet() called with wrong type model: [" + constrNodeType + "]. ";
+ throw new AAIException("AAI_6125", msg);
+ }
+
+ ArrayList <Vertex> choiceSetVertArray = new ArrayList<Vertex>();
+ Iterator<Vertex> vertI = this.traverseIncidentEdges(EdgeType.TREE, constrElemSetVtx, "element-choice-set");
+ int setCount = 0;
+ while( vertI != null && vertI.hasNext() ){
+ Vertex choiceSetVertex = vertI.next();
+ String constrSetType = choiceSetVertex.<String>property(AAIProperties.NODE_TYPE).orElse(null);
+ if( constrSetType != null && constrSetType.equals("element-choice-set") ){
+ choiceSetVertArray.add(choiceSetVertex);
+ setCount++;
+ }
+ }
+
+ if( setCount == 0 ){
+ String msg = "No element-choice-set found under constrained-element-set-uuid = " + constrElemSetUuid;
+ throw new AAIException("AAI_6132", msg);
+ }
+
+ // Loop through each choice-set and grab the model-elements
+ for( int i = 0; i < setCount; i++ ){
+ Vertex choiceSetVert = choiceSetVertArray.get(i);
+ Iterator<Vertex> mVertI = this.traverseIncidentEdges(EdgeType.TREE, choiceSetVert, "model-element");
+ int elCount = 0;
+ while( mVertI != null && mVertI.hasNext() ){
+ Vertex tmpElVertex = mVertI.next();
+ String elNodeType = tmpElVertex.<String>property(AAIProperties.NODE_TYPE).orElse(null);
+ if( elNodeType != null && elNodeType.equals("model-element") ){
+ String tmpVid = tmpElVertex.id().toString();
+ retElementHash.put(tmpVid, tmpElVertex);
+ elCount++;
+ }
+ else {
+ // unsupported node type found for this choice-set
+ String msg = "Unsupported nodeType (" + elNodeType
+ + ") found under choice-set under constrained-element-set-uuid = " + constrElemSetUuid;
+ throw new AAIException("AAI_6132", msg);
+ }
+ }
+
+ if( elCount == 0 ){
+ String msg = "No model-elements found in choice-set under constrained-element-set-uuid = " + constrElemSetUuid;
+ throw new AAIException("AAI_6132", msg);
+ }
+
+ }
+ return retElementHash;
+
+ } // End of getNextStepElementsFromSet()
+
+
+
+ /**
+ * Gen topo map 4 named Q.
+ *
+ * @param transId the trans id
+ * @param fromAppId the from app id
+ * @param queryVertex the query vertex
+ * @param namedQueryUuid the named query uuid
+ * @return MultiMap of valid next steps for each potential query-element
+ * @throws AAIException the AAI exception
+ */
+ public Multimap<String, String> genTopoMap4NamedQ( String transId, String fromAppId,
+ Vertex queryVertex, String namedQueryUuid )
+ throws AAIException {
+
+ if( queryVertex == null ){
+ throw new AAIException("AAI_6125", "null queryVertex passed to genTopoMap4NamedQ()");
+ }
+
+ Multimap <String, String> initialEmptyMap = ArrayListMultimap.create();
+ List<String> vidsTraversed = new ArrayList<>();
+
+ Vertex firstElementVertex = null;
+ Iterator<Vertex> vertI = this.traverseIncidentEdges(EdgeType.TREE, queryVertex, "named-query-element");
+ int elCount = 0;
+ while( vertI != null && vertI.hasNext() ){
+ elCount++;
+ firstElementVertex = vertI.next();
+ }
+
+ if( elCount > 1 ){
+ throw new AAIException("AAI_6133", "Illegal query defined: More than one first element defined for = " + namedQueryUuid);
+ }
+
+ if( firstElementVertex == null ){
+ throw new AAIException("AAI_6114", "Could not find first query element = " + namedQueryUuid);
+ }
+
+ Vertex modVtx = getModelThatNqElementRepresents( firstElementVertex, "" );
+ String modelType = getModelTypeFromModel( modVtx, "" );
+ if( ! modelType.equals("widget") ){
+ throw new AAIException("AAI_6133", "Bad Named Query Definition: First element must correspond to a widget type model. Named Query UUID = "
+ + namedQueryUuid);
+ }
+
+ Multimap <String, String> collectedMap = collectTopology4NamedQ( transId, fromAppId,
+ firstElementVertex, "",
+ initialEmptyMap, vidsTraversed, 0);
+
+ return collectedMap;
+
+ } // End of genTopoMap4NamedQ()
+
+
+
+ /**
+ * Collect topology 4 named Q.
+ *
+ * @param transId the trans id
+ * @param fromAppId the from app id
+ * @param thisLevelElemVtx the model element vertex for this level
+ * @param levelCounter the level counter
+ * @return resultSet
+ * @throws AAIException the AAI exception
+ */
+ public Multimap<String, String> collectTopology4NamedQ( String transId, String fromAppId,
+ Vertex thisLevelElemVtx, String incomingTrail,
+ Multimap <String,String> currentMap, List<String> vidsTraversed, int levelCounter )
+ throws AAIException {
+
+ levelCounter++;
+
+ Multimap <String, String> thisMap = ArrayListMultimap.create();
+ thisMap.putAll(currentMap);
+
+ String thisElemVid = thisLevelElemVtx.id().toString();
+ if( levelCounter > MAX_LEVELS ) {
+ throw new AAIException("AAI_6125", "collectModelStructure() has looped across more levels than allowed: " + MAX_LEVELS + ". ");
+ }
+ String thisGuysTrail = "";
+
+ // find out what widget (and thereby what aai-node-type) this element represents
+ String thisElementNodeType = getNqElementWidgetType( transId, fromAppId, thisLevelElemVtx, incomingTrail );
+
+ if( incomingTrail.equals("") ){
+ // This is the first one
+ thisGuysTrail = thisElementNodeType;
+ }
+ else {
+ thisGuysTrail = incomingTrail + "|" + thisElementNodeType;
+ }
+
+ vidsTraversed.add(thisElemVid);
+
+ // Look at the elements pointed to at this level and add on their data
+ Iterator<Vertex> vertI = this.traverseIncidentEdges(EdgeType.TREE, thisLevelElemVtx, "named-query-element");
+ while( vertI != null && vertI.hasNext() ){
+ Vertex tmpVert = vertI.next();
+ String tmpVid = tmpVert.id().toString();
+ String tmpElNT = getNqElementWidgetType( transId, fromAppId, tmpVert, thisGuysTrail );
+ thisMap.put(thisGuysTrail, tmpElNT);
+ if( !vidsTraversed.contains(tmpVid) ){
+ // This is one we would like to use - so we'll recursively get it's result set to add to ours
+ Multimap<String, String> tmpMap = collectTopology4NamedQ( transId, fromAppId,
+ tmpVert, thisGuysTrail,
+ currentMap, vidsTraversed, levelCounter);
+ thisMap.putAll(tmpMap);
+ }
+ }
+
+ return thisMap;
+
+ } // End of collectTopology4NamedQ()
+
+
+ /**
+ * Gets the model that NamedQuery element represents.
+ *
+ * @param elementVtx the NQ element vtx
+ * @param elementTrail the element trail
+ * @return the model that element represents
+ * @throws AAIException the AAI exception
+ */
+ public Vertex getModelThatNqElementRepresents( Vertex elementVtx, String elementTrail )
+ throws AAIException {
+
+ // Get the model that a named-query element represents
+ Vertex modVtx = null;
+ Iterator<Vertex> mvertI = this.traverseIncidentEdges(EdgeType.COUSIN, elementVtx, "model");
+ int modCount = 0;
+ while( mvertI != null && mvertI.hasNext() ){
+ modCount++;
+ modVtx = mvertI.next();
+ }
+
+ if( modCount > 1 ){
+ String msg = "Illegal element defined: More than one model pointed to by a single named-query-element at [" +
+ elementTrail + "].";
+ throw new AAIException("AAI_6125", msg);
+ }
+
+ if( modVtx == null ){
+ String msg = "Bad named-query definition: Could not find model for element. ";
+ if( !elementTrail.equals("") ){
+ msg = "Bad named-query definition: Could not find model for named-query-element at [" + elementTrail + "].";
+ }
+ throw new AAIException("AAI_6132", msg);
+ }
+
+ String nodeType = modVtx.<String>property(AAIProperties.NODE_TYPE).orElse(null);
+ if( (nodeType != null) && nodeType.equals("model") ){
+ return modVtx;
+ }
+ else {
+ String msg = "Illegal Named Query element defined: expecting a 'model', but found 'isA' edge pointing to nodeType = " +
+ nodeType + "] at [" + elementTrail + "].";
+ throw new AAIException("AAI_6125", msg);
+ }
+
+ }// getModelThatNqElementRepresents()
+
+
+ /**
+ * Gets the model-ver that element represents.
+ *
+ * @param elementVtx the element vtx
+ * @param elementTrail the element trail
+ * @return the model-ver that element represents
+ * @throws AAIException the AAI exception
+ */
+ public Vertex getModelVerThatElementRepresents( Vertex elementVtx, String elementTrail )
+ throws AAIException {
+
+ // Get the model-ver that an element represents
+ Vertex modVerVtx = null;
+ Iterator<Vertex> mvertI = this.traverseIncidentEdges(EdgeType.COUSIN, elementVtx, "model-ver");
+ int modCount = 0;
+ while( mvertI != null && mvertI.hasNext() ){
+ modCount++;
+ modVerVtx = mvertI.next();
+ }
+
+ if( modCount > 1 ){
+ String msg = "Illegal element defined: More than one model pointed to by a single element at [" +
+ elementTrail + "].";
+ throw new AAIException("AAI_6125", msg);
+ }
+
+ if( modVerVtx == null ){
+ String msg = "Bad model definition: Could not find model-ver for model-element. ";
+ if( !elementTrail.equals("") ){
+ msg = "Bad model definition: Could not find model-VER for model-element at [" + elementTrail + "].";
+ }
+ throw new AAIException("AAI_6132", msg);
+ }
+
+ String nodeType = modVerVtx.<String>property(AAIProperties.NODE_TYPE).orElse(null);
+ if( (nodeType != null) && nodeType.equals("model-ver") ){
+ return modVerVtx;
+ }
+ else {
+ String msg = "Illegal model-element defined: expecting a 'model-ver', but found 'isA' edge pointing to nodeType = " +
+ nodeType + "] at [" + elementTrail + "].";
+ throw new AAIException("AAI_6125", msg);
+ }
+
+ }// getModelVerThatElementRepresents()
+
+
+
+ /**
+ * Gets the model that is parent to model-ver node.
+ *
+ * @param modVerVtx the model-ver vtx
+ * @param elementTrail the element trail
+ * @return the model that element represents
+ * @throws AAIException the AAI exception
+ */
+ public Vertex getModelGivenModelVer( Vertex modVerVtx, String elementTrail )
+ throws AAIException {
+
+ // Get the parent model for this "model-ver" node
+ Vertex modVtx = null;
+ Iterator<Vertex> mvertI = this.traverseIncidentEdges(EdgeType.TREE, modVerVtx, "model");
+ int modCount = 0;
+ while( mvertI != null && mvertI.hasNext() ){
+ modCount++;
+ modVtx = mvertI.next();
+ }
+
+ if( modCount > 1 ){
+ String msg = "Illegal model-ver node defined: More than one model points to it with a 'has' edge [" +
+ elementTrail + "].";
+ throw new AAIException("AAI_6125", msg);
+ }
+
+ if( modVtx == null ){
+ String msg = "Bad model-ver node: Could not find parent model. ";
+ if( !elementTrail.equals("") ){
+ msg = "Bad model-ver node: Could not find parent model. [" + elementTrail + "].";
+ }
+ throw new AAIException("AAI_6132", msg);
+ }
+
+ String nodeType = modVtx.<String>property(AAIProperties.NODE_TYPE).orElse(null);;
+ if( (nodeType != null) && nodeType.equals("model") ){
+ // Found what we were looking for.
+ return modVtx;
+ }
+ else {
+ // Something is amiss
+ String msg = " Could not find parent model node for model-ver node at [" +
+ elementTrail + "].";
+ throw new AAIException("AAI_6125", msg);
+ }
+
+
+ }// getModelGivenModelVer()
+
+
+
+ /**
+ * Gets the model type.
+ *
+ * @param modelVtx the model vtx
+ * @param elementTrail the element trail
+ * @return the model type
+ * @throws AAIException the AAI exception
+ */
+ public String getModelTypeFromModel( Vertex modelVtx, String elementTrail )
+ throws AAIException {
+
+ // Get the model-type from a model vertex
+ if( modelVtx == null ){
+ String msg = " null modelVtx passed to getModelTypeFromModel() ";
+ throw new AAIException("AAI_6114", msg);
+ }
+
+ String modelType = modelVtx.<String>property("model-type").orElse(null);
+ if( (modelType == null) || modelType.equals("") ){
+ String msg = "Could not find model-type for model encountered at [" + elementTrail + "].";
+ throw new AAIException("AAI_6132", msg);
+ }
+
+ if( !modelType.equals("widget") && !modelType.equals("resource") && !modelType.equals("service") ){
+ String msg = "Unrecognized model-type, [" + modelType + "] for model pointed to by element at [" + elementTrail + "].";
+ throw new AAIException("AAI_6132", msg);
+ }
+
+ return modelType;
+
+ }// getModelTypeFromModel()
+
+
+
+ /**
+ * Gets the model type given model-ver
+ *
+ * @param modelVerVtx the model-ver vtx
+ * @param elementTrail the element trail
+ * @return the model type
+ * @throws AAIException the AAI exception
+ */
+ public String getModelTypeFromModelVer( Vertex modelVerVtx, String elementTrail )
+ throws AAIException {
+
+ // Get the model-type given a model-ver vertex
+ if( modelVerVtx == null ){
+ String msg = " null modelVerVtx passed to getModelTypeFromModelVer() ";
+ throw new AAIException("AAI_6114", msg);
+ }
+
+ Vertex modVtx = getModelGivenModelVer( modelVerVtx, elementTrail );
+ String modelType = modVtx.<String>property("model-type").orElse(null);
+ if( (modelType == null) || modelType.equals("") ){
+ String msg = "Could not find model-type for model encountered at [" + elementTrail + "].";
+ throw new AAIException("AAI_6132", msg);
+ }
+
+ if( !modelType.equals("widget") && !modelType.equals("resource") && !modelType.equals("service") ){
+ String msg = "Unrecognized model-type, [" + modelType + "] for model pointed to by element at [" + elementTrail + "].";
+ throw new AAIException("AAI_6132", msg);
+ }
+
+ return modelType;
+
+ }// getModelTypeFromModelVer()
+
+
+
+ /**
+ * Gets the model-element step name.
+ *
+ * @param elementVtx the model-element vtx
+ * @param elementTrail the element trail
+ * @param dbMaps the db maps
+ * @return the element step name
+ * @throws AAIException the AAI exception
+ */
+ public String getModelElementStepName( Vertex elementVtx, String elementTrail, DbMaps dbMaps)
+ throws AAIException {
+
+ // Get the "step name" for a model-element
+ // Step names look like this for widget-models: AAIProperties.NODE_TYPE
+ // Step names look like this for resource/service models: "aai-node-type,model-invariant-id,model-version-id"
+ // NOTE -- if the element points to a resource or service model, then we'll return the
+ // widget-type of the first element (crown widget) for that model.
+ String thisElementNodeType = "?";
+ Vertex modVerVtx = getModelVerThatElementRepresents( elementVtx, elementTrail );
+ String modelType = getModelTypeFromModelVer( modVerVtx, elementTrail );
+
+ if( modelType == null ){
+ String msg = " could not determine modelType in getModelElementStepName(). elementTrail = [" + elementTrail + "].";
+ throw new AAIException("AAI_6132", msg);
+ }
+
+ if( modelType.equals("widget") ){
+ // NOTE: for models that have model-type = "widget", their "model-name" maps directly to aai-node-type
+ thisElementNodeType = modVerVtx.<String>property("model-name").orElse(null);
+ if( (thisElementNodeType == null) || thisElementNodeType.equals("") ){
+ String msg = "Could not find model-name for the widget model pointed to by element at [" + elementTrail + "].";
+ throw new AAIException("AAI_6132", msg);
+ }
+ return thisElementNodeType;
+ }
+ else if( modelType.equals("resource") || modelType.equals("service") ){
+ Vertex modVtx = getModelGivenModelVer( modVerVtx, elementTrail );
+ String modInvId = modVtx.<String>property("model-invariant-id").orElse(null);
+ String modVerId = modVerVtx.<String>property("model-version-id").orElse(null);
+ Vertex relatedTopElementModelVtx = getTopElementForSvcOrResModelVer( modVerVtx, elementTrail );
+ Vertex relatedModelVtx = getModelVerThatElementRepresents( relatedTopElementModelVtx, elementTrail );
+ thisElementNodeType = relatedModelVtx.<String>property("model-name").orElse(null);
+
+ if( (thisElementNodeType == null) || thisElementNodeType.equals("") ){
+ String msg = "Could not find model-name for the widget model pointed to by element at [" + elementTrail + "].";
+ throw new AAIException("AAI_6132", msg);
+ }
+
+ String stepName = "";
+ if( nodeTypeSupportsPersona(thisElementNodeType, dbMaps) ){
+ // This nodeType that this resource or service model refers to does support persona-related fields, so
+ // we will use model-invariant-id and model-version-id as part of the step name.
+ stepName = thisElementNodeType + "," + modInvId + "," + modVerId;
+ }
+ else {
+ stepName = thisElementNodeType;
+ }
+ return stepName;
+ }
+ else {
+ String msg = " Unrecognized model-type = [" + modelType + "] pointed to by element at [" + elementTrail + "].";
+ throw new AAIException("AAI_6132", msg);
+ }
+
+ }// getModelElementStepName()
+
+
+
+ /**
+ * Node type supports persona.
+ *
+ * @param nodeType the node type
+ * @param dbMaps the db maps
+ * @return the boolean
+ * @throws AAIException the AAI exception
+ */
+ public Boolean nodeTypeSupportsPersona(String nodeType, DbMaps dbMaps)
+ throws AAIException {
+
+ if( nodeType == null || nodeType.equals("") ){
+ return false;
+ }
+
+ // Return true if this type of node supports the properties: "model-invariant-id-local" and "model-version-id-local"
+ if( ! dbMaps.NodeProps.containsKey(nodeType) ){
+ String emsg = " Unrecognized nodeType [" + nodeType + "]\n";
+ throw new AAIException("AAI_6115", emsg);
+ }
+
+ Collection <String> props4ThisNT = dbMaps.NodeProps.get(nodeType);
+ if( !props4ThisNT.contains("model-invariant-id-local") || !props4ThisNT.contains("model-version-id-local") ){
+ return false;
+ }
+ else {
+ return true;
+ }
+
+ }// nodeTypeSupportsPersona()
+
+
+ /**
+ * Gets a Named Query element's widget type.
+ *
+ * @param elementVtx the named-query element vtx
+ * @param elementTrail the element trail
+ * @return the element widget type
+ * @throws AAIException the AAI exception
+ */
+ public String getNqElementWidgetType( String transId, String fromAppId,
+ Vertex elementVtx, String elementTrail )
+ throws AAIException {
+
+ String thisNqElementWidgetType = "";
+ // Get the associated node-type for the model pointed to by a named-query-element.
+ // NOTE -- if the element points to a resource or service model, then we'll return the
+ // widget-type of the first element (crown widget) for that model.
+ Vertex modVtx = getModelThatNqElementRepresents( elementVtx, elementTrail );
+ String modelType = getModelTypeFromModel( modVtx, elementTrail );
+
+ if( modelType == null || !modelType.equals("widget") ){
+ String emsg = " Model Type must be 'widget' for NamedQuery elements. Found [" + modelType + "] at [" +
+ elementTrail + "]\n";
+ throw new AAIException("AAI_6132", emsg);
+ }
+ else {
+ // For a Widget model, the nodeType is just mapped to the model-element.model-name
+ List<Vertex> modVerVtxArr = getModVersUsingModel(transId, fromAppId, modVtx);
+ if( modVerVtxArr != null && !modVerVtxArr.isEmpty() ){
+ thisNqElementWidgetType = (modVerVtxArr.get(0)).<String>property("model-name").orElse(null);
+ }
+ if( thisNqElementWidgetType == null || thisNqElementWidgetType.equals("") ){
+ String emsg = " Widget type could not be determined at [" + elementTrail + "]\n";
+ throw new AAIException("AAI_6132", emsg);
+ }
+ else {
+ return thisNqElementWidgetType;
+ }
+ }
+
+
+ }// End getNqElementWidgetType()
+
+
+ /**
+ * Gets a model-element's top widget type.
+ *
+ * @param elementVtx the model element vtx
+ * @param elementTrail the element trail
+ * @return the element widget type
+ * @throws AAIException the AAI exception
+ */
+ public String getModElementWidgetType( Vertex elementVtx, String elementTrail )
+ throws AAIException {
+
+ // Get the associated node-type for the model-ver pointed to by a model-element.
+ // NOTE -- if the element points to a resource or service model, then we'll return the
+ // widget-type of the first element (crown widget) for that model.
+ Vertex modVerVtx = getModelVerThatElementRepresents( elementVtx, elementTrail );
+ String thisElementNodeType = getModelVerTopWidgetType( modVerVtx, elementTrail );
+ return thisElementNodeType;
+
+ }// End getModElementWidgetType()
+
+
+ /**
+ * Gets the node using unique identifier
+ *
+ * @param transId the trans id
+ * @param fromAppId the from app id
+ * @param nodeType the nodeType
+ * @param idPropertyName the property name of the unique identifier
+ * @param uniqueIdVal the UUID value
+ * @return unique vertex found using UUID
+ * @throws AAIException the AAI exception
+ */
+ public Vertex getNodeUsingUniqueId( String transId, String fromAppId,
+ String nodeType, String idPropertyName, String uniqueIdVal )
+ throws AAIException {
+
+ // Given a unique identifier, get the Vertex
+ if( uniqueIdVal == null || uniqueIdVal.equals("") ){
+ String emsg = " Bad uniqueIdVal passed to getNodeUsingUniqueId(): ["
+ + uniqueIdVal + "]\n";
+ throw new AAIException("AAI_6118", emsg);
+ }
+
+ if( idPropertyName == null || idPropertyName.equals("") ){
+ String emsg = " Bad idPropertyName passed to getNodeUsingUniqueId(): ["
+ + idPropertyName + "]\n";
+ throw new AAIException("AAI_6118", emsg);
+ }
+
+ if( nodeType == null || nodeType.equals("") ){
+ String emsg = " Bad nodeType passed to getNodeUsingUniqueId(): ["
+ + nodeType + "]\n";
+ throw new AAIException("AAI_6118", emsg);
+ }
+
+ Vertex uniqVtx = null;
+ Iterable <?> uniqVerts = null;
+ uniqVerts = engine.asAdmin().getReadOnlyTraversalSource().V().has(AAIProperties.NODE_TYPE,nodeType).has(idPropertyName,uniqueIdVal).toList();
+ if( uniqVerts == null ){
+ String emsg = "Node could not be found for nodeType = [" + nodeType
+ + "], propertyName = [" + idPropertyName
+ + "], propertyValue = [" + uniqueIdVal + "]\n";
+ throw new AAIException("AAI_6114", emsg);
+ }
+ else {
+ int count = 0;
+ Iterator <?> uniqVertsIter = uniqVerts.iterator();
+ if( !uniqVertsIter.hasNext() ){
+ String emsg = "Node could not be found for nodeType = [" + nodeType
+ + "], propertyName = [" + idPropertyName
+ + "], propertyValue = [" + uniqueIdVal + "]\n";
+ throw new AAIException("AAI_6114", emsg);
+ }
+ else {
+ while( uniqVertsIter.hasNext() ){
+ count++;
+ uniqVtx = (Vertex) uniqVertsIter.next();
+ if( count > 1 ){
+ String emsg = "More than one node found for nodeType = [" + nodeType
+ + "], propertyName = [" + idPropertyName
+ + "], propertyValue = [" + uniqueIdVal + "]\n";
+ throw new AAIException("AAI_6132", emsg);
+ }
+ }
+ }
+ }
+
+ return uniqVtx;
+ }// End getNodeUsingUniqueId()
+
+
+ /**
+ * Gets the model-ver nodes using name.
+ *
+ * @param transId the trans id
+ * @param fromAppId the from app id
+ * @param modelName the model name
+ * @return the model-ver's that use this name
+ * @throws AAIException the AAI exception
+ */
+ public List<Vertex> getModelVersUsingName( String transId, String fromAppId,
+ String modelName )
+ throws AAIException {
+
+ // Given a "model-name", find the model-ver vertices that this maps to
+ if( modelName == null || modelName.equals("") ){
+ String emsg = " Bad modelName passed to getModelVersUsingName(): ["
+ + modelName + "]\n";
+ throw new AAIException("AAI_6118", emsg);
+ }
+
+ List<Vertex> retVtxArr = new ArrayList<>();
+ Iterator<Vertex> modVertsIter = this.engine.asAdmin().getReadOnlyTraversalSource().V().has(AAIProperties.NODE_TYPE,"model-ver").has("model-name",modelName);
+ if( !modVertsIter.hasNext() ){
+ String emsg = "Model-ver record(s) could not be found for model-ver data passed. model-name = [" +
+ modelName + "]\n";
+ throw new AAIException("AAI_6132", emsg);
+ }
+ else {
+ while( modVertsIter.hasNext() ){
+ Vertex tmpModelVerVtx = (Vertex) modVertsIter.next();
+ retVtxArr.add(tmpModelVerVtx);
+ }
+ }
+
+ return retVtxArr;
+
+ }// End getModelVersUsingName()
+
+
+ /**
+ * Gets the model-ver nodes using model-invariant-id.
+ *
+ * @param transId the trans id
+ * @param fromAppId the from app id
+ * @param model-invariant-id (uniquely identifies a model)
+ * @return the model-ver's defined for the corresponding model
+ * @throws AAIException the AAI exception
+ */
+ public Iterator<Vertex> getModVersUsingModelInvId( String transId, String fromAppId,
+ String modelInvId )
+ throws AAIException {
+
+ // Given a "model-invariant-id", find the model-ver nodes that this maps to
+ if( modelInvId == null || modelInvId.equals("") ){
+ String emsg = " Bad model-invariant-id passed to getModVersUsingModelInvId(): ["
+ + modelInvId + "]\n";
+ throw new AAIException("AAI_6118", emsg);
+ }
+
+ Vertex modVtx = getNodeUsingUniqueId(transId, fromAppId, "model", "model-invariant-id", modelInvId);
+ List<Vertex> retVtxArr = getModVersUsingModel(transId, fromAppId, modVtx);
+ if( retVtxArr == null || retVtxArr.isEmpty() ){
+ String emsg = " Model-ver record(s) could not be found attached to model with model-invariant-id = [" +
+ modelInvId + "]\n";
+ throw new AAIException("AAI_6132", emsg);
+ }
+
+ return retVtxArr.iterator();
+ }// End getModVersUsingModelInvId()
+
+
+ /**
+ * Gets the model-ver nodes using a model node.
+ *
+ * @param transId the trans id
+ * @param fromAppId the from app id
+ * @param model vertex
+ * @return the model-ver's defined for the corresponding model
+ * @throws AAIException the AAI exception
+ */
+ public List<Vertex> getModVersUsingModel( String transId, String fromAppId,
+ Vertex modVtx )
+ throws AAIException {
+
+ if( modVtx == null ){
+ String emsg = " Null model vertex passed to getModVersUsingModel(): ";
+ throw new AAIException("AAI_6118", emsg);
+ }
+
+ List<Vertex> retVtxArr = new ArrayList<>();
+ Iterator<Vertex> modVerVertsIter = this.traverseIncidentEdges(EdgeType.TREE, modVtx, "model-ver");
+ if(!modVerVertsIter.hasNext()){
+ String modelInvId = modVtx.<String>property("model-invariant-id").orElse(null);
+ String emsg = "Model-ver record(s) could not be found attached to model with model-invariant-id = [" +
+ modelInvId + "]\n";
+ throw new AAIException("AAI_6132", emsg);
+ }
+ else {
+ while( modVerVertsIter.hasNext() ){
+ Vertex tmpModelVtx = (Vertex) modVerVertsIter.next();
+ retVtxArr.add(tmpModelVtx);
+ }
+ }
+
+ return retVtxArr;
+
+ }// End getModVersUsingModel()
+
+ /**
+ * Gets the model-version-ids using model-name.
+ *
+ * @param transId the trans id
+ * @param fromAppId the from app id
+ * @param modelName the model name
+ * @return the model uuids using name
+ * @throws AAIException the AAI exception
+ */
+ public List<String> getModelVerIdsUsingName( String transId, String fromAppId,
+ String modelName )
+ throws AAIException {
+
+ // Given a model-name find the model-ver nodes that it maps to
+ if( modelName == null || modelName.equals("") ){
+ String emsg = " Bad modelName passed to getModelVerIdsUsingName(): ["
+ + modelName + "]\n";
+ throw new AAIException("AAI_6118", emsg);
+ }
+
+ List<String> retArr = new ArrayList<>();
+ Iterator<Vertex> modVerVertsIter = this.engine.asAdmin().getReadOnlyTraversalSource().V().has(AAIProperties.NODE_TYPE,"model-ver").has("model-name",modelName);
+ if( !modVerVertsIter.hasNext() ){
+ String emsg = " model-ver record(s) could not be found for model data passed. model-name = [" +
+ modelName + "]\n";
+ throw new AAIException("AAI_6114", emsg);
+ }
+ else {
+ while( modVerVertsIter.hasNext() ){
+ Vertex modelVerVtx = (Vertex) modVerVertsIter.next();
+ String tmpUuid = modelVerVtx.<String>property("model-version-id").orElse(null);
+ if( (tmpUuid != null) && !tmpUuid.equals("") && !retArr.contains(tmpUuid) ){
+ retArr.add(tmpUuid);
+ }
+ }
+ }
+
+ if( retArr.isEmpty() ){
+ String emsg = "No model-ver record found for model-name = ["
+ + modelName + "]\n";
+ throw new AAIException("AAI_6132", emsg);
+ }
+
+ return retArr;
+ }// End getModelVerIdsUsingName()
+
+
+ /**
+ * Gets the model top widget type.
+ *
+ * @param transId the trans id
+ * @param fromAppId the from app id
+ * @param modelVersionId the model-version-id
+ * @param modelInvId the model-invariant-id
+ * @param modelName the model-name
+ * @return the model top widget type
+ * @throws AAIException the AAI exception
+ */
+ public String getModelVerTopWidgetType( String transId, String fromAppId,
+ String modelVersionId, String modelInvId, String modelName )
+ throws AAIException {
+
+ // Could be given a model-ver's key info (model-version-id), OR, just a (non-unique) model-name,
+ // Or just a model-invariant-id (which could have multiple model-ver records under it).
+ // In any case, they should only map to one single "top" node-type for the first element.
+
+ String nodeType = "?";
+ Iterator<Vertex> modVerVertsIter;
+
+ if( modelVersionId != null && !modelVersionId.equals("") ){
+ // this would be the best - we can just look up the model-ver records directly
+ modVerVertsIter = this.engine.asAdmin().getReadOnlyTraversalSource().V().has(AAIProperties.NODE_TYPE,"model-ver").has("model-version-id",modelVersionId);
+ }
+ else if( modelName != null && !modelName.equals("") ){
+ modVerVertsIter = this.engine.asAdmin().getReadOnlyTraversalSource().V().has(AAIProperties.NODE_TYPE,"model-ver").has("model-name",modelName);
+ }
+ else if( modelInvId != null && !modelInvId.equals("") ){
+ modVerVertsIter = getModVersUsingModelInvId(transId, fromAppId, modelInvId);
+ }
+ else {
+ String msg = "Neither modelVersionId, modelInvariantId, nor modelName passed to: getModelVerTopWidgetType() ";
+ throw new AAIException("AAI_6120", msg);
+ }
+
+ if( !modVerVertsIter.hasNext() ){
+ String emsg = "model-ver record(s) could not be found for model data passed: modelInvariantId = [" + modelInvId +
+ "], modeVersionId = [" + modelVersionId + "], modelName = [" + modelName + "]\n";
+ throw new AAIException("AAI_6114", emsg);
+ }
+ else {
+ String lastNT = "";
+ if( !modVerVertsIter.hasNext() ){
+ String emsg = "model-ver record(s) could not be found for model data passed: modelInvariantId = [" + modelInvId +
+ "], modeVersionId = [" + modelVersionId + "], modelName = [" + modelName + "]\n";
+ throw new AAIException("AAI_6114", emsg);
+ }
+ while( modVerVertsIter.hasNext() ){
+ Vertex tmpModVerVtx = (Vertex) modVerVertsIter.next();
+ String tmpNT = getModelVerTopWidgetType( tmpModVerVtx, "" );
+ if( lastNT != null && !lastNT.equals("") ){
+ if( !lastNT.equals(tmpNT) ){
+ String emsg = "Different top-node-types (" + tmpNT + ", " + lastNT
+ + ") found for model data passed. (" +
+ " modelVersionId = [" + modelVersionId +
+ "], modelId = [" + modelInvId +
+ "], modelName = [" + modelName +
+ "])\n";
+ throw new AAIException("AAI_6114", emsg);
+ }
+ }
+ lastNT = tmpNT;
+ nodeType = tmpNT;
+ }
+ }
+
+ return nodeType;
+
+ }// End getModelVerTopWidgetType()
+
+
+ /**
+ * Gets the widget type that this model-ver starts with.
+ *
+ * @param modVerVtx the model-version vtx
+ * @param elementTrail the element trail
+ * @return the widget type of the starting node of this model
+ * @throws AAIException the AAI exception
+ */
+ public String getModelVerTopWidgetType( Vertex modVerVtx, String elementTrail )
+ throws AAIException {
+ // Get the associated nodeType (Ie. aai-node-type / widget-type) for a model-ver.
+ // NOTE -- if the element points to a resource or service model, then we'll return the
+ // widget-type of the first element (crown widget) for that model.
+ String modelType = getModelTypeFromModelVer( modVerVtx, elementTrail );
+ if( modelType == null ){
+ String msg = " Could not determine modelType in getModelVerTopWidgetType(). elementTrail = [" + elementTrail + "].";
+ throw new AAIException("AAI_6132", msg);
+ }
+
+ String thisElementNodeType = "?";
+ if( modelType.equals("widget") ){
+ // NOTE: for models that have model-type = "widget", their child model-ver nodes will
+ // have "model-name" which maps directly to aai-node-type (all model-ver's under one
+ // model should start with the same widget-type, so we only need to look at one).
+ thisElementNodeType = modVerVtx.<String>property("model-name").orElse(null);
+ if( (thisElementNodeType == null) || thisElementNodeType.equals("") ){
+ String msg = "Could not find model-name for the widget model pointed to by element at [" + elementTrail + "].";
+ throw new AAIException("AAI_6132", msg);
+ }
+ }
+ else if( modelType.equals("resource") || modelType.equals("service") ){
+ Vertex relatedTopElementVtx = getTopElementForSvcOrResModelVer( modVerVtx, elementTrail );
+ Vertex relatedModVerVtx = getModelVerThatElementRepresents( relatedTopElementVtx, elementTrail );
+ thisElementNodeType = relatedModVerVtx.<String>property("model-name").orElse(null);
+ if( (thisElementNodeType == null) || thisElementNodeType.equals("") ){
+ String msg = "Could not find model-name for the widget model pointed to by element at [" + elementTrail + "].";
+ throw new AAIException("AAI_6132", msg);
+ }
+ }
+ else {
+ String msg = " Unrecognized model-type = [" + modelType + "] pointed to by element at [" + elementTrail + "].";
+ throw new AAIException("AAI_6132", msg);
+ }
+
+ return thisElementNodeType;
+
+ }// getModelVerTopWidgetType()
+
+
+ /**
+ * Validate model.
+ *
+ * @param transId the trans id
+ * @param fromAppId the from app id
+ * @param modelNameVersionId the model name version id
+ * @param apiVersion the api version
+ * @throws AAIException the AAI exception
+ */
+ public void validateModel(String transId, String fromAppId, String modelVersionIdVal, String apiVersion )
+ throws AAIException{
+
+ // Note - this will throw an exception if the model either can't be found, or if
+ // we can't figure out its topology map.
+ DbMaps dbMaps = IngestModelMoxyOxm.dbMapsContainer.get(AAIConfig.get(AAIConstants.AAI_DEFAULT_API_VERSION_PROP));
+ Vertex modelVerVtx = getNodeUsingUniqueId(transId, fromAppId, "model-ver",
+ "model-version-id", modelVersionIdVal);
+ if( modelVerVtx == null ){
+ String msg = " Could not find model-ver with modelVersionId = [" + modelVersionIdVal + "].";
+ throw new AAIException("AAI_6114", msg);
+ }
+ else {
+ Multimap<String, String> topoMap = genTopoMap4ModelVer( transId, fromAppId,
+ modelVerVtx, modelVersionIdVal, dbMaps );
+ String msg = " modelVer [" + modelVersionIdVal + "] topo multiMap looks like: \n[" + topoMap + "]";
+ System.out.println("INFO -- " + msg );
+ }
+ return;
+
+ }// End validateModel()
+
+
+ /**
+ * Validate named query.
+ *
+ * @param transId the trans id
+ * @param fromAppId the from app id
+ * @param namedQueryUuid the named query uuid
+ * @param apiVersion the api version
+ * @throws AAIException the AAI exception
+ */
+ public void validateNamedQuery(String transId, String fromAppId, String namedQueryUuid, String apiVersion )
+ throws AAIException{
+
+ // Note - this will throw an exception if the named query either can't be found, or if
+ // we can't figure out its topology map.
+ Vertex nqVtx = getNodeUsingUniqueId(transId, fromAppId, "named-query",
+ "named-query-uuid", namedQueryUuid);
+
+ if( nqVtx == null ){
+ String msg = " Could not find named-query with namedQueryUuid = [" + namedQueryUuid + "].";
+ throw new AAIException("AAI_6114", msg);
+ }
+ else {
+ //Multimap<String, String> topoMap = genTopoMap4NamedQ( "junkTransId", "junkFromAppId",
+ // graph, nqVtx, namedQueryUuid );
+ //System.out.println("DEBUG -- for test only : --- ");
+ //System.out.println("DEBUG -- topomap = [" + topoMap + "]");
+ }
+ return;
+
+ }// End validateNamedQuery()
+
+
+ /**
+ * Show result set.
+ *
+ * @param resSet the res set
+ * @param levelCount the level count
+ */
+ public void showResultSet( ResultSet resSet, int levelCount ) {
+
+ levelCount++;
+ String propsStr = "";
+ for( int i= 1; i <= levelCount; i++ ){
+ propsStr = propsStr + "-";
+ }
+ if( resSet.getVert() == null ){
+ return;
+ }
+ String nt = resSet.getVert().<String>property(AAIProperties.NODE_TYPE).orElse(null);
+ propsStr = propsStr + "[" + nt + "] ";
+
+ //propsStr = propsStr + " newDataDelFlag = " + resSet.getNewDataDelFlag() + ", trail = " + resSet.getLocationInModelSubGraph();
+ //propsStr = propsStr + "limitDesc = [" + resSet.getPropertyLimitDesc() + "]";
+ propsStr = propsStr + " trail = " + resSet.getLocationInModelSubGraph();
+
+ Map<String,Object> overrideHash = resSet.getPropertyOverRideHash();
+ if( overrideHash != null && !overrideHash.isEmpty() ){
+ for( Map.Entry<String, Object> entry : overrideHash.entrySet() ){
+ String propName = entry.getKey();
+ Object propVal = entry.getValue();
+ propsStr = propsStr + " [" + propName + " = " + propVal + "]";
+ }
+ }
+ else {
+ Iterator<VertexProperty<Object>> pI = resSet.getVert().properties();
+ while( pI.hasNext() ){
+ VertexProperty<Object> tp = pI.next();
+ if( ! tp.key().startsWith("aai")
+ && ! tp.key().equals("source-of-truth")
+ //&& ! tp.key().equals("resource-version")
+ && ! tp.key().startsWith("last-mod")
+ )
+ {
+ propsStr = propsStr + " [" + tp.key() + " = " + tp.value() + "]";
+ }
+ }
+ }
+ // Show the "extra" lookup values too
+ Map<String,Object> extraPropHash = resSet.getExtraPropertyHash();
+ if( extraPropHash != null && !extraPropHash.isEmpty() ){
+ for( Map.Entry<String, Object> entry : extraPropHash.entrySet() ){
+ String propName = entry.getKey();
+ Object propVal = entry.getValue();
+ propsStr = propsStr + " [" + propName + " = " + propVal.toString() + "]";
+ }
+ }
+
+ System.out.println( propsStr );
+ LOGGER.info(propsStr);
+
+ if( !resSet.getSubResultSet().isEmpty() ){
+ ListIterator<ResultSet> listItr = resSet.getSubResultSet().listIterator();
+ while( listItr.hasNext() ){
+ showResultSet( listItr.next(), levelCount );
+ }
+ }
+
+ }// end of showResultSet()
+
+ private Iterator<Vertex> traverseIncidentEdges(EdgeType treeType, Vertex startV, String connectedNodeType) throws AAIUnknownObjectException, AAIException {
+ QueryBuilder builder = this.engine.getQueryBuilder(startV).createEdgeTraversal(treeType, startV, loader.introspectorFromName(connectedNodeType));
+ return builder;
+ }
+
+ private Iterator<Vertex> traverseIncidentEdges(EdgeType treeType, Vertex startV, String... connectedNodeType) throws AAIUnknownObjectException, AAIException {
+ QueryBuilder[] builders = new QueryBuilder[connectedNodeType.length];
+ for (int i = 0; i < connectedNodeType.length; i++) {
+ builders[i] = this.engine.getQueryBuilder(startV).createEdgeTraversal(EdgeType.TREE, startV, loader.introspectorFromName(connectedNodeType[i]));
+ }
+ QueryBuilder builder = this.engine.getQueryBuilder(startV).union(builders);
+ return builder;
+
+ }
+
+}
+
diff --git a/aai-traversal/src/main/java/org/openecomp/aai/dbgraphgen/ResultSet.java b/aai-traversal/src/main/java/org/openecomp/aai/dbgraphgen/ResultSet.java
new file mode 100644
index 0000000..46c9b5e
--- /dev/null
+++ b/aai-traversal/src/main/java/org/openecomp/aai/dbgraphgen/ResultSet.java
@@ -0,0 +1,168 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * org.openecomp.aai
+ * ================================================================================
+ * Copyright (C) 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=========================================================
+ */
+
+package org.openecomp.aai.dbgraphgen;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.openecomp.aai.dbgen.PropertyLimitDesc;
+import com.thinkaurelius.titan.core.TitanVertex;
+
+public class ResultSet {
+ private TitanVertex vert;
+ private String newDataDelFlag;
+ private String doNotOutputFlag;
+ private String locationInModelSubGraph;
+ private List<ResultSet> subResultSet;
+ private PropertyLimitDesc propertyLimitDesc;
+ private Map<String,Object> propertyOverRideHash;
+ private Map<String,Object> extraPropertyHash;
+
+ /**
+ * Instantiates a new result set.
+ */
+ public ResultSet(){
+ this.vert = null;
+ this.newDataDelFlag = "";
+ this.doNotOutputFlag = "";
+ this.locationInModelSubGraph = "";
+ this.subResultSet = new ArrayList<>();
+ this.propertyLimitDesc = null;
+ this.propertyOverRideHash = new HashMap<>();
+ this.extraPropertyHash = new HashMap<>();
+ }
+
+
+ public void setPropertyLimitDesc(PropertyLimitDesc pld) {
+ this.propertyLimitDesc = pld;
+ }
+
+ /**
+ * Gets the vert.
+ *
+ * @return the vert
+ */
+ public TitanVertex getVert(){
+ return this.vert;
+ }
+
+ /**
+ * Gets the sub result set.
+ *
+ * @return the sub result set
+ */
+ public List<ResultSet> getSubResultSet(){
+ return this.subResultSet;
+ }
+
+ /**
+ * Gets the new data del flag.
+ *
+ * @return the new data del flag
+ */
+ public String getNewDataDelFlag(){
+ return this.newDataDelFlag;
+ }
+
+ /**
+ * Gets the do not output flag.
+ *
+ * @return the do not output flag
+ */
+ public String getDoNotOutputFlag(){
+ return this.doNotOutputFlag;
+ }
+
+ /**
+ * Gets the location in model sub graph.
+ *
+ * @return the location in model sub graph
+ */
+ public String getLocationInModelSubGraph(){
+ return this.locationInModelSubGraph;
+ }
+
+ /**
+ * Gets the property limit desc.
+ *
+ * @return the property limit desc
+ */
+ public PropertyLimitDesc getPropertyLimitDesc(){
+ return this.propertyLimitDesc;
+ }
+
+ /**
+ * Gets the property over ride hash.
+ *
+ * @return the property over ride hash
+ */
+ public Map<String,Object> getPropertyOverRideHash(){
+ return this.propertyOverRideHash;
+ }
+
+ /**
+ * Gets the extra property hash.
+ *
+ * @return the extra property hash
+ */
+ public Map<String,Object> getExtraPropertyHash(){
+ return this.extraPropertyHash;
+ }
+
+
+ public void setVert(TitanVertex vert) {
+ this.vert = vert;
+ }
+
+
+ public void setNewDataDelFlag(String newDataDelFlag) {
+ this.newDataDelFlag = newDataDelFlag;
+ }
+
+
+ public void setDoNotOutputFlag(String doNotOutputFlag) {
+ this.doNotOutputFlag = doNotOutputFlag;
+ }
+
+
+ public void setLocationInModelSubGraph(String locationInModelSubGraph) {
+ this.locationInModelSubGraph = locationInModelSubGraph;
+ }
+
+
+ public void setSubResultSet(List<ResultSet> subResultSet) {
+ this.subResultSet = subResultSet;
+ }
+
+
+ public void setPropertyOverRideHash(Map<String, Object> propertyOverRideHash) {
+ this.propertyOverRideHash = propertyOverRideHash;
+ }
+
+
+ public void setExtraPropertyHash(Map<String, Object> extraPropertyHash) {
+ this.extraPropertyHash = extraPropertyHash;
+ }
+
+
+}
diff --git a/aai-traversal/src/main/java/org/openecomp/aai/dbgraphmap/RelationshipGraph.java b/aai-traversal/src/main/java/org/openecomp/aai/dbgraphmap/RelationshipGraph.java
new file mode 100644
index 0000000..8277b2c
--- /dev/null
+++ b/aai-traversal/src/main/java/org/openecomp/aai/dbgraphmap/RelationshipGraph.java
@@ -0,0 +1,299 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * org.openecomp.aai
+ * ================================================================================
+ * Copyright (C) 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=========================================================
+ */
+
+package org.openecomp.aai.dbgraphmap;
+
+import java.io.UnsupportedEncodingException;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.commons.collections.map.MultiValueMap;
+import org.eclipse.persistence.dynamic.DynamicEntity;
+import org.eclipse.persistence.dynamic.DynamicType;
+import org.eclipse.persistence.jaxb.dynamic.DynamicJAXBContext;
+
+import org.openecomp.aai.dbgen.DbMeth;
+import org.openecomp.aai.dbgraphgen.DbEdgeGroup;
+import org.openecomp.aai.domain.model.AAIResources;
+import org.openecomp.aai.exceptions.AAIException;
+import org.openecomp.aai.extensions.AAIExtensionMap;
+import org.openecomp.aai.util.AAIConfig;
+import org.openecomp.aai.util.AAIConstants;
+import org.openecomp.aai.util.RestURL;
+import com.thinkaurelius.titan.core.TitanTransaction;
+import com.thinkaurelius.titan.core.TitanVertex;
+
+public class RelationshipGraph {
+
+ /**
+ * this method processes the one relationship for the startVertex that is
+ * sent.
+ *
+ * @param g the g
+ * @param startVertex the start vertex
+ * @param jaxbContext the jaxb context
+ * @param rel the rel
+ * @param aaiExtMap the aai ext map
+ * @throws AAIException the AAI exception
+ */
+ public static void updRelationship(TitanTransaction g, TitanVertex startVertex,
+ DynamicJAXBContext jaxbContext,
+ DynamicEntity rel,
+ AAIExtensionMap aaiExtMap)
+ throws AAIException {
+ String apiVersion = aaiExtMap.getApiVersion();
+ String transId = aaiExtMap.getTransId();
+ String fromAppId = aaiExtMap.getFromAppId();
+ MultiValueMap relatedNodesMap = new MultiValueMap();
+
+ if( rel != null ){
+ HashMap<String, Object> propFilterHash = new HashMap<String, Object>();
+ poplatePropertyHashWithRelData(rel, apiVersion, propFilterHash);
+ String relNodeType = (String)rel.get("relatedTo");
+ relatedNodesMap.put(relNodeType, propFilterHash);
+ }
+ DbEdgeGroup.replaceEdgeGroup(transId, fromAppId, g, startVertex,
+ "ONLY_PASSED_COUSINS_REL", relatedNodesMap, apiVersion);
+
+ }
+
+ /**
+ * Poplate property hash with rel data.
+ *
+ * @param rel the rel
+ * @param apiVersion the api version
+ * @param propFilterHash the prop filter hash
+ * @throws AAIException the AAI exception
+ */
+ private static void poplatePropertyHashWithRelData(DynamicEntity rel, String apiVersion,
+ HashMap<String, Object> propFilterHash) throws AAIException {
+
+ for( DynamicEntity relData: (List<DynamicEntity>)rel.get("relationshipData")) {
+ String prop = ((String)relData.get("relationshipKey")).toLowerCase().trim();
+ propFilterHash.put(prop, ((String)relData.get("relationshipValue")).trim());
+ }
+ }
+
+ /**
+ * this method gets any relationships for the startVertex being processed
+ * and sets the related-link.
+ *
+ * @param g the g
+ * @param startVertex the start vertex
+ * @param apiVersion the api version
+ * @param aaiExtMap the aai ext map
+ * @return the relationships
+ * @throws AAIException the AAI exception
+ * @throws UnsupportedEncodingException the unsupported encoding exception
+ */
+ public static DynamicEntity getRelationships(TitanTransaction g, TitanVertex startVertex,
+ String apiVersion, AAIExtensionMap aaiExtMap)
+ throws AAIException, UnsupportedEncodingException {
+
+ DynamicType relationshipsType = null;
+ DynamicType relationshipType = null;
+ DynamicType relationshipDataType = null;
+ DynamicType relatedToPropertyType = null;
+
+ Boolean setRelatedToProperty = true;
+
+ AAIResources aaiResources = org.openecomp.aai.ingestModel.IngestModelMoxyOxm.aaiResourceContainer
+ .get(apiVersion);
+
+ DynamicJAXBContext jaxbContext = aaiResources.getJaxbContext();
+
+ //String apiVersion = aaiExtMap.getApiVersion();
+ String transId = aaiExtMap.getTransId();
+ String fromAppId = aaiExtMap.getFromAppId();
+
+ HashMap <String, String> vidToNodeTypeHash = new HashMap <String, String>();
+ HashMap <String, TitanVertex> vidToVertexHash = new HashMap <String, TitanVertex>();
+
+ if ("v2".equals( apiVersion)) {
+ relationshipsType = jaxbContext.getDynamicType("inventory.aai.openecomp.org.RelationshipList");
+ relationshipType = jaxbContext.getDynamicType(".org.Relationship");
+ relationshipDataType = jaxbContext.getDynamicType("inventory.aai.openecomp.org.RelationshipData");
+ setRelatedToProperty = false;
+ } else {
+ relationshipsType = jaxbContext.getDynamicType("inventory.aai.openecomp.org." + apiVersion + ".RelationshipList");
+ relationshipType = jaxbContext.getDynamicType("inventory.aai.openecomp.org." + apiVersion + ".Relationship");
+ relationshipDataType = jaxbContext.getDynamicType("inventory.aai.openecomp.org." + apiVersion + ".RelationshipData");
+ relatedToPropertyType = jaxbContext.getDynamicType("inventory.aai.openecomp.org." + apiVersion + ".RelatedToProperty");
+ if (relatedToPropertyType == null) {
+ setRelatedToProperty = false; // some versions do not support this
+ }
+ }
+
+ DynamicEntity relationships = relationshipsType.newDynamicEntity();
+ List<DynamicEntity> listOfRelationships = new ArrayList<DynamicEntity>();
+
+ DbEdgeGroup.getEdgeGroup(transId,
+ fromAppId,
+ g,
+ startVertex,
+ vidToNodeTypeHash,
+ vidToVertexHash,
+ "ONLY_COUSIN_REL",
+ AAIConfig.get(AAIConstants.AAI_DEFAULT_API_VERSION_PROP));
+ // Convert the found relationships to a RelationshipList DynamicEntity
+ for( Map.Entry<String, TitanVertex> entry : vidToVertexHash.entrySet() ){
+
+ List<DynamicEntity> relationshipDataList = new ArrayList<DynamicEntity>();
+ List<DynamicEntity> relatedToPropertyList = new ArrayList<DynamicEntity>();
+
+ DynamicEntity relationship = relationshipType.newDynamicEntity();
+
+ TitanVertex relNode = entry.getValue();
+ String relNodeVid = entry.getKey();
+ String relNodeType = vidToNodeTypeHash.get(relNodeVid);
+ String relNodeURL = RestURL.get(g, relNode, apiVersion);
+
+ HashMap <String, Object> nodeKeyPropsHash = RestURL.getKeyHashes(g, relNode, AAIConfig.get(AAIConstants.AAI_DEFAULT_API_VERSION_PROP));
+ Iterator <Map.Entry<String,Object>>keyIterator = nodeKeyPropsHash.entrySet().iterator();
+ while( keyIterator.hasNext() ){
+ DynamicEntity relationshipData = relationshipDataType.newDynamicEntity();
+ Map.Entry <String,Object>pair = (Map.Entry<String,Object>)keyIterator.next();
+ String key = pair.getKey();
+
+ if (!key.contains(".")) {
+ key = relNodeType + "." + key;
+ }
+
+ String value = "";
+ if( pair.getValue() != null ){
+ value = pair.getValue().toString();
+ }
+
+ relationshipData.set("relationshipKey", key);
+ relationshipData.set("relationshipValue", value);
+
+ relationshipDataList.add(relationshipData);
+ }
+
+ if (setRelatedToProperty) {
+ HashMap <String, Object> nodeNamePropsHash = DbMeth.getNodeNamePropHash(transId, fromAppId, g, relNode, AAIConfig.get(AAIConstants.AAI_DEFAULT_API_VERSION_PROP));
+ Iterator <Map.Entry<String,Object>>nameIterator = nodeNamePropsHash.entrySet().iterator();
+ while( nameIterator.hasNext() ){
+ DynamicEntity relatedToProperty = relatedToPropertyType.newDynamicEntity();
+ Map.Entry <String,Object>pair = (Map.Entry<String,Object>)nameIterator.next();
+ String key = pair.getKey();
+
+ if (!key.contains(".")) {
+ key = relNodeType + "." + key;
+ }
+
+ String value = "";
+ if( pair.getValue() != null ){
+ value = pair.getValue().toString();
+ }
+ relatedToProperty.set("propertyKey", key);
+ relatedToProperty.set("propertyValue", value);
+
+ relatedToPropertyList.add(relatedToProperty);
+
+ }
+ relationship.set("relatedToProperty", relatedToPropertyList);
+ }
+ relationship.set("relatedTo", relNodeType);
+ relationship.set("relatedLink", relNodeURL);
+ relationship.set("relationshipData", relationshipDataList);
+
+ listOfRelationships.add(relationship);
+ }
+ relationships.set("relationship", listOfRelationships);
+ return relationships;
+ }
+
+ /**
+ * this method processes any relationships for the startVertex being
+ * processed.
+ *
+ * @param g the g
+ * @param startVertex the start vertex
+ * @param jaxbContext the jaxb context
+ * @param relationshipList the relationship list
+ * @param aaiExtMap the aai ext map
+ * @throws AAIException the AAI exception
+ */
+ public static void updRelationships(TitanTransaction g, TitanVertex startVertex,
+ DynamicJAXBContext jaxbContext,
+ DynamicEntity relationshipList,
+ AAIExtensionMap aaiExtMap)
+ throws AAIException {
+
+ String apiVersion = aaiExtMap.getApiVersion();
+ String transId = aaiExtMap.getTransId();
+ String fromAppId = aaiExtMap.getFromAppId();
+ MultiValueMap relatedNodesMap = new MultiValueMap();
+ if (relationshipList != null) {
+ if( relationshipList.get("relationship") != null ){
+ List <DynamicEntity> relListTmp = relationshipList.get("relationship");
+ for( DynamicEntity rel: relListTmp) {
+ HashMap<String, Object> propFilterHash = new HashMap<String, Object>();
+ poplatePropertyHashWithRelData(rel, apiVersion, propFilterHash);
+ String relNodeType = (String)rel.get("relatedTo");
+ relatedNodesMap.put(relNodeType, propFilterHash);
+
+
+ }
+ }
+ DbEdgeGroup.replaceEdgeGroup(transId, fromAppId, g, startVertex,
+ "ALL_COUSIN_REL", relatedNodesMap, apiVersion);
+ }
+ }
+
+ /**
+ * this method deletes the relationship sent in for the startVertex being
+ * processed.
+ *
+ * @param g the g
+ * @param startVertex the start vertex
+ * @param jaxbContext the jaxb context
+ * @param rel the rel
+ * @param aaiExtMap the aai ext map
+ * @throws AAIException the AAI exception
+ */
+ public static void delRelationship(TitanTransaction g, TitanVertex startVertex,
+ DynamicJAXBContext jaxbContext,
+ DynamicEntity rel,
+ AAIExtensionMap aaiExtMap)
+ throws AAIException {
+
+ String apiVersion = aaiExtMap.getApiVersion();
+ String transId = aaiExtMap.getTransId();
+ String fromAppId = aaiExtMap.getFromAppId();
+ MultiValueMap relatedNodesMap = new MultiValueMap();
+
+ if( rel != null ){
+ HashMap<String, Object> propFilterHash = new HashMap<String, Object>();
+ poplatePropertyHashWithRelData(rel, apiVersion, propFilterHash);
+ String relNodeType = (String)rel.get("relatedTo");
+ relatedNodesMap.put(relNodeType, propFilterHash);
+ }
+
+ DbEdgeGroup.deleteEdgeGroup(transId, fromAppId, g, startVertex,
+ relatedNodesMap, apiVersion);
+
+ }
+
+}
diff --git a/aai-traversal/src/main/java/org/openecomp/aai/dbgraphmap/SearchGraph.java b/aai-traversal/src/main/java/org/openecomp/aai/dbgraphmap/SearchGraph.java
new file mode 100644
index 0000000..f45c3f5
--- /dev/null
+++ b/aai-traversal/src/main/java/org/openecomp/aai/dbgraphmap/SearchGraph.java
@@ -0,0 +1,1207 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * org.openecomp.aai
+ * ================================================================================
+ * Copyright (C) 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=========================================================
+ */
+
+package org.openecomp.aai.dbgraphmap;
+
+import java.io.StringReader;
+import java.io.StringWriter;
+import java.io.UnsupportedEncodingException;
+import java.net.URI;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.ListIterator;
+import java.util.Map;
+import java.util.Optional;
+import java.util.Set;
+
+import javax.ws.rs.core.HttpHeaders;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+import javax.ws.rs.core.UriBuilderException;
+import javax.xml.bind.JAXBException;
+import javax.xml.transform.stream.StreamSource;
+
+import org.apache.tinkerpop.gremlin.process.traversal.P;
+import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversal;
+import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversalSource;
+import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.__;
+import org.apache.tinkerpop.gremlin.structure.Vertex;
+import org.eclipse.persistence.dynamic.DynamicEntity;
+import org.eclipse.persistence.dynamic.DynamicType;
+import org.eclipse.persistence.exceptions.DynamicException;
+import org.eclipse.persistence.jaxb.JAXBMarshaller;
+import org.eclipse.persistence.jaxb.JAXBUnmarshaller;
+import org.eclipse.persistence.jaxb.MarshallerProperties;
+import org.eclipse.persistence.jaxb.dynamic.DynamicJAXBContext;
+
+import org.openecomp.aai.db.DbMethHelper;
+import org.openecomp.aai.db.props.AAIProperties;
+import org.openecomp.aai.dbgen.PropertyLimitDesc;
+import org.openecomp.aai.dbgraphgen.ModelBasedProcessing;
+import org.openecomp.aai.dbgraphgen.ResultSet;
+import org.openecomp.aai.dbmap.DBConnectionType;
+import org.openecomp.aai.domain.model.AAIResources;
+import org.openecomp.aai.exceptions.AAIException;
+import org.openecomp.aai.extensions.AAIExtensionMap;
+import org.openecomp.aai.introspection.Introspector;
+import org.openecomp.aai.introspection.Loader;
+import org.openecomp.aai.introspection.LoaderFactory;
+import org.openecomp.aai.introspection.ModelType;
+import org.openecomp.aai.introspection.PropertyPredicates;
+import org.openecomp.aai.introspection.exceptions.AAIUnknownObjectException;
+import org.openecomp.aai.parsers.relationship.RelationshipToURI;
+import org.openecomp.aai.query.builder.QueryBuilder;
+import org.openecomp.aai.schema.enums.ObjectMetadata;
+import org.openecomp.aai.schema.enums.PropertyMetadata;
+import org.openecomp.aai.serialization.db.DBSerializer;
+import org.openecomp.aai.serialization.db.EdgeRule;
+import org.openecomp.aai.serialization.db.EdgeRules;
+import org.openecomp.aai.serialization.engines.QueryStyle;
+import org.openecomp.aai.serialization.engines.TitanDBEngine;
+import org.openecomp.aai.serialization.engines.TransactionalGraphEngine;
+import org.openecomp.aai.serialization.queryformats.utils.UrlBuilder;
+import org.openecomp.aai.util.AAIApiServerURLBase;
+import org.openecomp.aai.util.AAIApiVersion;
+import org.openecomp.aai.util.AAIConfig;
+import org.openecomp.aai.util.AAIConstants;
+import org.openecomp.aai.util.PojoUtils;
+import org.openecomp.aai.util.RestURL;
+import org.openecomp.aai.util.StoreNotificationEvent;
+import com.att.eelf.configuration.EELFLogger;
+import com.att.eelf.configuration.EELFManager;
+import com.google.common.base.CaseFormat;
+import com.thinkaurelius.titan.core.TitanTransaction;
+import com.thinkaurelius.titan.core.TitanVertex;
+
+import edu.emory.mathcs.backport.java.util.Collections;
+
+/**
+ * Database Mapping class which acts as the middle man between the REST interface objects
+ * for the Search namespace
+
+ */
+public class SearchGraph {
+
+ private final String COMPONENT = "aaidbmap";
+ private AAIExtensionMap aaiExtMap;
+ private static final EELFLogger LOGGER = EELFManager.getInstance().getLogger(SearchGraph.class);
+ /**
+ * Get the search result based on the includeNodeType and depth provided.
+ *
+ * @param fromAppId the from app id
+ * @param transId the trans id
+ * @param startNodeType the start node type
+ * @param startNodeKeyParams the start node key params
+ * @param includeNodeTypes the include node types
+ * @param depth the depth
+ * @param aaiExtMap the aai ext map
+ * @return Response
+ * @throws AAIException the AAI exception
+ */
+ public Response runGenericQuery (
+ HttpHeaders headers,
+ String startNodeType,
+ List <String> startNodeKeyParams,
+ List <String> includeNodeTypes,
+ final int depth,
+ TransactionalGraphEngine dbEngine,
+ Loader loader,
+ UrlBuilder urlBuilder) throws AAIException {
+ Response response = null;
+ boolean success = true;
+ String result = "";
+ try {
+ dbEngine.startTransaction();
+
+ if( startNodeType == null ){
+ throw new AAIException("AAI_6120", "null start-node-type passed to the generic query");
+ }
+
+ if( startNodeKeyParams == null ){
+ throw new AAIException("AAI_6120", "no key param passed to the generic query");
+ }
+
+ if( includeNodeTypes == null ){
+ throw new AAIException("AAI_6120", "no include params passed to the generic query");
+ }
+
+ if (depth > 6) {
+ throw new AAIException("AAI_6120", "The maximum depth supported by the generic query is 6");
+ }
+ final QueryBuilder queryBuilder;
+
+ // there is an issue with service-instance - it is a unique node but still dependent
+ // for now query it directly without attempting to craft a valid URI
+ if (startNodeType.equalsIgnoreCase("service-instance")) {
+ Introspector obj = loader.introspectorFromName(startNodeType);
+ // Build a hash with keys to uniquely identify the start Node
+ String keyName = null;
+ String keyValue = null;
+
+ QueryBuilder builder = dbEngine.getQueryBuilder().getVerticesByIndexedProperty(AAIProperties.NODE_TYPE, "service-instance");
+ for( String keyData : startNodeKeyParams ){
+ int colonIndex = keyData.indexOf(":");
+ if( colonIndex <= 0 ){
+ throw new AAIException("AAI_6120", "Bad key param passed in: [" + keyData + "]");
+ }
+ else {
+ keyName = keyData.substring(0, colonIndex).split("\\.")[1];
+ keyValue = keyData.substring(colonIndex + 1);
+ builder.getVerticesByProperty(keyName, keyValue);
+
+ }
+ }
+
+ queryBuilder = builder;
+ } else {
+ URI uri = craftUriFromQueryParams(loader, startNodeType, startNodeKeyParams);
+ queryBuilder = dbEngine.getQueryBuilder().createQueryFromURI(uri).getQueryBuilder();
+ }
+ List<Vertex> results = queryBuilder.toList();
+ if( results.isEmpty()){
+ throw new AAIException("AAI_6114", "No Node of type " +
+ startNodeType +
+ " found for properties: " +
+ startNodeKeyParams.toString());
+ } else if (results.size() > 1) {
+ String detail = "More than one Node found by getUniqueNode for params: " + startNodeKeyParams.toString() + "\n";
+ throw new AAIException("AAI_6112", detail);
+ }
+
+ Vertex startNode = results.get(0);
+
+ Collection <Vertex> ver = new HashSet <>();
+ List<Vertex> queryResults = new ArrayList<>();
+ GraphTraversalSource traversalSource = dbEngine.asAdmin().getReadOnlyTraversalSource();
+ GraphTraversal<Vertex, Vertex> traversal;
+ if (includeNodeTypes.contains(startNodeType) || depth == 0 || includeNodeTypes.contains("all") )
+ ver.add(startNode);
+
+ // Now look for a node of includeNodeType within a given depth
+ traversal = traversalSource.withSideEffect("x", ver).V(startNode)
+ .times(depth).repeat(__.both().store("x")).cap("x").unfold();
+
+ if (!includeNodeTypes.contains("all")) {
+ traversal.where(__.has(AAIProperties.NODE_TYPE, P.within(includeNodeTypes)));
+ }
+ queryResults = traversal.toList();
+
+
+ if( queryResults.isEmpty()){
+ LOGGER.warn("No nodes found - apipe was null/empty");
+ }
+ else {
+
+ Introspector searchResults = loader.introspectorFromName("search-results");
+ List<Object> resultDataList = searchResults.getValue("result-data");
+ for (Vertex thisNode: queryResults){
+ String nodeType = thisNode.<String>property(AAIProperties.NODE_TYPE).orElse(null);
+
+ String thisNodeURL = urlBuilder.pathed(thisNode);
+ Introspector resultData = loader.introspectorFromName("result-data");
+
+ resultData.setValue("resource-type", nodeType);
+ resultData.setValue("resource-link", thisNodeURL);
+ resultDataList.add(resultData.getUnderlyingObject());
+
+ }
+
+ String outputMediaType = getMediaType(headers.getAcceptableMediaTypes());
+ org.openecomp.aai.introspection.MarshallerProperties properties = new org.openecomp.aai.introspection.MarshallerProperties.Builder(
+ org.openecomp.aai.restcore.MediaType.getEnum(outputMediaType)).build();
+
+ result = searchResults.marshal(properties);
+ response = Response.ok().entity(result).build();
+
+ LOGGER.debug(ver.size() + " node(s) traversed, " + resultDataList.size() + " found");
+ }
+ success = true;
+ } catch (AAIException e) {
+ success = false;
+ throw e;
+ } catch (Exception e) {
+ success = false;
+ throw new AAIException("AAI_5105", e);
+ } finally {
+ if (dbEngine != null) {
+ if (success) {
+ dbEngine.commit();
+ } else {
+ dbEngine.rollback();
+ }
+ }
+
+ }
+
+ return response;
+ }
+
+ private URI craftUriFromQueryParams(Loader loader, String startNodeType, List<String> startNodeKeyParams) throws UnsupportedEncodingException, IllegalArgumentException, UriBuilderException, AAIException {
+ Introspector relationship = loader.introspectorFromName("relationship");
+
+ relationship.setValue("related-to", startNodeType);
+ List<Object> relationshipDataList = relationship.getValue("relationship-data");
+
+ for( String keyData : startNodeKeyParams ){
+ int colonIndex = keyData.indexOf(":");
+ if( colonIndex <= 0 ){
+ throw new AAIException("AAI_6120", "Bad key param passed in: [" + keyData + "]");
+ }
+ else {
+ Introspector data = loader.introspectorFromName("relationship-data");
+ data.setValue("relationship-key", keyData.substring(0, colonIndex));
+ data.setValue("relationship-value", keyData.substring(colonIndex + 1));
+ relationshipDataList.add(data.getUnderlyingObject());
+ }
+ }
+
+ RelationshipToURI parser = new RelationshipToURI(loader, relationship);
+
+ return parser.getUri();
+ }
+
+ /**
+ * Run nodes query.
+ *
+ * @param fromAppId the from app id
+ * @param transId the trans id
+ * @param targetNodeType the target node type
+ * @param edgeFilterParams the edge filter params
+ * @param filterParams the filter params
+ * @param aaiExtMap the aai ext map
+ * @return Response
+ * @throws AAIException the AAI exception
+ */
+ public Response runNodesQuery (
+ HttpHeaders headers,
+ String targetNodeType,
+ List <String> edgeFilterParams,
+ List <String> filterParams,
+ TransactionalGraphEngine dbEngine,
+ Loader loader,
+ UrlBuilder urlBuilder) throws AAIException {
+
+ Response response = null;
+ boolean success = true;
+ String result = "";
+ final String EQUALS = "EQUALS";
+ final String DOES_NOT_EQUAL = "DOES-NOT-EQUAL";
+ final String EXISTS = "EXISTS";
+ final String DOES_NOT_EXIST = "DOES-NOT-EXIST";
+ try {
+
+ dbEngine.startTransaction();
+
+ Introspector target;
+
+ if( targetNodeType == null || targetNodeType == "" ){
+ throw new AAIException("AAI_6120", "null or empty target-node-type passed to the node query");
+ }
+
+ try {
+ target = loader.introspectorFromName(targetNodeType);
+ } catch (AAIUnknownObjectException e) {
+ throw new AAIException("AAI_6115", "Unrecognized nodeType [" + targetNodeType + "] passed to node query.");
+ }
+
+ if( filterParams.isEmpty() && edgeFilterParams.isEmpty()){
+ // For now, it's ok to pass no filter params. We'll just return ALL the nodes of the requested type.
+ LOGGER.warn("No filters passed to the node query");
+ }
+
+ StringBuilder queryStringForMsg = new StringBuilder();
+ GraphTraversal<Vertex, Vertex> traversal = dbEngine.asAdmin().getReadOnlyTraversalSource().V().has(AAIProperties.NODE_TYPE, targetNodeType);
+ queryStringForMsg.append("has(\"aai-node-type\"," + targetNodeType + ")");
+
+ for( String filter : filterParams ) {
+ String [] pieces = filter.split(":");
+ if( pieces.length < 2 ){
+ throw new AAIException("AAI_6120", "bad filter passed to node query: [" + filter + "]");
+ }
+ else {
+ String propName = this.findDbPropName(target, pieces[0]);
+ String filterType = pieces[1];
+ if( filterType.equals(EQUALS)){
+ if( pieces.length < 3 ){
+ throw new AAIException("AAI_6120", "No value passed for filter: [" + filter + "]");
+ }
+ String value = "?";
+ if( pieces.length == 3 ){
+ value = pieces[2];
+ }
+ else if( pieces.length > 3 ){
+ // When a ipv6 address comes in as a value, it has colons in it which require us to
+ // pull the "value" off the end of the filter differently
+ int startPos4Value = propName.length() + filterType.length() + 3;
+ value = filter.substring(startPos4Value);
+ }
+ queryStringForMsg.append(".has(" + propName + "," + value + ")");
+ traversal.has(propName,value);
+ }
+ else if( filterType.equals(DOES_NOT_EQUAL)){
+ if( pieces.length < 3 ){
+ throw new AAIException("AAI_6120", "No value passed for filter: [" + filter + "]");
+ }
+ String value = "?";
+ if( pieces.length == 3 ){
+ value = pieces[2];
+ }
+ else if( pieces.length > 3 ){
+ // When a ipv6 address comes in as a value, it has colons in it which require us to
+ // pull the "value" off the end of the filter differently
+ int startPos4Value = propName.length() + filterType.length() + 3;
+ value = filter.substring(startPos4Value);
+ }
+ queryStringForMsg.append(".hasNot(" + propName + "," + value + ")");
+ traversal.not(__.has(propName,value));
+ }
+ else if( filterType.equals(EXISTS)){
+ queryStringForMsg.append(".has(" + propName + ")");
+ traversal.has(propName);
+ }
+ else if( filterType.equals(DOES_NOT_EXIST)){
+ queryStringForMsg.append(".hasNot(" + propName + ")");
+ traversal.hasNot(propName);
+ }
+ else {
+ throw new AAIException("AAI_6120", "bad filterType passed: [" + filterType + "]");
+ }
+ }
+ }
+
+ if (!edgeFilterParams.isEmpty()) {
+ // edge-filter=pserver:EXISTS: OR pserver:EXISTS:hostname:XXX
+ // edge-filter=pserver:DOES-NOT-EXIST: OR pserver:DOES-NOT-EXIST:hostname:XXX
+ String filter = edgeFilterParams.get(0); // we process and allow only one edge filter for now
+ String [] pieces = filter.split(":");
+ if( pieces.length < 2 || pieces.length == 3 || pieces.length > 4){
+ throw new AAIException("AAI_6120", "bad edge-filter passed: [" + filter + "]");
+ } else {
+ String nodeType = pieces[0].toLowerCase();
+ String filterType = pieces[1].toUpperCase();
+ Introspector otherNode;
+ if (!filterType.equals(EXISTS) && !filterType.equals(DOES_NOT_EXIST)) {
+ throw new AAIException("AAI_6120", "bad filterType passed: [" + filterType + "]");
+ }
+ try {
+ otherNode = loader.introspectorFromName(nodeType);
+ } catch (AAIUnknownObjectException e) {
+ throw new AAIException("AAI_6115", "Unrecognized nodeType [" + nodeType + "] passed to node query.");
+ }
+ String propName = null;
+ String propValue = null;
+ if ( pieces.length >= 3) {
+ propName = this.findDbPropName(otherNode, pieces[2].toLowerCase());
+ propValue = pieces[3];
+ }
+ String[] edgeLabels = getEdgeLabel(targetNodeType, nodeType);
+
+ GraphTraversal<Vertex, Vertex> edgeSearch = __.start();
+
+ edgeSearch.both(edgeLabels);
+ if (propName != null) {
+ // check for matching property
+ if (propValue != null) {
+ edgeSearch.has(propName, propValue);
+ } else {
+ edgeSearch.has(propName);
+ }
+ }
+
+ if( filterType.equals(DOES_NOT_EXIST)){
+ traversal.where(__.not(edgeSearch));
+ } else if (filterType.equals(EXISTS)) {
+ traversal.where(edgeSearch);
+ }
+ }
+ }
+
+ List<Vertex> results = traversal.toList();
+ Introspector searchResults = loader.introspectorFromName("search-results");
+ List<Object> resultDataList = searchResults.getValue("result-data");
+ for (Vertex thisNode: results){
+ String nodeType = thisNode.<String>property(AAIProperties.NODE_TYPE).orElse(null);
+
+ String thisNodeURL = urlBuilder.pathed(thisNode);
+ Introspector resultData = loader.introspectorFromName("result-data");
+
+ resultData.setValue("resource-type", nodeType);
+ resultData.setValue("resource-link", thisNodeURL);
+ resultDataList.add(resultData.getUnderlyingObject());
+
+ }
+
+ String outputMediaType = getMediaType(headers.getAcceptableMediaTypes());
+ org.openecomp.aai.introspection.MarshallerProperties properties = new org.openecomp.aai.introspection.MarshallerProperties.Builder(
+ org.openecomp.aai.restcore.MediaType.getEnum(outputMediaType)).build();
+
+ result = searchResults.marshal(properties);
+ response = Response.ok().entity(result).build();
+
+ success = true;
+ } catch (AAIException e) {
+ success = false;
+ throw e;
+ } catch (Exception e) {
+ success = false;
+ throw new AAIException("AAI_5105", e);
+ } finally {
+ if (dbEngine != null) {
+ if (success) {
+ dbEngine.commit();
+ } else {
+ dbEngine.rollback();
+ }
+ }
+ }
+
+ return response;
+ }
+
+ private String findDbPropName(Introspector obj, String propName) {
+
+ Optional<String> result = obj.getPropertyMetadata(propName, PropertyMetadata.DB_ALIAS);
+ if (result.isPresent()) {
+ return result.get();
+ } else {
+ return propName;
+ }
+ }
+
+
+ /**
+ * Gets the edge label.
+ *
+ * @param targetNodeType the target node type
+ * @param nodeType the node type
+ * @return the edge label
+ * @throws AAIException the AAI exception
+ */
+ public static String[] getEdgeLabel(String targetNodeType, String nodeType) throws AAIException{
+ Map<String, EdgeRule> rules = EdgeRules.getInstance().getEdgeRules(targetNodeType, nodeType);
+ String[] results = rules.keySet().toArray(new String[0]);
+ return results;
+ }
+
+
+ /**
+ * Run named query.
+ *
+ * @param fromAppId the from app id
+ * @param transId the trans id
+ * @param queryParameters the query parameters
+ * @param aaiExtMap the aai ext map
+ * @return the response
+ * @throws JAXBException the JAXB exception
+ * @throws AAIException the AAI exception
+ */
+ public Response runNamedQuery(String fromAppId, String transId, String queryParameters,
+ DBConnectionType connectionType,
+ AAIExtensionMap aaiExtMap) throws JAXBException, AAIException {
+ // TODO Auto-generated method stub
+ AAIResources aaiResources = org.openecomp.aai.ingestModel.IngestModelMoxyOxm.aaiResourceContainer
+ .get(aaiExtMap.getApiVersion());
+ DynamicJAXBContext jaxbContext = aaiResources.getJaxbContext();
+ JAXBUnmarshaller unmarshaller = jaxbContext.createUnmarshaller();
+
+ //String dynamicClass = aaiRes.getResourceClassName();
+
+ Introspector inventoryItems;
+ boolean success = true;
+ TitanTransaction g = null;
+ TransactionalGraphEngine dbEngine = null;
+ try {
+
+ Loader loader = LoaderFactory.createLoaderForVersion(ModelType.MOXY, AAIProperties.LATEST);
+ dbEngine = new TitanDBEngine(
+ QueryStyle.TRAVERSAL,
+ connectionType,
+ loader);
+ DBSerializer serializer = new DBSerializer(AAIProperties.LATEST, dbEngine, ModelType.MOXY, fromAppId);
+ ModelBasedProcessing processor = new ModelBasedProcessing(loader, dbEngine, serializer);
+
+ g = dbEngine.startTransaction();
+ if (aaiExtMap.getHttpServletRequest().getContentType() == null || // default to json
+ aaiExtMap.getHttpServletRequest().getContentType().contains("application/json")) {
+ unmarshaller.setProperty("eclipselink.media-type", "application/json");
+ unmarshaller.setProperty("eclipselink.json.include-root", false);
+ }
+
+ if (queryParameters.length() == 0) {
+ queryParameters = "{}";
+ unmarshaller.setProperty("eclipselink.media-type", "application/json");
+ unmarshaller.setProperty("eclipselink.json.include-root", false);
+ }
+ String dynamicClass = "inventory.aai.ecomp.org." + aaiExtMap.getApiVersion() + ".ModelAndNamedQuerySearch";
+ Class<? extends DynamicEntity> resultClass = jaxbContext.newDynamicEntity(dynamicClass).getClass();
+
+ StringReader reader = new StringReader(queryParameters);
+
+ DynamicEntity modelAndNamedQuerySearch = (DynamicEntity) unmarshaller.unmarshal(new StreamSource(reader), resultClass).getValue();
+
+ if (modelAndNamedQuerySearch == null) {
+ throw new AAIException("AAI_5105");
+ }
+
+ HashMap<String,Object> namedQueryLookupHash = new HashMap<String,Object>();
+
+ DynamicEntity qp = modelAndNamedQuerySearch.get("queryParameters");
+
+ String namedQueryUuid = null;
+ if (qp.isSet("namedQuery")) {
+ DynamicEntity namedQuery = (DynamicEntity) qp.get("namedQuery");
+
+ if (namedQuery.isSet("namedQueryUuid")) {
+ namedQueryUuid = namedQuery.get("namedQueryUuid");
+ }
+ if (namedQuery.isSet("namedQueryName")) {
+ namedQueryLookupHash.put("named-query-name", namedQuery.get("namedQueryName"));
+ }
+ if (namedQuery.isSet("namedQueryVersion")) {
+ namedQueryLookupHash.put("named-query-version", namedQuery.get("namedQueryVersion"));
+ }
+ }
+
+ if (namedQueryUuid == null) {
+
+ DbMethHelper dbMethHelper = new DbMethHelper(loader, dbEngine);
+ List<Vertex> namedQueryVertices = dbMethHelper.locateUniqueVertices("named-query", namedQueryLookupHash);
+ for (Vertex vert : namedQueryVertices) {
+ namedQueryUuid = vert.<String>property("named-query-uuid").orElse(null);
+ // there should only be one, we'll pick the first if not
+ break;
+ }
+ }
+
+ String secondaryFilterCutPoint = null;
+
+ if (modelAndNamedQuerySearch.isSet("secondaryFilterCutPoint")) {
+ secondaryFilterCutPoint = modelAndNamedQuerySearch.get("secondaryFilterCutPoint");
+ }
+
+ List<Map<String,Object>> startNodeFilterHash = new ArrayList<>();
+
+ mapInstanceFilters((DynamicEntity)modelAndNamedQuerySearch.get("instanceFilters"),
+ startNodeFilterHash, jaxbContext);
+
+ Map<String,Object> secondaryFilterHash = new HashMap<>();
+
+ mapSecondaryFilters((DynamicEntity)modelAndNamedQuerySearch.get("secondaryFilts"),
+ secondaryFilterHash, jaxbContext);
+
+ List<ResultSet> resultSet = processor.queryByNamedQuery(transId, fromAppId,
+ namedQueryUuid, startNodeFilterHash, aaiExtMap.getApiVersion(), secondaryFilterCutPoint, secondaryFilterHash);
+
+ inventoryItems = loader.introspectorFromName("inventory-response-items");
+
+ List<Object> invItemList = unpackResultSet(resultSet, dbEngine, loader, serializer);
+
+ inventoryItems.setValue("inventory-response-item", invItemList);
+ success = true;
+ } catch (AAIException e) {
+ success = false;
+ throw e;
+ } catch (Exception e) {
+ success = false;
+ throw new AAIException("AAI_5105", e);
+ } finally {
+ if (g != null) {
+ if (success) {
+ g.commit();
+ } else {
+ g.rollback();
+ }
+ }
+ }
+
+ return getResponseFromIntrospector(inventoryItems, aaiExtMap.getHttpHeaders());
+ }
+
+
+ /**
+ * Execute model operation.
+ *
+ * @param fromAppId the from app id
+ * @param transId the trans id
+ * @param queryParameters the query parameters
+ * @param isDelete the is delete
+ * @param aaiExtMap the aai ext map
+ * @return the response
+ * @throws JAXBException the JAXB exception
+ * @throws AAIException the AAI exception
+ * @throws DynamicException the dynamic exception
+ * @throws UnsupportedEncodingException the unsupported encoding exception
+ */
+ public Response executeModelOperation(String fromAppId, String transId, String queryParameters,
+ DBConnectionType connectionType,
+ boolean isDelete,
+ AAIExtensionMap aaiExtMap) throws JAXBException, AAIException, DynamicException, UnsupportedEncodingException {
+ // TODO Auto-generated method stub
+ AAIResources aaiResources = org.openecomp.aai.ingestModel.IngestModelMoxyOxm.aaiResourceContainer
+ .get(aaiExtMap.getApiVersion());
+ DynamicJAXBContext jaxbContext = aaiResources.getJaxbContext();
+ JAXBUnmarshaller unmarshaller = jaxbContext.createUnmarshaller();
+
+ //String dynamicClass = aaiRes.getResourceClassName();
+ Response response;
+ boolean success = true;
+ TitanTransaction g = null;
+ TransactionalGraphEngine dbEngine = null;
+ try {
+
+ Loader loader = LoaderFactory.createLoaderForVersion(ModelType.MOXY, AAIProperties.LATEST);
+ dbEngine = new TitanDBEngine(
+ QueryStyle.TRAVERSAL,
+ connectionType,
+ loader);
+ DBSerializer serializer = new DBSerializer(AAIProperties.LATEST, dbEngine, ModelType.MOXY, fromAppId);
+ ModelBasedProcessing processor = new ModelBasedProcessing(loader, dbEngine, serializer);
+ g = dbEngine.startTransaction();
+
+
+ if (aaiExtMap.getHttpServletRequest().getContentType() == null || // default to json
+ aaiExtMap.getHttpServletRequest().getContentType().contains("application/json")) {
+ unmarshaller.setProperty("eclipselink.media-type", "application/json");
+ unmarshaller.setProperty("eclipselink.json.include-root", false);
+ }
+
+ if (queryParameters.length() == 0) {
+ queryParameters = "{}";
+ unmarshaller.setProperty("eclipselink.media-type", "application/json");
+ unmarshaller.setProperty("eclipselink.json.include-root", false);
+ }
+ String dynamicClass = "inventory.aai.openecomp.org." + aaiExtMap.getApiVersion() + ".ModelAndNamedQuerySearch";
+ Class<? extends DynamicEntity> resultClass = jaxbContext.newDynamicEntity(dynamicClass).getClass();
+
+ StringReader reader = new StringReader(queryParameters);
+
+ DynamicEntity modelAndNamedQuerySearch = (DynamicEntity) unmarshaller.unmarshal(new StreamSource(reader), resultClass).getValue();
+
+ if (modelAndNamedQuerySearch == null) {
+ throw new AAIException("AAI_5105");
+ }
+
+ Map<String,Object> modelQueryLookupHash = new HashMap<>();
+
+ String modelVersionId = null;
+ String modelName = null;
+ String modelInvariantId = null;
+ String modelVersion = null;
+ String topNodeType = null;
+
+ if (modelAndNamedQuerySearch.isSet("topNodeType")) {
+ topNodeType = modelAndNamedQuerySearch.get("topNodeType");
+ }
+
+ // the ways to get a model:
+
+ // 1. model-version-id (previously model-name-version-id
+ // 2. model-invariant-id (previously model-id) + model-version
+ // 3. model-name + model-version
+
+ // we will support both using the OverloadedModel object in the v9 oxm. This allows us to unmarshal
+ // either an old-style model or new-style model + model-ver object
+ if (modelAndNamedQuerySearch.isSet("queryParameters")) {
+ DynamicEntity qp = modelAndNamedQuerySearch.get("queryParameters");
+
+ if (qp.isSet("model")) {
+ DynamicEntity model = (DynamicEntity) qp.get("model");
+
+ // on an old-style model object, the following 4 attrs were all present
+ if (model.isSet("modelNameVersionId")) {
+ modelVersionId = model.get("modelNameVersionId");
+ }
+ if (model.isSet("modelId")) {
+ modelInvariantId = model.get("modelId");
+ }
+ if (model.isSet("modelName")) {
+ modelName = model.get("modelName");
+ }
+ if (model.isSet("modelVersion")) {
+ modelVersion = model.get("modelVersion");
+ }
+
+ // new style splits model-invariant-id from the other 3 attrs. This is
+ // the only way to directly look up the model object
+ if (model.isSet("modelInvariantId")) {
+ modelInvariantId = model.get("modelInvariantId");
+ }
+
+ if (model.isSet("modelVers")) {
+ // we know that this is new style, because modelVers was not an option
+ // before v9
+ DynamicEntity modelVers = (DynamicEntity) model.get("modelVers");
+ if (modelVers.isSet("modelVer")) {
+ List<DynamicEntity> modelVerList = modelVers.get("modelVer");
+ // if they send more than one, too bad, they get the first one
+ DynamicEntity modelVer = modelVerList.get(0);
+ if (modelVer.isSet("modelName")) {
+ modelName = modelVer.get("modelName");
+ }
+ if (modelVer.isSet("modelVersionId")) {
+ modelVersionId = modelVer.get("modelVersionId");
+ }
+ if (modelVer.isSet("modelVersion")) {
+ modelVersion = modelVer.get("modelVersion");
+ }
+ }
+ }
+ }
+ }
+
+ List<Map<String,Object>> startNodeFilterHash = new ArrayList<>();
+
+ String resourceVersion = mapInstanceFilters((DynamicEntity)modelAndNamedQuerySearch.get("instanceFilters"),
+ startNodeFilterHash, jaxbContext);
+
+ if (isDelete) {
+
+ List<ResultSet> resultSet = processor.queryByModel(transId, fromAppId,
+ modelVersionId, modelInvariantId, modelName, topNodeType, startNodeFilterHash, aaiExtMap.getApiVersion() );
+
+ Map<Object,String> objectToVertMap = new HashMap<>();
+ List<Object> invItemList = unpackResultSet(resultSet, dbEngine, loader, serializer);
+
+ ResultSet rs = resultSet.get(0);
+
+ TitanVertex firstVert = rs.getVert();
+ String restURL = RestURL.get(g, firstVert);
+
+ Map<String,String> delResult = processor.runDeleteByModel( transId, fromAppId,
+ modelVersionId, topNodeType, startNodeFilterHash.get(0), aaiExtMap.getApiVersion(), resourceVersion );
+
+ String resultStr = "";
+ for (Map.Entry<String,String> ent : delResult.entrySet()) {
+ resultStr += "v[" + ent.getKey() + "] " + ent.getValue() + ",\n";
+ }
+ resultStr.trim();
+
+ DynamicEntity inventoryItems = jaxbContext.newDynamicEntity("inventory.aai.openecomp.org." + aaiExtMap.getApiVersion() + ".InventoryResponseItems");
+ DynamicEntity topInvItem = remapInventoryItems((DynamicEntity)invItemList.get(0), jaxbContext, delResult, objectToVertMap, aaiExtMap);
+
+ List<DynamicEntity> newInvItemList = new ArrayList<DynamicEntity>();
+ newInvItemList.add(topInvItem);
+ inventoryItems.set("inventoryResponseItem", newInvItemList);
+
+ // put the inventoryItems in a UEB notification object
+ String notificationVersion = AAIConfig.get("aai.notification.current.version");
+
+ AAIResources aaiNotificationResources = org.openecomp.aai.ingestModel.IngestModelMoxyOxm.aaiResourceContainer
+ .get(notificationVersion);
+
+ DynamicJAXBContext notificationJaxbContext = aaiNotificationResources.getJaxbContext();
+
+ DynamicEntity notificationHeader = notificationJaxbContext
+ .getDynamicType("inventory.aai.openecomp.org." + notificationVersion + ".NotificationEventHeader")
+ .newDynamicEntity();
+
+ notificationHeader.set("entityLink", restURL);
+ notificationHeader.set("action", "DELETE");
+
+ notificationHeader.set("entityType", "inventory-response-items");
+ notificationHeader.set("topEntityType", "inventory-response-items");
+ notificationHeader.set("sourceName", aaiExtMap.getFromAppId());
+ notificationHeader.set("version", notificationVersion);
+
+ StoreNotificationEvent sne = new StoreNotificationEvent();
+
+ sne.storeDynamicEvent(notificationJaxbContext, notificationVersion, notificationHeader, inventoryItems);
+
+ response = Response.ok(resultStr).build();
+
+ } else {
+ List<ResultSet> resultSet = processor.queryByModel( transId, fromAppId,
+ modelVersionId, modelInvariantId, modelName, topNodeType, startNodeFilterHash, aaiExtMap.getApiVersion() );
+
+ Introspector inventoryItems = loader.introspectorFromName("inventory-response-items");
+
+ List<Object> invItemList = unpackResultSet(resultSet, dbEngine, loader, serializer);
+
+ inventoryItems.setValue("inventory-response-item", invItemList);
+
+ response = getResponseFromIntrospector(inventoryItems, aaiExtMap.getHttpHeaders());
+ }
+ success = true;
+ } catch (AAIException e) {
+ success = false;
+ throw e;
+ } catch (Exception e) {
+ success = false;
+ throw new AAIException("AAI_5105", e);
+ } finally {
+ if (g != null) {
+ if (success) {
+ g.commit();
+ } else {
+ g.rollback();
+ }
+ }
+ }
+
+ return response;
+ }
+
+ private Response getResponseFromIntrospector(Introspector obj, HttpHeaders headers) {
+ boolean isJson = false;
+ for (MediaType mt : headers.getAcceptableMediaTypes()) {
+ if (MediaType.APPLICATION_JSON_TYPE.isCompatible(mt)) {
+ isJson = true;
+ break;
+ }
+ }
+ org.openecomp.aai.introspection.MarshallerProperties properties;
+ if (isJson) {
+ properties =
+ new org.openecomp.aai.introspection.MarshallerProperties.Builder(org.openecomp.aai.restcore.MediaType.APPLICATION_JSON_TYPE).build();
+ } else {
+ properties =
+ new org.openecomp.aai.introspection.MarshallerProperties.Builder(org.openecomp.aai.restcore.MediaType.APPLICATION_XML_TYPE).build();
+ }
+
+ String marshalledObj = obj.marshal(properties);
+ return Response.ok().entity(marshalledObj).build();
+ }
+
+ /**
+ * Map instance filters.
+ *
+ * @param instanceFilters the instance filters
+ * @param startNodeFilterHash the start node filter hash
+ * @param jaxbContext the jaxb context
+ * @return the string
+ */
+ private String mapInstanceFilters(DynamicEntity instanceFilters, List<Map<String,Object>> startNodeFilterHash, DynamicJAXBContext jaxbContext) {
+
+ if (instanceFilters == null || !instanceFilters.isSet("instanceFilter")) {
+ return null;
+ }
+ @SuppressWarnings("unchecked")
+ List<DynamicEntity> instanceFilter = (ArrayList<DynamicEntity>)instanceFilters.get("instanceFilter");
+ String resourceVersion = null;
+
+ for (DynamicEntity instFilt : instanceFilter) {
+ List<DynamicEntity> any = instFilt.get("any");
+ HashMap<String,Object> thisNodeFilterHash = new HashMap<String,Object>();
+ for (DynamicEntity anyEnt : any) {
+ String clazz = anyEnt.getClass().getCanonicalName();
+ String simpleClazz = anyEnt.getClass().getSimpleName();
+
+ String nodeType = CaseFormat.LOWER_CAMEL.to(CaseFormat.LOWER_HYPHEN, simpleClazz);
+
+ DynamicType anyEntType = jaxbContext.getDynamicType(clazz);
+
+ for (String propName : anyEntType.getPropertiesNames()) {
+ // hyphencase the prop and throw it on the hash
+ if (anyEnt.isSet(propName)) {
+ thisNodeFilterHash.put(nodeType + "." + CaseFormat.LOWER_CAMEL.to(CaseFormat.LOWER_HYPHEN, propName), anyEnt.get(propName));
+ if (propName.equals("resourceVersion") && resourceVersion == null) {
+ resourceVersion = (String)anyEnt.get(propName);
+ }
+ }
+ }
+ }
+ startNodeFilterHash.add(thisNodeFilterHash);
+ }
+ return resourceVersion;
+ }
+
+ /**
+ * Map secondary filters.
+ *
+ * @param secondaryFilts the secondary filters
+ * @param secondaryFilterHash the secondary filter hash
+ * @param jaxbContext the jaxb context
+ * @return the string
+ */
+ private void mapSecondaryFilters(DynamicEntity secondaryFilts, Map<String,Object> secondaryFilterHash, DynamicJAXBContext jaxbContext) {
+
+ if (secondaryFilts == null || !secondaryFilts.isSet("secondaryFilt")) {
+ return;
+ }
+ @SuppressWarnings("unchecked")
+ List<DynamicEntity> secondaryFilter = (ArrayList<DynamicEntity>)secondaryFilts.get("secondaryFilt");
+
+ for (DynamicEntity secondaryFilt : secondaryFilter) {
+ List<DynamicEntity> any = secondaryFilt.get("any");
+
+ for (DynamicEntity anyEnt : any) {
+ String clazz = anyEnt.getClass().getCanonicalName();
+ String simpleClazz = anyEnt.getClass().getSimpleName();
+
+ String nodeType = CaseFormat.LOWER_CAMEL.to(CaseFormat.LOWER_HYPHEN, simpleClazz);
+
+ DynamicType anyEntType = jaxbContext.getDynamicType(clazz);
+
+ for (String propName : anyEntType.getPropertiesNames()) {
+ // hyphencase the prop and throw it on the hash
+ if (anyEnt.isSet(propName)) {
+ secondaryFilterHash.put(nodeType + "." + CaseFormat.LOWER_CAMEL.to(CaseFormat.LOWER_HYPHEN, propName), anyEnt.get(propName));
+ }
+ }
+ }
+ }
+ }
+
+ /**
+ * Remap inventory items.
+ *
+ * @param invResultItem the inv result item
+ * @param jaxbContext the jaxb context
+ * @param includeTheseVertices the include these vertices
+ * @param objectToVertMap the object to vert map
+ * @param aaiExtMap the aai ext map
+ * @return the dynamic entity
+ */
+ private DynamicEntity remapInventoryItems(DynamicEntity invResultItem, DynamicJAXBContext jaxbContext,
+ Map<String,String> includeTheseVertices, Map<Object,String> objectToVertMap, AAIExtensionMap aaiExtMap) {
+
+
+ DynamicEntity inventoryItem = jaxbContext.newDynamicEntity("inventory.aai.ecomp.org." + aaiExtMap.getApiVersion() + ".InventoryResponseItem");
+ Object item = invResultItem.get("item");
+ inventoryItem.set("modelName", invResultItem.get("modelName"));
+ inventoryItem.set("item", item);
+ inventoryItem.set("extraProperties", invResultItem.get("extraProperties"));
+
+ String vertexId = "";
+
+ if (objectToVertMap.containsKey(item)) {
+ vertexId = objectToVertMap.get(item);
+ }
+
+ if (includeTheseVertices.containsKey(vertexId)) {
+ if (invResultItem.isSet("inventoryResponseItems")) {
+ List<DynamicEntity> invItemList = new ArrayList<DynamicEntity>();
+ DynamicEntity inventoryItems = jaxbContext.newDynamicEntity("inventory.aai.ecomp.org." + aaiExtMap.getApiVersion() + ".InventoryResponseItems");
+ DynamicEntity subInventoryResponseItems = invResultItem.get("inventoryResponseItems");
+ List<DynamicEntity> subInventoryResponseItemList = subInventoryResponseItems.get("inventoryResponseItem");
+ for (DynamicEntity ent : subInventoryResponseItemList) {
+ DynamicEntity invItem = remapInventoryItems(ent, jaxbContext, includeTheseVertices, objectToVertMap, aaiExtMap);
+ if (invItem != null) {
+ invItemList.add(invItem);
+ }
+ }
+ if (invItemList != null) {
+ inventoryItems.set("inventoryResponseItem", invItemList);
+ inventoryItem.set("inventoryResponseItems", inventoryItems);
+ }
+ }
+ }
+ return inventoryItem;
+ }
+
+ /**
+ * Unpack result set.
+ *
+ * @param g the g
+ * @param resultSetList the result set list
+ * @param jaxbContext the jaxb context
+ * @param aaiResources the aai resources
+ * @param objectToVertMap the object to vert map
+ * @param aaiExtMap the aai ext map
+ * @return the array list
+ * @throws AAIException the AAI exception
+ */
+ // this should return an inventoryItem
+ private List<Object> unpackResultSet(List<ResultSet> resultSetList,
+ TransactionalGraphEngine engine,
+ Loader loader,
+ DBSerializer serializer) throws AAIException {
+
+ List<Object> resultList = new ArrayList<>();
+
+ for (ResultSet resultSet : resultSetList) {
+
+ if( resultSet.getVert() == null ){
+ continue;
+ }
+
+ Introspector inventoryItem = loader.introspectorFromName("inventory-response-item");
+ Introspector inventoryItems = loader.introspectorFromName("inventory-response-items");
+ // add this inventoryItem to the resultList for this level
+ resultList.add(inventoryItem.getUnderlyingObject());
+
+ TitanVertex vert = resultSet.getVert();
+
+ Long vertId = (Long)vert.longId();
+
+ String aaiNodeType = vert.<String>property("aai-node-type").orElse(null);
+
+
+
+ PojoUtils pu = new PojoUtils();
+ if (aaiNodeType != null) {
+ Introspector thisObj = loader.introspectorFromName(aaiNodeType);
+
+ if (resultSet.getExtraPropertyHash() != null) {
+ Map<String,Object> extraProperties = resultSet.getExtraPropertyHash();
+
+ Introspector extraPropertiesEntity = loader.introspectorFromName("extra-properties");
+
+ List<Object> extraPropsList = extraPropertiesEntity.getValue("extra-property");
+
+ for (Map.Entry<String,Object> ent : extraProperties.entrySet()) {
+ String propName = ent.getKey();
+ Object propVal = ent.getValue();
+
+ Introspector extraPropEntity = loader.introspectorFromName("extra-property");
+
+ extraPropEntity.setValue("property-name", propName);
+ extraPropEntity.setValue("property-value", propVal);
+
+ extraPropsList.add(extraPropEntity.getUnderlyingObject());
+
+ }
+ inventoryItem.setValue("extra-properties", extraPropertiesEntity.getUnderlyingObject());
+ }
+
+ try {
+ serializer.dbToObject(Collections.singletonList(vert), thisObj, 0, true, "false");
+ } catch (UnsupportedEncodingException e1) {
+ throw new AAIException("AAI_5105");
+ }
+ PropertyLimitDesc propertyLimitDesc = resultSet.getPropertyLimitDesc();
+
+ if (propertyLimitDesc != null) {
+
+ if (PropertyLimitDesc.SHOW_NONE.equals(propertyLimitDesc)) {
+ HashMap<String,Object> emptyPropertyOverRideHash = new HashMap<String,Object>();
+ for (String key : thisObj.getAllKeys()) {
+ emptyPropertyOverRideHash.put(key, null);
+ }
+ filterProperties(thisObj, emptyPropertyOverRideHash);
+ } else if (PropertyLimitDesc.SHOW_ALL.equals(propertyLimitDesc)) {
+ //keep everything
+ } else if (PropertyLimitDesc.SHOW_NAME_AND_KEYS_ONLY.equals(propertyLimitDesc)) {
+ HashMap<String,Object> keysAndNamesPropHash = new HashMap<String,Object>();
+
+ for (String key : thisObj.getAllKeys()) {
+ keysAndNamesPropHash.put(key, null);
+ }
+ String namePropMetaData = thisObj.getMetadata(ObjectMetadata.NAME_PROPS);
+ if (namePropMetaData != null) {
+ String[] nameProps = namePropMetaData.split(",");
+ for (String names : nameProps) {
+ keysAndNamesPropHash.put(names, null);
+ }
+ }
+ filterProperties(thisObj, keysAndNamesPropHash);
+ }
+ } else {
+ if (resultSet.getPropertyOverRideHash() != null && resultSet.getPropertyOverRideHash().size() > 0) {
+ Map<String,Object> propertyOverRideHash = resultSet.getPropertyOverRideHash();
+ if (propertyOverRideHash.containsKey("persona-model-id")) {
+ propertyOverRideHash.remove("persona-model-id");
+ propertyOverRideHash.put("model-invariant-id", null);
+ }
+ for (String key : thisObj.getAllKeys()) {
+ propertyOverRideHash.put(key, null);
+ }
+ filterProperties(thisObj, propertyOverRideHash);
+ } else {
+ //keep everything
+ }
+ }
+
+ if (thisObj != null) {
+ inventoryItem.setValue("item", thisObj.getUnderlyingObject());
+
+ String modelName = null;
+ try {
+ String modelInvariantIdLocal = (String)vert.<String>property("model-invariant-id-local").orElse(null); // this one points at a model
+ String modelVersionIdLocal = (String)vert.<String>property("model-version-id-local").orElse(null); // this one points at a model-ver
+
+ if ( (modelInvariantIdLocal != null && modelVersionIdLocal != null)
+ && (modelInvariantIdLocal.length() > 0 && modelVersionIdLocal.length() > 0) ) {
+ HashMap<String,Object> modelLookupHash = new HashMap<String,Object>();
+
+ Introspector modelVer = loader.introspectorFromName("model-ver");
+ modelVer.setValue("model-version-id", modelVersionIdLocal);
+ QueryBuilder builder = engine.getQueryBuilder().createDBQuery(modelVer);
+
+ List<Vertex> modelVerVerts = builder.toList();
+ if (modelVerVerts.size() != 1) {
+ throw new AAIException("AAI_6112");
+ }
+ Vertex modelVerVert = modelVerVerts.get(0);
+
+ modelName = modelVerVert.<String>property("model-name").orElse(null);
+
+ if (modelName != null && modelName.length() > 0) {
+ inventoryItem.setValue("model-name", modelName);
+ }
+ }
+ } catch (DynamicException e) {
+ ; // it's ok, dynamic object might not have these fields
+ } catch (AAIException e) {
+ if (e.getErrorObject().getErrorCode().equals("6114")) {
+ // it's ok, couldn't find a matching model
+ } else {
+ throw e;
+ }
+ }
+
+ if (resultSet.getSubResultSet() != null) {
+ List<ResultSet> subResultSet = resultSet.getSubResultSet();
+ if (subResultSet != null && subResultSet.size() > 0 ) {
+ List<Object> res = unpackResultSet(subResultSet, engine, loader, serializer);
+ if (res.size() > 0) {
+ inventoryItems.setValue("inventory-response-item", res);
+ inventoryItem.setValue("inventory-response-items", inventoryItems.getUnderlyingObject());
+ }
+ }
+ }
+ }
+ }
+ }
+
+ return resultList;
+ }
+
+ private void filterProperties(Introspector thisObj, Map<String, Object> override) {
+
+ thisObj.getProperties().stream().filter(x -> {
+ return !override.containsKey(x);
+ }).forEach(prop -> {
+ if (thisObj.isSimpleType(prop)) {
+ thisObj.setValue(prop, null);
+ }
+ });
+
+ }
+
+ /**
+ * Gets the media type.
+ *
+ * @param mediaTypeList the media type list
+ * @return the media type
+ */
+ protected String getMediaType(List <MediaType> mediaTypeList) {
+ String mediaType = MediaType.APPLICATION_JSON; // json is the default
+ for (MediaType mt : mediaTypeList) {
+ if (MediaType.APPLICATION_XML_TYPE.isCompatible(mt)) {
+ mediaType = MediaType.APPLICATION_XML;
+ }
+ }
+ return mediaType;
+ }
+}
diff --git a/aai-traversal/src/main/java/org/openecomp/aai/dmaap/AAIDmaapEventJMSConsumer.java b/aai-traversal/src/main/java/org/openecomp/aai/dmaap/AAIDmaapEventJMSConsumer.java
new file mode 100644
index 0000000..d8a0ce7
--- /dev/null
+++ b/aai-traversal/src/main/java/org/openecomp/aai/dmaap/AAIDmaapEventJMSConsumer.java
@@ -0,0 +1,163 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * org.openecomp.aai
+ * ================================================================================
+ * Copyright (C) 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=========================================================
+ */
+
+package org.openecomp.aai.dmaap;
+
+import java.io.File;
+import java.io.FileReader;
+import java.io.IOException;
+import java.util.Properties;
+
+import javax.jms.JMSException;
+import javax.jms.Message;
+import javax.jms.MessageListener;
+import javax.jms.TextMessage;
+import javax.ws.rs.core.MediaType;
+
+import org.apache.log4j.MDC;
+import org.eclipse.jetty.util.security.Password;
+import org.json.JSONException;
+import org.json.JSONObject;
+
+import org.openecomp.aai.logging.ErrorLogHelper;
+import org.openecomp.aai.util.AAIConstants;
+import com.att.eelf.configuration.EELFLogger;
+import com.att.eelf.configuration.EELFManager;
+import com.att.nsa.mr.client.MRBatchingPublisher;
+import com.att.nsa.mr.client.MRClientFactory;
+import com.sun.jersey.api.client.Client;
+import com.sun.jersey.api.client.ClientResponse;
+import com.sun.jersey.api.client.WebResource;
+import com.sun.jersey.api.client.filter.HTTPBasicAuthFilter;
+
+public class AAIDmaapEventJMSConsumer implements MessageListener {
+
+ private static final EELFLogger LOGGER = EELFManager.getInstance().getLogger(AAIDmaapEventJMSConsumer.class);
+
+ private final static String COMPONENT = "aaiDmaapEvent";
+ private MRBatchingPublisher adp = null;
+
+ private Properties props;
+
+ private String username;
+ private String password;
+ private String contentType;
+
+ private String url;
+ private Client client;
+
+ public AAIDmaapEventJMSConsumer() throws org.apache.commons.configuration.ConfigurationException {
+ super();
+
+ if (this.adp == null) {
+ try {
+ FileReader reader = new FileReader(new File(AAIConstants.AAI_EVENT_DMAAP_PROPS));
+ props = new Properties();
+ props.load(reader);
+ props.setProperty("DME2preferredRouterFilePath", AAIConstants.AAI_HOME_ETC_APP_PROPERTIES + "preferredRoute.txt");
+ if (props.getProperty("password") != null && props.getProperty("password").startsWith("OBF:")) {
+ props.setProperty("password", Password.deobfuscate(props.getProperty("password")));
+ }
+ this.adp = MRClientFactory.createBatchingPublisher(props);
+
+ String host = props.getProperty("host");
+ String topic = props.getProperty("topic");
+ String protocol = props.getProperty("Protocol");
+
+ username = props.getProperty("username");
+ password = props.getProperty("password");
+ contentType = props.getProperty("contenttype");
+
+ url = protocol + "://" + host + "/events/" + topic;
+ client = Client.create();
+ client.addFilter(new HTTPBasicAuthFilter(username, password));
+
+ } catch (IOException e) {
+ ErrorLogHelper.logError("AAI_4000", "Error updating dmaap config file for aai event.");
+ }
+ }
+
+ }
+
+ @Override
+ public void onMessage(Message message) {
+
+ String jsmMessageTxt = "";
+ String aaiEvent = "";
+ String transId = "";
+ String fromAppId = "";
+ String fullId = "";
+
+ if (message instanceof TextMessage) {
+ try {
+ jsmMessageTxt = ((TextMessage) message).getText();
+ JSONObject jo = new JSONObject(jsmMessageTxt);
+
+ if (jo.has("aaiEventPayload")) {
+ aaiEvent = jo.getJSONObject("aaiEventPayload").toString();
+ } else {
+ return;
+ }
+ if (jo.getString("transId") != null) {
+ MDC.put("requestId", jo.getString("transId"));
+ }
+ if (jo.getString("fromAppId") != null) {
+ MDC.put("partnerName", jo.getString("fromAppId"));
+ }
+ if (jo.getString("fullId") != null) {
+ fullId = jo.getString("fullId");
+ }
+
+ LOGGER.info(fullId + "|" + transId + "|" + fromAppId + "|" + aaiEvent);
+
+ String environment = System.getProperty("lrmRO");
+
+ if (environment == null) {
+ this.adp.send(aaiEvent);
+ } else {
+ if (environment.startsWith("dev") || environment.startsWith("testINT") || environment.startsWith("testEXT")) {
+
+ WebResource webResource = client.resource(url);
+
+ ClientResponse response = webResource.accept(contentType).type(MediaType.APPLICATION_JSON).post(ClientResponse.class, aaiEvent);
+
+ if (response.getStatus() != 200) {
+ System.out.println("Failed : HTTP error code : " + response.getStatus());
+ }
+ } else {
+ this.adp.send(aaiEvent);
+ }
+ }
+
+ } catch (IOException e) {
+ if (e instanceof java.net.SocketException) {
+ if (e.getMessage().contains("Connection reset")) {
+ } else {
+ ErrorLogHelper.logError("AAI_7304", "Error reaching DMaaP to send event. " + aaiEvent);
+ }
+ } else {
+ ErrorLogHelper.logError("AAI_7304", "Error reaching DMaaP to send event. " + aaiEvent);
+ }
+ } catch (JMSException | JSONException e) {
+ ErrorLogHelper.logError("AAI_7350", "Error parsing aaievent jsm message for sending to dmaap. " + jsmMessageTxt);
+ }
+ }
+ }
+}
diff --git a/aai-traversal/src/main/java/org/openecomp/aai/dmaap/AAIDmaapEventJMSProducer.java b/aai-traversal/src/main/java/org/openecomp/aai/dmaap/AAIDmaapEventJMSProducer.java
new file mode 100644
index 0000000..305e585
--- /dev/null
+++ b/aai-traversal/src/main/java/org/openecomp/aai/dmaap/AAIDmaapEventJMSProducer.java
@@ -0,0 +1,44 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * org.openecomp.aai
+ * ================================================================================
+ * Copyright (C) 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=========================================================
+ */
+
+package org.openecomp.aai.dmaap;
+
+import org.apache.activemq.ActiveMQConnectionFactory;
+import org.apache.activemq.command.ActiveMQQueue;
+import org.json.JSONObject;
+import org.springframework.jms.connection.CachingConnectionFactory;
+import org.springframework.jms.core.JmsTemplate;
+
+public class AAIDmaapEventJMSProducer {
+
+ private JmsTemplate jmsTemplate;
+
+ public AAIDmaapEventJMSProducer() {
+ this.jmsTemplate = new JmsTemplate();
+ this.jmsTemplate.setConnectionFactory(new CachingConnectionFactory(new ActiveMQConnectionFactory("tcp://localhost:61446")));
+ this.jmsTemplate.setDefaultDestination(new ActiveMQQueue("IN_QUEUE"));
+ }
+
+ public void sendMessageToDefaultDestination(JSONObject finalJson) {
+ jmsTemplate.convertAndSend(finalJson.toString());
+ CachingConnectionFactory ccf = (CachingConnectionFactory)this.jmsTemplate.getConnectionFactory();
+ ccf.destroy();
+ }
+}
diff --git a/aai-traversal/src/main/java/org/openecomp/aai/extensions/AAIExtensionMap.java b/aai-traversal/src/main/java/org/openecomp/aai/extensions/AAIExtensionMap.java
new file mode 100644
index 0000000..167dae4
--- /dev/null
+++ b/aai-traversal/src/main/java/org/openecomp/aai/extensions/AAIExtensionMap.java
@@ -0,0 +1,827 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * org.openecomp.aai
+ * ================================================================================
+ * Copyright (C) 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=========================================================
+ */
+
+package org.openecomp.aai.extensions;
+
+import java.lang.reflect.Method;
+import java.util.ArrayList;
+import java.util.HashMap;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.ws.rs.core.HttpHeaders;
+import javax.ws.rs.core.UriInfo;
+
+import org.eclipse.persistence.jaxb.dynamic.DynamicJAXBContext;
+
+import org.openecomp.aai.domain.responseMessage.AAIResponseMessages;
+import org.openecomp.aai.introspection.Loader;
+import org.openecomp.aai.rest.db.DBRequest;
+import org.openecomp.aai.rest.db.HttpEntry;
+import org.openecomp.aai.serialization.engines.TransactionalGraphEngine;
+import com.thinkaurelius.titan.core.TitanTransaction;
+import com.thinkaurelius.titan.core.TitanVertex;
+
+public class AAIExtensionMap {
+ // =======================================================================
+ // Attribute | Type
+ // =======================================================================
+ // message | java.lang.String (RW)
+ // ----------------------------------------------------------------------
+ // templateVars | java.lang.ArrayList<String> (RW)
+ // -----------------------------------------------------------------------
+ // preExtException | java.lang.Exception (RW)
+ // -----------------------------------------------------------------------
+ // preExtErrorCallback | java.lang.reflect.Method (RW)
+ // -----------------------------------------------------------------------
+ // postExtException | java.lang.Exception (RW)
+ // -----------------------------------------------------------------------
+ // postExtErrorCallback | java.lang.reflect.Method (RW)
+ // -----------------------------------------------------------------------
+ // servletRequest | javax.servlet.http.HttpServletRequest (RO)
+ // -----------------------------------------------------------------------
+ // headers | javax.ws.rs.core.HttpHeaders (RO)
+ // -----------------------------------------------------------------------
+ // objFromRequestType | String (ex. ?org.openecomp.aai.domain.yang.Vce?) (RO)
+ // -----------------------------------------------------------------------
+ // objFromRequest | $TYPE {ObjFromRequestType) (RO)
+ // -----------------------------------------------------------------------
+ // preExtFailOnError | java.lang.Boolean (RW)
+ // -----------------------------------------------------------------------
+ // postExtFailOnError | java.lang.Boolean (RW)
+ // -----------------------------------------------------------------------
+ // preExtSkipErrorCallback | java.lang.Boolean (RW)
+ // -----------------------------------------------------------------------
+ // postExtSkipErrorCallback | java.lang.Boolean (RW)
+ // -----------------------------------------------------------------------
+ // graph | com.thinkaurelius.titan.core.TitanGraph (RW)
+ // -----------------------------------------------------------------------
+ // objectFromResponse | Object
+ // -----------------------------------------------------------------------
+ // precheckAddedList | java.util.HashMap
+ // -----------------------------------------------------------------------
+ // precheckResponseMessages | org.openecomp.aai.extensions.AAIResponseMessages
+ // =======================================================================
+
+ private String message;
+ private ArrayList<String> templateVars;
+ private Exception preExtException;
+ private Exception postExtException;
+ private Method preExtErrorCallback;
+ private Method postExtErrorCallback;
+ private HttpServletRequest servletRequest;
+ private HttpHeaders httpHeaders;
+ private String objectFromRequestType;
+ private Object objectFromRequest;
+ private boolean preExtFailOnError = true;
+ private boolean postExtFailOnError = true;
+ private boolean preExtSkipErrorCallback = true;
+ private boolean postExtSkipErrorCallback = true;
+ private String fromAppId;
+ private String transId;
+ private TitanTransaction graph;
+ private Object objectFromResponse;
+ private HashMap<String, Object> lookupHashMap;
+ private HashMap<String, ArrayList<String>> precheckAddedList;
+ private AAIResponseMessages precheckResponseMessages;
+ private HashMap<String, Object> topology;
+ private HashMap<String, TitanVertex> vertexCache;
+ private String baseObject;
+ private String namespace;
+ private String fullResourceName;
+ private String topObjectFullResourceName;
+ private String uri;
+ private String notificationUri;
+ private String apiVersion;
+ private long startTime;
+ private long checkpointTime;
+ private DynamicJAXBContext jaxbContext;
+ private String objectFromResponseType;
+ private String eventAction;
+ private TransactionalGraphEngine dbEngine;
+ private Loader loader;
+ private UriInfo uriInfo;
+ private DBRequest dbRequest;
+ private HttpEntry httpEntry;
+ /**
+ * Sets the message.
+ *
+ * @param _message the new message
+ */
+ public void setMessage(String _message) {
+ this.message = _message;
+ }
+
+ /**
+ * Sets the template vars.
+ *
+ * @param _templateVars the new template vars
+ */
+ public void setTemplateVars(ArrayList<String> _templateVars) {
+ this.templateVars = _templateVars;
+ }
+
+ /**
+ * Sets the pre ext exception.
+ *
+ * @param _exception the new pre ext exception
+ */
+ public void setPreExtException(Exception _exception) {
+ this.preExtException = _exception;
+ }
+
+ /**
+ * Sets the pre ext error callback.
+ *
+ * @param _errorCallback the new pre ext error callback
+ */
+ public void setPreExtErrorCallback(Method _errorCallback) {
+ this.preExtErrorCallback = _errorCallback;
+ }
+
+ /**
+ * Sets the post ext exception.
+ *
+ * @param _exception the new post ext exception
+ */
+ public void setPostExtException(Exception _exception) {
+ this.postExtException = _exception;
+ }
+
+ /**
+ * Sets the post ext error callback.
+ *
+ * @param _errorCallback the new post ext error callback
+ */
+ public void setPostExtErrorCallback(Method _errorCallback) {
+ this.postExtErrorCallback = _errorCallback;
+ }
+
+ /**
+ * Sets the servlet request.
+ *
+ * @param _httpServletRequest the new servlet request
+ */
+ public void setServletRequest(HttpServletRequest _httpServletRequest) {
+ this.servletRequest = _httpServletRequest;
+ }
+
+ /**
+ * Sets the http headers.
+ *
+ * @param _httpHeaders the new http headers
+ */
+ public void setHttpHeaders(HttpHeaders _httpHeaders) {
+ this.httpHeaders = _httpHeaders;
+ }
+
+ /**
+ * Sets the object from request type.
+ *
+ * @param _objectFromRequestType the new object from request type
+ */
+ public void setObjectFromRequestType(String _objectFromRequestType) {
+ this.objectFromRequestType = _objectFromRequestType;
+ }
+
+ /**
+ * Sets the object from request.
+ *
+ * @param _objectFromRequest the new object from request
+ */
+ public void setObjectFromRequest(Object _objectFromRequest) {
+ this.objectFromRequest = _objectFromRequest;
+ }
+
+ /**
+ * Sets the object from response type.
+ *
+ * @param resourceClassName the new object from response type
+ */
+ public void setObjectFromResponseType(String resourceClassName) {
+ // TODO Auto-generated method stub
+ this.objectFromResponseType = resourceClassName;
+ }
+
+ /**
+ * Gets the object from response type.
+ *
+ * @return the object from response type
+ */
+ public String getObjectFromResponseType() {
+ // TODO Auto-generated method stub
+ return this.objectFromResponseType;
+ }
+
+ /**
+ * Sets the pre ext fail on error.
+ *
+ * @param _failOnError the new pre ext fail on error
+ */
+ public void setPreExtFailOnError(boolean _failOnError) {
+ this.preExtFailOnError = _failOnError;
+ }
+
+ /**
+ * Sets the post ext fail on error.
+ *
+ * @param _failOnError the new post ext fail on error
+ */
+ public void setPostExtFailOnError(boolean _failOnError) {
+ this.postExtFailOnError = _failOnError;
+ }
+
+ /**
+ * Gets the message.
+ *
+ * @return the message
+ */
+ public String getMessage() {
+ return this.message;
+ }
+
+ /**
+ * Gets the template vars.
+ *
+ * @return the template vars
+ */
+ public ArrayList<String> getTemplateVars() {
+ if (this.templateVars == null) {
+ this.templateVars = new ArrayList<String>();
+ }
+ return this.templateVars;
+ }
+
+ /**
+ * Gets the pre ext exception.
+ *
+ * @return the pre ext exception
+ */
+ public Exception getPreExtException() {
+ return this.preExtException;
+ }
+
+ /**
+ * Gets the pre ext error callback.
+ *
+ * @return the pre ext error callback
+ */
+ public Method getPreExtErrorCallback() {
+ return this.preExtErrorCallback;
+ }
+
+ /**
+ * Gets the post ext exception.
+ *
+ * @return the post ext exception
+ */
+ public Exception getPostExtException() {
+ return this.postExtException;
+ }
+
+ /**
+ * Gets the post ext error callback.
+ *
+ * @return the post ext error callback
+ */
+ public Method getPostExtErrorCallback() {
+ return this.postExtErrorCallback;
+ }
+
+ /**
+ * Gets the http servlet request.
+ *
+ * @return the http servlet request
+ */
+ public HttpServletRequest getHttpServletRequest() {
+ return this.servletRequest;
+ }
+
+ /**
+ * Gets the http headers.
+ *
+ * @return the http headers
+ */
+ public HttpHeaders getHttpHeaders() {
+ return this.httpHeaders;
+ }
+
+ /**
+ * Gets the object from request type.
+ *
+ * @return the object from request type
+ */
+ public String getObjectFromRequestType() {
+ return this.objectFromRequestType;
+ }
+
+ /**
+ * Gets the object from request.
+ *
+ * @return the object from request
+ */
+ public Object getObjectFromRequest() {
+ return this.objectFromRequest;
+ }
+
+ /**
+ * Gets the pre ext fail on error.
+ *
+ * @return the pre ext fail on error
+ */
+ public boolean getPreExtFailOnError() {
+ return this.preExtFailOnError;
+ }
+
+ /**
+ * Gets the post ext fail on error.
+ *
+ * @return the post ext fail on error
+ */
+ public boolean getPostExtFailOnError() {
+ return this.postExtFailOnError;
+ }
+
+ /**
+ * Gets the from app id.
+ *
+ * @return the from app id
+ */
+ public String getFromAppId() {
+ return this.fromAppId;
+ }
+
+ /**
+ * Sets the from app id.
+ *
+ * @param fromAppId the new from app id
+ */
+ public void setFromAppId(String fromAppId) {
+ this.fromAppId = fromAppId;
+ }
+
+ /**
+ * Gets the trans id.
+ *
+ * @return the trans id
+ */
+ public String getTransId() {
+ return this.transId;
+ }
+
+ /**
+ * Sets the trans id.
+ *
+ * @param transId the new trans id
+ */
+ public void setTransId(String transId) {
+ this.transId = transId;
+ }
+
+ /**
+ * Gets the pre ext skip error callback.
+ *
+ * @return the pre ext skip error callback
+ */
+ public boolean getPreExtSkipErrorCallback() {
+ return preExtSkipErrorCallback;
+ }
+
+ /**
+ * Sets the pre ext skip error callback.
+ *
+ * @param preExtSkipErrorCallback the new pre ext skip error callback
+ */
+ public void setPreExtSkipErrorCallback(boolean preExtSkipErrorCallback) {
+ this.preExtSkipErrorCallback = preExtSkipErrorCallback;
+ }
+
+ /**
+ * Gets the post ext skip error callback.
+ *
+ * @return the post ext skip error callback
+ */
+ public boolean getPostExtSkipErrorCallback() {
+ return postExtSkipErrorCallback;
+ }
+
+ /**
+ * Sets the post ext skip error callback.
+ *
+ * @param postExtSkipErrorCallback the new post ext skip error callback
+ */
+ public void setPostExtSkipErrorCallback(boolean postExtSkipErrorCallback) {
+ this.postExtSkipErrorCallback = postExtSkipErrorCallback;
+ }
+
+ /**
+ * Gets the graph.
+ *
+ * @return the graph
+ */
+ public TitanTransaction getGraph() {
+ return graph;
+ }
+
+ /**
+ * Sets the graph.
+ *
+ * @param graph the new graph
+ */
+ public void setGraph(TitanTransaction graph) {
+ this.graph = graph;
+ }
+
+ /**
+ * Gets the object from response.
+ *
+ * @return the object from response
+ */
+ public Object getObjectFromResponse() {
+ return objectFromResponse;
+ }
+
+ /**
+ * Sets the object from response.
+ *
+ * @param objectFromResponse the new object from response
+ */
+ public void setObjectFromResponse(Object objectFromResponse) {
+ this.objectFromResponse = objectFromResponse;
+ }
+
+ /**
+ * Gets the lookup hash map.
+ *
+ * @return the lookup hash map
+ */
+ public HashMap<String, Object> getLookupHashMap() {
+ if (this.lookupHashMap == null) {
+ this.lookupHashMap = new HashMap<String, Object>();
+ }
+ return this.lookupHashMap;
+ }
+
+ /**
+ * Sets the lookup hash map.
+ *
+ * @param lookupHashMap the lookup hash map
+ */
+ public void setLookupHashMap(HashMap<String, Object> lookupHashMap) {
+ this.lookupHashMap = lookupHashMap;
+ }
+
+ /**
+ * Gets the precheck added list.
+ *
+ * @return the precheck added list
+ */
+ public HashMap<String, ArrayList<String>> getPrecheckAddedList() {
+ if (this.precheckAddedList == null) {
+ this.precheckAddedList = new HashMap<String, ArrayList<String>>();
+ }
+ return precheckAddedList;
+ }
+
+ /**
+ * Sets the precheck added list.
+ *
+ * @param precheckAddedList the precheck added list
+ */
+ public void setPrecheckAddedList(HashMap<String, ArrayList<String>> precheckAddedList) {
+ this.precheckAddedList = precheckAddedList;
+ }
+
+ /**
+ * Gets the precheck response messages.
+ *
+ * @return the precheck response messages
+ */
+ public AAIResponseMessages getPrecheckResponseMessages() {
+ if (this.precheckResponseMessages == null) {
+ this.precheckResponseMessages = new AAIResponseMessages();
+ }
+ return precheckResponseMessages;
+ }
+
+ /**
+ * Sets the precheck response messages.
+ *
+ * @param precheckResponseData the new precheck response messages
+ */
+ public void setPrecheckResponseMessages(AAIResponseMessages precheckResponseData) {
+ this.precheckResponseMessages = precheckResponseData;
+ }
+
+ /**
+ * Gets the topology.
+ *
+ * @return the topology
+ */
+ public HashMap<String, Object> getTopology() {
+ if (this.topology == null) {
+ this.topology = new HashMap<String, Object>();
+ }
+ return topology;
+ }
+
+ /**
+ * Gets the vertex cache.
+ *
+ * @return the vertex cache
+ */
+ public HashMap<String, TitanVertex> getVertexCache() {
+ if (this.vertexCache == null) {
+ this.vertexCache = new HashMap<String, TitanVertex>();
+ }
+ return vertexCache;
+ }
+
+ /**
+ * Gets the base object.
+ *
+ * @return the base object
+ */
+ public String getBaseObject() {
+ return baseObject;
+ }
+
+ /**
+ * Sets the base object.
+ *
+ * @param baseObject the new base object
+ */
+ public void setBaseObject(String baseObject) {
+ this.baseObject = baseObject;
+ }
+
+ /**
+ * Gets the namespace.
+ *
+ * @return the namespace
+ */
+ public String getNamespace() {
+ return namespace;
+ }
+
+ /**
+ * Sets the namespace.
+ *
+ * @param namespace the new namespace
+ */
+ public void setNamespace(String namespace) {
+ this.namespace = namespace;
+ }
+
+ /**
+ * Gets the full resource name.
+ *
+ * @return the full resource name
+ */
+ public String getFullResourceName() {
+ return fullResourceName;
+ }
+
+ /**
+ * Sets the full resource name.
+ *
+ * @param fullResourceName the new full resource name
+ */
+ public void setFullResourceName(String fullResourceName) {
+ this.fullResourceName = fullResourceName;
+ }
+
+ /**
+ * Gets the top object full resource name.
+ *
+ * @return the top object full resource name
+ */
+ public String getTopObjectFullResourceName() {
+ return topObjectFullResourceName;
+ }
+
+ /**
+ * Sets the top object full resource name.
+ *
+ * @param topObjectFullResourceName the new top object full resource name
+ */
+ public void setTopObjectFullResourceName(String topObjectFullResourceName) {
+ this.topObjectFullResourceName = topObjectFullResourceName;
+ }
+
+ /**
+ * Gets the uri.
+ *
+ * @return the uri
+ */
+ public String getUri() {
+ return uri;
+ }
+
+ /**
+ * Sets the uri.
+ *
+ * @param uri the new uri
+ */
+ public void setUri(String uri) {
+ this.uri = uri;
+ }
+
+ /**
+ * Gets the api version.
+ *
+ * @return the api version
+ */
+ public String getApiVersion() {
+ return apiVersion;
+ }
+
+ /**
+ * Sets the api version.
+ *
+ * @param apiVersion the new api version
+ */
+ public void setApiVersion(String apiVersion) {
+ this.apiVersion = apiVersion;
+ }
+
+ /**
+ * Sets the notification uri.
+ *
+ * @param uri the new notification uri
+ */
+ public void setNotificationUri(String uri) {
+ this.notificationUri = uri;
+
+ }
+
+ /**
+ * Gets the notification uri.
+ *
+ * @return the notification uri
+ */
+ public String getNotificationUri() {
+ return this.notificationUri;
+
+ }
+
+ /**
+ * Gets the start time.
+ *
+ * @return the start time
+ */
+ public long getStartTime() {
+ return startTime;
+ }
+
+ /**
+ * Sets the start time.
+ *
+ * @param startTime the new start time
+ */
+ public void setStartTime(long startTime) {
+ this.startTime = startTime;
+ }
+
+ /**
+ * Gets the checkpoint time.
+ *
+ * @return the checkpoint time
+ */
+ public long getCheckpointTime() {
+ return checkpointTime;
+ }
+
+ /**
+ * Sets the checkpoint time.
+ *
+ * @param checkpointTime the new checkpoint time
+ */
+ public void setCheckpointTime(long checkpointTime) {
+ this.checkpointTime = checkpointTime;
+ }
+
+ /**
+ * Gets the jaxb context.
+ *
+ * @return the jaxb context
+ */
+ public DynamicJAXBContext getJaxbContext() {
+ return jaxbContext;
+ }
+
+ /**
+ * Sets the jaxb context.
+ *
+ * @param jaxbContext the new jaxb context
+ */
+ public void setJaxbContext(DynamicJAXBContext jaxbContext) {
+ this.jaxbContext = jaxbContext;
+ }
+
+ /**
+ * Sets the event action.
+ *
+ * @param eventAction the new event action
+ */
+ public void setEventAction(String eventAction) {
+ this.eventAction = eventAction;
+ }
+
+ /**
+ * Gets the event action.
+ *
+ * @return the event action
+ */
+ public String getEventAction() {
+ return this.eventAction;
+ }
+
+ /**
+ * Gets the transactional graph engine.
+ *
+ * @return the transactional graph engine
+ */
+ public TransactionalGraphEngine getTransactionalGraphEngine() {
+ return this.dbEngine;
+
+ }
+
+ /**
+ * Sets the transactional graph engine.
+ *
+ * @param dbEngine the new transactional graph engine
+ */
+ public void setTransactionalGraphEngine(TransactionalGraphEngine dbEngine) {
+ this.dbEngine = dbEngine;
+
+ }
+
+ /**
+ * Gets the loader.
+ *
+ * @return the loader
+ */
+ public Loader getLoader() {
+ return loader;
+ }
+
+ /**
+ * Sets the loader.
+ *
+ * @param loader the new loader
+ */
+ public void setLoader(Loader loader) {
+ this.loader = loader;
+ }
+
+ /**
+ * Gets the uri info.
+ *
+ * @return the uri info
+ */
+ public UriInfo getUriInfo() {
+ return uriInfo;
+ }
+
+ /**
+ * Sets the uri info.
+ *
+ * @param uriInfo the new uri info
+ */
+ public void setUriInfo(UriInfo uriInfo) {
+ this.uriInfo = uriInfo;
+ }
+
+ public DBRequest getDbRequest() {
+ return dbRequest;
+ }
+
+ public void setDbRequest(DBRequest dbRequest) {
+ this.dbRequest = dbRequest;
+ }
+
+ public HttpEntry getHttpEntry() {
+ return httpEntry;
+ }
+
+ public void setHttpEntry(HttpEntry httpEntry) {
+ this.httpEntry = httpEntry;
+ }
+}
diff --git a/aai-traversal/src/main/java/org/openecomp/aai/extensions/ExtensionController.java b/aai-traversal/src/main/java/org/openecomp/aai/extensions/ExtensionController.java
new file mode 100644
index 0000000..09cfe50
--- /dev/null
+++ b/aai-traversal/src/main/java/org/openecomp/aai/extensions/ExtensionController.java
@@ -0,0 +1,145 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * org.openecomp.aai
+ * ================================================================================
+ * Copyright (C) 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=========================================================
+ */
+
+package org.openecomp.aai.extensions;
+
+import java.lang.reflect.Method;
+
+import org.openecomp.aai.exceptions.AAIException;
+import org.openecomp.aai.util.AAIConfig;
+import com.att.eelf.configuration.EELFLogger;
+import com.att.eelf.configuration.EELFManager;
+
+public class ExtensionController {
+
+ private static final EELFLogger LOGGER = EELFManager.getInstance().getLogger(ExtensionController.class);
+
+ /**
+ * Run extension.
+ *
+ * @param apiVersion the api version
+ * @param namespace the namespace
+ * @param resourceName the resource name
+ * @param methodName the method name
+ * @param aaiExtMap the aai ext map
+ * @param isPreExtension the is pre extension
+ * @throws AAIException the AAI exception
+ */
+ public void runExtension(String apiVersion, String namespace,
+ String resourceName, String methodName, AAIExtensionMap aaiExtMap,
+ boolean isPreExtension) throws AAIException {
+ String extensionClassName = "org.openecomp.aai.extensions."
+ + apiVersion.toLowerCase() + "." + namespace + "."
+ + resourceName + "Extension";
+ String defaultErrorCallback = resourceName + "ExtensionErrorCallback";
+
+ String configOption = "aai.extensions." + apiVersion.toLowerCase()
+ + "." + namespace.toLowerCase() + "."
+ + resourceName.toLowerCase() + ".enabled";
+
+ try {
+
+ String extensionEnabled = AAIConfig.get(configOption, "true");
+ if (extensionEnabled.equalsIgnoreCase("false")) {
+ return;
+ }
+
+ Class<?> clazz = Class.forName(extensionClassName);
+
+ Method extension = clazz.getMethod(methodName,
+ new Class[] { AAIExtensionMap.class });
+ if (extension != null) {
+
+ Object ret = extension.invoke(clazz.newInstance(), aaiExtMap);
+
+ if (ret instanceof Integer) {
+ Exception e = null;
+
+ if (isPreExtension == true) {
+ e = aaiExtMap.getPreExtException();
+ } else {
+ e = aaiExtMap.getPostExtException();
+ }
+
+ boolean failOnError = true;
+ if (isPreExtension == true) {
+ failOnError = aaiExtMap.getPreExtFailOnError();
+ } else {
+ failOnError = aaiExtMap.getPostExtFailOnError();
+ }
+
+ if (e != null) {
+ boolean handleException = true;
+ if (isPreExtension == true) {
+ if (aaiExtMap.getPreExtSkipErrorCallback() == true) {
+ handleException = false;
+ }
+ } else {
+ if (aaiExtMap.getPostExtSkipErrorCallback() == true) {
+ handleException = false;
+ }
+ }
+ if (handleException == true) {
+ Method errorCallback = null;
+ if (isPreExtension == true) {
+ errorCallback = aaiExtMap
+ .getPreExtErrorCallback();
+ } else {
+ errorCallback = aaiExtMap
+ .getPostExtErrorCallback();
+ }
+
+ if (errorCallback != null) {
+ errorCallback.invoke(clazz.newInstance(),
+ aaiExtMap);
+ } else {
+ Method defaultErrorCallbackExtension = clazz
+ .getMethod(
+ defaultErrorCallback,
+ new Class[] { AAIExtensionMap.class });
+ defaultErrorCallbackExtension.invoke(
+ clazz.newInstance(), aaiExtMap);
+ }
+ }
+ }
+
+ if (failOnError == true && e != null) {
+ throw e;
+ } else if (failOnError == false && e != null) { // in this
+ // case, we
+ // just note
+ // the error
+ // without
+ // stopping
+ LOGGER.warn("Error while processing extension - " + aaiExtMap.getMessage());
+ }
+ }
+ }
+ } catch (ClassNotFoundException ex) {
+ LOGGER.debug("Extension class not found: " + extensionClassName + ", method: " + methodName + ".");
+ } catch (NoSuchMethodException e) {
+ LOGGER.debug("Method " + methodName + " does not exist for class " + extensionClassName);
+ } catch (AAIException e) {
+ throw e;
+ } catch (Exception e) {
+ throw new AAIException("AAI_5105", e);
+ }
+ }
+}
diff --git a/aai-traversal/src/main/java/org/openecomp/aai/interceptors/AAIHeaderProperties.java b/aai-traversal/src/main/java/org/openecomp/aai/interceptors/AAIHeaderProperties.java
new file mode 100644
index 0000000..4798d90
--- /dev/null
+++ b/aai-traversal/src/main/java/org/openecomp/aai/interceptors/AAIHeaderProperties.java
@@ -0,0 +1,26 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * org.openecomp.aai
+ * ================================================================================
+ * Copyright (C) 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=========================================================
+ */
+
+package org.openecomp.aai.interceptors;
+
+public class AAIHeaderProperties {
+
+ public static final String REQUEST_CONTEXT = "aai-request-context";
+}
diff --git a/aai-traversal/src/main/java/org/openecomp/aai/interceptors/AAILogJAXRSInInterceptor.java b/aai-traversal/src/main/java/org/openecomp/aai/interceptors/AAILogJAXRSInInterceptor.java
new file mode 100644
index 0000000..80127d0
--- /dev/null
+++ b/aai-traversal/src/main/java/org/openecomp/aai/interceptors/AAILogJAXRSInInterceptor.java
@@ -0,0 +1,283 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * org.openecomp.aai
+ * ================================================================================
+ * Copyright (C) 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=========================================================
+ */
+
+package org.openecomp.aai.interceptors;
+
+import java.io.InputStream;
+import java.text.DateFormat;
+import java.text.SimpleDateFormat;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Date;
+import java.util.List;
+import java.util.Map;
+import java.util.UUID;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import javax.ws.rs.core.MediaType;
+
+import org.apache.commons.io.IOUtils;
+import org.apache.cxf.helpers.CastUtils;
+import org.apache.cxf.interceptor.LoggingMessage;
+import org.apache.cxf.jaxrs.interceptor.JAXRSInInterceptor;
+import org.apache.cxf.message.Message;
+
+import org.openecomp.aai.exceptions.AAIException;
+import org.openecomp.aai.logging.ErrorLogHelper;
+import org.openecomp.aai.rest.util.EchoResponse;
+import org.openecomp.aai.util.AAIConfig;
+import org.openecomp.aai.util.AAIConstants;
+import org.openecomp.aai.util.HbaseSaltPrefixer;
+import com.att.eelf.configuration.EELFLogger;
+import com.att.eelf.configuration.EELFManager;
+
+public class AAILogJAXRSInInterceptor extends JAXRSInInterceptor {
+
+ protected final String COMPONENT = "aairest";
+ protected final String CAMEL_REQUEST ="CamelHttpUrl";
+ private static final Pattern uuidPattern = Pattern.compile("^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$");
+ private static final EELFLogger LOGGER = EELFManager.getInstance().getLogger(AAILogJAXRSInInterceptor.class);
+
+ /**
+ * {@inheritDoc}
+ */
+ public void handleMessage(Message message) {
+
+ boolean go = false;
+ String uri = null;
+ String query = null;
+ try {
+
+ uri = (String)message.get(CAMEL_REQUEST);
+ if (uri != null) {
+ query = (String)message.get(Message.QUERY_STRING);
+ }
+
+ if (AAIConfig.get(AAIConstants.AAI_LOGGING_HBASE_INTERCEPTOR).equalsIgnoreCase("true") &&
+ AAIConfig.get(AAIConstants.AAI_LOGGING_HBASE_ENABLED).equalsIgnoreCase("true")) {
+ go = true;
+ message.getExchange().put("AAI_LOGGING_HBASE_ENABLED", 1);
+ if (AAIConfig.get(AAIConstants.AAI_LOGGING_HBASE_LOGREQUEST).equalsIgnoreCase("true") ) {
+ message.getExchange().put("AAI_LOGGING_HBASE_LOGREQUEST", 1);
+ }
+ if (AAIConfig.get(AAIConstants.AAI_LOGGING_HBASE_LOGRESPONSE).equalsIgnoreCase("true") ) {
+ message.getExchange().put("AAI_LOGGING_HBASE_LOGRESPONSE", 1);
+ }
+ }
+ if (AAIConfig.get(AAIConstants.AAI_LOGGING_TRACE_ENABLED).equalsIgnoreCase("true") ) {
+ go = true;
+ message.getExchange().put("AAI_LOGGING_TRACE_ENABLED", 1);
+ if (AAIConfig.get(AAIConstants.AAI_LOGGING_TRACE_LOGREQUEST).equalsIgnoreCase("true") ) {
+ message.getExchange().put("AAI_LOGGING_TRACE_LOGREQUEST", 1);
+ }
+ if (AAIConfig.get(AAIConstants.AAI_LOGGING_TRACE_LOGRESPONSE).equalsIgnoreCase("true") ) {
+ message.getExchange().put("AAI_LOGGING_TRACE_LOGRESPONSE", 1);
+ }
+ }
+ } catch (AAIException e1) {
+ ErrorLogHelper.logException(e1);
+ }
+
+ if (uri.contains(EchoResponse.echoPath)) {
+ // if it's a health check, we don't want to log ANYTHING if it's a lightweight one
+ if (query == null) {
+ if (message.getExchange().containsKey("AAI_LOGGING_HBASE_ENABLED")) {
+ message.getExchange().remove("AAI_LOGGING_HBASE_ENABLED");
+ }
+ if (message.getExchange().containsKey("AAI_LOGGING_TRACE_ENABLED")) {
+ message.getExchange().remove("AAI_LOGGING_TRACE_ENABLED");
+ }
+ go = false;
+ }
+ }
+ else if (uri.contains("/translog/")) {
+ // if it's a translog query, we don't want to log the responses
+ if (message.getExchange().containsKey("AAI_LOGGING_HBASE_LOGRESPONSE")) {
+ message.getExchange().remove("AAI_LOGGING_HBASE_LOGRESPONSE");
+ }
+ if (message.getExchange().containsKey("AAI_LOGGING_TRACE_LOGRESPONSE")) {
+ message.getExchange().remove("AAI_LOGGING_TRACE_LOGRESPONSE");
+ }
+ }
+
+ if (go == false) { // there's nothing to do
+ return;
+ }
+
+ // DONE: get a TXID based on hostname, time (YYYYMMDDHHMMSSMILLIS, and LoggingMessage.nextId(); 20150326145301-1
+ String now = genDate();
+
+ message.getExchange().put("AAI_RQST_TM", now);
+
+ String id = (String)message.getExchange().get(LoggingMessage.ID_KEY);
+
+ String fullId = null;
+ try {
+ if (id == null) {
+ id = LoggingMessage.nextId();
+ }
+ fullId = AAIConfig.get(AAIConstants.AAI_NODENAME) + "-" + now + "-" + id;
+ fullId = HbaseSaltPrefixer.getInstance().prependSalt(fullId);
+ message.getExchange().put(LoggingMessage.ID_KEY, fullId);
+ } catch (AAIException e1) {
+ LOGGER.debug("config problem", e1);
+ }
+
+ if (fullId == null) {
+ fullId = now + "-" + id;
+ fullId = HbaseSaltPrefixer.getInstance().prependSalt(fullId);
+ }
+ message.put(LoggingMessage.ID_KEY, fullId);
+ final LoggingMessage buffer = new LoggingMessage("Message", fullId);
+
+ Integer responseCode = (Integer)message.get(Message.RESPONSE_CODE);
+ if (responseCode != null) {
+ buffer.getResponseCode().append(responseCode);
+ }
+
+ String encoding = (String)message.get(Message.ENCODING);
+
+ if (encoding != null) {
+ buffer.getEncoding().append(encoding);
+ }
+ String httpMethod = (String)message.get(Message.HTTP_REQUEST_METHOD);
+ if (httpMethod != null) {
+ buffer.getHttpMethod().append(httpMethod);
+ }
+
+ String ct = (String)message.get(Message.CONTENT_TYPE);
+ if (ct != null) {
+ if ("*/*".equals(ct)) {
+ message.put(Message.CONTENT_TYPE, MediaType.APPLICATION_JSON);
+ ct = MediaType.APPLICATION_JSON;
+ }
+ buffer.getContentType().append(ct);
+
+ }
+ Object headers = message.get(Message.PROTOCOL_HEADERS);
+ if (headers != null) {
+ buffer.getHeader().append(headers);
+
+ Map<String, List<String>> headersList = CastUtils.cast((Map<?, ?>)message.get(Message.PROTOCOL_HEADERS));
+ String transId = "";
+ List<String> xt = headersList.get("X-TransactionId");
+ String newTransId = transId;
+ boolean missingTransId = false;
+ boolean replacedTransId = false;
+ String logMsg = null;
+ if (xt != null) {
+ for (String transIdValue : xt) {
+ transId = transIdValue;
+ }
+ Matcher matcher = uuidPattern.matcher(transId);
+ if (!matcher.find()) {
+ replacedTransId = true;
+ // check if there's a colon, and check the first group?
+ if (transId.contains(":")) {
+ String[] uuidParts = transId.split(":");
+ Matcher matcher2 = uuidPattern.matcher(uuidParts[0]);
+ if (matcher2.find()) {
+ newTransId = uuidParts[0];
+ } else {
+ // punt, we tried to find it, it has a colon but no UUID-1
+ newTransId = UUID.randomUUID().toString();
+ }
+ } else {
+ newTransId = UUID.randomUUID().toString();
+ }
+ }
+ } else {
+ newTransId = UUID.randomUUID().toString();
+ missingTransId = true;
+ }
+
+ if (missingTransId || replacedTransId) {
+ List<String> txList = new ArrayList<String>();
+ txList.add(newTransId);
+ headersList.put("X-TransactionId", txList);
+ if (missingTransId) {
+ logMsg = "Missing requestID. Assigned " + newTransId;
+ } else if (replacedTransId) {
+ logMsg = "Replaced invalid requestID of " + transId + " Assigned " + newTransId;
+ }
+ }
+
+ List<String> contentType = headersList.get("Content-Type");
+ if (contentType == null) {
+ ct = (String)message.get(Message.CONTENT_TYPE);
+ headersList.put(Message.CONTENT_TYPE, Collections.singletonList(ct));
+ }
+
+ LOGGER.auditEvent("REST " + httpMethod + " " + ((query != null)? uri+"?"+query : uri) + " HbaseTxId=" + fullId);
+ LOGGER.info(logMsg);
+ }
+
+
+ if (uri != null) {
+ buffer.getAddress().append(uri);
+ if (query != null) {
+ buffer.getAddress().append("?").append(query);
+ }
+ }
+
+ InputStream is = message.getContent(InputStream.class);
+ if (is != null) {
+ try {
+ String currentPayload = IOUtils.toString(is, "UTF-8");
+ IOUtils.closeQuietly(is);
+ buffer.getPayload().append(currentPayload);
+ is = IOUtils.toInputStream(currentPayload, "UTF-8");
+ message.setContent(InputStream.class, is);
+ IOUtils.closeQuietly(is);
+ } catch (Exception e) {
+ // It's ok to not have request input content
+ // throw new Fault(e);
+ }
+ }
+
+ // this will be saved in the message exchange, and can be pulled out later...
+ message.getExchange().put(fullId + "_REQUEST", buffer.toString());
+ }
+
+ /**
+ * Gen date.
+ *
+ * @param aaiLogger the aai logger
+ * @param logline the logline
+ * @return the string
+ */
+ protected String genDate() {
+ Date date = new Date();
+ DateFormat formatter = null;
+ try {
+ formatter = new SimpleDateFormat(AAIConfig.get(AAIConstants.HBASE_TABLE_TIMESTAMP_FORMAT));
+ } catch (AAIException ex) {
+ ErrorLogHelper.logException(ex);
+ } finally {
+ if (formatter == null) {
+ formatter = new SimpleDateFormat("YYMMdd-HH:mm:ss:SSS");
+ }
+ }
+
+ return formatter.format(date);
+ }
+
+}
diff --git a/aai-traversal/src/main/java/org/openecomp/aai/interceptors/AAILogJAXRSOutInterceptor.java b/aai-traversal/src/main/java/org/openecomp/aai/interceptors/AAILogJAXRSOutInterceptor.java
new file mode 100644
index 0000000..0f5e457
--- /dev/null
+++ b/aai-traversal/src/main/java/org/openecomp/aai/interceptors/AAILogJAXRSOutInterceptor.java
@@ -0,0 +1,323 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * org.openecomp.aai
+ * ================================================================================
+ * Copyright (C) 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=========================================================
+ */
+
+package org.openecomp.aai.interceptors;
+
+import java.io.OutputStream;
+import java.text.DateFormat;
+import java.text.SimpleDateFormat;
+import java.util.Collections;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.cxf.helpers.CastUtils;
+import org.apache.cxf.interceptor.LoggingMessage;
+import org.apache.cxf.io.CacheAndWriteOutputStream;
+import org.apache.cxf.io.CachedOutputStream;
+import org.apache.cxf.io.CachedOutputStreamCallback;
+import org.apache.cxf.jaxrs.interceptor.JAXRSOutInterceptor;
+import org.apache.cxf.message.Message;
+
+import org.openecomp.aai.exceptions.AAIException;
+import org.openecomp.aai.logging.ErrorLogHelper;
+import org.openecomp.aai.util.AAIConfig;
+import org.openecomp.aai.util.AAIConstants;
+import com.att.eelf.configuration.EELFLogger;
+import com.att.eelf.configuration.EELFManager;
+
+// right after the request is complete, there may be content
+public class AAILogJAXRSOutInterceptor extends JAXRSOutInterceptor {
+
+ private static final EELFLogger LOGGER = EELFManager.getInstance().getLogger(AAILogJAXRSOutInterceptor.class);
+
+ protected final String COMPONENT = "aairest";
+ protected final String CAMEL_REQUEST = "CamelHttpUrl";
+
+ /**
+ * {@inheritDoc}
+ */
+ public void handleMessage(Message message) {
+
+ String fullId = (String) message.getExchange().get(LoggingMessage.ID_KEY);
+
+ Map<String, List<String>> headers = CastUtils.cast((Map<?, ?>) message.get(Message.PROTOCOL_HEADERS));
+ if (headers == null) {
+ headers = new HashMap<String, List<String>>();
+ }
+
+ headers.put("X-AAI-TXID", Collections.singletonList(fullId));
+ message.put(Message.PROTOCOL_HEADERS, headers);
+
+ Message outMessage = message.getExchange().getOutMessage();
+ final OutputStream os = outMessage.getContent(OutputStream.class);
+ if (os == null) {
+ return;
+ }
+
+ // we only want to register the callback if there is good reason for it.
+ if (message.getExchange().containsKey("AAI_LOGGING_HBASE_ENABLED") || message.getExchange().containsKey("AAI_LOGGING_TRACE_ENABLED")) {
+
+ final CacheAndWriteOutputStream newOut = new CacheAndWriteOutputStream(os);
+ message.setContent(OutputStream.class, newOut);
+ newOut.registerCallback(new LoggingCallback(message, os));
+ }
+
+ }
+
+ class LoggingCallback implements CachedOutputStreamCallback {
+
+ private final Message message;
+ private final OutputStream origStream;
+
+ public LoggingCallback(final Message msg, final OutputStream os) {
+ this.message = msg;
+ this.origStream = os;
+ }
+
+ public void onFlush(CachedOutputStream cos) {
+
+ }
+
+ public void onClose(CachedOutputStream cos) {
+
+ String getValue = "";
+ String postValue = "";
+ String logValue = "";
+
+ try {
+ logValue = AAIConfig.get("aai.transaction.logging");
+ getValue = AAIConfig.get("aai.transaction.logging.get");
+ postValue = AAIConfig.get("aai.transaction.logging.post");
+ } catch (AAIException e) {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ }
+
+ if (!message.getExchange().containsKey("AAI_LOGGING_HBASE_ENABLED") && !message.getExchange().containsKey("AAI_LOGGING_TRACE_ENABLED")) {
+ return;
+ }
+
+ String fullId = (String) message.getExchange().get(LoggingMessage.ID_KEY);
+
+ Message inMessage = message.getExchange().getInMessage();
+ String transId = null;
+ String fromAppId = null;
+
+ Map<String, List<String>> headersList = CastUtils.cast((Map<?, ?>) inMessage.get(Message.PROTOCOL_HEADERS));
+ if (headersList != null) {
+ List<String> xt = headersList.get("X-TransactionId");
+ if (xt != null) {
+ for (String transIdValue : xt) {
+ transId = transIdValue;
+ }
+ }
+ List<String> fa = headersList.get("X-FromAppId");
+ if (fa != null) {
+ for (String fromAppIdValue : fa) {
+
+ fromAppId = fromAppIdValue;
+ }
+ }
+ }
+
+ String httpMethod = (String) inMessage.get(Message.HTTP_REQUEST_METHOD);
+
+ String uri = (String) inMessage.get(CAMEL_REQUEST);
+ String fullUri = uri;
+ if (uri != null) {
+ String query = (String) message.get(Message.QUERY_STRING);
+ if (query != null) {
+ fullUri = uri + "?" + query;
+ }
+ }
+
+ String request = (String) message.getExchange().get(fullId + "_REQUEST");
+
+ Message outMessage = message.getExchange().getOutMessage();
+
+ final LoggingMessage buffer = new LoggingMessage("OUTMessage", fullId);
+
+ // should we check this, and make sure it's not an error?
+ Integer responseCode = (Integer) outMessage.get(Message.RESPONSE_CODE);
+ if (responseCode == null) {
+ responseCode = 200; // this should never happen, but just in
+ // case we don't get one
+ }
+ buffer.getResponseCode().append(responseCode);
+
+ String encoding = (String) outMessage.get(Message.ENCODING);
+
+ if (encoding != null) {
+ buffer.getEncoding().append(encoding);
+ }
+
+ String ct = (String) outMessage.get(Message.CONTENT_TYPE);
+ if (ct != null) {
+ buffer.getContentType().append(ct);
+ }
+
+ Object headers = outMessage.get(Message.PROTOCOL_HEADERS);
+ if (headers != null) {
+ buffer.getHeader().append(headers);
+ }
+
+ Boolean ss = false;
+ if (responseCode >= 200 && responseCode <= 299) {
+ ss = true;
+ }
+ String response = buffer.toString();
+
+ // this should have been set by the in interceptor
+ String rqstTm = (String) message.getExchange().get("AAI_RQST_TM");
+
+ // just in case it wasn't, we'll put this here. not great, but it'll
+ // have a val.
+ if (rqstTm == null) {
+ rqstTm = genDate();
+ }
+
+
+ String respTm = genDate();
+
+ try {
+ String actualRequest = request;
+ StringBuilder builder = new StringBuilder();
+ cos.writeCacheTo(builder, 100000);
+ // here comes my xml:
+ String payload = builder.toString();
+
+ String actualResponse = response;
+ if (payload == null) {
+
+ } else {
+ actualResponse = response + payload;
+ }
+
+ // we only log to AAI log if it's eanbled in the config props
+ // file
+ if (message.getExchange().containsKey("AAI_LOGGING_TRACE_ENABLED")) {
+
+ if (message.getExchange().containsKey("AAI_LOGGING_TRACE_LOGREQUEST")) {
+
+ // strip newlines from request
+ String traceRequest = actualRequest;
+ traceRequest = traceRequest.replace("\n", " ");
+ traceRequest = traceRequest.replace("\r", "");
+ traceRequest = traceRequest.replace("\t", "");
+ LOGGER.debug(traceRequest);
+ }
+ if (message.getExchange().containsKey("AAI_LOGGING_TRACE_LOGRESPONSE")) {
+ // strip newlines from response
+ String traceResponse = actualResponse;
+ traceResponse = traceResponse.replace("\n", " ");
+ traceResponse = traceResponse.replace("\r", "");
+ traceResponse = traceResponse.replace("\t", "");
+
+ LOGGER.debug(traceResponse);
+ }
+ }
+
+ // we only log to HBASE if it's enabled in the config props file
+ // TODO: pretty print XML/JSON. we might need to get the payload
+ // and envelope seperately
+ if (message.getExchange().containsKey("AAI_LOGGING_HBASE_ENABLED")) {
+ if (!message.getExchange().containsKey("AAI_LOGGING_HBASE_LOGREQUEST")) {
+ actualRequest = "loggingDisabled";
+ }
+ if (!message.getExchange().containsKey("AAI_LOGGING_HBASE_LOGRESPONSE")) {
+ actualResponse = "loggingDisabled";
+ }
+
+ LOGGER.debug("action={}, urlin={}, HbTransId={}", httpMethod, fullUri, fullId);
+
+ if (logValue.equals("false")) {
+ } else if (getValue.equals("false") && httpMethod.equals("GET")) {
+ } else if (postValue.equals("false") && httpMethod.equals("POST")) {
+ } else {
+ putTransaction(transId, responseCode.toString(), rqstTm, respTm, fromAppId + ":" + transId, fullUri, httpMethod, request, response, actualResponse);
+
+ }
+ }
+ } catch (Exception ex) {
+ // ignore
+ }
+
+ message.setContent(OutputStream.class, origStream);
+
+ LOGGER.auditEvent("HTTP Response Code: {}", responseCode.toString());
+ }
+
+ }
+
+ protected String genDate() {
+ Date date = new Date();
+ DateFormat formatter = null;
+ try {
+ formatter = new SimpleDateFormat(AAIConfig.get(AAIConstants.HBASE_TABLE_TIMESTAMP_FORMAT));
+ } catch (AAIException ex) {
+ ErrorLogHelper.logException(ex);
+ } finally {
+ if (formatter == null) {
+ formatter = new SimpleDateFormat("YYMMdd-HH:mm:ss:SSS");
+ }
+ }
+ return formatter.format(date);
+ }
+
+ public String putTransaction(String tid, String status, String rqstTm, String respTm, String srcId, String rsrcId, String rsrcType, String rqstBuf, String respBuf, String actualResponse) {
+ String tm = null;
+ String fromAppId = srcId.substring(0, srcId.indexOf(':'));
+ String transId = srcId.substring(srcId.indexOf(':') + 1);
+
+ if (tid == null || "".equals(tid)) {
+ Date date = new Date();
+ DateFormat formatter = null;
+ try {
+ formatter = new SimpleDateFormat(AAIConfig.get(AAIConstants.HBASE_TABLE_TIMESTAMP_FORMAT));
+ } catch (Exception e) {
+ formatter = new SimpleDateFormat("YYYYMMdd-HH:mm:ss:SSS");
+ }
+ tm = formatter.format(date);
+ tid = tm + "-";
+ }
+
+ String htid = tid;
+
+ if (rqstTm == null || "".equals(rqstTm)) {
+ rqstTm = tm;
+ }
+
+ if (respTm == null || "".equals(respTm)) {
+ respTm = tm;
+ }
+
+ try {
+ LOGGER.debug(" transactionId:" + tid + " status: " + status + " rqstDate: " + rqstTm + " respDate: " + respTm + " sourceId: " + srcId + " resourceId: "
+ + rsrcId + " resourceType: " + rsrcType + " payload rqstBuf: " + rqstBuf + " payload respBuf: " + respBuf + " Payload Error Messages: " + actualResponse);
+ return htid;
+ } catch (Exception e) {
+ ErrorLogHelper.logError("AAI_4000", "Exception updating HBase:");
+ return htid;
+ }
+
+ }
+}
diff --git a/aai-traversal/src/main/java/org/openecomp/aai/interceptors/PostAaiAjscInterceptor.java b/aai-traversal/src/main/java/org/openecomp/aai/interceptors/PostAaiAjscInterceptor.java
new file mode 100644
index 0000000..3a4f899
--- /dev/null
+++ b/aai-traversal/src/main/java/org/openecomp/aai/interceptors/PostAaiAjscInterceptor.java
@@ -0,0 +1,63 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * org.openecomp.aai
+ * ================================================================================
+ * Copyright (C) 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=========================================================
+ */
+
+package org.openecomp.aai.interceptors;
+
+import java.util.Map;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.openecomp.aai.logging.LoggingContext;
+import org.openecomp.aai.logging.LoggingContext.StatusCode;
+import com.att.eelf.configuration.EELFLogger;
+import com.att.eelf.configuration.EELFManager;
+
+import ajsc.beans.interceptors.AjscInterceptor;
+
+public class PostAaiAjscInterceptor implements AjscInterceptor {
+
+ private static final EELFLogger LOGGER = EELFManager.getInstance().getLogger(PostAaiAjscInterceptor.class);
+
+ private static class LazyAaiAjscInterceptor {
+ public static final PostAaiAjscInterceptor INSTANCE = new PostAaiAjscInterceptor();
+ }
+
+ public static PostAaiAjscInterceptor getInstance() {
+ return LazyAaiAjscInterceptor.INSTANCE;
+ }
+
+ @Override
+ public boolean allowOrReject(HttpServletRequest req, HttpServletResponse resp, Map<?, ?> paramMap)
+ throws Exception {
+ final String responseCode = LoggingContext.responseCode();
+
+ if (responseCode != null && responseCode.startsWith("ERR.")) {
+ LoggingContext.statusCode(StatusCode.ERROR);
+ LOGGER.error(req.getRequestURL() + " call failed with responseCode=" + responseCode);
+ } else {
+ LoggingContext.statusCode(StatusCode.COMPLETE);
+ LOGGER.info(req.getRequestURL() + " call succeeded");
+ }
+
+ LoggingContext.clear();
+ return true;
+ }
+}
diff --git a/aai-traversal/src/main/java/org/openecomp/aai/interceptors/PreAaiAjscInterceptor.java b/aai-traversal/src/main/java/org/openecomp/aai/interceptors/PreAaiAjscInterceptor.java
new file mode 100644
index 0000000..a2c56d0
--- /dev/null
+++ b/aai-traversal/src/main/java/org/openecomp/aai/interceptors/PreAaiAjscInterceptor.java
@@ -0,0 +1,54 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * org.openecomp.aai
+ * ================================================================================
+ * Copyright (C) 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=========================================================
+ */
+
+package org.openecomp.aai.interceptors;
+
+import java.util.Map;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.openecomp.aai.logging.LoggingContext;
+
+import ajsc.beans.interceptors.AjscInterceptor;
+
+public class PreAaiAjscInterceptor implements AjscInterceptor {
+
+ private static class LazyAaiAjscInterceptor {
+ public static final PreAaiAjscInterceptor INSTANCE = new PreAaiAjscInterceptor();
+ }
+
+ public static PreAaiAjscInterceptor getInstance() {
+ return LazyAaiAjscInterceptor.INSTANCE;
+ }
+
+ @Override
+ public boolean allowOrReject(HttpServletRequest req, HttpServletResponse resp, Map<?, ?> paramMap)
+ throws Exception {
+
+ LoggingContext.init();
+
+ LoggingContext.requestId(req.getHeader("X-TransactionId"));
+ LoggingContext.partnerName(req.getHeader("X-FromAppId"));
+ LoggingContext.serviceName(req.getMethod() + " " + req.getRequestURI().toString());
+
+ return true;
+ }
+}
diff --git a/aai-traversal/src/main/java/org/openecomp/aai/rest/ExceptionHandler.java b/aai-traversal/src/main/java/org/openecomp/aai/rest/ExceptionHandler.java
new file mode 100644
index 0000000..f1a6f47
--- /dev/null
+++ b/aai-traversal/src/main/java/org/openecomp/aai/rest/ExceptionHandler.java
@@ -0,0 +1,129 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * org.openecomp.aai
+ * ================================================================================
+ * Copyright (C) 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=========================================================
+ */
+
+package org.openecomp.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.openecomp.aai.exceptions.AAIException;
+import org.openecomp.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-traversal/src/main/java/org/openecomp/aai/rest/QueryConsumer.java b/aai-traversal/src/main/java/org/openecomp/aai/rest/QueryConsumer.java
new file mode 100644
index 0000000..af1d350
--- /dev/null
+++ b/aai-traversal/src/main/java/org/openecomp/aai/rest/QueryConsumer.java
@@ -0,0 +1,182 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * org.openecomp.aai
+ * ================================================================================
+ * Copyright (C) 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=========================================================
+ */
+
+package org.openecomp.aai.rest;
+
+import java.net.URI;
+import java.util.ArrayList;
+import java.util.LinkedHashSet;
+import java.util.List;
+import java.util.Set;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.ws.rs.Consumes;
+import javax.ws.rs.DefaultValue;
+import javax.ws.rs.Encoded;
+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.Response;
+import javax.ws.rs.core.Response.Status;
+import javax.ws.rs.core.UriInfo;
+
+import org.apache.tinkerpop.gremlin.structure.Vertex;
+
+import org.openecomp.aai.dbmap.DBConnectionType;
+import org.openecomp.aai.exceptions.AAIException;
+import org.openecomp.aai.introspection.ModelType;
+import org.openecomp.aai.introspection.Version;
+import org.openecomp.aai.parsers.query.QueryParser;
+import org.openecomp.aai.rest.db.HttpEntry;
+import org.openecomp.aai.rest.search.GenericQueryProcessor;
+import org.openecomp.aai.rest.search.QueryProcessorType;
+import org.openecomp.aai.restcore.HttpMethod;
+import org.openecomp.aai.restcore.RESTAPI;
+import org.openecomp.aai.restcore.util.URITools;
+import org.openecomp.aai.serialization.db.DBSerializer;
+import org.openecomp.aai.serialization.engines.QueryStyle;
+import org.openecomp.aai.serialization.engines.TransactionalGraphEngine;
+import org.openecomp.aai.serialization.queryformats.Format;
+import org.openecomp.aai.serialization.queryformats.FormatFactory;
+import org.openecomp.aai.serialization.queryformats.Formatter;
+import org.openecomp.aai.serialization.queryformats.SubGraphStyle;
+import com.google.gson.JsonElement;
+import com.google.gson.JsonObject;
+import com.google.gson.JsonParser;
+
+@Path("{version: v9|v1[0]}/query")
+public class QueryConsumer extends RESTAPI {
+
+ /** The introspector factory type. */
+ private ModelType introspectorFactoryType = ModelType.MOXY;
+
+ private QueryProcessorType processorType = QueryProcessorType.GREMLIN_SERVER;
+ /** The query style. */
+ private QueryStyle queryStyle = QueryStyle.TRAVERSAL;
+ @PUT
+ @Consumes({ MediaType.APPLICATION_JSON})
+ @Produces({ MediaType.APPLICATION_JSON})
+ public Response executeQuery(String content, @PathParam("version")String versionParam, @PathParam("uri") @Encoded String uri, @DefaultValue("graphson") @QueryParam("format") String queryFormat,@DefaultValue("no_op") @QueryParam("subgraph") String subgraph, @Context HttpHeaders headers, @Context UriInfo info, @Context HttpServletRequest req) {
+
+ String sourceOfTruth = headers.getRequestHeaders().getFirst("X-FromAppId");
+ String realTime = headers.getRequestHeaders().getFirst("Real-Time");
+ String queryProcessor = headers.getRequestHeaders().getFirst("QueryProcessor");
+ QueryProcessorType processorType = this.processorType;
+ Response response = null;
+ TransactionalGraphEngine dbEngine = null;
+ try {
+
+ Format format = Format.valueOf(queryFormat);
+ if (queryProcessor != null) {
+ processorType = QueryProcessorType.valueOf(queryProcessor);
+ }
+ SubGraphStyle subGraphStyle = SubGraphStyle.valueOf(subgraph);
+ JsonParser parser = new JsonParser();
+
+ JsonObject input = parser.parse(content).getAsJsonObject();
+
+ JsonElement startElement = input.get("start");
+ JsonElement queryElement = input.get("query");
+ JsonElement gremlinElement = input.get("gremlin");
+ List<URI> startURIs = new ArrayList<>();
+ String queryURI = "";
+ String gremlin = "";
+
+ Version version = Version.valueOf(versionParam);
+ DBConnectionType type = this.determineConnectionType(sourceOfTruth, realTime);
+ HttpEntry httpEntry = new HttpEntry(version, introspectorFactoryType, queryStyle, type);
+ dbEngine = httpEntry.getDbEngine();
+
+ if (startElement != null) {
+
+ if (startElement.isJsonArray()) {
+ for (JsonElement element : startElement.getAsJsonArray()) {
+ startURIs.add(new URI(element.getAsString()));
+ }
+ } else {
+ startURIs.add(new URI(startElement.getAsString()));
+ }
+ }
+
+ if (queryElement != null) {
+ queryURI = queryElement.getAsString();
+ }
+ if (gremlinElement != null) {
+ gremlin = gremlinElement.getAsString();
+ }
+ URI queryURIObj = new URI(queryURI);
+ GenericQueryProcessor processor = null;
+
+ if (!startURIs.isEmpty()) {
+ Set<Vertex> vertexSet = new LinkedHashSet<>();
+ QueryParser uriQuery;
+ List<Vertex> vertices;
+ for (URI startUri : startURIs) {
+ uriQuery = dbEngine.getQueryBuilder().createQueryFromURI(startUri, URITools.getQueryMap(startUri));
+ vertices = uriQuery.getQueryBuilder().toList();
+ vertexSet.addAll(vertices);
+ }
+
+ processor = new GenericQueryProcessor.Builder(dbEngine)
+ .startFrom(vertexSet).queryFrom(queryURIObj)
+ .processWith(processorType).create();
+ } else if (!queryURI.equals("")){
+ processor = new GenericQueryProcessor.Builder(dbEngine)
+ .queryFrom(queryURIObj)
+ .processWith(processorType).create();
+ } else {
+ processor = new GenericQueryProcessor.Builder(dbEngine)
+ .queryFrom(gremlin)
+ .processWith(processorType).create();
+ }
+ String result = "";
+ List<Object> vertices = processor.execute(subGraphStyle);
+ DBSerializer serializer = new DBSerializer(version, dbEngine, introspectorFactoryType, sourceOfTruth);
+ FormatFactory ff = new FormatFactory(httpEntry.getLoader(), serializer);
+
+ Formatter formater = ff.get(format);
+
+ result = formater.output(vertices).toString();
+
+ response = Response.status(Status.OK)
+ .type(MediaType.APPLICATION_JSON)
+ .entity(result).build();
+
+ } 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) {
+ dbEngine.rollback();
+ }
+ }
+
+ return response;
+ }
+
+}
diff --git a/aai-traversal/src/main/java/org/openecomp/aai/rest/db/DBRequest.java b/aai-traversal/src/main/java/org/openecomp/aai/rest/db/DBRequest.java
new file mode 100644
index 0000000..e7b6858
--- /dev/null
+++ b/aai-traversal/src/main/java/org/openecomp/aai/rest/db/DBRequest.java
@@ -0,0 +1,251 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * org.openecomp.aai
+ * ================================================================================
+ * Copyright (C) 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=========================================================
+ */
+
+package org.openecomp.aai.rest.db;
+
+import java.net.URI;
+import java.util.Optional;
+
+import javax.ws.rs.core.HttpHeaders;
+import javax.ws.rs.core.UriInfo;
+
+import org.openecomp.aai.introspection.Introspector;
+import org.openecomp.aai.introspection.MarshallerProperties;
+import org.openecomp.aai.parsers.query.QueryParser;
+import org.openecomp.aai.restcore.HttpMethod;
+
+/**
+ * The Class DBRequest.
+ */
+public class DBRequest {
+
+ private final QueryParser parser;
+
+ private final Introspector introspector;
+
+ private final HttpHeaders headers;
+
+ private final String transactionId;
+
+ private final UriInfo info;
+
+ private final HttpMethod method;
+
+ private final URI uri;
+
+ private final Optional<String> rawRequestContent;
+
+ private final Optional<MarshallerProperties> marshallerProperties;
+
+
+ /**
+ * Instantiates a new DB request.
+ *
+ * @param method the method
+ * @param uri the uri
+ * @param parser the parser
+ * @param obj the obj
+ * @param headers the headers
+ * @param info the info
+ * @param transactionId the transaction id
+ */
+ private DBRequest(Builder builder) {
+ this.method = builder.getMethod();
+ this.parser = builder.getParser();
+ this.introspector = builder.getIntrospector();
+ this.headers = builder.getHeaders();
+ this.transactionId = builder.getTransactionId();
+ this.info = builder.getInfo();
+ this.uri = builder.getUri();
+ this.marshallerProperties = builder.getMarshallerProperties();
+ this.rawRequestContent = builder.getRawRequestContent();
+ }
+
+ /**
+ * Gets the headers.
+ *
+ * @return the headers
+ */
+ public HttpHeaders getHeaders() {
+ return headers;
+ }
+
+
+ /**
+ * Gets the transaction id.
+ *
+ * @return the transaction id
+ */
+ public String getTransactionId() {
+ return transactionId;
+ }
+
+ /**
+ * Gets the info.
+ *
+ * @return the info
+ */
+ public UriInfo getInfo() {
+ return info;
+ }
+
+ /**
+ * Gets the parser.
+ *
+ * @return the parser
+ */
+ public QueryParser getParser() {
+ return parser;
+ }
+
+ /**
+ * Gets the introspector.
+ *
+ * @return the introspector
+ */
+ public Introspector getIntrospector() {
+ return introspector;
+ }
+
+ /**
+ * Gets the method.
+ *
+ * @return the method
+ */
+ public HttpMethod getMethod() {
+ return method;
+ }
+
+ /**
+ * Gets the uri.
+ *
+ * @return the uri
+ */
+ public URI getUri() {
+ return uri;
+ }
+
+ /**
+ * Gets the raw content.
+ *
+ * @return the raw content
+ */
+ public Optional<String> getRawRequestContent() {
+ return rawRequestContent;
+ }
+
+ public Optional<MarshallerProperties> getMarshallerProperties() {
+ return marshallerProperties;
+ }
+
+
+
+ public static class Builder {
+
+ private QueryParser parser = null;
+
+ private Introspector introspector = null;
+
+ private HttpHeaders headers = null;
+
+ private String transactionId = null;
+
+ private UriInfo info = null;
+
+ private HttpMethod method = null;
+
+ private URI uri = null;
+
+ private Optional<MarshallerProperties> marshallerProperties = Optional.empty();
+
+ private Optional<String> rawRequestContent = Optional.empty();
+ /**
+ * Instantiates a new DB request.
+ *
+ * @param method the method
+ * @param uri the uri
+ * @param parser the parser
+ * @param obj the obj
+ * @param headers the headers
+ * @param info the info
+ * @param transactionId the transaction id
+ */
+ public Builder(HttpMethod method, URI uri, QueryParser parser, Introspector obj, HttpHeaders headers, UriInfo info, String transactionId) {
+ this.method = method;
+ this.parser = parser;
+ this.introspector = obj;
+ this.headers = headers;
+ this.transactionId = transactionId;
+ this.info = info;
+ this.uri = uri;
+
+ }
+
+ public QueryParser getParser() {
+ return parser;
+ }
+
+ public Introspector getIntrospector() {
+ return introspector;
+ }
+
+ public HttpHeaders getHeaders() {
+ return headers;
+ }
+
+ public String getTransactionId() {
+ return transactionId;
+ }
+
+ public UriInfo getInfo() {
+ return info;
+ }
+
+ public HttpMethod getMethod() {
+ return method;
+ }
+
+ public URI getUri() {
+ return uri;
+ }
+
+ public Builder customMarshaller(MarshallerProperties properties) {
+ this.marshallerProperties = Optional.of(properties);
+ return this;
+ }
+
+ public Builder rawRequestContent(String content) {
+ this.rawRequestContent = Optional.of(content);
+ return this;
+ }
+ protected Optional<MarshallerProperties> getMarshallerProperties() {
+ return marshallerProperties;
+ }
+ protected Optional<String> getRawRequestContent() {
+ return rawRequestContent;
+ }
+ public DBRequest build() {
+
+ return new DBRequest(this);
+ }
+
+
+ }
+}
diff --git a/aai-traversal/src/main/java/org/openecomp/aai/rest/db/HttpEntry.java b/aai-traversal/src/main/java/org/openecomp/aai/rest/db/HttpEntry.java
new file mode 100644
index 0000000..60438de
--- /dev/null
+++ b/aai-traversal/src/main/java/org/openecomp/aai/rest/db/HttpEntry.java
@@ -0,0 +1,672 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * org.openecomp.aai
+ * ================================================================================
+ * Copyright (C) 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=========================================================
+ */
+
+package org.openecomp.aai.rest.db;
+
+import java.io.IOException;
+import java.io.UnsupportedEncodingException;
+import java.lang.reflect.InvocationTargetException;
+import java.net.MalformedURLException;
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Set;
+
+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.UriBuilder;
+
+import org.apache.commons.lang.StringUtils;
+import org.apache.tinkerpop.gremlin.structure.Vertex;
+import org.javatuples.Pair;
+
+import org.openecomp.aai.db.props.AAIProperties;
+import org.openecomp.aai.dbmap.DBConnectionType;
+import org.openecomp.aai.domain.responseMessage.AAIResponseMessage;
+import org.openecomp.aai.domain.responseMessage.AAIResponseMessageDatum;
+import org.openecomp.aai.exceptions.AAIException;
+import org.openecomp.aai.extensions.AAIExtensionMap;
+import org.openecomp.aai.extensions.ExtensionController;
+import org.openecomp.aai.introspection.Introspector;
+import org.openecomp.aai.introspection.Loader;
+import org.openecomp.aai.introspection.LoaderFactory;
+import org.openecomp.aai.introspection.MarshallerProperties;
+import org.openecomp.aai.introspection.ModelInjestor;
+import org.openecomp.aai.introspection.ModelType;
+import org.openecomp.aai.introspection.Version;
+import org.openecomp.aai.introspection.exceptions.AAIUnknownObjectException;
+import org.openecomp.aai.logging.ErrorLogHelper;
+import org.openecomp.aai.parsers.query.QueryParser;
+import org.openecomp.aai.parsers.uri.URIToExtensionInformation;
+import org.openecomp.aai.rest.ueb.UEBNotification;
+import org.openecomp.aai.restcore.HttpMethod;
+import org.openecomp.aai.schema.enums.ObjectMetadata;
+import org.openecomp.aai.serialization.db.DBSerializer;
+import org.openecomp.aai.serialization.engines.QueryStyle;
+import org.openecomp.aai.serialization.engines.TitanDBEngine;
+import org.openecomp.aai.serialization.engines.TransactionalGraphEngine;
+import org.openecomp.aai.serialization.engines.query.QueryEngine;
+import com.att.eelf.configuration.EELFLogger;
+import com.att.eelf.configuration.EELFManager;
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.github.fge.jsonpatch.JsonPatchException;
+import com.github.fge.jsonpatch.mergepatch.JsonMergePatch;
+import com.thinkaurelius.titan.core.TitanException;
+import com.thinkaurelius.titan.core.TitanTransaction;
+
+/**
+ * The Class HttpEntry.
+ */
+public class HttpEntry {
+
+ private static final EELFLogger LOGGER = EELFManager.getInstance().getLogger(HttpEntry.class);
+
+ private final ModelType introspectorFactoryType;
+
+ private final QueryStyle queryStyle;
+
+ private final Version version;
+
+ private final Loader loader;
+
+ private final TransactionalGraphEngine dbEngine;
+
+ private boolean processSingle = true;
+
+ /**
+ * Instantiates a new http entry.
+ *
+ * @param version the version
+ * @param modelType the model type
+ * @param queryStyle the query style
+ * @param llBuilder the ll builder
+ */
+ public HttpEntry(Version version, ModelType modelType, QueryStyle queryStyle, DBConnectionType connectionType) {
+ this.introspectorFactoryType = modelType;
+ this.queryStyle = queryStyle;
+ this.version = version;
+ this.loader = LoaderFactory.createLoaderForVersion(introspectorFactoryType, version);
+ this.dbEngine = new TitanDBEngine(
+ queryStyle,
+ connectionType,
+ loader);
+ //start transaction on creation
+ dbEngine.startTransaction();
+
+ }
+
+ /**
+ * Gets the introspector factory type.
+ *
+ * @return the introspector factory type
+ */
+ public ModelType getIntrospectorFactoryType() {
+ return introspectorFactoryType;
+ }
+
+ /**
+ * Gets the query style.
+ *
+ * @return the query style
+ */
+ public QueryStyle getQueryStyle() {
+ return queryStyle;
+ }
+
+ /**
+ * Gets the version.
+ *
+ * @return the version
+ */
+ public Version getVersion() {
+ return version;
+ }
+
+ /**
+ * Gets the loader.
+ *
+ * @return the loader
+ */
+ public Loader getLoader() {
+ return loader;
+ }
+
+ /**
+ * Gets the db engine.
+ *
+ * @return the db engine
+ */
+ public TransactionalGraphEngine getDbEngine() {
+ return dbEngine;
+ }
+
+ public Pair<Boolean, List<Pair<URI, Response>>> process (List<DBRequest> requests, String sourceOfTruth) throws AAIException {
+ return this.process(requests, sourceOfTruth, true);
+ }
+ /**
+ * Process.
+ * @param requests the requests
+ * @param sourceOfTruth the source of truth
+ *
+ * @return the pair
+ * @throws AAIException the AAI exception
+ */
+ public Pair<Boolean, List<Pair<URI, Response>>> process (List<DBRequest> requests, String sourceOfTruth, boolean enableResourceVersion) throws AAIException {
+ DBSerializer serializer = new DBSerializer(version, dbEngine, introspectorFactoryType, sourceOfTruth);
+ Response response = null;
+ Status status = Status.NOT_FOUND;
+ Introspector obj = null;
+ QueryParser query = null;
+ URI uri = null;
+ String transactionId = null;
+ UEBNotification notification = new UEBNotification(loader);
+ int depth = AAIProperties.MAXIMUM_DEPTH;
+ List<Pair<URI,Response>> responses = new ArrayList<>();
+ MultivaluedMap<String, String> params = null;
+ HttpMethod method = null;
+ String uriTemp = "";
+ Boolean success = true;
+ QueryEngine queryEngine = dbEngine.getQueryEngine();
+ int maxRetries = 10;
+ int retry = 0;
+ for (DBRequest request : requests) {
+ try {
+ for (retry = 0; retry < maxRetries; ++retry) {
+ try {
+ method = request.getMethod();
+ obj = request.getIntrospector();
+ query = request.getParser();
+ transactionId = request.getTransactionId();
+ uriTemp = request.getUri().getRawPath().replaceFirst("^v\\d+/", "");
+ uri = UriBuilder.fromPath(uriTemp).build();
+ List<Vertex> vertices = query.getQueryBuilder().toList();
+ boolean isNewVertex = false;
+ String outputMediaType = getMediaType(request.getHeaders().getAcceptableMediaTypes());
+ String result = null;
+ params = request.getInfo().getQueryParameters(false);
+ depth = setDepth(obj, params.getFirst("depth"));
+ String cleanUp = params.getFirst("cleanup");
+ String requestContext = "";
+ List<String> requestContextList = request.getHeaders().getRequestHeader("aai-request-context");
+ if (requestContextList != null) {
+ requestContext = requestContextList.get(0);
+ }
+
+ if (cleanUp == null) {
+ cleanUp = "false";
+ }
+ if (vertices.size() > 1 && processSingle && !method.equals(HttpMethod.GET)) {
+ if (method.equals(HttpMethod.DELETE)) {
+ throw new AAIException("AAI_6138");
+ } else {
+ throw new AAIException("AAI_6137");
+ }
+ }
+ if (method.equals(HttpMethod.PUT)) {
+ String resourceVersion = (String)obj.getValue("resource-version");
+ if (vertices.size() == 1) {
+ if (enableResourceVersion) {
+ serializer.verifyResourceVersion("update", query.getResultType(), (String)vertices.get(0).<String>property("resource-version").orElse(null), resourceVersion, obj.getURI());
+ }
+ isNewVertex = false;
+ } else {
+ if (enableResourceVersion) {
+ serializer.verifyResourceVersion("create", query.getResultType(), "", resourceVersion, obj.getURI());
+ }
+ isNewVertex = true;
+ }
+ } else {
+ if (vertices.size() == 0) {
+ String msg = createNotFoundMessage(query.getResultType(), request.getUri());
+ throw new AAIException("AAI_6114", msg);
+ } else {
+ isNewVertex = false;
+ }
+ }
+ Vertex v = null;
+ if (!isNewVertex) {
+ v = vertices.get(0);
+ }
+ HashMap<String, Introspector> relatedObjects = new HashMap<>();
+ switch (method) {
+ case GET:
+ String nodeOnly = params.getFirst("nodes-only");
+ boolean isNodeOnly = nodeOnly != null;
+
+ obj = this.getObjectFromDb(vertices, serializer, query, obj, request.getUri(), depth, isNodeOnly, cleanUp);
+ if (obj != null) {
+ status = Status.OK;
+ MarshallerProperties properties;
+ if (!request.getMarshallerProperties().isPresent()) {
+ properties =
+ new MarshallerProperties.Builder(org.openecomp.aai.restcore.MediaType.getEnum(outputMediaType)).build();
+ } else {
+ properties = request.getMarshallerProperties().get();
+ }
+ result = obj.marshal(properties);
+ }
+
+ break;
+ case PUT:
+ response = this.invokeExtension(dbEngine, this.dbEngine.tx(), method, request, sourceOfTruth, version, loader, obj, uri, true);
+ if (isNewVertex) {
+ v = serializer.createNewVertex(obj);
+ } else {
+ serializer.touchStandardVertexProperties(v, false);
+ }
+ serializer.serializeToDb(obj, v, query, uri.getRawPath(), requestContext);
+ this.invokeExtension(dbEngine, this.dbEngine.tx(), HttpMethod.PUT, request, sourceOfTruth, version, loader, obj, uri, false);
+ status = Status.OK;
+ if (isNewVertex) {
+ status = Status.CREATED;
+ }
+ obj = serializer.getLatestVersionView(v);
+ if (query.isDependent()) {
+ relatedObjects = this.getRelatedObjects(serializer, queryEngine, v);
+ }
+ notification.createNotificationEvent(transactionId, sourceOfTruth, status, uri, obj, relatedObjects);
+
+ break;
+ case PUT_EDGE:
+ serializer.touchStandardVertexProperties(v, false);
+ serializer.createEdge(obj, v);
+ status = Status.OK;
+ break;
+ case MERGE_PATCH:
+ Introspector existingObj = (Introspector) obj.clone();
+ existingObj = this.getObjectFromDb(vertices, serializer, query, existingObj, request.getUri(), 0, false, cleanUp);
+ String existingJson = existingObj.marshal(false);
+ String newJson;
+
+ if (request.getRawRequestContent().isPresent()) {
+ newJson = request.getRawRequestContent().get();
+ } else {
+ newJson = "";
+ }
+ Object relationshipList = request.getIntrospector().getValue("relationship-list");
+ ObjectMapper mapper = new ObjectMapper();
+ try {
+ JsonNode existingNode = mapper.readTree(existingJson);
+ JsonNode newNode = mapper.readTree(newJson);
+ JsonMergePatch patch = JsonMergePatch.fromJson(newNode);
+ JsonNode completed = patch.apply(existingNode);
+ String patched = mapper.writeValueAsString(completed);
+ Introspector patchedObj = loader.unmarshal(existingObj.getName(), patched);
+ if (relationshipList == null) {
+ //if the caller didn't touch the relationship-list, we shouldn't either
+ patchedObj.setValue("relationship-list", null);
+ }
+ serializer.touchStandardVertexProperties(v, false);
+ serializer.serializeToDb(patchedObj, v, query, uri.getRawPath(), requestContext);
+ status = Status.OK;
+ patchedObj = serializer.getLatestVersionView(v);
+ if (query.isDependent()) {
+ relatedObjects = this.getRelatedObjects(serializer, queryEngine, v);
+ }
+ notification.createNotificationEvent(transactionId, sourceOfTruth, status, uri, patchedObj, relatedObjects);
+ } catch (IOException | JsonPatchException e) {
+ throw new AAIException("AAI_3000", "could not perform patch operation");
+ }
+ break;
+ case DELETE:
+ String resourceVersion = params.getFirst("resource-version");
+ obj = serializer.getLatestVersionView(v);
+ if (query.isDependent()) {
+ relatedObjects = this.getRelatedObjects(serializer, queryEngine, v);
+ }
+ this.invokeExtension(dbEngine, this.dbEngine.tx(), method, request, sourceOfTruth, version, loader, obj, uri, true);
+ serializer.delete(v, resourceVersion, enableResourceVersion);
+ this.invokeExtension(dbEngine, this.dbEngine.tx(), method, request, sourceOfTruth, version, loader, obj, uri, false);
+ status = Status.NO_CONTENT;
+ notification.createNotificationEvent(transactionId, sourceOfTruth, status, uri, obj, relatedObjects);
+ break;
+ case DELETE_EDGE:
+ serializer.touchStandardVertexProperties(v, false);
+ serializer.deleteEdge(obj, v);
+ status = Status.NO_CONTENT;
+ break;
+ default:
+ break;
+ }
+
+
+ /* temporarily adding vertex id to the headers
+ * to be able to use for testing the vertex id endpoint functionality
+ * since we presently have no other way of generating those id urls
+ */
+ if (response == null && v != null && (
+ method.equals(HttpMethod.PUT)
+ || method.equals(HttpMethod.GET)
+ || method.equals(HttpMethod.MERGE_PATCH))
+ ) {
+ String myvertid = v.id().toString();
+ response = Response.status(status)
+ .header("vertex-id", myvertid)
+ .entity(result)
+ .type(outputMediaType).build();
+ } else if (response == null) {
+ response = Response.status(status)
+ .type(outputMediaType).build();
+ } else {
+ //response already set to something
+ }
+ Pair<URI,Response> pairedResp = Pair.with(request.getUri(), response);
+ responses.add(pairedResp);
+ //break out of retry loop
+ break;
+ } catch (TitanException e) {
+ this.dbEngine.rollback();
+ AAIException ex = new AAIException("AAI_6142", e);
+ ErrorLogHelper.logException(ex);
+ Thread.sleep((retry + 1) * 20);
+ this.dbEngine.startTransaction();
+ queryEngine = dbEngine.getQueryEngine();
+ serializer = new DBSerializer(version, dbEngine, introspectorFactoryType, sourceOfTruth);
+ }
+
+ if (retry == maxRetries) {
+ throw new AAIException("AAI_6134");
+ }
+ }
+ } catch (AAIException e) {
+ success = false;
+ ArrayList<String> templateVars = new ArrayList<String>();
+ templateVars.add(request.getMethod().toString()); //GET, PUT, etc
+ templateVars.add(request.getUri().getPath().toString());
+ templateVars.addAll(e.getTemplateVars());
+
+ response = Response
+ .status(e.getErrorObject().getHTTPResponseCode())
+ .entity(ErrorLogHelper.getRESTAPIErrorResponse(request.getHeaders().getAcceptableMediaTypes(), e, templateVars))
+ .build();
+ Pair<URI,Response> pairedResp = Pair.with(request.getUri(), response);
+ responses.add(pairedResp);
+ continue;
+ } catch (Exception e) {
+ success = false;
+ e.printStackTrace();
+ AAIException ex = new AAIException("AAI_4000", e);
+ ArrayList<String> templateVars = new ArrayList<String>();
+ templateVars.add(request.getMethod().toString()); //GET, PUT, etc
+ templateVars.add(request.getUri().getPath().toString());
+
+ response = Response
+ .status(ex.getErrorObject().getHTTPResponseCode())
+ .entity(ErrorLogHelper.getRESTAPIErrorResponse(request.getHeaders().getAcceptableMediaTypes(), ex, templateVars))
+ .build();
+ Pair<URI, Response> pairedResp = Pair.with(request.getUri(), response);
+ responses.add(pairedResp);
+ continue;
+ }
+ }
+
+ notification.triggerEvents();
+ Pair<Boolean, List<Pair<URI, Response>>> tuple = Pair.with(success, responses);
+ return tuple;
+ }
+
+ /**
+ * Gets the media type.
+ *
+ * @param mediaTypeList the media type list
+ * @return the media type
+ */
+ private String getMediaType(List <MediaType> mediaTypeList) {
+ String mediaType = MediaType.APPLICATION_JSON; // json is the default
+ for (MediaType mt : mediaTypeList) {
+ if (MediaType.APPLICATION_XML_TYPE.isCompatible(mt)) {
+ mediaType = MediaType.APPLICATION_XML;
+ }
+ }
+ return mediaType;
+ }
+
+ /**
+ * Gets the object from db.
+ *
+ * @param serializer the serializer
+ * @param g the g
+ * @param query the query
+ * @param obj the obj
+ * @param uri the uri
+ * @param depth the depth
+ * @param cleanUp the clean up
+ * @return the object from db
+ * @throws AAIException the AAI exception
+ * @throws IllegalAccessException the illegal access exception
+ * @throws IllegalArgumentException the illegal argument exception
+ * @throws InvocationTargetException the invocation target exception
+ * @throws SecurityException the security exception
+ * @throws InstantiationException the instantiation exception
+ * @throws NoSuchMethodException the no such method exception
+ * @throws UnsupportedEncodingException the unsupported encoding exception
+ * @throws MalformedURLException the malformed URL exception
+ * @throws AAIUnknownObjectException
+ * @throws URISyntaxException
+ */
+ private Introspector getObjectFromDb(List<Vertex> results, DBSerializer serializer, QueryParser query, Introspector obj, URI uri, int depth, boolean nodeOnly, String cleanUp) throws AAIException, IllegalAccessException, IllegalArgumentException, InvocationTargetException, SecurityException, InstantiationException, NoSuchMethodException, UnsupportedEncodingException, AAIUnknownObjectException, URISyntaxException {
+
+ //nothing found
+ if (results.size() == 0) {
+ String msg = createNotFoundMessage(query.getResultType(), uri);
+ throw new AAIException("AAI_6114", msg);
+ }
+
+ obj = serializer.dbToObject(results, obj, depth, nodeOnly, cleanUp);
+
+ return obj;
+ }
+
+ /**
+ * Invoke extension.
+ *
+ * @param dbEngine the db engine
+ * @param g the g
+ * @param httpMethod the http method
+ * @param transId the trans id
+ * @param fromAppId the from app id
+ * @param apiVersion the api version
+ * @param loader the loader
+ * @param obj the obj
+ * @param uri the uri
+ * @param headers the headers
+ * @param isPreprocess the is preprocess
+ * @return the response
+ * @throws IllegalArgumentException the illegal argument exception
+ * @throws UnsupportedEncodingException the unsupported encoding exception
+ * @throws AAIException the AAI exception
+ */
+ private Response invokeExtension(TransactionalGraphEngine dbEngine, TitanTransaction g, HttpMethod httpMethod, DBRequest request, String fromAppId, Version apiVersion, Loader loader, Introspector obj, URI uri, boolean isPreprocess) throws IllegalArgumentException, UnsupportedEncodingException, AAIException {
+ AAIExtensionMap aaiExtMap = new AAIExtensionMap();
+ ModelInjestor injestor = ModelInjestor.getInstance();
+ Response response = null;
+ URIToExtensionInformation extensionInformation = new URIToExtensionInformation(loader, uri);
+ aaiExtMap.setHttpEntry(this);
+ aaiExtMap.setDbRequest(request);
+ aaiExtMap.setTransId(request.getTransactionId());
+ aaiExtMap.setFromAppId(fromAppId);
+ aaiExtMap.setGraph(g);
+ aaiExtMap.setApiVersion(apiVersion.toString());
+ aaiExtMap.setObjectFromRequest(obj);
+ aaiExtMap.setObjectFromRequestType(obj.getJavaClassName());
+ aaiExtMap.setObjectFromResponse(obj);
+ aaiExtMap.setObjectFromResponseType(obj.getJavaClassName());
+ aaiExtMap.setJaxbContext(injestor.getContextForVersion(apiVersion));
+ aaiExtMap.setUri(uri.getRawPath());
+ aaiExtMap.setTransactionalGraphEngine(dbEngine);
+ aaiExtMap.setLoader(loader);
+ aaiExtMap.setNamespace(extensionInformation.getNamespace());
+
+ ExtensionController ext = new ExtensionController();
+ ext.runExtension(aaiExtMap.getApiVersion(),
+ extensionInformation.getNamespace(),
+ extensionInformation.getTopObject(),
+ extensionInformation.getMethodName(httpMethod, isPreprocess),
+ aaiExtMap,
+ isPreprocess);
+
+ if (aaiExtMap.getPrecheckAddedList().size() > 0) {
+ response = notifyOnSkeletonCreation(aaiExtMap, obj, request.getHeaders());
+ }
+
+ return response;
+ }
+
+ /**
+ * Notify on skeleton creation.
+ *
+ * @param aaiExtMap the aai ext map
+ * @param input the input
+ * @param headers the headers
+ * @return the response
+ */
+ //Legacy support
+ private Response notifyOnSkeletonCreation(AAIExtensionMap aaiExtMap, Introspector input, HttpHeaders headers) {
+ Response response = null;
+ HashMap<AAIException, ArrayList<String>> exceptionList = new HashMap<AAIException, ArrayList<String>>();
+
+ String keyString = "";
+
+ Set<String> resourceKeys = input.getKeys();
+ for (String key : resourceKeys) {
+ keyString += key + "=" + input.getValue(key) + " ";
+ }
+
+ for (AAIResponseMessage msg : aaiExtMap.getPrecheckResponseMessages().getAAIResponseMessage()) {
+ ArrayList<String> templateVars = new ArrayList<String>();
+
+ templateVars.add("PUT " + input.getDbName());
+ templateVars.add(keyString);
+ List<String> keys = new ArrayList<String>();
+ templateVars.add(msg.getAaiResponseMessageResourceType());
+ for (AAIResponseMessageDatum dat : msg.getAaiResponseMessageData().getAAIResponseMessageDatum()) {
+ keys.add(dat.getAaiResponseMessageDatumKey() + "=" + dat.getAaiResponseMessageDatumValue());
+ }
+ templateVars.add(StringUtils.join(keys, ", "));
+ exceptionList.put(new AAIException("AAI_0004", msg.getAaiResponseMessageResourceType()),
+ templateVars);
+ }
+ response = Response
+ .status(Status.ACCEPTED).entity(ErrorLogHelper
+ .getRESTAPIInfoResponse(headers.getAcceptableMediaTypes(), exceptionList))
+ .build();
+
+ return response;
+ }
+
+ /**
+ * Creates the not found message.
+ *
+ * @param resultType the result type
+ * @param uri the uri
+ * @return the string
+ */
+ private String createNotFoundMessage(String resultType, URI uri) {
+
+ String msg = "No Node of type " + resultType + " found at: " + uri.getPath();
+
+ return msg;
+ }
+
+ /**
+ * Sets the depth.
+ *
+ * @param depthParam the depth param
+ * @return the int
+ * @throws AAIException the AAI exception
+ */
+ protected int setDepth(Introspector obj, String depthParam) throws AAIException {
+ int depth = AAIProperties.MAXIMUM_DEPTH;
+
+ if(depthParam == null){
+ if(this.version.compareTo(Version.v9) >= 0){
+ depth = 0;
+ } else {
+ depth = AAIProperties.MAXIMUM_DEPTH;
+ }
+ } else {
+ if (depthParam.length() > 0 && !depthParam.equals("all")){
+ try {
+ depth = Integer.valueOf(depthParam);
+ } catch (Exception e) {
+ throw new AAIException("AAI_4016");
+ }
+
+ }
+ }
+ String maxDepth = obj.getMetadata(ObjectMetadata.MAXIMUM_DEPTH);
+
+ int maximumDepth = AAIProperties.MAXIMUM_DEPTH;
+
+ if(maxDepth != null){
+ try {
+ maximumDepth = Integer.parseInt(maxDepth);
+ } catch(Exception ex){
+ throw new AAIException("AAI_4018");
+ }
+ }
+
+ if(depth > maximumDepth){
+ throw new AAIException("AAI_3303");
+ }
+
+ return depth;
+ }
+
+ /**
+ * Checks if is modification method.
+ *
+ * @param method the method
+ * @return true, if is modification method
+ */
+ private boolean isModificationMethod(HttpMethod method) {
+ boolean result = false;
+
+ if (method.equals(HttpMethod.PUT) || method.equals(HttpMethod.PUT_EDGE) || method.equals(HttpMethod.DELETE_EDGE) || method.equals(HttpMethod.MERGE_PATCH)) {
+ result = true;
+ }
+
+ return result;
+
+ }
+
+ private HashMap<String, Introspector> getRelatedObjects(DBSerializer serializer, QueryEngine queryEngine, Vertex v) throws IllegalAccessException, IllegalArgumentException, InvocationTargetException, SecurityException, InstantiationException, NoSuchMethodException, UnsupportedEncodingException, AAIException, URISyntaxException {
+ HashMap<String, Introspector> relatedVertices = new HashMap<>();
+ List<Vertex> vertexChain = queryEngine.findParents(v);
+ for (Vertex vertex : vertexChain) {
+ try {
+ final Introspector vertexObj = serializer.getVertexProperties(vertex);
+ relatedVertices.put(vertexObj.getObjectId(), vertexObj);
+ } catch (AAIUnknownObjectException e) {
+ LOGGER.warn("Unable to get vertex properties, partial list of related vertices returned");
+ }
+
+ }
+
+ return relatedVertices;
+ }
+
+}
diff --git a/aai-traversal/src/main/java/org/openecomp/aai/rest/retired/RetiredConsumer.java b/aai-traversal/src/main/java/org/openecomp/aai/rest/retired/RetiredConsumer.java
new file mode 100644
index 0000000..99974ef
--- /dev/null
+++ b/aai-traversal/src/main/java/org/openecomp/aai/rest/retired/RetiredConsumer.java
@@ -0,0 +1,143 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * org.openecomp.aai
+ * ================================================================================
+ * Copyright (C) 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=========================================================
+ */
+
+package org.openecomp.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.openecomp.aai.exceptions.AAIException;
+import org.openecomp.aai.logging.ErrorLogHelper;
+import org.openecomp.aai.restcore.RESTAPI;
+import org.openecomp.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-traversal/src/main/java/org/openecomp/aai/rest/retired/V3ThroughV7Consumer.java b/aai-traversal/src/main/java/org/openecomp/aai/rest/retired/V3ThroughV7Consumer.java
new file mode 100644
index 0000000..55d9482
--- /dev/null
+++ b/aai-traversal/src/main/java/org/openecomp/aai/rest/retired/V3ThroughV7Consumer.java
@@ -0,0 +1,28 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * org.openecomp.aai
+ * ================================================================================
+ * Copyright (C) 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=========================================================
+ */
+
+package org.openecomp.aai.rest.retired;
+
+import javax.ws.rs.Path;
+
+@Path("{version: v[3-7]}")
+public class V3ThroughV7Consumer extends RetiredConsumer {
+
+}
diff --git a/aai-traversal/src/main/java/org/openecomp/aai/rest/retired/V7V8NamedQueries.java b/aai-traversal/src/main/java/org/openecomp/aai/rest/retired/V7V8NamedQueries.java
new file mode 100644
index 0000000..3f022a2
--- /dev/null
+++ b/aai-traversal/src/main/java/org/openecomp/aai/rest/retired/V7V8NamedQueries.java
@@ -0,0 +1,28 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * org.openecomp.aai
+ * ================================================================================
+ * Copyright (C) 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=========================================================
+ */
+
+package org.openecomp.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-traversal/src/main/java/org/openecomp/aai/rest/search/GenericQueryProcessor.java b/aai-traversal/src/main/java/org/openecomp/aai/rest/search/GenericQueryProcessor.java
new file mode 100644
index 0000000..2e9e6a5
--- /dev/null
+++ b/aai-traversal/src/main/java/org/openecomp/aai/rest/search/GenericQueryProcessor.java
@@ -0,0 +1,227 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * org.openecomp.aai
+ * ================================================================================
+ * Copyright (C) 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=========================================================
+ */
+
+package org.openecomp.aai.rest.search;
+
+import java.io.FileNotFoundException;
+import java.net.URI;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Optional;
+import java.util.Vector;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import javax.ws.rs.core.MultivaluedHashMap;
+import javax.ws.rs.core.MultivaluedMap;
+
+import org.apache.tinkerpop.gremlin.process.traversal.P;
+import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversal;
+import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.__;
+import org.apache.tinkerpop.gremlin.structure.Graph;
+import org.apache.tinkerpop.gremlin.structure.Vertex;
+import org.javatuples.Pair;
+
+import org.openecomp.aai.restcore.util.URITools;
+import org.openecomp.aai.serialization.engines.TransactionalGraphEngine;
+import org.openecomp.aai.serialization.queryformats.SubGraphStyle;
+
+import jersey.repackaged.com.google.common.base.Joiner;
+
+public abstract class GenericQueryProcessor {
+
+ protected final Optional<URI> uri;
+ protected final MultivaluedMap<String, String> queryParams;
+ protected final Optional<Collection<Vertex>> vertices;
+ protected static Pattern p = Pattern.compile("query/(.*+)");
+ protected Optional<String> gremlin;
+ protected final TransactionalGraphEngine dbEngine;
+ protected static GremlinServerSingleton gremlinServerSingleton = GremlinServerSingleton.getInstance();
+ protected final boolean isGremlin;
+
+ protected GenericQueryProcessor(Builder builder) {
+ this.uri = builder.getUri();
+ this.dbEngine = builder.getDbEngine();
+ this.vertices = builder.getVertices();
+ this.gremlin = builder.getGremlin();
+ this.isGremlin = builder.isGremlin();
+ if (uri.isPresent()) {
+ queryParams = URITools.getQueryMap(uri.get());
+ } else {
+ queryParams = new MultivaluedHashMap<>();
+ }
+ }
+
+ protected abstract GraphTraversal<?,?> runQuery(String query, Map<String, Object> params);
+
+ protected List<Object> processSubGraph(SubGraphStyle style, GraphTraversal<?,?> g) {
+ final List<Object> resultVertices = new Vector<>();
+ g.store("x");
+
+ if (SubGraphStyle.prune.equals(style) || SubGraphStyle.star.equals(style)) {
+ g.barrier().bothE();
+ if (SubGraphStyle.prune.equals(style)) {
+ g.where(__.otherV().where(P.within("x")));
+ }
+ g.dedup().subgraph("subGraph").cap("subGraph").map(x -> (Graph)x.get()).next().traversal().V().forEachRemaining(x -> {
+ resultVertices.add(x);
+ });
+ } else {
+ resultVertices.addAll(g.toList());
+ }
+ return resultVertices;
+ }
+
+ public List<Object> execute(SubGraphStyle style) throws FileNotFoundException {
+ final List<Object> resultVertices;
+
+ Pair<String, Map<String, Object>> tuple = this.createQuery();
+ String query = tuple.getValue0();
+ Map<String, Object> params = tuple.getValue1();
+
+ if (query.equals("") && (vertices.isPresent() && vertices.get().isEmpty())) {
+ //nothing to do, just exit
+ return new ArrayList<>();
+ }
+ GraphTraversal<?,?> g = this.runQuery(query, params);
+
+ resultVertices = this.processSubGraph(style, g);
+
+ return resultVertices;
+ }
+
+ protected Pair<String, Map<String, Object>> createQuery() {
+ Map<String, Object> params = new HashMap<>();
+ String query = "";
+ if (!this.isGremlin) {
+ Matcher m = p.matcher(uri.get().getPath());
+ String queryName = "";
+ if (m.find()) {
+ queryName = m.group(1);
+ }
+
+ for (String key : queryParams.keySet()) {
+ params.put(key, queryParams.getFirst(key));
+ }
+
+ query = gremlinServerSingleton.getStoredQuery(queryName);
+ if (query == null) {
+ query = "";
+ }
+
+ List<Object> ids = new ArrayList<>();
+
+ if (vertices.isPresent() && !vertices.get().isEmpty()) {
+ for (Vertex v : vertices.get()) {
+ ids.add(v.id());
+ }
+ StringBuilder sb = new StringBuilder();
+ sb.append("[");
+ sb.append(Joiner.on(",").join(ids));
+ sb.append("]");
+ String startPrefix = "aaiStartQuery = " + sb.toString() + " as Object[];g.V(aaiStartQuery)";
+ if (!"".equals(query)) {
+ query = startPrefix + "." + query;
+ } else {
+ query = startPrefix;
+ }
+ }
+
+ } else {
+ query = gremlin.get();
+ }
+
+ return new Pair<>(query, params);
+ }
+
+ public static class Builder {
+
+ private final TransactionalGraphEngine dbEngine;
+ private Optional<URI> uri = Optional.empty();
+ private Optional<String> gremlin = Optional.empty();
+ private boolean isGremlin = false;
+ private Optional<Collection<Vertex>> vertices = Optional.empty();
+ private QueryProcessorType processorType = QueryProcessorType.GREMLIN_SERVER;
+
+ public Builder(TransactionalGraphEngine dbEngine) {
+ this.dbEngine = dbEngine;
+ }
+
+ public Builder queryFrom(URI uri) {
+ this.uri = Optional.of(uri);
+ this.isGremlin = false;
+ return this;
+ }
+
+ public Builder startFrom(Collection<Vertex> vertices) {
+ this.vertices = Optional.of(vertices);
+ return this;
+ }
+
+ public Builder queryFrom(String gremlin) {
+ this.gremlin = Optional.of(gremlin);
+ this.isGremlin = true;
+ return this;
+ }
+
+ public Builder processWith(QueryProcessorType type) {
+ this.processorType = type;
+ return this;
+ }
+ public TransactionalGraphEngine getDbEngine() {
+ return dbEngine;
+ }
+
+ public Optional<URI> getUri() {
+ return uri;
+ }
+
+ public Optional<String> getGremlin() {
+ return gremlin;
+ }
+
+ public boolean isGremlin() {
+ return isGremlin;
+ }
+
+ public Optional<Collection<Vertex>> getVertices() {
+ return vertices;
+ }
+
+ public QueryProcessorType getProcessorType() {
+ return processorType;
+ }
+
+ public GenericQueryProcessor create() {
+
+ if (this.getProcessorType().equals(QueryProcessorType.GREMLIN_SERVER)) {
+ return new GremlinServerImpl(this);
+ } else if (this.getProcessorType().equals(QueryProcessorType.LOCAL_GROOVY)) {
+ return new GroovyShellImpl(this);
+ } else {
+ return new GremlinServerImpl(this);
+ }
+ }
+
+ }
+}
diff --git a/aai-traversal/src/main/java/org/openecomp/aai/rest/search/GremlinGroovyShellSingleton.java b/aai-traversal/src/main/java/org/openecomp/aai/rest/search/GremlinGroovyShellSingleton.java
new file mode 100644
index 0000000..64159a4
--- /dev/null
+++ b/aai-traversal/src/main/java/org/openecomp/aai/rest/search/GremlinGroovyShellSingleton.java
@@ -0,0 +1,88 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * org.openecomp.aai
+ * ================================================================================
+ * Copyright (C) 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=========================================================
+ */
+
+package org.openecomp.aai.rest.search;
+
+import java.util.HashMap;
+import java.util.Map;
+import java.util.concurrent.TimeUnit;
+
+import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversal;
+import org.codehaus.groovy.ast.ClassHelper;
+import org.codehaus.groovy.ast.expr.ClassExpression;
+import org.codehaus.groovy.ast.expr.PropertyExpression;
+import org.codehaus.groovy.control.CompilerConfiguration;
+import org.codehaus.groovy.control.customizers.ASTTransformationCustomizer;
+import org.codehaus.groovy.control.customizers.ImportCustomizer;
+
+import groovy.lang.Binding;
+import groovy.lang.GroovyShell;
+import groovy.lang.Script;
+import groovy.transform.TimedInterrupt;
+
+/**
+ * Creates and returns a groovy shell with the
+ * configuration to statically import graph classes
+ *
+ */
+public class GremlinGroovyShellSingleton {
+
+ private final GroovyShell shell;
+ private GremlinGroovyShellSingleton() {
+ Map<String, Object> parameters = new HashMap<>();
+ parameters.put("value", 30000);
+ parameters.put("unit", new PropertyExpression(new ClassExpression(ClassHelper.make(TimeUnit.class)),"MILLISECONDS"));
+
+ ASTTransformationCustomizer custom = new ASTTransformationCustomizer(parameters, TimedInterrupt.class);
+ ImportCustomizer imports = new ImportCustomizer();
+ imports.addStaticStars(
+ "org.apache.tinkerpop.gremlin.process.traversal.P"
+ );
+ imports.addImports(
+ "org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.__",
+ "org.apache.tinkerpop.gremlin.structure.T",
+ "org.apache.tinkerpop.gremlin.process.traversal.P");
+ CompilerConfiguration config = new CompilerConfiguration();
+ config.addCompilationCustomizers(custom, imports);
+
+ this.shell = new GroovyShell(config);
+ }
+
+ private static class Helper {
+ private static final GremlinGroovyShellSingleton INSTANCE = new GremlinGroovyShellSingleton();
+ }
+
+ public static GremlinGroovyShellSingleton getInstance() {
+
+ return Helper.INSTANCE;
+ }
+
+ /**
+ * @param traversal
+ * @param params
+ * @return result of graph traversal
+ */
+ public GraphTraversal<?, ?> executeTraversal (String traversal, Map<String, Object> params) {
+ Binding binding = new Binding(params);
+ Script script = shell.parse(traversal);
+ script.setBinding(binding);
+ return (GraphTraversal<?, ?>) script.run();
+ }
+}
diff --git a/aai-traversal/src/main/java/org/openecomp/aai/rest/search/GremlinServerImpl.java b/aai-traversal/src/main/java/org/openecomp/aai/rest/search/GremlinServerImpl.java
new file mode 100644
index 0000000..a759b86
--- /dev/null
+++ b/aai-traversal/src/main/java/org/openecomp/aai/rest/search/GremlinServerImpl.java
@@ -0,0 +1,76 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * org.openecomp.aai
+ * ================================================================================
+ * Copyright (C) 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=========================================================
+ */
+
+package org.openecomp.aai.rest.search;
+
+import java.util.List;
+import java.util.Map;
+import java.util.Vector;
+
+import org.apache.tinkerpop.gremlin.driver.Client;
+import org.apache.tinkerpop.gremlin.driver.Cluster;
+import org.apache.tinkerpop.gremlin.driver.ResultSet;
+import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversal;
+import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.__;
+
+import org.openecomp.aai.util.AAIConfig;
+
+public class GremlinServerImpl extends GenericQueryProcessor {
+
+
+ protected GremlinServerImpl(Builder builder) {
+ super(builder);
+ }
+
+
+ @Override
+ protected GraphTraversal<?,?> runQuery(String query, Map<String, Object> params) {
+
+ //must force them into ids because of serialization issue with
+ //tinkerpop-3.0.1-incubating
+ query += ".id()";
+ String rebindGraph = AAIConfig.get("aai.server.rebind", "g");
+
+ if(!"g".equals(rebindGraph)){
+ query = query.replaceFirst("g\\.V\\(", rebindGraph + ".V(");
+ }
+
+ Cluster cluster = gremlinServerSingleton.getCluster();
+ Client client = cluster.connect();
+
+ ResultSet results = client.submit(query, params);
+
+
+ List<Object> vIds = new Vector<>();
+ results.stream().forEach(x -> {
+ Object obj = x.getObject();
+ vIds.add(obj);
+ });
+
+ client.close();
+
+ if (vIds.isEmpty()) {
+ return __.start();
+ } else {
+ return this.dbEngine.asAdmin().getTraversalSource().V(vIds.toArray());
+ }
+ }
+
+}
diff --git a/aai-traversal/src/main/java/org/openecomp/aai/rest/search/GremlinServerSingleton.java b/aai-traversal/src/main/java/org/openecomp/aai/rest/search/GremlinServerSingleton.java
new file mode 100644
index 0000000..c54b310
--- /dev/null
+++ b/aai-traversal/src/main/java/org/openecomp/aai/rest/search/GremlinServerSingleton.java
@@ -0,0 +1,130 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * org.openecomp.aai
+ * ================================================================================
+ * Copyright (C) 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=========================================================
+ */
+
+package org.openecomp.aai.rest.search;
+
+import org.openecomp.aai.util.AAIConstants;
+import org.openecomp.aai.util.FileWatcher;
+import com.att.eelf.configuration.EELFLogger;
+import com.att.eelf.configuration.EELFManager;
+import org.apache.tinkerpop.gremlin.driver.Cluster;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.util.Date;
+import java.util.Properties;
+import java.util.Timer;
+import java.util.TimerTask;
+
+public class GremlinServerSingleton {
+
+ private static EELFLogger logger = EELFManager.getInstance().getLogger(GremlinServerSingleton.class);
+
+ private Cluster cluster;
+ private boolean timerSet;
+ private Timer timer;
+ private Properties properties;
+
+ private static class Helper {
+ private static final GremlinServerSingleton INSTANCE = new GremlinServerSingleton();
+ }
+
+ public static GremlinServerSingleton getInstance() {
+ return Helper.INSTANCE;
+ }
+
+ private GremlinServerSingleton(){
+ init();
+ }
+
+ /**
+ * Initializes the gremlin server singleton
+ * Loads the configuration of the gremlin server and creates a cluster
+ * Loads the gremlin query file into the properties object
+ * Then creates a file watcher to watch the file every ten seconds
+ * and if there is a change in the file, then reloads the file into
+ * the properties object
+ *
+ */
+ private void init() {
+
+ properties = new Properties();
+
+ try {
+ cluster = Cluster.build(new File(AAIConstants.AAI_HOME_ETC_APP_PROPERTIES + "gremlin-server-config.yaml"))
+ .maxContentLength(6537920)
+ .create();
+ } catch (FileNotFoundException e) {
+ logger.error("Unable to find the file: " + e);
+ }
+
+ File queryFile = new File(AAIConstants.AAI_HOME_ETC_QUERY);
+
+ try (FileInputStream fis = new FileInputStream(queryFile)){
+ properties.load(fis);
+ } catch (IOException e) {
+ logger.error("Error occurred during the processing of query file: " + e);
+ }
+
+
+ TimerTask task = new FileWatcher(new File(AAIConstants.AAI_HOME_ETC_QUERY)) {
+ @Override
+ protected void onChange(File file) {
+ File queryFile = new File(AAIConstants.AAI_HOME_ETC_QUERY);
+ try (FileInputStream fis = new FileInputStream(queryFile)){
+ properties.load(fis);
+ logger.debug("File: " + file + " was changed so the cluster is rebuild for gremlin server");
+ } catch (FileNotFoundException e) {
+ logger.error("Unable to find the file: " + e);
+ } catch (IOException e) {
+ logger.error("Error occurred during the processing of query file: " + e);
+ }
+ }
+ };
+
+ if (!timerSet) {
+ timerSet = true;
+ timer = new Timer();
+ timer.schedule( task , new Date(), 10000 );
+ }
+
+ }
+
+ public Cluster getCluster(){
+ return cluster;
+ }
+
+ /**
+ * Gets the key if the properties contains that key
+ *
+ * Purposely not checking if the property exists due
+ * to if you check for the property and then get the property
+ * Then you are going to have to synchronize the method
+ *
+ * @param key the query to check if it exists in the file
+ * @return string if the key exists or null if it doesn't
+ */
+ public String getStoredQuery(String key){
+ return (String) properties.get(key);
+ }
+
+}
diff --git a/aai-traversal/src/main/java/org/openecomp/aai/rest/search/GroovyShellImpl.java b/aai-traversal/src/main/java/org/openecomp/aai/rest/search/GroovyShellImpl.java
new file mode 100644
index 0000000..1b64d21
--- /dev/null
+++ b/aai-traversal/src/main/java/org/openecomp/aai/rest/search/GroovyShellImpl.java
@@ -0,0 +1,47 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * org.openecomp.aai
+ * ================================================================================
+ * Copyright (C) 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=========================================================
+ */
+
+package org.openecomp.aai.rest.search;
+
+import java.util.Map;
+
+import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversal;
+
+import org.openecomp.aai.restcore.search.GremlinGroovyShellSingleton;
+
+public class GroovyShellImpl extends GenericQueryProcessor {
+
+ protected GroovyShellImpl(Builder builder) {
+ super(builder);
+ }
+
+ @Override
+ protected GraphTraversal<?,?> runQuery(String query, Map<String, Object> params) {
+
+ params.put("g", this.dbEngine.asAdmin().getTraversalSource());
+
+ GremlinGroovyShellSingleton shell = GremlinGroovyShellSingleton.getInstance();
+
+ return shell.executeTraversal(query, params);
+ }
+
+}
+
+
diff --git a/aai-traversal/src/main/java/org/openecomp/aai/rest/search/ModelAndNamedQueryRestProvider.java b/aai-traversal/src/main/java/org/openecomp/aai/rest/search/ModelAndNamedQueryRestProvider.java
new file mode 100644
index 0000000..f333dd8
--- /dev/null
+++ b/aai-traversal/src/main/java/org/openecomp/aai/rest/search/ModelAndNamedQueryRestProvider.java
@@ -0,0 +1,203 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * org.openecomp.aai
+ * ================================================================================
+ * Copyright (C) 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=========================================================
+ */
+
+package org.openecomp.aai.rest.search;
+
+import java.util.ArrayList;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.ws.rs.POST;
+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.openecomp.aai.dbgraphmap.SearchGraph;
+import org.openecomp.aai.dbmap.DBConnectionType;
+import org.openecomp.aai.exceptions.AAIException;
+import org.openecomp.aai.extensions.AAIExtensionMap;
+import org.openecomp.aai.logging.ErrorLogHelper;
+import org.openecomp.aai.restcore.RESTAPI;
+import org.openecomp.aai.util.AAIApiVersion;
+
+/**
+ * Implements the search subdomain in the REST API. All API calls must include
+ * X-FromAppId and X-TransactionId in the header.
+ *
+
+ *
+ */
+
+@Path("/search")
+public class ModelAndNamedQueryRestProvider extends RESTAPI {
+
+ protected static String authPolicyFunctionName = "search";
+
+ public static final String NAMED_QUERY = "/named-query";
+
+ public static final String MODEL_QUERY = "/model";
+
+ /**
+ * Gets the named query response.
+ *
+ * @param headers the headers
+ * @param req the req
+ * @param queryParameters the query parameters
+ * @return the named query response
+ */
+ /* ---------------- Start Named Query --------------------- */
+ @POST
+ @Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
+ @Path(NAMED_QUERY)
+ public Response getNamedQueryResponse(@Context HttpHeaders headers,
+ @Context HttpServletRequest req,
+ String queryParameters) {
+ AAIException ex = null;
+ Response response = null;
+ String fromAppId = null;
+ String transId = null;
+ String rqstTm = genDate();
+ ArrayList<String> templateVars = new ArrayList<String>();
+ try {
+ fromAppId = getFromAppId(headers);
+ transId = getTransId(headers);
+
+ AAIExtensionMap aaiExtMap = new AAIExtensionMap();
+ aaiExtMap.setHttpHeaders(headers);
+ aaiExtMap.setServletRequest(req);
+ aaiExtMap.setApiVersion(AAIApiVersion.get());
+ String realTime = headers.getRequestHeaders().getFirst("Real-Time");
+ //only consider header value for search
+ DBConnectionType type = this.determineConnectionType("force-cache", realTime);
+
+ SearchGraph searchGraph = new SearchGraph();
+ response = searchGraph.runNamedQuery(fromAppId, transId, queryParameters, type, aaiExtMap);
+
+ String respTm = genDate();
+ logTransaction(fromAppId, transId, "GETSDNZONERESPONSE",
+ req.getRequestURI(), rqstTm, respTm, "", response);
+
+ } catch (AAIException e) {
+ // send error response
+ ex = e;
+ templateVars.add("POST Search");
+ templateVars.add("getNamedQueryResponse");
+ response = Response
+ .status(e.getErrorObject().getHTTPResponseCode())
+ .entity(ErrorLogHelper.getRESTAPIErrorResponse(headers.getAcceptableMediaTypes(), e, templateVars))
+ .build();
+ } catch (Exception e) {
+ // send error response
+ ex = new AAIException("AAI_4000", e);
+ templateVars.add("POST Search");
+ templateVars.add("getNamedQueryResponse");
+ response = Response
+ .status(Status.INTERNAL_SERVER_ERROR)
+ .entity(ErrorLogHelper.getRESTAPIErrorResponse(headers.getAcceptableMediaTypes(), ex, templateVars))
+ .build();
+ } finally {
+ // log success or failure
+ if (ex != null) {
+ ErrorLogHelper.logException(ex);
+ }
+ }
+ return response;
+ }
+
+ /**
+ * Gets the model query response.
+ *
+ * @param headers the headers
+ * @param req the req
+ * @param inboundPayload the inbound payload
+ * @param action the action
+ * @return the model query response
+ */
+ /* ---------------- Start Named Query --------------------- */
+ @POST
+ @Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
+ @Path(MODEL_QUERY)
+ public Response getModelQueryResponse(@Context HttpHeaders headers,
+ @Context HttpServletRequest req,
+ String inboundPayload,
+ @QueryParam("action") String action) {
+ AAIException ex = null;
+ Response response = null;
+ String fromAppId = null;
+ String transId = null;
+ String rqstTm = genDate();
+ ArrayList<String> templateVars = new ArrayList<String>();
+ try {
+ fromAppId = getFromAppId(headers);
+ transId = getTransId(headers);
+
+ AAIExtensionMap aaiExtMap = new AAIExtensionMap();
+ aaiExtMap.setHttpHeaders(headers);
+ aaiExtMap.setServletRequest(req);
+ aaiExtMap.setApiVersion(AAIApiVersion.get());
+ aaiExtMap.setFromAppId(fromAppId);
+ aaiExtMap.setTransId(transId);
+
+ String realTime = headers.getRequestHeaders().getFirst("Real-Time");
+ //only consider header value for search
+ DBConnectionType type = this.determineConnectionType("force-cache", realTime);
+
+ SearchGraph searchGraph = new SearchGraph();
+ if (action != null && action.equalsIgnoreCase("DELETE")) {
+ response = searchGraph.executeModelOperation(fromAppId, transId, inboundPayload, type, true, aaiExtMap);
+ } else {
+ response = searchGraph.executeModelOperation(fromAppId, transId, inboundPayload, type, false, aaiExtMap);
+ }
+ String respTm = genDate();
+ logTransaction(fromAppId, transId, "POSTMODELQUERYRESPONSE",
+ req.getRequestURI(), rqstTm, respTm, "", response);
+
+ } catch (AAIException e) {
+ // send error response
+ ex = e;
+ templateVars.add("POST Search");
+ templateVars.add("getModelQueryResponse");
+ response = Response
+ .status(e.getErrorObject().getHTTPResponseCode())
+ .entity(ErrorLogHelper.getRESTAPIErrorResponse(headers.getAcceptableMediaTypes(), e, templateVars))
+ .build();
+ } catch (Exception e) {
+ // send error response
+ ex = new AAIException("AAI_4000", e);
+ templateVars.add("POST Search");
+ templateVars.add("getModelQueryResponse");
+ response = Response
+ .status(Status.INTERNAL_SERVER_ERROR)
+ .entity(ErrorLogHelper.getRESTAPIErrorResponse(headers.getAcceptableMediaTypes(), ex, templateVars))
+ .build();
+ } finally {
+ // log success or failure
+ if (ex != null) {
+ ErrorLogHelper.logException(ex);
+ }
+ }
+ return response;
+ }
+
+}
diff --git a/aai-traversal/src/main/java/org/openecomp/aai/rest/search/QueryProcessorType.java b/aai-traversal/src/main/java/org/openecomp/aai/rest/search/QueryProcessorType.java
new file mode 100644
index 0000000..33d7a90
--- /dev/null
+++ b/aai-traversal/src/main/java/org/openecomp/aai/rest/search/QueryProcessorType.java
@@ -0,0 +1,27 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * org.openecomp.aai
+ * ================================================================================
+ * Copyright (C) 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=========================================================
+ */
+
+package org.openecomp.aai.rest.search;
+
+public enum QueryProcessorType {
+
+ GREMLIN_SERVER,
+ LOCAL_GROOVY
+}
diff --git a/aai-traversal/src/main/java/org/openecomp/aai/rest/search/SearchProvider.java b/aai-traversal/src/main/java/org/openecomp/aai/rest/search/SearchProvider.java
new file mode 100644
index 0000000..d6712ce
--- /dev/null
+++ b/aai-traversal/src/main/java/org/openecomp/aai/rest/search/SearchProvider.java
@@ -0,0 +1,269 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * org.openecomp.aai
+ * ================================================================================
+ * Copyright (C) 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=========================================================
+ */
+
+package org.openecomp.aai.rest.search;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.ws.rs.Consumes;
+import javax.ws.rs.GET;
+import javax.ws.rs.POST;
+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.UriInfo;
+
+import org.eclipse.persistence.dynamic.DynamicEntity;
+import org.eclipse.persistence.jaxb.dynamic.DynamicJAXBContext;
+
+import org.openecomp.aai.db.props.AAIProperties;
+import org.openecomp.aai.dbgraphmap.SearchGraph;
+import org.openecomp.aai.dbmap.DBConnectionType;
+import org.openecomp.aai.domain.model.AAIResource;
+import org.openecomp.aai.domain.model.AAIResources;
+import org.openecomp.aai.exceptions.AAIException;
+import org.openecomp.aai.extensions.AAIExtensionMap;
+import org.openecomp.aai.ingestModel.IngestModelMoxyOxm;
+import org.openecomp.aai.introspection.Loader;
+import org.openecomp.aai.introspection.LoaderFactory;
+import org.openecomp.aai.introspection.ModelType;
+import org.openecomp.aai.introspection.Version;
+import org.openecomp.aai.logging.ErrorLogHelper;
+import org.openecomp.aai.restcore.RESTAPI;
+import org.openecomp.aai.serialization.db.DBSerializer;
+import org.openecomp.aai.serialization.engines.QueryStyle;
+import org.openecomp.aai.serialization.engines.TitanDBEngine;
+import org.openecomp.aai.serialization.engines.TransactionalGraphEngine;
+import org.openecomp.aai.serialization.queryformats.utils.UrlBuilder;
+import org.openecomp.aai.util.AAIApiVersion;
+
+/**
+ * Implements the search subdomain in the REST API. All API calls must include
+ * X-FromAppId and X-TransactionId in the header.
+ *
+
+ *
+ */
+
+@Path("/{version: v2|v[789]|v1[0]|latest}/search")
+public class SearchProvider extends RESTAPI {
+
+ protected static String authPolicyFunctionName = "search";
+
+ public static final String GENERIC_QUERY = "/generic-query";
+
+ public static final String NODES_QUERY = "/nodes-query";
+
+ /**
+ * Gets the generic query response.
+ *
+ * @param headers the headers
+ * @param req the req
+ * @param startNodeType the start node type
+ * @param startNodeKeyParams the start node key params
+ * @param includeNodeTypes the include node types
+ * @param depth the depth
+ * @return the generic query response
+ */
+ /* ---------------- Start Generic Query --------------------- */
+ @GET
+ @Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
+ @Path(GENERIC_QUERY)
+ public Response getGenericQueryResponse(@Context HttpHeaders headers,
+ @Context HttpServletRequest req,
+ @QueryParam("start-node-type") final String startNodeType,
+ @QueryParam("key") final List<String> startNodeKeyParams,
+ @QueryParam("include") final List<String> includeNodeTypes,
+ @QueryParam("depth") final int depth,
+ @PathParam("version")String versionParam
+ ) {
+
+ AAIException ex = null;
+ Response searchResult = null;
+ String fromAppId = null;
+ String transId = null;
+ String rqstTm = genDate();
+ ArrayList<String> templateVars = new ArrayList<String>();
+ try {
+ fromAppId = getFromAppId(headers);
+ transId = getTransId(headers);
+ String realTime = headers.getRequestHeaders().getFirst("Real-Time");
+ //only consider header value for search
+ DBConnectionType type = this.determineConnectionType("force-cache", realTime);
+ final Version version;
+ if (versionParam.equals("latest")) {
+ version = AAIProperties.LATEST;
+ } else {
+ version = Version.valueOf(versionParam);
+ }
+ final ModelType factoryType = ModelType.MOXY;
+ Loader loader = LoaderFactory.createLoaderForVersion(factoryType, version);
+ TransactionalGraphEngine dbEngine = new TitanDBEngine(
+ QueryStyle.TRAVERSAL,
+ type,
+ loader);
+ DBSerializer dbSerializer = new DBSerializer(version, dbEngine, factoryType, fromAppId);
+ UrlBuilder urlBuilder = new UrlBuilder(version, dbSerializer);
+ SearchGraph searchGraph = new SearchGraph();
+ searchResult = searchGraph.runGenericQuery(
+ headers,
+ startNodeType,
+ startNodeKeyParams,
+ includeNodeTypes,
+ depth,
+ dbEngine,
+ loader,
+ urlBuilder
+
+ );
+
+ String respTm = genDate();
+ logTransaction(fromAppId, transId,
+ "GETGENERICQUERYRESPONSE", req.getRequestURI(), rqstTm, respTm,
+ "", searchResult);
+
+ } catch (AAIException e) {
+ // send error response
+ ex = e;
+ templateVars.add("GET Search");
+ templateVars.add("getGenericQueryResponse");
+ searchResult = Response
+ .status(e.getErrorObject().getHTTPResponseCode())
+ .entity(ErrorLogHelper.getRESTAPIErrorResponse(headers.getAcceptableMediaTypes(), e, templateVars))
+ .build();
+ } catch (Exception e) {
+ // send error response
+ ex = new AAIException("AAI_4000", e);
+ templateVars.add("GET Search");
+ templateVars.add("getGenericQueryResponse");
+ searchResult = Response
+ .status(Status.INTERNAL_SERVER_ERROR)
+ .entity(ErrorLogHelper.getRESTAPIErrorResponse(headers.getAcceptableMediaTypes(), ex, templateVars))
+ .build();
+ } finally {
+ // log success or failure
+ if (ex != null){
+ ErrorLogHelper.logException(ex);
+ }
+ }
+
+ return searchResult;
+ }
+
+ /* ---------------- End Generic Query --------------------- */
+
+ /**
+ * Gets the nodes query response.
+ *
+ * @param headers the headers
+ * @param req the req
+ * @param searchNodeType the search node type
+ * @param edgeFilterList the edge filter list
+ * @param filterList the filter list
+ * @return the nodes query response
+ */
+ /* ---------------- Start Nodes Query --------------------- */
+ @GET
+ @Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
+ @Path(NODES_QUERY)
+ public Response getNodesQueryResponse(@Context HttpHeaders headers,
+ @Context HttpServletRequest req,
+ @QueryParam("search-node-type") final String searchNodeType,
+ @QueryParam("edge-filter") final List<String> edgeFilterList,
+ @QueryParam("filter") final List<String> filterList,
+ @PathParam("version")String versionParam) {
+ AAIException ex = null;
+ Response searchResult = null;
+ String fromAppId = null;
+ String transId = null;
+ String rqstTm = genDate();
+ ArrayList<String> templateVars = new ArrayList<String>();
+ try {
+ fromAppId = getFromAppId(headers);
+ transId = getTransId(headers);
+ String realTime = headers.getRequestHeaders().getFirst("Real-Time");
+ //only consider header value for search
+ DBConnectionType type = this.determineConnectionType("force-cache", realTime);
+
+ final Version version;
+ if (versionParam.equals("latest")) {
+ version = AAIProperties.LATEST;
+ } else {
+ version = Version.valueOf(versionParam);
+ }
+ final ModelType factoryType = ModelType.MOXY;
+ Loader loader = LoaderFactory.createLoaderForVersion(factoryType, version);
+ TransactionalGraphEngine dbEngine = new TitanDBEngine(
+ QueryStyle.TRAVERSAL,
+ type,
+ loader);
+ DBSerializer dbSerializer = new DBSerializer(version, dbEngine, factoryType, fromAppId);
+ UrlBuilder urlBuilder = new UrlBuilder(version, dbSerializer);
+ SearchGraph searchGraph = new SearchGraph();
+
+ searchResult = searchGraph.runNodesQuery(headers,
+ searchNodeType,
+ edgeFilterList,
+ filterList,
+ dbEngine,
+ loader,
+ urlBuilder);
+
+ String respTm = genDate();
+ logTransaction(fromAppId, transId, "GETNODESQUERYRESPONSE",
+ req.getRequestURI(), rqstTm, respTm, "", searchResult);
+ } catch (AAIException e) {
+ // send error response
+ ex = e;
+ templateVars.add("GET Search");
+ templateVars.add("getNodesQueryResponse");
+ searchResult = Response
+ .status(e.getErrorObject().getHTTPResponseCode())
+ .entity(ErrorLogHelper.getRESTAPIErrorResponse(headers.getAcceptableMediaTypes(), e, templateVars))
+ .build();
+ } catch (Exception e) {
+ // send error response
+ ex = new AAIException("AAI_4000", e);
+ templateVars.add("GET Search");
+ templateVars.add("getNodesQueryResponse");
+ searchResult = Response
+ .status(Status.INTERNAL_SERVER_ERROR)
+ .entity(ErrorLogHelper.getRESTAPIErrorResponse(headers.getAcceptableMediaTypes(), ex, templateVars))
+ .build();
+ } finally {
+ // log success or failure
+ if (ex != null){
+ ErrorLogHelper.logException(ex);
+ }
+ }
+ return searchResult;
+ }
+
+
+
+}
diff --git a/aai-traversal/src/main/java/org/openecomp/aai/rest/ueb/NotificationEvent.java b/aai-traversal/src/main/java/org/openecomp/aai/rest/ueb/NotificationEvent.java
new file mode 100644
index 0000000..389d296
--- /dev/null
+++ b/aai-traversal/src/main/java/org/openecomp/aai/rest/ueb/NotificationEvent.java
@@ -0,0 +1,96 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * org.openecomp.aai
+ * ================================================================================
+ * Copyright (C) 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=========================================================
+ */
+
+package org.openecomp.aai.rest.ueb;
+
+import org.openecomp.aai.exceptions.AAIException;
+import org.openecomp.aai.introspection.Introspector;
+import org.openecomp.aai.introspection.Loader;
+import org.openecomp.aai.introspection.Version;
+import org.openecomp.aai.util.StoreNotificationEvent;
+
+/**
+ * The Class NotificationEvent.
+ */
+public class NotificationEvent {
+
+ private Loader loader = null;
+
+ private Introspector eventHeader = null;
+
+ private Introspector obj = null;
+
+ /**
+ * Instantiates a new notification event.
+ *
+ * @param version the version
+ * @param eventHeader the event header
+ * @param obj the obj
+ */
+ public NotificationEvent (Loader loader, Introspector eventHeader, Introspector obj) {
+ this.loader = loader;
+ this.eventHeader = eventHeader;
+ this.obj = obj;
+ }
+
+ /**
+ * Trigger.
+ *
+ * @throws AAIException the AAI exception
+ */
+ public void trigger() throws AAIException {
+
+ StoreNotificationEvent sne = new StoreNotificationEvent();
+
+ sne.storeEvent(loader, eventHeader, obj);
+
+ }
+
+ /**
+ * Gets the notification version.
+ *
+ * @return the notification version
+ */
+ public Version getNotificationVersion() {
+ return loader.getVersion();
+ }
+
+ /**
+ * Gets the event header.
+ *
+ * @return the event header
+ */
+ public Introspector getEventHeader() {
+ return eventHeader;
+ }
+
+ /**
+ * Gets the obj.
+ *
+ * @return the obj
+ */
+ public Introspector getObj() {
+ return obj;
+ }
+
+
+
+
+}
diff --git a/aai-traversal/src/main/java/org/openecomp/aai/rest/ueb/UEBNotification.java b/aai-traversal/src/main/java/org/openecomp/aai/rest/ueb/UEBNotification.java
new file mode 100644
index 0000000..397082f
--- /dev/null
+++ b/aai-traversal/src/main/java/org/openecomp/aai/rest/ueb/UEBNotification.java
@@ -0,0 +1,178 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * org.openecomp.aai
+ * ================================================================================
+ * Copyright (C) 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=========================================================
+ */
+
+package org.openecomp.aai.rest.ueb;
+
+import java.io.UnsupportedEncodingException;
+import java.net.URI;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+
+import javax.ws.rs.core.Response.Status;
+
+import org.openecomp.aai.db.props.AAIProperties;
+import org.openecomp.aai.exceptions.AAIException;
+import org.openecomp.aai.introspection.Introspector;
+import org.openecomp.aai.introspection.Loader;
+import org.openecomp.aai.introspection.LoaderFactory;
+import org.openecomp.aai.introspection.Version;
+import org.openecomp.aai.introspection.exceptions.AAIUnknownObjectException;
+import org.openecomp.aai.introspection.exceptions.AAIUnmarshallingException;
+import org.openecomp.aai.parsers.uri.URIToObject;
+import org.openecomp.aai.util.AAIConfig;
+import com.att.eelf.configuration.EELFLogger;
+import com.att.eelf.configuration.EELFManager;
+
+/**
+ * The Class UEBNotification.
+ */
+public class UEBNotification {
+
+ private static final EELFLogger LOGGER = EELFManager.getInstance().getLogger(UEBNotification.class);
+
+ private Loader currentVersionLoader = null;
+ protected List<NotificationEvent> events = null;
+ private String urlBase = null;
+ private Version notificationVersion = null;
+
+ /**
+ * Instantiates a new UEB notification.
+ *
+ * @param loader the loader
+ */
+ public UEBNotification(Loader loader) {
+ events = new ArrayList<>();
+ currentVersionLoader = LoaderFactory.createLoaderForVersion(loader.getModelType(), AAIProperties.LATEST);
+ urlBase = AAIConfig.get("aai.server.url.base","");
+ notificationVersion = Version.valueOf(AAIConfig.get("aai.notification.current.version","v10"));
+ }
+
+
+ /**
+ * Creates the notification event.
+ *
+ * @param transactionId the X-TransactionId
+ * @param sourceOfTruth
+ * @param status the status
+ * @param uri the uri
+ * @param obj the obj
+ * @throws AAIException the AAI exception
+ * @throws IllegalArgumentException the illegal argument exception
+ * @throws UnsupportedEncodingException the unsupported encoding exception
+ */
+ public void createNotificationEvent(String transactionId, String sourceOfTruth, Status status, URI uri, Introspector obj, HashMap<String, Introspector> relatedObjects) throws AAIException, IllegalArgumentException, UnsupportedEncodingException {
+
+ String action = "UPDATE";
+
+ if (status.equals(Status.CREATED)) {
+ action = "CREATE";
+ } else if (status.equals(Status.OK)) {
+ action = "UPDATE";
+ } else if (status.equals(Status.NO_CONTENT)) {
+ action = "DELETE";
+ }
+
+ try {
+ Introspector eventHeader = currentVersionLoader.introspectorFromName("notification-event-header");
+ URIToObject parser = new URIToObject(currentVersionLoader, uri, relatedObjects);
+
+ String entityLink = "";
+ if (uri.toString().startsWith("/")) {
+ entityLink = urlBase + notificationVersion + uri;
+ } else {
+ entityLink = urlBase + notificationVersion + "/" + uri;
+ }
+
+
+ eventHeader.setValue("entity-link", entityLink);
+ eventHeader.setValue("action", action);
+ eventHeader.setValue("entity-type", obj.getDbName());
+ eventHeader.setValue("top-entity-type", parser.getTopEntityName());
+ eventHeader.setValue("source-name", sourceOfTruth);
+ eventHeader.setValue("version", notificationVersion.toString());
+ eventHeader.setValue("id", transactionId);
+
+ List<Object> parentList = parser.getParentList();
+ parentList.clear();
+
+ if (!parser.getTopEntity().equals(parser.getEntity())) {
+ Introspector child = obj;
+ if (!parser.getLoader().getVersion().equals(obj.getVersion())) {
+ String json = obj.marshal(false);
+ child = parser.getLoader().unmarshal(parser.getEntity().getName(), json);
+ }
+
+ //wrap the child object in its parents
+ parentList.add(child.getUnderlyingObject());
+ }
+
+ final Introspector eventObject;
+
+ //convert to most resent version
+ if (!parser.getLoader().getVersion().equals(currentVersionLoader.getVersion())) {
+ String json = "";
+ if (parser.getTopEntity().equals(parser.getEntity())) {
+ //convert the parent object passed in
+ json = obj.marshal(false);
+ eventObject = currentVersionLoader.unmarshal(obj.getName(), json);
+ } else {
+ //convert the object created in the parser
+ json = parser.getTopEntity().marshal(false);
+ eventObject = currentVersionLoader.unmarshal(parser.getTopEntity().getName(), json);
+ }
+ } else {
+ if (parser.getTopEntity().equals(parser.getEntity())) {
+ //take the top level parent object passed in
+ eventObject = obj;
+ } else {
+ //take the wrapped child objects (ogres are like onions)
+ eventObject = parser.getTopEntity();
+ }
+ }
+
+ final NotificationEvent event = new NotificationEvent(currentVersionLoader, eventHeader, eventObject);
+ events.add(event);
+ } catch (AAIUnknownObjectException e) {
+ throw new RuntimeException("Fatal error - notification-event-header object not found!");
+ } catch (AAIUnmarshallingException e) {
+ LOGGER.error("Unmarshalling error occurred while generating UEBNotification", e);
+ }
+ }
+
+ /**
+ * Trigger events.
+ *
+ * @throws AAIException the AAI exception
+ */
+ public void triggerEvents() throws AAIException {
+ for (NotificationEvent event : events) {
+ event.trigger();
+ }
+ events.clear();
+ }
+
+ public List<NotificationEvent> getEvents() {
+ return this.events;
+ }
+
+
+
+}
diff --git a/aai-traversal/src/main/java/org/openecomp/aai/rest/util/EchoResponse.java b/aai-traversal/src/main/java/org/openecomp/aai/rest/util/EchoResponse.java
new file mode 100644
index 0000000..6d01435
--- /dev/null
+++ b/aai-traversal/src/main/java/org/openecomp/aai/rest/util/EchoResponse.java
@@ -0,0 +1,121 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * org.openecomp.aai
+ * ================================================================================
+ * Copyright (C) 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=========================================================
+ */
+
+package org.openecomp.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.openecomp.aai.exceptions.AAIException;
+import org.openecomp.aai.logging.ErrorLogHelper;
+import org.openecomp.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-traversal/src/main/java/org/openecomp/aai/rest/util/LogFormatTools.java b/aai-traversal/src/main/java/org/openecomp/aai/rest/util/LogFormatTools.java
new file mode 100644
index 0000000..d6fcd67
--- /dev/null
+++ b/aai-traversal/src/main/java/org/openecomp/aai/rest/util/LogFormatTools.java
@@ -0,0 +1,36 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * org.openecomp.aai
+ * ================================================================================
+ * Copyright (C) 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=========================================================
+ */
+
+package org.openecomp.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-traversal/src/main/java/org/openecomp/aai/rest/util/ValidateEncoding.java b/aai-traversal/src/main/java/org/openecomp/aai/rest/util/ValidateEncoding.java
new file mode 100644
index 0000000..a09a317
--- /dev/null
+++ b/aai-traversal/src/main/java/org/openecomp/aai/rest/util/ValidateEncoding.java
@@ -0,0 +1,160 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * org.openecomp.aai
+ * ================================================================================
+ * Copyright (C) 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=========================================================
+ */
+
+package org.openecomp.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;
+ }
+}
diff --git a/aai-traversal/src/main/java/org/openecomp/aai/transforms/Converter.java b/aai-traversal/src/main/java/org/openecomp/aai/transforms/Converter.java
new file mode 100644
index 0000000..44a0222
--- /dev/null
+++ b/aai-traversal/src/main/java/org/openecomp/aai/transforms/Converter.java
@@ -0,0 +1,25 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * org.openecomp.aai
+ * ================================================================================
+ * Copyright (C) 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=========================================================
+ */
+
+package org.openecomp.aai.transforms;
+
+public interface Converter {
+ String convert(String input);
+}
diff --git a/aai-traversal/src/main/java/org/openecomp/aai/transforms/LowerCamelToLowerHyphenConverter.java b/aai-traversal/src/main/java/org/openecomp/aai/transforms/LowerCamelToLowerHyphenConverter.java
new file mode 100644
index 0000000..a31da05
--- /dev/null
+++ b/aai-traversal/src/main/java/org/openecomp/aai/transforms/LowerCamelToLowerHyphenConverter.java
@@ -0,0 +1,34 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * org.openecomp.aai
+ * ================================================================================
+ * Copyright (C) 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=========================================================
+ */
+
+package org.openecomp.aai.transforms;
+
+import com.google.common.base.CaseFormat;
+
+public class LowerCamelToLowerHyphenConverter implements Converter {
+
+ @Override
+ public String convert(String input) {
+ if(input == null){
+ return null;
+ }
+ return CaseFormat.LOWER_CAMEL.to(CaseFormat.LOWER_HYPHEN, input);
+ }
+}
diff --git a/aai-traversal/src/main/java/org/openecomp/aai/transforms/LowerHyphenToLowerCamelConverter.java b/aai-traversal/src/main/java/org/openecomp/aai/transforms/LowerHyphenToLowerCamelConverter.java
new file mode 100644
index 0000000..784adbe
--- /dev/null
+++ b/aai-traversal/src/main/java/org/openecomp/aai/transforms/LowerHyphenToLowerCamelConverter.java
@@ -0,0 +1,81 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * org.openecomp.aai
+ * ================================================================================
+ * Copyright (C) 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=========================================================
+ */
+
+package org.openecomp.aai.transforms;
+
+/**
+ * <b>LowerHyphenToLowerCamelConverter</b> is the converter to use
+ * for converting from the lower hyphen to lower camel case
+ * <p>
+ * Examples:
+ * lower-test => lowerTest
+ * lower-Test => lowerTest
+ * lowerTest => lowerTest
+ * lower-test-val => lowerTestVal
+ * <p>
+ *
+ */
+public class LowerHyphenToLowerCamelConverter implements Converter {
+
+ /**
+ * Converts the dash formatted string into a camel case string
+ * Ensure that the capitalization is not lost during this conversion
+ * <p>
+ * Loops through each character in the string
+ * checks if the current character is '-' and if it is then sets the
+ * boolean isPreviousCharDash to true and continues to the next iteration
+ * If the character is not '-', then checks if the previous character is dash
+ * If it is, then it will upper case the current character and appends to the builder
+ * Otherwise, it will just append the current character without any modification
+ *
+ * @param input the input string to convert to camel case
+ * @return a string that is converted to camel case
+ * if the input is null, then it returns null
+ */
+ @Override
+ public String convert(String input) {
+ if(input == null){
+ return null;
+ }
+
+ int size = input.length();
+ StringBuilder builder = new StringBuilder(size);
+
+ boolean isPreviousCharDash = false;
+
+ for(int index = 0; index < size; ++index){
+ char ch = input.charAt(index);
+
+ if(ch == '-'){
+ isPreviousCharDash = true;
+ continue;
+ }
+ if(isPreviousCharDash){
+ builder.append(Character.toUpperCase(ch));
+ isPreviousCharDash = false;
+ } else{
+ builder.append(ch);
+ }
+ }
+
+ return builder.toString();
+ }
+
+}
diff --git a/aai-traversal/src/main/java/org/openecomp/aai/transforms/MapTraverser.java b/aai-traversal/src/main/java/org/openecomp/aai/transforms/MapTraverser.java
new file mode 100644
index 0000000..7695240
--- /dev/null
+++ b/aai-traversal/src/main/java/org/openecomp/aai/transforms/MapTraverser.java
@@ -0,0 +1,87 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * org.openecomp.aai
+ * ================================================================================
+ * Copyright (C) 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=========================================================
+ */
+
+package org.openecomp.aai.transforms;
+
+
+import joptsimple.internal.Objects;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+public class MapTraverser {
+
+ private Converter converter;
+
+ public MapTraverser(Converter converter){
+ this.converter = converter;
+ }
+
+ public Map<String, Object> convertKeys(Map<String, Object> map){
+
+ Objects.ensureNotNull(map);
+
+ Map<String, Object> modifiedMap = new HashMap<String, Object>();
+ convertKeys(map, modifiedMap);
+
+ return modifiedMap;
+ }
+
+ private Map<String, Object> convertKeys(Map<String, Object> original, Map<String, Object> modified){
+
+ for(Map.Entry<String, Object> entry : original.entrySet()){
+ String key = entry.getKey();
+ key = converter.convert(key);
+ Object value = entry.getValue();
+ if(value instanceof Map){
+ modified.put(key, convertKeys((Map<String, Object>)value, new HashMap<String, Object>()));
+ } else if(value instanceof List){
+ modified.put(key, convertKeys((List<Object>) value));
+ } else {
+ modified.put(key, value);
+ }
+ }
+
+ return modified;
+ }
+
+ public List<Object> convertKeys(List<Object> list){
+
+ List<Object> modifiedList = new ArrayList<Object>();
+ if(list != null && list.size() > 0){
+
+ for(Object o : list){
+ if(o instanceof Map){
+ Map<String, Object> map = (Map<String, Object>) o;
+ modifiedList.add(convertKeys(map));
+ } else if(o instanceof List){
+ List<Object> l = (List<Object>) o;
+ modifiedList.add(convertKeys(l));
+ } else {
+ modifiedList.add(o);
+ }
+ }
+ }
+
+ return modifiedList;
+ }
+}
diff --git a/aai-traversal/src/main/java/org/openecomp/aai/util/AAIAppServletContextListener.java b/aai-traversal/src/main/java/org/openecomp/aai/util/AAIAppServletContextListener.java
new file mode 100644
index 0000000..97b7edb
--- /dev/null
+++ b/aai-traversal/src/main/java/org/openecomp/aai/util/AAIAppServletContextListener.java
@@ -0,0 +1,104 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * org.openecomp.aai
+ * ================================================================================
+ * Copyright (C) 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=========================================================
+ */
+
+package org.openecomp.aai.util;
+
+import java.io.IOException;
+
+import javax.servlet.ServletContextEvent;
+import javax.servlet.ServletContextListener;
+
+import org.apache.activemq.broker.BrokerService;
+
+import org.openecomp.aai.dbmap.AAIGraph;
+import org.openecomp.aai.exceptions.AAIException;
+import org.openecomp.aai.introspection.ModelInjestor;
+import org.openecomp.aai.logging.ErrorLogHelper;
+import com.att.eelf.configuration.EELFLogger;
+import com.att.eelf.configuration.EELFManager;
+
+public class AAIAppServletContextListener implements ServletContextListener {
+
+ private static final EELFLogger LOGGER = EELFManager.getInstance().getLogger(AAIAppServletContextListener.class.getName());
+
+ private BrokerService broker = new BrokerService();
+
+ /**
+ * Destroys Context
+ *
+ * @param arg0 the ServletContextEvent
+ */
+ public void contextDestroyed(ServletContextEvent arg0) {
+ LOGGER.info("AAIGraph shutting down");
+ AAIGraph.getInstance().graphShutdown();
+ LOGGER.info("AAIGraph shutdown");
+
+ try {
+ broker.stop();
+ } catch (Exception e) {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ }
+ }
+
+ /**
+ * Initializes Context
+ *
+ * @param arg0 the ServletContextEvent
+ */
+ public void contextInitialized(ServletContextEvent arg0) {
+ System.setProperty("org.openecomp.aai.serverStarted", "false");
+ LOGGER.info("***AAI Server initialization started...");
+
+ try {
+ LOGGER.info("Loading aaiconfig.properties");
+ AAIConfig.init();
+
+ LOGGER.info("Loading error.properties");
+ ErrorLogHelper.loadProperties();
+
+ LOGGER.info("Loading graph database");
+
+ AAIGraph.getInstance();
+ ModelInjestor.getInstance();
+
+ // Jsm internal broker for aai events
+ broker = new BrokerService();
+ broker.addConnector("tcp://localhost:61446");
+ broker.setPersistent(false);
+ broker.setUseJmx(false);
+ broker.setSchedulerSupport(false);
+ broker.start();
+
+ LOGGER.info("A&AI Server initialization succcessful.");
+ System.setProperty("org.openecomp.aai.serverStarted", "true");
+
+ } catch (AAIException e) {
+ ErrorLogHelper.logException(e);
+ throw new RuntimeException("AAIException caught while initializing A&AI server", e);
+ } catch (IOException e) {
+ ErrorLogHelper.logError("AAI_4000", e.getMessage());
+ throw new RuntimeException("IOException caught while initializing A&AI server", e);
+ } catch (Exception e) {
+ LOGGER.error("Unknown failure while initializing A&AI Server", e);
+ throw new RuntimeException("Unknown failure while initializing A&AI server", e);
+ }
+ }
+}
diff --git a/aai-traversal/src/main/java/org/openecomp/aai/util/RestURL.java b/aai-traversal/src/main/java/org/openecomp/aai/util/RestURL.java
new file mode 100644
index 0000000..7c70929
--- /dev/null
+++ b/aai-traversal/src/main/java/org/openecomp/aai/util/RestURL.java
@@ -0,0 +1,704 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * org.openecomp.aai
+ * ================================================================================
+ * Copyright (C) 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=========================================================
+ */
+
+package org.openecomp.aai.util;
+
+import java.io.UnsupportedEncodingException;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.LinkedHashMap;
+
+import org.apache.tinkerpop.gremlin.structure.Direction;
+import org.apache.tinkerpop.gremlin.structure.Edge;
+import org.springframework.web.util.UriUtils;
+
+import org.openecomp.aai.domain.model.AAIResource;
+import org.openecomp.aai.domain.model.AAIResourceKey;
+import org.openecomp.aai.domain.model.AAIResourceKeys;
+import org.openecomp.aai.domain.model.AAIResources;
+import org.openecomp.aai.exceptions.AAIException;
+import org.openecomp.aai.extensions.AAIExtensionMap;
+import org.openecomp.aai.ingestModel.DbMaps;
+import org.openecomp.aai.ingestModel.IngestModelMoxyOxm;
+import com.google.common.base.CaseFormat;
+import com.thinkaurelius.titan.core.TitanEdge;
+import com.thinkaurelius.titan.core.TitanTransaction;
+import com.thinkaurelius.titan.core.TitanVertex;
+
+public class RestURL {
+
+
+ /*
+ * method returns a REST URL for the given node based on its nodetype and key
+ * information
+ */
+
+ /**
+ * Gets the.
+ *
+ * @param graph the graph
+ * @param node the node
+ * @param apiVersion the api version
+ * @param isLegacyVserverUEB the is legacy vserver UEB
+ * @param isCallbackurl the is callbackurl
+ * @return the string
+ * @throws AAIException the AAI exception
+ * @throws UnsupportedEncodingException the unsupported encoding exception
+ */
+ public static String get(TitanTransaction graph, TitanVertex node, String apiVersion, Boolean isLegacyVserverUEB, Boolean isCallbackurl) throws AAIException, UnsupportedEncodingException
+ {
+ String nodeType = node.<String>property("aai-node-type").orElse(null);
+ String url = "";
+ String currentNodeType = nodeType;
+ Boolean noMoreDependentNodes = true;
+ TitanVertex currentNode = node;
+
+ // if the caller supplies an apiVersion we'll use it, otherwise we'll just
+ // reflect back from the called URI
+ if (apiVersion == null) {
+ apiVersion = AAIApiVersion.get();
+ }
+
+ String nodeURI = null;
+ if (Boolean.parseBoolean(AAIConfig.get("aai.use.unique.key", "false")))
+ nodeURI = node.<String>property("aai-unique-key").orElse(null);
+
+ if (nodeURI != null && !nodeURI.equals("")) {
+ if (isCallbackurl) {
+ url = AAIConfig.get(AAIConstants.AAI_GLOBAL_CALLBACK_URL) + apiVersion + "/" + nodeURI;
+ return url;
+ } else {
+ url = AAIApiServerURLBase.get() + apiVersion + "/" + nodeURI;
+ return url;
+ }
+ }
+
+ // TODO
+ DbMaps dbMaps = IngestModelMoxyOxm.dbMapsContainer.get(AAIConfig.get(AAIConstants.AAI_DEFAULT_API_VERSION_PROP));
+
+ // add the url component for the dependent on nodes for the node passed in
+ while (noMoreDependentNodes) {
+ Collection <String> depNodeTypeColl = dbMaps.NodeDependencies.get(currentNodeType);
+ Iterator <String> depNodeTypeListIterator = (Iterator<String>) depNodeTypeColl.iterator();
+ if (!depNodeTypeListIterator.hasNext()) {
+ noMoreDependentNodes = false;
+ break;
+ }
+
+ // Look for IN edges for the current Node and find its Parent - and make it the current Node
+ boolean foundParent = false;
+ Iterator <Edge> inEdges = currentNode.edges(Direction.IN);
+ while( inEdges.hasNext() ){
+ TitanEdge inEdge = (TitanEdge) inEdges.next();
+ Boolean inEdgeIsParent = inEdge.<Boolean>property("isParent").orElse(null);
+ if( inEdgeIsParent != null && inEdgeIsParent ){
+ foundParent = true;
+ currentNode = (TitanVertex) inEdge.otherVertex(currentNode);
+ break;
+ }
+ }
+
+ if (foundParent == false) {
+ break;
+ }
+
+ // find the key(s) and add to the url
+ // first see what type of node the parent is - note some nodes can have one of many kinds of parents
+ String depNodeType = currentNode.<String>property("aai-node-type").orElse(null);
+ Collection <String> keyProps = dbMaps.NodeKeyProps.get(depNodeType);
+ Iterator <String> keyPropI = keyProps.iterator();
+
+ String nodeUrl = null;
+ String depNodeTypePlural = dbMaps.NodePlural.get(depNodeType);
+
+ if (depNodeTypePlural != null)
+ {
+ nodeUrl = depNodeTypePlural + "/" + depNodeType + "/";
+ }
+
+ while (keyPropI.hasNext()) {
+ Object nodeKey = currentNode.<Object>property(keyPropI.next()).orElse(null);
+ nodeUrl += RestURLEncoder.encodeURL(nodeKey.toString()) + "/";
+ }
+
+ currentNodeType = depNodeType;
+
+ url = nodeUrl + url;
+ }
+ // use the name space of the highest level of unique node since lots of children node types
+ // are common ex. l-interface is in the path for pserver and vpe
+ String urlNamespace = dbMaps.NodeNamespace.get(currentNodeType) + "/";
+ urlNamespace = CaseFormat.UPPER_CAMEL.to(CaseFormat.LOWER_HYPHEN, urlNamespace);
+
+ // add the url component for the node passed in
+ Collection <String> keyProps = dbMaps.NodeKeyProps.get(nodeType);
+ Iterator <String> keyPropI = keyProps.iterator();
+
+ String nodeUrl = null;
+ String nodeTypePlural = "";
+ nodeTypePlural = dbMaps.NodePlural.get(nodeType);
+
+
+ if (nodeTypePlural != null && !nodeTypePlural.equals("")){
+ nodeUrl = nodeTypePlural + "/" + nodeType + "/";
+ } else {
+ nodeUrl = nodeType + "/";
+ }
+
+ if (nodeType.equals("ipaddress")) { // this has 2 keys but API only uses port-or -address in URL
+ String nodeKey = node.<String>property("port-or-interface").orElse(null);
+ nodeUrl += RestURLEncoder.encodeURL(nodeKey) + "/";
+ } else {
+ while (keyPropI.hasNext()) {
+ Object nodeKey = node.<Object>property(keyPropI.next()).orElse(null);
+ nodeUrl += RestURLEncoder.encodeURL(nodeKey.toString()) + "/";
+ }
+ }
+ if (isCallbackurl) {
+ url = AAIConfig.get(AAIConstants.AAI_GLOBAL_CALLBACK_URL) + apiVersion + "/" + urlNamespace + url + nodeUrl;
+ } else {
+ url = AAIApiServerURLBase.get() + apiVersion + "/" + urlNamespace + url + nodeUrl;
+ }
+ return url;
+ }
+
+ /**
+ * Gets the search url.
+ *
+ * @param graph the graph
+ * @param node the node
+ * @param apiVersion the api version
+ * @return the search url
+ * @throws AAIException the AAI exception
+ * @throws UnsupportedEncodingException the unsupported encoding exception
+ */
+ public static String getSearchUrl(TitanTransaction graph, TitanVertex node, String apiVersion) throws AAIException, UnsupportedEncodingException
+ {
+ String nodeType = node.<String>property("aai-node-type").orElse(null);
+ String url = "";
+ String currentNodeType = nodeType;
+ Boolean noMoreDependentNodes = true;
+ TitanVertex currentNode = node;
+ Boolean hasCloudRegion = false;
+
+ // if the caller supplies an apiVersion we'll use it, otherwise we'll just
+ // reflect back from the called URI
+ if (apiVersion == null) {
+ apiVersion = AAIApiVersion.get();
+ }
+
+ DbMaps dbMaps = IngestModelMoxyOxm.dbMapsContainer.get(AAIConfig.get(AAIConstants.AAI_DEFAULT_API_VERSION_PROP));
+
+ // add the url component for the dependent on nodes for the node passed in
+ while (noMoreDependentNodes) {
+ Collection <String> depNodeTypeColl = dbMaps.NodeDependencies.get(currentNodeType);
+ Iterator <String> depNodeTypeListIterator = (Iterator<String>) depNodeTypeColl.iterator();
+ if (!depNodeTypeListIterator.hasNext()) {
+ noMoreDependentNodes = false;
+ break;
+ }
+
+ // Look for IN edges for the current Node and find its Parent - and make it the current Node
+ boolean foundParent = false;
+ Iterator <Edge> inEdges = currentNode.edges(Direction.IN);
+ while( inEdges.hasNext() ){
+ TitanEdge inEdge = (TitanEdge) inEdges.next();
+ Boolean inEdgeIsParent = inEdge.<Boolean>property("isParent").orElse(null);
+ if( inEdgeIsParent != null && inEdgeIsParent ){
+ foundParent = true;
+ currentNode = inEdge.otherVertex(currentNode);
+ break;
+ }
+ }
+
+ if (foundParent == false) {
+ break;
+ }
+
+ // find the key(s) and add to the url
+ // first see what type of node the parent is - note some nodes can have one of many kinds of parents
+ String depNodeType = currentNode.<String>property("aai-node-type").orElse(null);
+ Collection <String> keyProps = dbMaps.NodeKeyProps.get(depNodeType);
+ Iterator <String> keyPropI = keyProps.iterator();
+
+ String nodeUrl = null;
+ String depNodeTypePlural = dbMaps.NodePlural.get(depNodeType);
+
+ if (depNodeTypePlural != null)
+ nodeUrl = depNodeTypePlural + "/" + depNodeType + "/";
+
+ while (keyPropI.hasNext()) {
+ Object nodeKey = currentNode.<Object>property(keyPropI.next()).orElse(null);
+ nodeUrl += RestURLEncoder.encodeURL(nodeKey.toString()) + "/";
+ }
+
+ currentNodeType = depNodeType;
+
+ url = nodeUrl + url;
+ }
+ // use the name space of the highest level of unique node since lots of children node types
+ // are common ex. l-interface is in the path for pserver and vpe
+ String urlNamespace = dbMaps.NodeNamespace.get(currentNodeType) + "/";
+ urlNamespace = CaseFormat.UPPER_CAMEL.to(CaseFormat.LOWER_HYPHEN, urlNamespace);
+
+ // add the url component for the node passed in
+ Collection <String> keyProps = dbMaps.NodeKeyProps.get(nodeType);
+ Iterator <String> keyPropI = keyProps.iterator();
+
+ String nodeUrl = null;
+ String nodeTypePlural = "";
+ nodeTypePlural = dbMaps.NodePlural.get(nodeType);
+
+ if (nodeTypePlural != null && !nodeTypePlural.equals(""))
+ nodeUrl = nodeTypePlural + "/" + nodeType + "/";
+ else
+ nodeUrl = nodeType + "/";
+
+ if (nodeType.equals("ipaddress")) { // this has 2 keys but API only uses port-or -address in URL
+ String nodeKey = node.<String>property("port-or-interface").orElse(null);
+ nodeUrl += RestURLEncoder.encodeURL(nodeKey) + "/";
+ } else {
+ while (keyPropI.hasNext()) {
+ Object nodeKey = node.<Object>property(keyPropI.next()).orElse(null);
+ nodeUrl += RestURLEncoder.encodeURL(nodeKey.toString()) + "/";
+ }
+ }
+
+ String nodeVersion = dbMaps.NodeVersionInfoMap.get(nodeType);
+ String urlVersion = null;
+ int nodeVerNum = Integer.parseInt(nodeVersion.substring(1));
+ int apiVerNum = Integer.parseInt(apiVersion.substring(1));
+
+ if (hasCloudRegion) {
+ if (apiVerNum < 7)
+ urlVersion = "v7"; // or set to the latest version?
+ else
+ urlVersion = apiVersion;
+ } else {
+ if (nodeVerNum == apiVerNum || nodeVerNum < apiVerNum)
+ urlVersion = apiVersion;
+ else
+ urlVersion = nodeVersion;
+ }
+ url = AAIApiServerURLBase.get() + urlVersion + "/" + urlNamespace + url + nodeUrl;
+ //remove the trailing "/"
+ url = url.substring(0, url.length()-1);
+ return url;
+ }
+
+ /**
+ * Gets the.
+ *
+ * @param graph the graph
+ * @param node the node
+ * @return the string
+ * @throws AAIException the AAI exception
+ * @throws UnsupportedEncodingException the unsupported encoding exception
+ */
+ public static String get(TitanTransaction graph, TitanVertex node) throws AAIException, UnsupportedEncodingException
+ {
+ return get(graph, node, null, false, false);
+ }
+
+ /**
+ * Gets the.
+ *
+ * @param graph the graph
+ * @param node the node
+ * @param apiVersion the api version
+ * @return the string
+ * @throws AAIException the AAI exception
+ * @throws UnsupportedEncodingException the unsupported encoding exception
+ */
+ public static String get(TitanTransaction graph, TitanVertex node, String apiVersion) throws AAIException, UnsupportedEncodingException
+ {
+ return get(graph, node, apiVersion, false, false);
+ }
+
+ /**
+ * Gets the.
+ *
+ * @param graph the graph
+ * @param node the node
+ * @param apiVersion the api version
+ * @param isLegacyVserverUEB the is legacy vserver UEB
+ * @return the string
+ * @throws AAIException the AAI exception
+ * @throws UnsupportedEncodingException the unsupported encoding exception
+ */
+ public static String get(TitanTransaction graph, TitanVertex node, String apiVersion, Boolean isLegacyVserverUEB) throws AAIException, UnsupportedEncodingException
+ {
+ return get(graph, node, apiVersion, isLegacyVserverUEB, false);
+ }
+
+ /**
+ * Gets the key hashes.
+ *
+ * @param graph the graph
+ * @param node the node
+ * @return the key hashes
+ * @throws AAIException the AAI exception
+ * @throws UnsupportedEncodingException the unsupported encoding exception
+ */
+ public static LinkedHashMap<String, Object> getKeyHashes(TitanTransaction graph, TitanVertex node) throws AAIException, UnsupportedEncodingException
+ {
+ return getKeyHashes(graph, node, null);
+ }
+
+ /*
+ * method returns a Hash of Hashes for each parents keys for the given node based on its nodetype
+ * Special cases for REST URLs:
+ * - old URLS for vserver, ipaddress and volume node types for v2/v3
+ * - images, flavor, vnic and l-interface node types will return new url
+ * - nodetypes with multiple keys such as service capability
+ * - nodetypes with multiple keys such as ipaddress where we use one key in the URL
+ * - cvlan-tags and *list nodetypes - have special or no plurals - they get handled via the hash Map
+ */
+
+ /**
+ * Gets the key hashes.
+ *
+ * @param graph the graph
+ * @param node the node
+ * @param apiVersion the api version
+ * @return the key hashes
+ * @throws AAIException the AAI exception
+ * @throws UnsupportedEncodingException the unsupported encoding exception
+ */
+ public static LinkedHashMap <String,Object> getKeyHashes(TitanTransaction graph, TitanVertex node, String apiVersion) throws AAIException, UnsupportedEncodingException
+ {
+ String nodeType = node.<String>property("aai-node-type").orElse(null);
+ Boolean noMoreDependentNodes = true;
+ TitanVertex currentNode = node;
+
+ if (apiVersion == null || apiVersion.equals("")) {
+ apiVersion = AAIConfig.get(AAIConstants.AAI_DEFAULT_API_VERSION_PROP);
+ }
+
+ DbMaps dbMaps = IngestModelMoxyOxm.dbMapsContainer.get(apiVersion);
+
+ // Hash of hashes of keys for each node and its ancestry
+ LinkedHashMap <String,Object> returnHash = new LinkedHashMap <String,Object> ();
+
+ // create the hash for the keys for the node passed in
+ HashMap <String,Object> thisNodeHash = new HashMap <String,Object> ();
+ Collection <String> keyProps = dbMaps.NodeKeyProps.get(nodeType);
+ Iterator <String> keyPropI = keyProps.iterator();
+
+ if (nodeType.equals("ipaddress")) { // this has 2 keys but API only uses port-or -address in URL
+ String nodeKeyValue = node.<String>property("port-or-interface").orElse(null);
+ thisNodeHash.put("port-or-interface", nodeKeyValue);
+ } else {
+ while (keyPropI.hasNext()) {
+ String nodeKeyName = keyPropI.next();
+ Object nodeKeyValue = node.<Object>property(nodeKeyName).orElse(null);
+ thisNodeHash.put(nodeKeyName, nodeKeyValue);
+ nodeKeyName = nodeType + "." + nodeKeyName;
+ }
+ }
+ returnHash.putAll(thisNodeHash);
+
+ // create and add the hashes for the dependent nodes for the node passed in
+ while (noMoreDependentNodes) {
+// Collection <String> depNodeTypeColl = DbRules.NodeDependencies.get(currentNodeType);
+// Iterator <String> depNodeTypeListIterator = (Iterator<String>) depNodeTypeColl.iterator();
+ HashMap <String,Object> depNodeHash = new HashMap <String,Object> ();
+//
+// if (!depNodeTypeListIterator.hasNext()) {
+// noMoreDependentNodes = false;
+// break;
+// }
+
+ boolean foundParent = false;
+
+ // Look for IN edges for the current Node and find its Parent - and make it the current Node
+ Iterator <Edge> inEdges = currentNode.edges(Direction.IN);
+ while( inEdges.hasNext() ){
+ TitanEdge inEdge = (TitanEdge) inEdges.next();
+ Boolean inEdgeIsParent = inEdge.<Boolean>property("isParent").orElse(null);
+ if( inEdgeIsParent != null && inEdgeIsParent ){
+ currentNode = inEdge.otherVertex(currentNode);
+ foundParent = true;
+ break;
+ }
+ }
+ if (foundParent == false) {
+ break;
+ }
+
+ // find the key(s) and add to the url
+ // first see what type of node the parent is - note some nodes can have one of many kinds of parents
+ String depNodeType = currentNode.<String>property("aai-node-type").orElse(null);
+ keyProps = dbMaps.NodeKeyProps.get(depNodeType);
+ keyPropI = keyProps.iterator();
+
+ while (keyPropI.hasNext()) {
+ String nodeKeyName = keyPropI.next();
+ Object nodeKeyValue = currentNode.<Object>property(nodeKeyName).orElse(null);
+ nodeKeyName = depNodeType + "." + nodeKeyName;
+ // key name will be like tenant.tenant-id
+
+ depNodeHash.put(nodeKeyName, nodeKeyValue);
+ }
+ returnHash.putAll(depNodeHash);
+ }
+
+ return returnHash;
+ }
+
+ /*
+ * method returns a Hash of Hashes for each parents keys for the given node based on its nodeURI
+ * Special cases for REST URLs:
+ * - images, flavor, vnic and l-interface node types will return new url
+ * - nodetypes with multiple keys such as service capability
+ * - nodetypes with multiple keys such as ipaddress where we use one key in the URL
+ * - cvlan-tags and *list nodetypes - have special or no plurals - they get handled via the hash Map
+ */
+
+ /**
+ * Gets the key hashes.
+ *
+ * @param nodeURI the node URI
+ * @return the key hashes
+ * @throws AAIException the AAI exception
+ * @throws UnsupportedEncodingException the unsupported encoding exception
+ */
+ public static LinkedHashMap <String,Object> getKeyHashes(String nodeURI) throws AAIException, UnsupportedEncodingException
+ {
+ return getKeyHashes(nodeURI, null);
+
+ }
+
+ /**
+ * Gets the key hashes.
+ *
+ * @param nodeURI the node URI
+ * @param apiVersion the api version
+ * @return the key hashes
+ * @throws AAIException the AAI exception
+ * @throws UnsupportedEncodingException the unsupported encoding exception
+ */
+ public static LinkedHashMap <String,Object> getKeyHashes(String nodeURI, String apiVersion) throws AAIException, UnsupportedEncodingException
+ {
+
+ if (apiVersion == null || apiVersion.equals(""))
+ apiVersion = AAIConfig.get(AAIConstants.AAI_DEFAULT_API_VERSION_PROP);
+
+ DbMaps dbMaps = IngestModelMoxyOxm.dbMapsContainer.get(apiVersion);
+
+ // Hash of hashes of keys for each node and its ancestry
+ LinkedHashMap <String,Object> returnHash = new LinkedHashMap <String,Object> ();
+
+ String path = nodeURI.replaceFirst("^/", "");
+ Path p = Paths.get(path);
+ int index = p.getNameCount() - 2; // index of where we expect the node type to be
+
+ // if the node type has one key
+ String currentNodeType = p.getName(index).toString();
+ // if the node type has two keys - this assumes max 2 keys
+ if (!dbMaps.NodeKeyProps.containsKey(currentNodeType))
+ currentNodeType = p.getName(--index).toString();
+
+ // create the hash for the keys for the node passed in
+ LinkedHashMap <String,Object> thisNodeHash = new LinkedHashMap <String,Object> ();
+ Collection <String> keyProps = dbMaps.NodeKeyProps.get(currentNodeType);
+ Iterator <String> keyPropI = keyProps.iterator();
+
+ if (currentNodeType.equals("ipaddress")) { // this has 2 keys but API only uses port-or -address in URL
+ String nodeKeyValue = p.getName(index + 1).toString();
+ thisNodeHash.put("port-or-interface", nodeKeyValue);
+ } else {
+ int j = 1;
+ while (keyPropI.hasNext()) {
+ String nodeKeyName = currentNodeType + "." + keyPropI.next();
+ String nodeKeyValue = p.getName(index + j++).toString();
+ thisNodeHash.put(nodeKeyName, nodeKeyValue);
+ }
+ }
+ returnHash.putAll(thisNodeHash);
+ if (!currentNodeType.contains("-list"))
+ index -= 3;
+ else
+ index -= 2; // no plural in this case
+
+
+ // create and add the hashes for the dependent nodes for the node passed in
+ LinkedHashMap <String,Object> depNodeHash = new LinkedHashMap <String,Object> ();
+ String depNodeType = null;
+ while (index >= 2) {
+ if (depNodeType == null) depNodeType = p.getName(index).toString();
+ //System.out.println("index=" + index);
+ // if the node type has one key
+ currentNodeType = p.getName(index).toString();
+ // if the node type has two keys - this assumes max 2 keys
+ if (!dbMaps.NodeKeyProps.containsKey(currentNodeType))
+ currentNodeType = p.getName(--index).toString();
+
+ keyProps = dbMaps.NodeKeyProps.get(currentNodeType);
+ keyPropI = keyProps.iterator();
+
+ if (currentNodeType.equals("ipaddress")) { // this has 2 keys but API only uses port-or -address in URL
+ String nodeKeyValue = p.getName(index + 1).toString();
+ depNodeHash.put("port-or-interface", nodeKeyValue);
+ } else {
+ int j = 1;
+ while (keyPropI.hasNext()) {
+ String nodeKeyName = currentNodeType + "." + keyPropI.next();
+ String nodeKeyValue = p.getName(index + j++).toString();
+ depNodeHash.put(nodeKeyName, nodeKeyValue);
+ }
+ }
+
+ if (!currentNodeType.contains("-list"))
+ index -= 3;
+ else
+ index -= 2; // no plural in this case
+ }
+ if (depNodeType != null)
+ returnHash.putAll(depNodeHash);
+
+ return returnHash;
+ }
+
+ /**
+ * Parses the uri.
+ *
+ * @param allKeys the all keys
+ * @param keyList the key list
+ * @param uri the uri
+ * @param aaiExtMap the aai ext map
+ * @return the AAI resource
+ * @throws UnsupportedEncodingException the unsupported encoding exception
+ * @throws AAIException the AAI exception
+ */
+ public static AAIResource parseUri(HashMap<String, String> allKeys, LinkedHashMap<String,
+ LinkedHashMap<String,Object>> keyList, String uri,
+ AAIExtensionMap aaiExtMap) throws UnsupportedEncodingException, AAIException {
+
+ String[] ps = uri.split("/");
+
+ String apiVersion = ps[0];
+ aaiExtMap.setApiVersion(apiVersion);
+
+ AAIResources aaiResources = org.openecomp.aai.ingestModel.IngestModelMoxyOxm.aaiResourceContainer.get(apiVersion);
+
+ String namespace = ps[1];
+
+ aaiExtMap.setNamespace(namespace);
+
+ // /vces/vce/{vnf-id}/port-groups/port-group/{port-group-id}/cvlan-tag-entry/cvlan-tag/{cvlan-tag}
+
+ // FullName -> /Vces/Vce/PortGroups/PortGroup/CvlanTagEntry/CvlanTag <-
+
+ String fullResourceName = "/" + CaseFormat.LOWER_HYPHEN.to(CaseFormat.UPPER_CAMEL, namespace);
+ AAIResources theseResources = new AAIResources();
+
+ StringBuffer thisUri = new StringBuffer();
+
+ // the URI config option in the props file has a trailing slash
+ thisUri.append("/" + namespace);
+
+ boolean firstNode = true;
+
+ AAIResource lastResource = null;
+
+ for (int i = 2; i < ps.length; i++) {
+
+ AAIResource aaiRes;
+ StringBuffer tmpResourceName = new StringBuffer();
+
+ String p = ps[i];
+ String seg =ps[i];
+
+ thisUri.append("/" + seg);
+
+ tmpResourceName.append(fullResourceName);
+
+ if (seg.equals("cvlan-tag")) {
+ seg = "cvlan-tag-entry";
+ }
+ tmpResourceName.append("/" + CaseFormat.LOWER_HYPHEN.to(CaseFormat.UPPER_CAMEL, seg));
+
+ String tmpResource = tmpResourceName.toString();
+
+ if (aaiResources.getAaiResources().containsKey(tmpResource)) {
+ aaiRes = aaiResources.getAaiResources().get(tmpResource);
+ lastResource = aaiRes;
+ theseResources.getAaiResources().put(tmpResource, aaiRes);
+ fullResourceName = tmpResource;
+ if ("node".equals(aaiRes.getResourceType())) {
+
+ if (firstNode == true) {
+ aaiExtMap.setTopObjectFullResourceName(fullResourceName);
+ firstNode = false;
+ }
+
+ // get the keys, which will be in order and the next path segment(s)
+ AAIResourceKeys keys = aaiRes.getAaiResourceKeys();
+
+ LinkedHashMap<String,Object> subKeyList = new LinkedHashMap<String,Object>();
+
+ // there might not be another path segment
+ if ( (i + 1) < ps.length) {
+
+ for (AAIResourceKey rk : keys.getAaiResourceKey()) {
+ String p1 = ps[++i];
+ String encodedKey = p1.toString();
+ thisUri.append("/" + encodedKey);
+ String decodedKey = UriUtils.decode(p1.toString(), "UTF-8");
+ subKeyList.put(rk.getKeyName(), decodedKey);
+ }
+ keyList.put(tmpResource, subKeyList);
+ // this is the key
+ allKeys.put(tmpResource, thisUri.toString());
+ }
+ } else { // examples sit directly under the container level, should probably be query params!!!
+ if ( (i + 1) < ps.length) {
+ String p1 = ps[i+1];
+ if (p1.toString().equals("example") || p1.toString().equals("singletonExample")) {
+ LinkedHashMap<String,Object> subKeyList = new LinkedHashMap<String,Object>();
+ subKeyList.put("container|example", p1.toString());
+ keyList.put(tmpResource, subKeyList);
+ }
+ }
+ }
+ } else {
+ if (p.equals("relationship-list")) {
+ LinkedHashMap<String,Object> subKeyList = new LinkedHashMap<String,Object>();
+ subKeyList.put("container|relationship", p.toString());
+ keyList.put(tmpResource, subKeyList);
+ } else if ( p.toString().length() > 0 && !p.toString().equals("example") && !p.toString().equals("singletonExample")
+ && !p.toString().equals("relationship") ) {
+ // this means the URL will break the model, so we bail
+ throw new AAIException("AAI_3001", "bad path");
+ }
+ }
+ }
+ aaiExtMap.setUri(AAIConfig.get("aai.global.callback.url") + apiVersion + thisUri.toString());
+ aaiExtMap.setNotificationUri(AAIConfig.get("aai.global.callback.url") + AAIConfig.get("aai.notification.current.version") + thisUri.toString());
+ aaiExtMap.setFullResourceName(fullResourceName);
+ return lastResource;
+ }
+
+}
+
diff --git a/aai-traversal/src/main/java/org/openecomp/aai/util/StoreNotificationEvent.java b/aai-traversal/src/main/java/org/openecomp/aai/util/StoreNotificationEvent.java
new file mode 100644
index 0000000..996abba
--- /dev/null
+++ b/aai-traversal/src/main/java/org/openecomp/aai/util/StoreNotificationEvent.java
@@ -0,0 +1,358 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * org.openecomp.aai
+ * ================================================================================
+ * Copyright (C) 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=========================================================
+ */
+
+package org.openecomp.aai.util;
+
+import java.io.StringWriter;
+import java.text.DateFormat;
+import java.text.SimpleDateFormat;
+import java.util.Date;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.UUID;
+
+import javax.xml.bind.Marshaller;
+
+import org.apache.cxf.helpers.CastUtils;
+import org.apache.cxf.message.Message;
+import org.apache.cxf.phase.PhaseInterceptorChain;
+import org.eclipse.persistence.dynamic.DynamicEntity;
+import org.eclipse.persistence.jaxb.dynamic.DynamicJAXBContext;
+import org.json.JSONException;
+import org.json.JSONObject;
+
+import org.openecomp.aai.dmaap.AAIDmaapEventJMSProducer;
+import org.openecomp.aai.domain.notificationEvent.NotificationEvent;
+import org.openecomp.aai.exceptions.AAIException;
+import org.openecomp.aai.introspection.Introspector;
+import org.openecomp.aai.introspection.Loader;
+import org.openecomp.aai.introspection.exceptions.AAIUnknownObjectException;
+
+public class StoreNotificationEvent {
+
+ private AAIDmaapEventJMSProducer messageProducer;
+ private String fromAppId = "";
+ private String transId = "";
+
+ /**
+ * Instantiates a new store notification event.
+ */
+ public StoreNotificationEvent() {
+ this.messageProducer = new AAIDmaapEventJMSProducer();
+ Message inMessage = PhaseInterceptorChain.getCurrentMessage().getExchange().getInMessage();
+ Map<String, List<String>> headersList = CastUtils.cast((Map<?, ?>) inMessage.get(Message.PROTOCOL_HEADERS));
+ if (headersList != null) {
+ List<String> xt = headersList.get("X-TransactionId");
+ if (xt != null) {
+ for (String transIdValue : xt) {
+ transId = transIdValue;
+ }
+ }
+ List<String> fa = headersList.get("X-FromAppId");
+ if (fa != null) {
+ for (String fromAppIdValue : fa) {
+
+ fromAppId = fromAppIdValue;
+ }
+ }
+ }
+ }
+
+ /**
+ * Store event.
+ *
+ * @param eh
+ * the eh
+ * @param obj
+ * the obj
+ * @throws AAIException
+ * the AAI exception
+ */
+ public void storeEvent(NotificationEvent.EventHeader eh, Object obj) throws AAIException {
+
+ if (obj == null) {
+ throw new AAIException("AAI_7350");
+ }
+
+ org.openecomp.aai.domain.notificationEvent.ObjectFactory factory = new org.openecomp.aai.domain.notificationEvent.ObjectFactory();
+
+ org.openecomp.aai.domain.notificationEvent.NotificationEvent ne = factory.createNotificationEvent();
+
+ if (eh.getId() == null) {
+ eh.setId(genDate2() + "-" + UUID.randomUUID().toString());
+ }
+ if (eh.getTimestamp() == null) {
+ eh.setTimestamp(genDate());
+ }
+
+ // there's no default, but i think we want to put this in hbase?
+
+ if (eh.getEntityLink() == null) {
+ eh.setEntityLink("UNK");
+ }
+
+ if (eh.getAction() == null) {
+ eh.setAction("UNK");
+ }
+
+ if (eh.getEventType() == null) {
+ eh.setEventType(AAIConfig.get("aai.notificationEvent.default.eventType", "UNK"));
+ }
+
+ if (eh.getDomain() == null) {
+ eh.setDomain(AAIConfig.get("aai.notificationEvent.default.domain", "UNK"));
+ }
+
+ if (eh.getSourceName() == null) {
+ eh.setSourceName(AAIConfig.get("aai.notificationEvent.default.sourceName", "UNK"));
+ }
+
+ if (eh.getSequenceNumber() == null) {
+ eh.setSequenceNumber(AAIConfig.get("aai.notificationEvent.default.sequenceNumber", "UNK"));
+ }
+
+ if (eh.getSeverity() == null) {
+ eh.setSeverity(AAIConfig.get("aai.notificationEvent.default.severity", "UNK"));
+ }
+
+ if (eh.getVersion() == null) {
+ eh.setVersion(AAIConfig.get("aai.notificationEvent.default.version", "UNK"));
+ }
+
+ ne.setCambriaPartition(AAIConstants.UEB_PUB_PARTITION_AAI);
+ ne.setEventHeader(eh);
+ ne.setEntity(obj);
+
+ try {
+ PojoUtils pu = new PojoUtils();
+ String entityJson = pu.getJsonFromObject(ne);
+ sendToDmaapJmsQueue(entityJson);
+ } catch (Exception e) {
+ throw new AAIException("AAI_7350", e);
+ }
+ }
+
+ /**
+ * Store dynamic event.
+ *
+ * @param notificationJaxbContext
+ * the notification jaxb context
+ * @param notificationVersion
+ * the notification version
+ * @param eventHeader
+ * the event header
+ * @param obj
+ * the obj
+ * @throws AAIException
+ * the AAI exception
+ */
+ public void storeDynamicEvent(DynamicJAXBContext notificationJaxbContext, String notificationVersion, DynamicEntity eventHeader, DynamicEntity obj) throws AAIException {
+
+ if (obj == null) {
+ throw new AAIException("AAI_7350");
+ }
+
+ DynamicEntity notificationEvent = notificationJaxbContext.getDynamicType("inventory.aai.inventory.org." + notificationVersion + ".NotificationEvent").newDynamicEntity();
+
+ if (eventHeader.get("id") == null) {
+ eventHeader.set("id", genDate2() + "-" + UUID.randomUUID().toString());
+ }
+
+ if (eventHeader.get("timestamp") == null) {
+ eventHeader.set("timestamp", genDate());
+ }
+
+ if (eventHeader.get("entityLink") == null) {
+ eventHeader.set("entityLink", "UNK");
+ }
+
+ if (eventHeader.get("action") == null) {
+ eventHeader.set("action", "UNK");
+ }
+
+ if (eventHeader.get("eventType") == null) {
+ eventHeader.set("eventType", AAIConfig.get("aai.notificationEvent.default.eventType", "UNK"));
+ }
+
+ if (eventHeader.get("domain") == null) {
+ eventHeader.set("domain", AAIConfig.get("aai.notificationEvent.default.domain", "UNK"));
+ }
+
+ if (eventHeader.get("sourceName") == null) {
+ eventHeader.set("sourceName", AAIConfig.get("aai.notificationEvent.default.sourceName", "UNK"));
+ }
+
+ if (eventHeader.get("sequenceNumber") == null) {
+ eventHeader.set("sequenceNumber", AAIConfig.get("aai.notificationEvent.default.sequenceNumber", "UNK"));
+ }
+
+ if (eventHeader.get("severity") == null) {
+ eventHeader.set("severity", AAIConfig.get("aai.notificationEvent.default.severity", "UNK"));
+ }
+
+ if (eventHeader.get("version") == null) {
+ eventHeader.set("version", AAIConfig.get("aai.notificationEvent.default.version", "UNK"));
+ }
+
+ if (notificationEvent.get("cambriaPartition") == null) {
+ notificationEvent.set("cambriaPartition", AAIConstants.UEB_PUB_PARTITION_AAI);
+ }
+
+ notificationEvent.set("eventHeader", eventHeader);
+ notificationEvent.set("entity", obj);
+
+ try {
+ StringWriter result = new StringWriter();
+
+ Marshaller marshaller = notificationJaxbContext.createMarshaller();
+ marshaller.setProperty(org.eclipse.persistence.jaxb.MarshallerProperties.MEDIA_TYPE, "application/json");
+ marshaller.setProperty(org.eclipse.persistence.jaxb.MarshallerProperties.JSON_INCLUDE_ROOT, false);
+ marshaller.setProperty(org.eclipse.persistence.jaxb.MarshallerProperties.JSON_WRAPPER_AS_ARRAY_NAME, false);
+ marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, false);
+ marshaller.marshal(notificationEvent, result);
+
+ this.sendToDmaapJmsQueue(result.toString());
+
+ } catch (Exception e) {
+ throw new AAIException("AAI_7350", e);
+ }
+ }
+
+ public void storeEvent(Loader loader, Introspector eventHeader, Introspector obj) throws AAIException {
+ if (obj == null) {
+ throw new AAIException("AAI_7350");
+ }
+
+ try {
+ final Introspector notificationEvent = loader.introspectorFromName("notification-event");
+
+ if (eventHeader.getValue("id") == null) {
+ eventHeader.setValue("id", genDate2() + "-" + UUID.randomUUID().toString());
+ }
+
+ if (eventHeader.getValue("timestamp") == null) {
+ eventHeader.setValue("timestamp", genDate());
+ }
+
+ if (eventHeader.getValue("entity-link") == null) {
+ eventHeader.setValue("entity-link", "UNK");
+ }
+
+ if (eventHeader.getValue("action") == null) {
+ eventHeader.setValue("action", "UNK");
+ }
+
+ if (eventHeader.getValue("event-type") == null) {
+ eventHeader.setValue("event-type", AAIConfig.get("aai.notificationEvent.default.eventType", "UNK"));
+ }
+
+ if (eventHeader.getValue("domain") == null) {
+ eventHeader.setValue("domain", AAIConfig.get("aai.notificationEvent.default.domain", "UNK"));
+ }
+
+ if (eventHeader.getValue("source-name") == null) {
+ eventHeader.setValue("source-name", AAIConfig.get("aai.notificationEvent.default.sourceName", "UNK"));
+ }
+
+ if (eventHeader.getValue("sequence-number") == null) {
+ eventHeader.setValue("sequence-number", AAIConfig.get("aai.notificationEvent.default.sequenceNumber", "UNK"));
+ }
+
+ if (eventHeader.getValue("severity") == null) {
+ eventHeader.setValue("severity", AAIConfig.get("aai.notificationEvent.default.severity", "UNK"));
+ }
+
+ if (eventHeader.getValue("version") == null) {
+ eventHeader.setValue("version", AAIConfig.get("aai.notificationEvent.default.version", "UNK"));
+ }
+
+ if (notificationEvent.getValue("cambria-partition") == null) {
+ notificationEvent.setValue("cambria-partition", AAIConstants.UEB_PUB_PARTITION_AAI);
+ }
+
+ notificationEvent.setValue("event-header", eventHeader.getUnderlyingObject());
+ notificationEvent.setValue("entity", obj.getUnderlyingObject());
+
+ String entityJson = notificationEvent.marshal(false);
+ sendToDmaapJmsQueue(entityJson);
+ } catch (JSONException e) {
+ throw new AAIException("AAI_7350", e);
+ } catch (AAIUnknownObjectException e) {
+ throw new AAIException("AAI_7350", e);
+ }
+ }
+
+ private void sendToDmaapJmsQueue(String entityString) throws JSONException {
+
+ JSONObject entityJsonObject = new JSONObject(entityString);
+
+ JSONObject entityJsonObjectUpdated = new JSONObject();
+ JSONObject finalJson = new JSONObject();
+
+ JSONObject entityHeader = entityJsonObject.getJSONObject("event-header");
+ String cambriaPartition = entityJsonObject.getString("cambria.partition");
+
+ entityJsonObject.remove("event-header");
+ entityJsonObject.remove("cambria.partition");
+
+ entityJsonObjectUpdated.put("event-header", entityHeader);
+ entityJsonObjectUpdated.put("cambria.partition", cambriaPartition);
+
+ Iterator<String> iter = entityJsonObject.keys();
+ JSONObject entity = new JSONObject();
+ if (iter.hasNext()) {
+ entity = entityJsonObject.getJSONObject(iter.next());
+ }
+
+ entityJsonObjectUpdated.put("entity", entity);
+
+ finalJson.put("event-topic", "AAI-EVENT");
+ finalJson.put("transId", transId);
+ finalJson.put("fromAppId", fromAppId);
+ finalJson.put("fullId", "");
+ finalJson.put("aaiEventPayload", entityJsonObjectUpdated);
+
+ messageProducer.sendMessageToDefaultDestination(finalJson);
+ }
+
+ /**
+ * Gen date.
+ *
+ * @return the string
+ */
+ public static String genDate() {
+ Date date = new Date();
+ DateFormat formatter = new SimpleDateFormat("YYYYMMdd-HH:mm:ss:SSS");
+ return formatter.format(date);
+ }
+
+ /**
+ * Gen date 2.
+ *
+ * @return the string
+ */
+ public static String genDate2() {
+ Date date = new Date();
+ DateFormat formatter = new SimpleDateFormat("YYYYMMddHHmmss");
+ return formatter.format(date);
+ }
+
+}