aboutsummaryrefslogtreecommitdiffstats
path: root/aai-resources/src/main/java/org/onap
diff options
context:
space:
mode:
Diffstat (limited to 'aai-resources/src/main/java/org/onap')
-rw-r--r--aai-resources/src/main/java/org/onap/aai/ajsc_aai/JaxrsErrorMessageLookupService.java99
-rw-r--r--aai-resources/src/main/java/org/onap/aai/ajsc_aai/JaxrsUserService.java55
-rw-r--r--aai-resources/src/main/java/org/onap/aai/ajsc_aai/filemonitor/ServicePropertiesListener.java38
-rw-r--r--aai-resources/src/main/java/org/onap/aai/ajsc_aai/filemonitor/ServicePropertiesMap.java127
-rw-r--r--aai-resources/src/main/java/org/onap/aai/ajsc_aai/filemonitor/ServicePropertyService.java219
-rw-r--r--aai-resources/src/main/java/org/onap/aai/ajsc_aai/util/ServicePropertiesMapBean.java38
-rw-r--r--aai-resources/src/main/java/org/onap/aai/config/DmaapConfig.java43
-rw-r--r--aai-resources/src/main/java/org/onap/aai/dbgen/DataSnapshot.java267
-rw-r--r--aai-resources/src/main/java/org/onap/aai/dbgen/ForceDeleteTool.java726
-rw-r--r--aai-resources/src/main/java/org/onap/aai/dbgen/GraphMLTokens.java58
-rw-r--r--aai-resources/src/main/java/org/onap/aai/dbgen/UpdateEdgeTags.java311
-rw-r--r--aai-resources/src/main/java/org/onap/aai/interceptors/AAIHeaderProperties.java27
-rw-r--r--aai-resources/src/main/java/org/onap/aai/interceptors/AAILogJAXRSInInterceptor.java285
-rw-r--r--aai-resources/src/main/java/org/onap/aai/interceptors/AAILogJAXRSOutInterceptor.java303
-rw-r--r--aai-resources/src/main/java/org/onap/aai/interceptors/PostAaiAjscInterceptor.java64
-rw-r--r--aai-resources/src/main/java/org/onap/aai/interceptors/PreAaiAjscInterceptor.java55
-rw-r--r--aai-resources/src/main/java/org/onap/aai/migration/EdgeMigrator.java163
-rw-r--r--aai-resources/src/main/java/org/onap/aai/migration/Enabled.java37
-rw-r--r--aai-resources/src/main/java/org/onap/aai/migration/EventAction.java31
-rw-r--r--aai-resources/src/main/java/org/onap/aai/migration/MigrationController.java50
-rw-r--r--aai-resources/src/main/java/org/onap/aai/migration/MigrationControllerInternal.java424
-rw-r--r--aai-resources/src/main/java/org/onap/aai/migration/Migrator.java263
-rw-r--r--aai-resources/src/main/java/org/onap/aai/migration/NotificationHelper.java107
-rw-r--r--aai-resources/src/main/java/org/onap/aai/migration/PropertyMigrator.java150
-rw-r--r--aai-resources/src/main/java/org/onap/aai/migration/Status.java31
-rw-r--r--aai-resources/src/main/java/org/onap/aai/migration/VertexMerge.java246
-rw-r--r--aai-resources/src/main/java/org/onap/aai/rest/BulkAddConsumer.java43
-rw-r--r--aai-resources/src/main/java/org/onap/aai/rest/BulkConsumer.java485
-rw-r--r--aai-resources/src/main/java/org/onap/aai/rest/BulkProcessConsumer.java43
-rw-r--r--aai-resources/src/main/java/org/onap/aai/rest/ExampleConsumer.java105
-rw-r--r--aai-resources/src/main/java/org/onap/aai/rest/ExceptionHandler.java130
-rw-r--r--aai-resources/src/main/java/org/onap/aai/rest/LegacyMoxyConsumer.java597
-rw-r--r--aai-resources/src/main/java/org/onap/aai/rest/URLFromVertexIdConsumer.java121
-rw-r--r--aai-resources/src/main/java/org/onap/aai/rest/VertexIdConsumer.java146
-rw-r--r--aai-resources/src/main/java/org/onap/aai/rest/exceptions/AAIInvalidXMLNamespace.java41
-rw-r--r--aai-resources/src/main/java/org/onap/aai/rest/retired/RetiredConsumer.java144
-rw-r--r--aai-resources/src/main/java/org/onap/aai/rest/retired/V3ThroughV7Consumer.java29
-rw-r--r--aai-resources/src/main/java/org/onap/aai/rest/retired/V7V8Models.java29
-rw-r--r--aai-resources/src/main/java/org/onap/aai/rest/retired/V7V8NamedQueries.java29
-rw-r--r--aai-resources/src/main/java/org/onap/aai/rest/tools/ModelVersionTransformer.java410
-rw-r--r--aai-resources/src/main/java/org/onap/aai/rest/util/EchoResponse.java122
-rw-r--r--aai-resources/src/main/java/org/onap/aai/rest/util/LogFormatTools.java37
-rw-r--r--aai-resources/src/main/java/org/onap/aai/rest/util/ValidateEncoding.java161
-rw-r--r--aai-resources/src/main/java/org/onap/aai/transforms/Converter.java26
-rw-r--r--aai-resources/src/main/java/org/onap/aai/transforms/LowerCamelToLowerHyphenConverter.java35
-rw-r--r--aai-resources/src/main/java/org/onap/aai/transforms/LowerHyphenToLowerCamelConverter.java82
-rw-r--r--aai-resources/src/main/java/org/onap/aai/transforms/MapTraverser.java88
-rw-r--r--aai-resources/src/main/java/org/onap/aai/util/AAIAppServletContextListener.java94
-rw-r--r--aai-resources/src/main/java/org/onap/aai/util/DataConversionHelper.java64
-rw-r--r--aai-resources/src/main/java/org/onap/aai/util/JettyObfuscationConversionCommandLineUtil.java100
50 files changed, 7378 insertions, 0 deletions
diff --git a/aai-resources/src/main/java/org/onap/aai/ajsc_aai/JaxrsErrorMessageLookupService.java b/aai-resources/src/main/java/org/onap/aai/ajsc_aai/JaxrsErrorMessageLookupService.java
new file mode 100644
index 0000000..f7b08d9
--- /dev/null
+++ b/aai-resources/src/main/java/org/onap/aai/ajsc_aai/JaxrsErrorMessageLookupService.java
@@ -0,0 +1,99 @@
+/**
+ * ============LICENSE_START=======================================================
+ * org.onap.aai
+ * ================================================================================
+ * Copyright © 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END=========================================================
+ *
+ * ECOMP is a trademark and service mark of AT&T Intellectual Property.
+ */
+package org.onap.aai.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-resources/src/main/java/org/onap/aai/ajsc_aai/JaxrsUserService.java b/aai-resources/src/main/java/org/onap/aai/ajsc_aai/JaxrsUserService.java
new file mode 100644
index 0000000..a1cc2ca
--- /dev/null
+++ b/aai-resources/src/main/java/org/onap/aai/ajsc_aai/JaxrsUserService.java
@@ -0,0 +1,55 @@
+/**
+ * ============LICENSE_START=======================================================
+ * org.onap.aai
+ * ================================================================================
+ * Copyright © 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END=========================================================
+ *
+ * ECOMP is a trademark and service mark of AT&T Intellectual Property.
+ */
+package org.onap.aai.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-resources/src/main/java/org/onap/aai/ajsc_aai/filemonitor/ServicePropertiesListener.java b/aai-resources/src/main/java/org/onap/aai/ajsc_aai/filemonitor/ServicePropertiesListener.java
new file mode 100644
index 0000000..38ea8c6
--- /dev/null
+++ b/aai-resources/src/main/java/org/onap/aai/ajsc_aai/filemonitor/ServicePropertiesListener.java
@@ -0,0 +1,38 @@
+/**
+ * ============LICENSE_START=======================================================
+ * org.onap.aai
+ * ================================================================================
+ * Copyright © 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END=========================================================
+ *
+ * ECOMP is a trademark and service mark of AT&T Intellectual Property.
+ */
+package org.onap.aai.ajsc_aai.filemonitor;
+
+import java.io.File;
+
+//import com.att.ssf.filemonitor.FileChangedListener;
+
+//public class ServicePropertiesListener implements FileChangedListener {
+
+ /**
+ * {@inheritDoc}
+ */
+ //@Override
+ //public void update(File file) throws Exception
+ //{
+ //ServicePropertiesMap.refresh(file);
+ //}
+//}
diff --git a/aai-resources/src/main/java/org/onap/aai/ajsc_aai/filemonitor/ServicePropertiesMap.java b/aai-resources/src/main/java/org/onap/aai/ajsc_aai/filemonitor/ServicePropertiesMap.java
new file mode 100644
index 0000000..7274c61
--- /dev/null
+++ b/aai-resources/src/main/java/org/onap/aai/ajsc_aai/filemonitor/ServicePropertiesMap.java
@@ -0,0 +1,127 @@
+/**
+ * ============LICENSE_START=======================================================
+ * org.onap.aai
+ * ================================================================================
+ * Copyright © 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END=========================================================
+ *
+ * ECOMP is a trademark and service mark of AT&T Intellectual Property.
+ */
+package org.onap.aai.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-resources/src/main/java/org/onap/aai/ajsc_aai/filemonitor/ServicePropertyService.java b/aai-resources/src/main/java/org/onap/aai/ajsc_aai/filemonitor/ServicePropertyService.java
new file mode 100644
index 0000000..956d0e4
--- /dev/null
+++ b/aai-resources/src/main/java/org/onap/aai/ajsc_aai/filemonitor/ServicePropertyService.java
@@ -0,0 +1,219 @@
+/**
+ * ============LICENSE_START=======================================================
+ * org.onap.aai
+ * ================================================================================
+ * Copyright © 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END=========================================================
+ *
+ * ECOMP is a trademark and service mark of AT&T Intellectual Property.
+ */
+package org.onap.aai.ajsc_aai.filemonitor;
+
+//import java.io.File;
+//import java.io.FileInputStream;
+//import java.io.IOException;
+//import java.lang.reflect.Method;
+//import java.util.ArrayList;
+//import java.util.List;
+//import java.util.Properties;
+
+//import javax.annotation.PostConstruct;
+
+//import org.slf4j.Logger;
+//import org.slf4j.LoggerFactory;
+
+//import com.att.ssf.filemonitor.FileChangedListener;
+//import com.att.ssf.filemonitor.FileMonitor;
+
+//public class ServicePropertyService {
+ //private boolean loadOnStartup;
+ //private ServicePropertiesListener fileChangedListener;
+ //private ServicePropertiesMap filePropertiesMap;
+ //private String ssfFileMonitorPollingInterval;
+ //private String ssfFileMonitorThreadpoolSize;
+ //private List<File> fileList;
+ //private static final String FILE_CHANGE_LISTENER_LOC = System
+ //.getProperty("AJSC_CONF_HOME") + "/etc";
+ //private static final String USER_CONFIG_FILE = "service-file-monitor.properties";
+ //static final Logger logger = LoggerFactory
+ //.getLogger(ServicePropertyService.class);
+
+ //// do not remove the postConstruct annotation, init method will not be
+ //// called after constructor
+ /**
+ * Inits the.
+ *
+ * @throws Exception the exception
+ */
+ //@PostConstruct
+ //public void init() throws Exception {
+
+ //try {
+ //getFileList(FILE_CHANGE_LISTENER_LOC);
+
+ //for (File file : fileList) {
+ //try {
+ //FileChangedListener fileChangedListener = this.fileChangedListener;
+ //Object filePropertiesMap = this.filePropertiesMap;
+ //Method m = filePropertiesMap.getClass().getMethod(
+ //"refresh", File.class);
+ //m.invoke(filePropertiesMap, file);
+ //FileMonitor fm = FileMonitor.getInstance();
+ //fm.addFileChangedListener(file, fileChangedListener,
+ //loadOnStartup);
+ //} catch (Exception ioe) {
+ //logger.error("Error in the file monitor block", ioe);
+ //}
+ //}
+ //} catch (Exception ex) {
+ //logger.error("Error creating property map ", ex);
+ //}
+
+ //}
+
+ /**
+ * Gets the file list.
+ *
+ * @param dirName the dir name
+ * @return the file list
+ * @throws IOException Signals that an I/O exception has occurred.
+ */
+ //private void getFileList(String dirName) throws IOException {
+ //File directory = new File(dirName);
+ //FileInputStream fis = null;
+
+ //if (fileList == null)
+ //fileList = new ArrayList<File>();
+
+ //// get all the files that are ".json" or ".properties", from a directory
+ //// & it's sub-directories
+ //File[] fList = directory.listFiles();
+
+ //for (File file : fList) {
+ //// read service property files from the configuration file
+ //if (file.isFile() && file.getPath().endsWith(USER_CONFIG_FILE)) {
+ //try {
+ //fis = new FileInputStream(file);
+ //Properties prop = new Properties();
+ //prop.load(fis);
+
+ //for (String filePath : prop.stringPropertyNames()) {
+ //fileList.add(new File(prop.getProperty(filePath)));
+ //}
+ //} catch (Exception ioe) {
+ //logger.error("Error reading the file stream ", ioe);
+ //} finally {
+ //fis.close();
+ //}
+ //} else if (file.isDirectory()) {
+ //getFileList(file.getPath());
+ //}
+ //}
+
+ //}
+
+ /**
+ * Sets the load on startup.
+ *
+ * @param loadOnStartup the new load on startup
+ */
+ //public void setLoadOnStartup(boolean loadOnStartup) {
+ //this.loadOnStartup = loadOnStartup;
+ //}
+
+ /**
+ * Sets the ssf file monitor polling interval.
+ *
+ * @param ssfFileMonitorPollingInterval the new ssf file monitor polling interval
+ */
+ //public void setSsfFileMonitorPollingInterval(
+ //String ssfFileMonitorPollingInterval) {
+ //this.ssfFileMonitorPollingInterval = ssfFileMonitorPollingInterval;
+ //}
+
+ /**
+ * Sets the ssf file monitor threadpool size.
+ *
+ * @param ssfFileMonitorThreadpoolSize the new ssf file monitor threadpool size
+ */
+ //public void setSsfFileMonitorThreadpoolSize(
+ //String ssfFileMonitorThreadpoolSize) {
+ //this.ssfFileMonitorThreadpoolSize = ssfFileMonitorThreadpoolSize;
+ //}
+
+ /**
+ * Gets the load on startup.
+ *
+ * @return the load on startup
+ */
+ //public boolean getLoadOnStartup() {
+ //return loadOnStartup;
+ //}
+
+ /**
+ * Gets the ssf file monitor polling interval.
+ *
+ * @return the ssf file monitor polling interval
+ */
+ //public String getSsfFileMonitorPollingInterval() {
+ //return ssfFileMonitorPollingInterval;
+ //}
+
+ /**
+ * Gets the ssf file monitor threadpool size.
+ *
+ * @return the ssf file monitor threadpool size
+ */
+ //public String getSsfFileMonitorThreadpoolSize() {
+ //return ssfFileMonitorThreadpoolSize;
+ //}
+
+ /**
+ * Gets the file changed listener.
+ *
+ * @return the file changed listener
+ */
+ //public ServicePropertiesListener getFileChangedListener() {
+ //return fileChangedListener;
+ //}
+
+ /**
+ * Sets the file changed listener.
+ *
+ * @param fileChangedListener the new file changed listener
+ */
+ //public void setFileChangedListener(
+ //ServicePropertiesListener fileChangedListener) {
+ //this.fileChangedListener = fileChangedListener;
+ //}
+
+ /**
+ * Gets the file properties map.
+ *
+ * @return the file properties map
+ */
+ //public ServicePropertiesMap getFilePropertiesMap() {
+ //return filePropertiesMap;
+ //}
+
+ /**
+ * Sets the file properties map.
+ *
+ * @param filePropertiesMap the new file properties map
+ */
+ //public void setFilePropertiesMap(ServicePropertiesMap filePropertiesMap) {
+ //this.filePropertiesMap = filePropertiesMap;
+ //}
+//}
diff --git a/aai-resources/src/main/java/org/onap/aai/ajsc_aai/util/ServicePropertiesMapBean.java b/aai-resources/src/main/java/org/onap/aai/ajsc_aai/util/ServicePropertiesMapBean.java
new file mode 100644
index 0000000..71c290b
--- /dev/null
+++ b/aai-resources/src/main/java/org/onap/aai/ajsc_aai/util/ServicePropertiesMapBean.java
@@ -0,0 +1,38 @@
+/**
+ * ============LICENSE_START=======================================================
+ * org.onap.aai
+ * ================================================================================
+ * Copyright © 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END=========================================================
+ *
+ * ECOMP is a trademark and service mark of AT&T Intellectual Property.
+ */
+package org.onap.aai.ajsc_aai.util;
+
+import org.onap.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-resources/src/main/java/org/onap/aai/config/DmaapConfig.java b/aai-resources/src/main/java/org/onap/aai/config/DmaapConfig.java
new file mode 100644
index 0000000..c34ae0a
--- /dev/null
+++ b/aai-resources/src/main/java/org/onap/aai/config/DmaapConfig.java
@@ -0,0 +1,43 @@
+/**
+ * ============LICENSE_START=======================================================
+ * org.onap.aai
+ * ================================================================================
+ * Copyright © 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END=========================================================
+ *
+ * ECOMP is a trademark and service mark of AT&T Intellectual Property.
+ */
+package org.onap.aai.config;
+
+import org.apache.activemq.broker.BrokerService;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+
+@Configuration
+public class DmaapConfig {
+
+ @Bean(destroyMethod = "stop")
+ public BrokerService brokerService() throws Exception {
+
+ BrokerService broker = new BrokerService();
+ broker.addConnector("tcp://localhost:61447");
+ broker.setPersistent(false);
+ broker.setUseJmx(false);
+ broker.setSchedulerSupport(false);
+ broker.start();
+
+ return broker;
+ }
+}
diff --git a/aai-resources/src/main/java/org/onap/aai/dbgen/DataSnapshot.java b/aai-resources/src/main/java/org/onap/aai/dbgen/DataSnapshot.java
new file mode 100644
index 0000000..01c6185
--- /dev/null
+++ b/aai-resources/src/main/java/org/onap/aai/dbgen/DataSnapshot.java
@@ -0,0 +1,267 @@
+/**
+ * ============LICENSE_START=======================================================
+ * org.onap.aai
+ * ================================================================================
+ * Copyright © 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END=========================================================
+ *
+ * ECOMP is a trademark and service mark of AT&T Intellectual Property.
+ */
+package org.onap.aai.dbgen;
+
+import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.Properties;
+
+import org.apache.tinkerpop.gremlin.structure.io.IoCore;
+import org.apache.tinkerpop.gremlin.structure.io.graphson.LegacyGraphSONReader;
+import org.onap.aai.dbmap.AAIGraph;
+import org.onap.aai.exceptions.AAIException;
+import org.onap.aai.logging.ErrorLogHelper;
+import org.onap.aai.util.AAIConfig;
+import org.onap.aai.util.AAIConstants;
+import org.onap.aai.util.FormatDate;
+
+import com.att.eelf.configuration.Configuration;
+import com.att.eelf.configuration.EELFLogger;
+import com.att.eelf.configuration.EELFManager;
+import com.thinkaurelius.titan.core.TitanGraph;
+import com.thinkaurelius.titan.core.util.TitanCleanup;
+
+public class DataSnapshot {
+
+ private static EELFLogger LOGGER;
+ /**
+ * The main method.
+ *
+ * @param args
+ * the arguments
+ */
+ public static void main(String[] args) {
+ // Set the logging file properties to be used by EELFManager
+ Properties props = System.getProperties();
+ props.setProperty(Configuration.PROPERTY_LOGGING_FILE_NAME, AAIConstants.AAI_DATA_SNAPSHOT_LOGBACK_PROPS);
+ props.setProperty(Configuration.PROPERTY_LOGGING_FILE_PATH, AAIConstants.AAI_HOME_ETC_APP_PROPERTIES);
+ LOGGER = EELFManager.getInstance().getLogger(DataSnapshot.class);
+ Boolean dbClearFlag = false;
+ TitanGraph graph = null;
+ String command = "JUST_TAKE_SNAPSHOT"; // This is the default
+ String oldSnapshotFileName = "";
+ if (args.length == 1) {
+ command = args[0];
+ }
+ if (args.length == 2) {
+ // If they pass in a RELOAD_ENTIRE_DB argument, then we will be
+ // reloading the database
+ // from the filename passed in -which will be expected to be found
+ // in our snapshot directory.
+ command = args[0];
+ oldSnapshotFileName = args[1];
+ }
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ try {
+ AAIConfig.init();
+ ErrorLogHelper.loadProperties();
+ System.out.println("Command = " + command + ", oldSnapshotFileName = " + oldSnapshotFileName);
+ String targetDir = AAIConstants.AAI_HOME + AAIConstants.AAI_FILESEP + "logs" + AAIConstants.AAI_FILESEP + "data" + AAIConstants.AAI_FILESEP + "dataSnapshots";
+
+ // Make sure the dataSnapshots directory is there
+ new File(targetDir).mkdirs();
+
+ System.out.println(" ---- NOTE --- about to open graph (takes a little while)\n");
+
+ graph = AAIGraph.getInstance().getGraph();
+
+ if (graph == null) {
+ String emsg = "Not able to get a graph object in DataSnapshot.java\n";
+ System.out.println(emsg);
+ System.exit(1);
+ }
+
+ if (command.equals("JUST_TAKE_SNAPSHOT")) {
+ // ------------------------------------------
+ // They just want to take a snapshot.
+ // ------------------------------------------
+ FormatDate fd = new FormatDate("yyyyMMddHHmm", "GMT");
+ String dteStr = fd.getDateTime();
+ String newSnapshotOutFname = targetDir + AAIConstants.AAI_FILESEP + "dataSnapshot.graphSON." + dteStr;
+
+ graph.io(IoCore.graphson()).writeGraph(newSnapshotOutFname);
+
+ System.out.println("Snapshot written to " + newSnapshotOutFname);
+ /****
+ * Don't really want to do this every hour ************** int
+ * vCount = 0; Iterator vIt =
+ * graph.query().vertices().iterator(); while( vIt.hasNext() ){
+ * vCount++; vIt.next(); } System.out.println(
+ * "A little after taking the snapshot, we see: " + vCount +
+ * " vertices in the db.");
+ ************/
+ } else if (command.equals("CLEAR_ENTIRE_DATABASE")) {
+ // ------------------------------------------------------------------
+ // They are calling this to clear the db before re-loading it
+ // later
+ // ------------------------------------------------------------------
+
+ // First - make sure the backup file they will be using can be
+ // found and has data
+ if (oldSnapshotFileName.equals("")) {
+ String emsg = "No oldSnapshotFileName passed to DataSnapshot.";
+ System.out.println(emsg);
+ System.exit(1);
+ }
+ String oldSnapshotFullFname = targetDir + AAIConstants.AAI_FILESEP + oldSnapshotFileName;
+ File f = new File(oldSnapshotFullFname);
+ if (!f.exists()) {
+ String emsg = "oldSnapshotFile " + oldSnapshotFullFname + " could not be found.";
+ System.out.println(emsg);
+ System.exit(1);
+ } else if (!f.canRead()) {
+ String emsg = "oldSnapshotFile " + oldSnapshotFullFname + " could not be read.";
+ System.out.println(emsg);
+ System.exit(1);
+ } else if (f.length() == 0) {
+ String emsg = "oldSnapshotFile " + oldSnapshotFullFname + " had no data.";
+ System.out.println(emsg);
+ System.exit(1);
+ }
+
+ System.out.println("\n>>> WARNING <<<< ");
+ System.out.println(">>> All data and schema in this database will be removed at this point. <<<");
+ System.out.println(">>> Processing will begin in 5 seconds. <<<");
+ System.out.println(">>> WARNING <<<< ");
+
+ try {
+ // Give them a chance to back out of this
+ Thread.sleep(5000);
+ } catch (java.lang.InterruptedException ie) {
+ System.out.println(" DB Clearing has been aborted. ");
+ System.exit(1);
+ }
+
+ System.out.println(" Begin clearing out old data. ");
+ graph.close();
+ TitanCleanup.clear(graph);
+ System.out.println(" Done clearing data. ");
+ System.out.println(">>> IMPORTANT - NOTE >>> you need to run the SchemaGenerator (use GenTester) before ");
+ System.out.println(" reloading data or the data will be put in without indexes. ");
+ dbClearFlag = true;
+
+ } else if (command.equals("RELOAD_LEGACY_DATA")) {
+ // -------------------------------------------------------------------
+ // They want to restore the database from an old snapshot file
+ // -------------------------------------------------------------------
+ if (oldSnapshotFileName.equals("")) {
+ String emsg = "No oldSnapshotFileName passed to DataSnapshot when RELOAD_LEGACY_DATA used.";
+ System.out.println(emsg);
+ System.exit(1);
+ }
+ String oldSnapshotFullFname = targetDir + AAIConstants.AAI_FILESEP + oldSnapshotFileName;
+ File f = new File(oldSnapshotFullFname);
+ if (!f.exists()) {
+ String emsg = "oldSnapshotFile " + oldSnapshotFullFname + " could not be found.";
+ System.out.println(emsg);
+ System.exit(1);
+ } else if (!f.canRead()) {
+ String emsg = "oldSnapshotFile " + oldSnapshotFullFname + " could not be read.";
+ System.out.println(emsg);
+ System.exit(1);
+ } else if (f.length() == 0) {
+ String emsg = "oldSnapshotFile " + oldSnapshotFullFname + " had no data.";
+ System.out.println(emsg);
+ System.exit(1);
+ }
+
+ System.out.println("We will load data IN from the file = " + oldSnapshotFullFname);
+ System.out.println(" Begin reloading Titan 0.5 data. ");
+
+ LegacyGraphSONReader lgr = LegacyGraphSONReader.build().create();
+ InputStream is = new FileInputStream(oldSnapshotFullFname);
+ lgr.readGraph(is, graph);
+
+ System.out.println("Completed the inputGraph command, now try to commit()... ");
+ graph.tx().commit();
+ System.out.println("Completed reloading Titan 0.5 data.");
+
+ long vCount = graph.traversal().V().count().next();
+ System.out.println("A little after repopulating from an old snapshot, we see: " + vCount + " vertices in the db.");
+ } else if (command.equals("RELOAD_DATA")) {
+ // -------------------------------------------------------------------
+ // They want to restore the database from an old snapshot file
+ // -------------------------------------------------------------------
+ if (oldSnapshotFileName.equals("")) {
+ String emsg = "No oldSnapshotFileName passed to DataSnapshot when RELOAD_DATA used.";
+ System.out.println(emsg);
+ System.exit(1);
+ }
+ String oldSnapshotFullFname = targetDir + AAIConstants.AAI_FILESEP + oldSnapshotFileName;
+ File f = new File(oldSnapshotFullFname);
+ if (!f.exists()) {
+ String emsg = "oldSnapshotFile " + oldSnapshotFullFname + " could not be found.";
+ System.out.println(emsg);
+ System.exit(1);
+ } else if (!f.canRead()) {
+ String emsg = "oldSnapshotFile " + oldSnapshotFullFname + " could not be read.";
+ System.out.println(emsg);
+ System.exit(1);
+ } else if (f.length() == 0) {
+ String emsg = "oldSnapshotFile " + oldSnapshotFullFname + " had no data.";
+ System.out.println(emsg);
+ System.exit(1);
+ }
+
+ System.out.println("We will load data IN from the file = " + oldSnapshotFullFname);
+ System.out.println(" Begin reloading data. ");
+ graph.io(IoCore.graphson()).readGraph(oldSnapshotFullFname);
+ System.out.println("Completed the inputGraph command, now try to commit()... ");
+ graph.tx().commit();
+ System.out.println("Completed reloading data.");
+
+ long vCount = graph.traversal().V().count().next();
+
+ System.out.println("A little after repopulating from an old snapshot, we see: " + vCount + " vertices in the db.");
+ } else {
+ String emsg = "Bad command passed to DataSnapshot: [" + command + "]";
+ System.out.println(emsg);
+ System.exit(1);
+ }
+
+ } catch (AAIException e) {
+ ErrorLogHelper.logError("AAI_6128", e.getMessage());
+ } catch (Exception ex) {
+ ErrorLogHelper.logError("AAI_6128", ex.getMessage());
+ } finally {
+ if (!dbClearFlag && graph != null) {
+ // Any changes that worked correctly should have already done
+ // thier commits.
+ if (graph.isOpen()) {
+ graph.tx().rollback();
+ graph.close();
+ }
+ }
+ try {
+ baos.close();
+ } catch (IOException iox) {
+ }
+ }
+
+ System.exit(0);
+
+ }// End of main()
+
+}
diff --git a/aai-resources/src/main/java/org/onap/aai/dbgen/ForceDeleteTool.java b/aai-resources/src/main/java/org/onap/aai/dbgen/ForceDeleteTool.java
new file mode 100644
index 0000000..518c551
--- /dev/null
+++ b/aai-resources/src/main/java/org/onap/aai/dbgen/ForceDeleteTool.java
@@ -0,0 +1,726 @@
+/**
+ * ============LICENSE_START=======================================================
+ * org.onap.aai
+ * ================================================================================
+ * Copyright © 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END=========================================================
+ *
+ * ECOMP is a trademark and service mark of AT&T Intellectual Property.
+ */
+package org.onap.aai.dbgen;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.Properties;
+import java.util.Scanner;
+
+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.Direction;
+import org.apache.tinkerpop.gremlin.structure.Edge;
+import org.apache.tinkerpop.gremlin.structure.Vertex;
+import org.apache.tinkerpop.gremlin.structure.VertexProperty;
+import org.onap.aai.exceptions.AAIException;
+import org.onap.aai.serialization.db.AAIDirection;
+import org.onap.aai.serialization.db.EdgeProperty;
+import org.onap.aai.util.AAIConfig;
+import org.onap.aai.util.AAIConstants;
+import org.slf4j.MDC;
+
+import com.att.eelf.configuration.Configuration;
+import com.att.eelf.configuration.EELFLogger;
+import com.att.eelf.configuration.EELFManager;
+import com.thinkaurelius.titan.core.TitanFactory;
+import com.thinkaurelius.titan.core.TitanGraph;
+
+
+
+public class ForceDeleteTool {
+ /*
+ * The main method.
+ *
+ * @param args the arguments
+ */
+ public static void main(String[] args) {
+
+ //SWGK 01/21/2016 - To suppress the warning message when the tool is run from the Terminal.
+
+ // Set the logging file properties to be used by EELFManager
+ Properties props = System.getProperties();
+ props.setProperty(Configuration.PROPERTY_LOGGING_FILE_NAME, "forceDelete-logback.xml");
+ props.setProperty(Configuration.PROPERTY_LOGGING_FILE_PATH, AAIConstants.AAI_HOME_ETC_APP_PROPERTIES);
+ EELFLogger logger = EELFManager.getInstance().getLogger(ForceDeleteTool.class.getSimpleName());
+ MDC.put("logFilenameAppender", ForceDeleteTool.class.getSimpleName());
+
+ String actionVal = "";
+ String userIdVal = "";
+ String dataString = "";
+ Boolean displayAllVidsFlag = false; // Note - This should rarely be needed
+ Boolean overRideProtection = false; // This should rarely be used - it overrides all our new checking
+ long vertexIdLong = 0;
+ String edgeIdStr = "";
+ String argStr4Msg = "";
+
+ if (args != null && args.length > 0) {
+ // They passed some arguments in that will affect processing
+ for (int i = 0; i < args.length; i++) {
+ String thisArg = args[i];
+ argStr4Msg = argStr4Msg + " " + thisArg;
+
+ if (thisArg.equals("-action")) {
+ i++;
+ if (i >= args.length) {
+ logger.error(" No value passed with -action option. ");
+ System.exit(0);
+ }
+ actionVal = args[i];
+ argStr4Msg = argStr4Msg + " " + actionVal;
+ }
+ else if (thisArg.equals("-userId")) {
+ i++;
+ if (i >= args.length) {
+ logger.error(" No value passed with -userId option. ");
+ System.exit(0);
+ }
+ userIdVal = args[i];
+ argStr4Msg = argStr4Msg + " " + userIdVal;
+ }
+ else if (thisArg.equals("-overRideProtection")) {
+ overRideProtection = true;
+ }
+ else if (thisArg.equals("-DISPLAY_ALL_VIDS")) {
+ displayAllVidsFlag = true;
+ }
+ else if (thisArg.equals("-vertexId")) {
+ i++;
+ if (i >= args.length) {
+ logger.error(" No value passed with -vertexId option. ");
+ System.exit(0);
+ }
+ String nextArg = args[i];
+ argStr4Msg = argStr4Msg + " " + nextArg;
+ try {
+ vertexIdLong = Long.parseLong(nextArg);
+ } catch (Exception e) {
+ logger.error("Bad value passed with -vertexId option: ["
+ + nextArg + "]");
+ System.exit(0);
+ }
+ }
+ else if (thisArg.equals("-params4Collect")) {
+ i++;
+ if (i >= args.length) {
+ logger.error(" No value passed with -params4Collect option. ");
+ System.exit(0);
+ }
+ dataString = args[i];
+ argStr4Msg = argStr4Msg + " " + dataString;
+ }
+ else if (thisArg.equals("-edgeId")) {
+ i++;
+ if (i >= args.length) {
+ logger.error(" No value passed with -edgeId option. ");
+ System.exit(0);
+ }
+ String nextArg = args[i];
+ argStr4Msg = argStr4Msg + " " + nextArg;
+ edgeIdStr = nextArg;
+ }
+ else {
+ logger.error(" Unrecognized argument passed to ForceDeleteTool: ["
+ + thisArg + "]. ");
+ logger.error(" Valid values are: -action -userId -vertexId -edgeId -overRideProtection -params4Collect -DISPLAY_ALL_VIDS");
+ System.exit(0);
+ }
+ }
+ }
+
+ if( !actionVal.equals("COLLECT_DATA") && !actionVal.equals("DELETE_NODE") && !actionVal.equals("DELETE_EDGE")){
+ String emsg = "Bad action parameter [" + actionVal + "] passed to ForceDeleteTool(). Valid values = COLLECT_DATA or DELETE_NODE or DELETE_EDGE\n";
+ System.out.println(emsg);
+ logger.error(emsg);
+ System.exit(0);
+ }
+
+ if( actionVal.equals("DELETE_NODE") && vertexIdLong == 0 ){
+ String emsg = "ERROR: No vertex ID passed on DELETE_NODE request. \n";
+ System.out.println(emsg);
+ logger.error(emsg);
+ System.exit(0);
+ }
+ else if( actionVal.equals("DELETE_EDGE") && edgeIdStr.equals("")){
+ String emsg = "ERROR: No edge ID passed on DELETE_EDGE request. \n";
+ System.out.println(emsg);
+ logger.error(emsg);
+ System.exit(0);
+ }
+
+
+ userIdVal = userIdVal.trim();
+ if( (userIdVal.length() < 6) || userIdVal.toUpperCase().equals("AAIADMIN") ){
+ String emsg = "Bad userId parameter [" + userIdVal + "] passed to ForceDeleteTool(). must be not empty and not aaiadmin \n";
+ System.out.println(emsg);
+ logger.error(emsg);
+ System.exit(0);
+ }
+
+ String msg = "";
+ TitanGraph graph = null;
+ try {
+ AAIConfig.init();
+ System.out.println(" ---- NOTE --- about to open graph (takes a little while)--------\n");
+ graph = TitanFactory.open(AAIConstants.REALTIME_DB_CONFIG);
+ if( graph == null ){
+ String emsg = "could not get graph object in ForceDeleteTool() \n";
+ System.out.println(emsg);
+ logger.error(emsg);
+ System.exit(0);
+ }
+ }
+ catch (AAIException e1) {
+ msg = e1.getErrorObject().toString();
+ System.out.println(msg);
+ logger.error(msg);
+ System.exit(0);
+ }
+ catch (Exception e2) {
+ msg = e2.toString();
+ System.out.println(msg);
+ logger.error(msg);
+ System.exit(0);
+ }
+
+ msg = "ForceDelete called by: userId [" + userIdVal + "] with these params: [" + argStr4Msg + "]";
+ System.out.println(msg);
+ logger.info(msg);
+
+ ForceDelete fd = new ForceDelete(graph);
+ if( actionVal.equals("COLLECT_DATA") ){
+ // When doing COLLECT_DATA, we expect the dataString string to be comma separated
+ // name value pairs like this:
+ // "propName1|propVal1,propName2|propVal2" etc. We will look for a node or nodes
+ // that have properties that ALL match what was passed in.
+
+ int resCount = 0;
+ int firstPipeLoc = dataString.indexOf("|");
+ if( firstPipeLoc <= 0 ){
+ msg = "Must use the -params4Collect option when collecting data with data string in a format like: 'propName1|propVal1,propName2|propVal2'";
+ System.out.println(msg);
+ logger.error(msg);
+ System.exit(0);
+ }
+ GraphTraversal<Vertex, Vertex> g = graph.traversal().V();
+ String qStringForMsg = " graph.traversal().V()";
+ // Note - if they're only passing on parameter, there won't be any commas
+ String [] paramArr = dataString.split(",");
+ for( int i = 0; i < paramArr.length; i++ ){
+ int pipeLoc = paramArr[i].indexOf("|");
+ if( pipeLoc <= 0 ){
+ msg = "Must use the -params4Collect option when collecting data with data string in a format like: 'propName1|propVal1,propName2|propVal2'";
+ System.out.println(msg);
+ logger.error(msg);
+ System.exit(0);
+ }
+ else {
+ String propName = paramArr[i].substring(0,pipeLoc);
+ String propVal = paramArr[i].substring(pipeLoc + 1);
+ g = g.has(propName,propVal);
+ qStringForMsg = qStringForMsg + ".has(" + propName + "," + propVal + ")";
+ }
+ }
+ if( (g != null)){
+ Iterator<Vertex> vertItor = g;
+ while( vertItor.hasNext() ){
+ resCount++;
+ Vertex v = vertItor.next();
+ fd.showNodeInfo( logger, v, displayAllVidsFlag );
+ int descendantCount = fd.countDescendants( logger, v, 0 );
+ String infMsg = " Found " + descendantCount + " descendant nodes \n";
+ System.out.println( infMsg );
+ logger.info( infMsg );
+ }
+ }
+ else {
+ msg = "Bad TitanGraphQuery object. ";
+ System.out.println(msg);
+ logger.error(msg);
+ System.exit(0);
+ }
+
+ String infMsg = "\n\n Found: " + resCount + " nodes for this query: [" + qStringForMsg + "]\n";
+ System.out.println( infMsg );
+ logger.info( infMsg );
+ }
+ else if( actionVal.equals("DELETE_NODE") ){
+ Iterator <Vertex> vtxItr = graph.vertices( vertexIdLong );
+ if( vtxItr != null && vtxItr.hasNext() ) {
+ Vertex vtx = vtxItr.next();
+ fd.showNodeInfo( logger, vtx, displayAllVidsFlag );
+ int descendantCount = fd.countDescendants( logger, vtx, 0 );
+ String infMsg = " Found " + descendantCount + " descendant nodes. Note - forceDelete does not cascade to " +
+ " child nodes, but they may become unreachable after the delete. \n";
+ System.out.println( infMsg );
+ logger.info( infMsg );
+
+ int edgeCount = fd.countEdges( logger, vtx );
+
+ infMsg = " Found total of " + edgeCount + " edges incident on this node. \n";
+ System.out.println( infMsg );
+ logger.info( infMsg );
+
+ if( fd.getNodeDelConfirmation(logger, userIdVal, vtx, descendantCount, edgeCount, overRideProtection) ){
+ vtx.remove();
+ graph.tx().commit();
+ infMsg = ">>>>>>>>>> Removed node with vertexId = " + vertexIdLong;
+ logger.info( infMsg );
+ System.out.println(infMsg);
+ }
+ else {
+ infMsg = " Delete Cancelled. ";
+ System.out.println(infMsg);
+ logger.info( infMsg );
+ }
+ }
+ else {
+ String infMsg = ">>>>>>>>>> Vertex with vertexId = " + vertexIdLong + " not found.";
+ System.out.println( infMsg );
+ logger.info( infMsg );
+ }
+ }
+ else if( actionVal.equals("DELETE_EDGE") ){
+ Edge thisEdge = null;
+ Iterator <Edge> edItr = graph.edges( edgeIdStr );
+ if( edItr != null && edItr.hasNext() ) {
+ thisEdge = edItr.next();
+ }
+
+ if( thisEdge == null ){
+ String infMsg = ">>>>>>>>>> Edge with edgeId = " + edgeIdStr + " not found.";
+ logger.info( infMsg );
+ System.out.println(infMsg);
+ System.exit(0);
+ }
+
+ if( fd.getEdgeDelConfirmation(logger, userIdVal, thisEdge, overRideProtection) ){
+ thisEdge.remove();
+ graph.tx().commit();
+ String infMsg = ">>>>>>>>>> Removed edge with edgeId = " + edgeIdStr;
+ logger.info( infMsg );
+ System.out.println(infMsg);
+ }
+ else {
+ String infMsg = " Delete Cancelled. ";
+ System.out.println(infMsg);
+ logger.info( infMsg );
+ }
+ System.exit(0);
+ }
+ else {
+ String emsg = "Unknown action parameter [" + actionVal + "] passed to ForceDeleteTool(). Valid values = COLLECT_DATA, DELETE_NODE or DELETE_EDGE \n";
+ System.out.println(emsg);
+ logger.info( emsg );
+ System.exit(0);
+ }
+
+ System.exit(0);
+
+ }// end of main()
+
+ public static class ForceDelete {
+
+ private final int MAXDESCENDENTDEPTH = 15;
+ private final TitanGraph graph;
+ public ForceDelete(TitanGraph graph) {
+ this.graph = graph;
+ }
+ public void showNodeInfo(EELFLogger logger, Vertex tVert, Boolean displayAllVidsFlag ){
+
+ try {
+ Iterator<VertexProperty<Object>> pI = tVert.properties();
+ String infStr = ">>> Found Vertex with VertexId = " + tVert.id() + ", properties: ";
+ System.out.println( infStr );
+ logger.info(infStr);
+ while( pI.hasNext() ){
+ VertexProperty<Object> tp = pI.next();
+ infStr = " [" + tp.key() + "|" + tp.value() + "] ";
+ System.out.println( infStr );
+ logger.info(infStr);
+ }
+
+ ArrayList <String> retArr = collectEdgeInfoForNode( logger, tVert, displayAllVidsFlag );
+ for( String infoStr : retArr ){
+ System.out.println( infoStr );
+ logger.info(infoStr);
+ }
+ }
+ catch (Exception e){
+ String warnMsg = " -- Error -- trying to display edge info. [" + e.getMessage() + "]";
+ System.out.println( warnMsg );
+ logger.warn(warnMsg);
+ }
+
+ }// End of showNodeInfo()
+
+
+ public void showPropertiesForEdge( EELFLogger logger, Edge tEd ){
+ String infMsg = "";
+ if( tEd == null ){
+ infMsg = "null Edge object passed to showPropertiesForEdge()";
+ System.out.print(infMsg);
+ logger.info(infMsg);
+ return;
+ }
+
+ // Try to show the edge properties
+ try {
+ infMsg =" Label for this Edge = [" + tEd.label() + "] ";
+ System.out.print(infMsg);
+ logger.info(infMsg);
+
+ infMsg =" EDGE Properties for edgeId = " + tEd.id() + ": ";
+ System.out.print(infMsg);
+ logger.info(infMsg);
+ Iterator <String> pI = tEd.keys().iterator();
+ while( pI.hasNext() ){
+ String propKey = pI.next();
+ infMsg = "Prop: [" + propKey + "], val = ["
+ + tEd.property(propKey) + "] ";
+ System.out.print(infMsg);
+ logger.info(infMsg);
+ }
+ }
+ catch( Exception ex ){
+ infMsg = " Could not retrieve properties for this edge. exMsg = ["
+ + ex.getMessage() + "] ";
+ System.out.println( infMsg );
+ logger.info(infMsg);
+ }
+
+ // Try to show what's connected to the IN side of this Edge
+ try {
+ infMsg = " Looking for the Vertex on the IN side of the edge: ";
+ System.out.print(infMsg);
+ logger.info(infMsg);
+ Vertex inVtx = tEd.inVertex();
+ Iterator<VertexProperty<Object>> pI = inVtx.properties();
+ String infStr = ">>> Found Vertex with VertexId = " + inVtx.id()
+ + ", properties: ";
+ System.out.println( infStr );
+ logger.info(infStr);
+ while( pI.hasNext() ){
+ VertexProperty<Object> tp = pI.next();
+ infStr = " [" + tp.key() + "|" + tp.value() + "] ";
+ System.out.println( infStr );
+ logger.info(infStr);
+ }
+ }
+ catch( Exception ex ){
+ infMsg = " Could not retrieve vertex data for the IN side of "
+ + "the edge. exMsg = [" + ex.getMessage() + "] ";
+ System.out.println( infMsg );
+ logger.info(infMsg);
+ }
+
+ // Try to show what's connected to the OUT side of this Edge
+ try {
+ infMsg = " Looking for the Vertex on the OUT side of the edge: ";
+ System.out.print(infMsg);
+ logger.info(infMsg);
+ Vertex outVtx = tEd.outVertex();
+ Iterator<VertexProperty<Object>> pI = outVtx.properties();
+ String infStr = ">>> Found Vertex with VertexId = " + outVtx.id()
+ + ", properties: ";
+ System.out.println( infStr );
+ logger.info(infStr);
+ while( pI.hasNext() ){
+ VertexProperty<Object> tp = pI.next();
+ infStr = " [" + tp.key() + "|" + tp.value() + "] ";
+ System.out.println( infStr );
+ logger.info(infStr);
+ }
+ }
+ catch( Exception ex ){
+ infMsg = " Could not retrieve vertex data for the OUT side of "
+ + "the edge. exMsg = [" + ex.getMessage() + "] ";
+ System.out.println( infMsg );
+ logger.info(infMsg);
+ }
+
+ }// end showPropertiesForEdge()
+
+
+
+ public ArrayList <String> collectEdgeInfoForNode( EELFLogger logger, Vertex tVert, boolean displayAllVidsFlag ){
+ ArrayList <String> retArr = new ArrayList <String> ();
+ Direction dir = Direction.OUT;
+ for ( int i = 0; i <= 1; i++ ){
+ if( i == 1 ){
+ // Second time through we'll look at the IN edges.
+ dir = Direction.IN;
+ }
+ Iterator <Edge> eI = tVert.edges(dir);
+ if( ! eI.hasNext() ){
+ retArr.add("No " + dir + " edges were found for this vertex. ");
+ }
+ while( eI.hasNext() ){
+ Edge ed = eI.next();
+ String lab = ed.label();
+ Vertex vtx = null;
+ if( dir == Direction.OUT ){
+ // get the vtx on the "other" side
+ vtx = ed.inVertex();
+ }
+ else {
+ // get the vtx on the "other" side
+ vtx = ed.outVertex();
+ }
+ 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);
+ if( displayAllVidsFlag ){
+ // This should rarely be needed
+ String vid = vtx.id().toString();
+ retArr.add("Found an " + dir + " edge (" + lab + ") between this vertex and a [" + nType + "] node with VtxId = " + vid );
+ }
+ else {
+ // This is the normal case
+ retArr.add("Found an " + dir + " edge (" + lab + ") between this vertex and a [" + nType + "] node. ");
+ }
+ }
+ }
+ }
+ return retArr;
+
+ }// end of collectEdgeInfoForNode()
+
+
+ public int countEdges( EELFLogger logger, Vertex vtx ){
+ int edgeCount = 0;
+ try {
+ Iterator<Edge> edgesItr = vtx.edges(Direction.BOTH);
+ while( edgesItr.hasNext() ){
+ edgesItr.next();
+ edgeCount++;
+ }
+ }
+ catch (Exception e) {
+ String wMsg = "-- ERROR -- Stopping the counting of edges because of Exception [" + e.getMessage() + "]";
+ System.out.println( wMsg );
+ logger.warn( wMsg );
+ }
+ return edgeCount;
+
+ }// end of countEdges()
+
+
+ public int countDescendants(EELFLogger logger, Vertex vtx, int levelVal ){
+ int totalCount = 0;
+ int thisLevel = levelVal + 1;
+
+ if( thisLevel > MAXDESCENDENTDEPTH ){
+ String wMsg = "Warning -- Stopping the counting of descendents because we reached the max depth of " + MAXDESCENDENTDEPTH;
+ System.out.println( wMsg );
+ logger.warn( wMsg );
+ return totalCount;
+ }
+
+ try {
+ Iterator <Vertex> vertI = graph.traversal().V(vtx).union(__.outE().has(EdgeProperty.CONTAINS.toString(), AAIDirection.OUT.toString()).inV(), __.inE().has(EdgeProperty.CONTAINS.toString(), AAIDirection.IN.toString()).outV());
+ while( vertI != null && vertI.hasNext() ){
+ totalCount++;
+ Vertex childVtx = vertI.next();
+ totalCount = totalCount + countDescendants( logger, childVtx, thisLevel );
+ }
+ }
+ catch (Exception e) {
+ String wMsg = "Error -- Stopping the counting of descendents because of Exception [" + e.getMessage() + "]";
+ System.out.println( wMsg );
+ logger.warn( wMsg );
+ }
+
+ return totalCount;
+ }// end of countDescendants()
+
+
+ public boolean getEdgeDelConfirmation( EELFLogger logger, String uid, Edge ed,
+ Boolean overRideProtection ) {
+
+ showPropertiesForEdge( logger, ed );
+ System.out.print("\n Are you sure you want to delete this EDGE? (y/n): ");
+ Scanner s = new Scanner(System.in);
+ s.useDelimiter("");
+ String confirm = s.next();
+ s.close();
+
+ if (!confirm.equalsIgnoreCase("y")) {
+ String infMsg = " User [" + uid + "] has chosen to abandon this delete request. ";
+ System.out.println("\n" + infMsg);
+ logger.info(infMsg);
+ return false;
+ }
+ else {
+ String infMsg = " User [" + uid + "] has confirmed this delete request. ";
+ System.out.println("\n" + infMsg);
+ logger.info(infMsg);
+ return true;
+ }
+
+ } // End of getEdgeDelConfirmation()
+
+
+ public boolean getNodeDelConfirmation( EELFLogger logger, String uid, Vertex vtx, int edgeCount,
+ int descendantCount, Boolean overRideProtection ) {
+ String thisNodeType = "";
+ try {
+ thisNodeType = vtx.<String>property("aai-node-type").orElse(null);
+ }
+ catch ( Exception nfe ){
+ // Let the user know something is going on - but they can confirm the delete if they want to.
+ String infMsg = " -- WARNING -- could not get an aai-node-type for this vertex. -- WARNING -- ";
+ System.out.println( infMsg );
+ logger.warn( infMsg );
+ }
+
+ String ntListString = "";
+ String maxDescString = "";
+ String maxEdgeString = "";
+
+ int maxDescCount = 10; // default value
+ int maxEdgeCount = 10; // default value
+ ArrayList <String> protectedNTypes = new ArrayList <String> ();
+ protectedNTypes.add("cloud-region"); // default value
+
+ try {
+ ntListString = AAIConfig.get("aai.forceDel.protected.nt.list");
+ maxDescString = AAIConfig.get("aai.forceDel.protected.descendant.count");
+ maxEdgeString = AAIConfig.get("aai.forceDel.protected.edge.count");
+ }
+ catch ( Exception nfe ){
+ // Don't worry, we will use default values
+ String infMsg = "-- WARNING -- could not get aai.forceDel.protected values from aaiconfig.properties -- will use default values. ";
+ System.out.println( infMsg );
+ logger.warn( infMsg );
+ }
+
+ if( maxDescString != null && !maxDescString.equals("") ){
+ try {
+ maxDescCount = Integer.parseInt(maxDescString);
+ }
+ catch ( Exception nfe ){
+ // Don't worry, we will leave "maxDescCount" set to the default value
+ }
+ }
+
+ if( maxEdgeString != null && !maxEdgeString.equals("") ){
+ try {
+ maxEdgeCount = Integer.parseInt(maxEdgeString);
+ }
+ catch ( Exception nfe ){
+ // Don't worry, we will leave "maxEdgeCount" set to the default value
+ }
+ }
+
+ if( ntListString != null && !ntListString.trim().equals("") ){
+ String [] nodeTypes = ntListString.split("\\|");
+ for( int i = 0; i < nodeTypes.length; i++ ){
+ protectedNTypes.add(nodeTypes[i]);
+ }
+ }
+
+ boolean giveProtOverRideMsg = false;
+ boolean giveProtErrorMsg = false;
+ if( descendantCount > maxDescCount ){
+ // They are trying to delete a node with a lots of descendants
+ String infMsg = " >> WARNING >> This node has more descendant edges than the max ProtectedDescendantCount: " + edgeCount + ". Max = " +
+ maxEdgeCount + ". It can be DANGEROUS to delete one of these. << WARNING << ";
+ System.out.println(infMsg);
+ logger.info(infMsg);
+ if( ! overRideProtection ){
+ // They cannot delete this kind of node without using the override option
+ giveProtErrorMsg = true;
+ }
+ else {
+ giveProtOverRideMsg = true;
+ }
+ }
+
+ if( edgeCount > maxEdgeCount ){
+ // They are trying to delete a node with a lot of edges
+ String infMsg = " >> WARNING >> This node has more edges than the max ProtectedEdgeCount: " + edgeCount + ". Max = " +
+ maxEdgeCount + ". It can be DANGEROUS to delete one of these. << WARNING << ";
+ System.out.println(infMsg);
+ logger.info(infMsg);
+ if( ! overRideProtection ){
+ // They cannot delete this kind of node without using the override option
+ giveProtErrorMsg = true;
+ }
+ else {
+ giveProtOverRideMsg = true;
+ }
+ }
+
+ if( thisNodeType != null && !thisNodeType.equals("") && protectedNTypes.contains(thisNodeType) ){
+ // They are trying to delete a protected Node Type
+ String infMsg = " >> WARNING >> This node is a PROTECTED NODE-TYPE (" + thisNodeType + "). " +
+ " It can be DANGEROUS to delete one of these. << WARNING << ";
+ System.out.println(infMsg);
+ logger.info(infMsg);
+ if( ! overRideProtection ){
+ // They cannot delete this kind of node without using the override option
+ giveProtErrorMsg = true;
+ }
+ else {
+ giveProtOverRideMsg = true;
+ }
+ }
+
+ if( giveProtOverRideMsg ){
+ String infMsg = " !!>> WARNING >>!! you are using the overRideProtection parameter which will let you do this potentially dangerous delete.";
+ System.out.println("\n" + infMsg);
+ logger.info(infMsg);
+ }
+ else if( giveProtErrorMsg ) {
+ String errMsg = " ERROR >> this kind of node can only be deleted if you pass the overRideProtection parameter.";
+ System.out.println("\n" + errMsg);
+ logger.error(errMsg);
+ return false;
+ }
+
+ System.out.print("\n Are you sure you want to do this delete? (y/n): ");
+ Scanner s = new Scanner(System.in);
+ s.useDelimiter("");
+ String confirm = s.next();
+ s.close();
+
+ if (!confirm.equalsIgnoreCase("y")) {
+ String infMsg = " User [" + uid + "] has chosen to abandon this delete request. ";
+ System.out.println("\n" + infMsg);
+ logger.info(infMsg);
+ return false;
+ }
+ else {
+ String infMsg = " User [" + uid + "] has confirmed this delete request. ";
+ System.out.println("\n" + infMsg);
+ logger.info(infMsg);
+ return true;
+ }
+
+ } // End of getNodeDelConfirmation()
+ }
+
+}
+
+
diff --git a/aai-resources/src/main/java/org/onap/aai/dbgen/GraphMLTokens.java b/aai-resources/src/main/java/org/onap/aai/dbgen/GraphMLTokens.java
new file mode 100644
index 0000000..2eb35e8
--- /dev/null
+++ b/aai-resources/src/main/java/org/onap/aai/dbgen/GraphMLTokens.java
@@ -0,0 +1,58 @@
+/**
+ * ============LICENSE_START=======================================================
+ * org.onap.aai
+ * ================================================================================
+ * Copyright © 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END=========================================================
+ *
+ * ECOMP is a trademark and service mark of AT&T Intellectual Property.
+ */
+package org.onap.aai.dbgen;
+
+/**
+ * A collection of tokens used for GraphML related data.
+ */
+public class GraphMLTokens {
+ public static final String GRAPHML = "graphml";
+ public static final String XMLNS = "xmlns";
+ public static final String GRAPHML_XMLNS = "http://graphml.graphdrawing.org/xmlns";
+ public static final String G = "G";
+ public static final String EDGEDEFAULT = "edgedefault";
+ public static final String DIRECTED = "directed";
+ public static final String KEY = "key";
+ public static final String FOR = "for";
+ public static final String ID = "id";
+ public static final String ATTR_NAME = "attr.name";
+ public static final String ATTR_TYPE = "attr.type";
+ public static final String GRAPH = "graph";
+ public static final String NODE = "node";
+ public static final String EDGE = "edge";
+ public static final String SOURCE = "source";
+ public static final String TARGET = "target";
+ public static final String DATA = "data";
+ public static final String LABEL = "label";
+ public static final String STRING = "string";
+ public static final String FLOAT = "float";
+ public static final String DOUBLE = "double";
+ public static final String LONG = "long";
+ public static final String BOOLEAN = "boolean";
+ public static final String INT = "int";
+ public static final String ARRAY = "array";
+ public static final String SET = "set";
+ public static final String LIST = "list";
+ public static final String ITEM = "item";
+ public static final String _DEFAULT = "_default";
+
+}
diff --git a/aai-resources/src/main/java/org/onap/aai/dbgen/UpdateEdgeTags.java b/aai-resources/src/main/java/org/onap/aai/dbgen/UpdateEdgeTags.java
new file mode 100644
index 0000000..9fbed5d
--- /dev/null
+++ b/aai-resources/src/main/java/org/onap/aai/dbgen/UpdateEdgeTags.java
@@ -0,0 +1,311 @@
+/**
+ * ============LICENSE_START=======================================================
+ * org.onap.aai
+ * ================================================================================
+ * Copyright © 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END=========================================================
+ *
+ * ECOMP is a trademark and service mark of AT&T Intellectual Property.
+ */
+package org.onap.aai.dbgen;
+
+import com.google.common.collect.Multimap;
+import com.thinkaurelius.titan.core.TitanGraph;
+import org.apache.tinkerpop.gremlin.structure.Edge;
+import org.apache.tinkerpop.gremlin.structure.Graph;
+import org.apache.tinkerpop.gremlin.structure.Vertex;
+import org.onap.aai.dbmap.AAIGraph;
+import org.onap.aai.exceptions.AAIException;
+import org.onap.aai.logging.ErrorLogHelper;
+import org.onap.aai.serialization.db.EdgeRule;
+import org.onap.aai.serialization.db.EdgeRules;
+import org.onap.aai.util.AAIConfig;
+
+import java.util.*;
+
+
+public class UpdateEdgeTags {
+
+ private static final String FROMAPPID = "AAI-DB";
+ private static final String TRANSID = UUID.randomUUID().toString();
+
+ /**
+ * The main method.
+ *
+ * @param args the arguments
+ */
+ public static void main(String[] args) {
+
+ if( args == null || args.length != 1 ){
+ String msg = "usage: UpdateEdgeTags edgeRuleKey (edgeRuleKey can be either, all, or a rule key like 'nodeTypeA|nodeTypeB') \n";
+ System.out.println(msg);
+ System.exit(1);
+ }
+ String edgeRuleKeyVal = args[0];
+
+ TitanGraph graph = null;
+ EdgeRules edgeRulesInstance = EdgeRules.getInstance();
+ Multimap<String, EdgeRule> edgeRuleMultimap = edgeRulesInstance.getAllRules();
+
+ HashMap <String,Object> edgeRuleHash = new HashMap <String,Object>();
+ HashMap <String,Object> edgeRulesFullHash = new HashMap <String,Object>();
+ HashMap <String,Object> edgeRuleLabelToKeyHash = new HashMap <String,Object>();
+ ArrayList <String> labelMapsToMultipleKeys = new <String> ArrayList ();
+
+ // Loop through all the edge-rules make sure they look right and
+ // collect info about which labels support duplicate ruleKeys.
+ Iterator<String> edgeRulesIterator = edgeRuleMultimap.keySet().iterator();
+
+ while( edgeRulesIterator.hasNext() ){
+ String ruleKey = edgeRulesIterator.next();
+ Collection <EdgeRule> edRuleColl = edgeRuleMultimap.get(ruleKey);
+ Iterator <EdgeRule> ruleItr = edRuleColl.iterator();
+ if( ruleItr.hasNext() ){
+ // For now, we only look for one type of edge between two nodes.
+ EdgeRule edgeRule = ruleItr.next();
+ String edgeRuleString = String.format("%s,%s,%s,%s,%s,%s",
+ edgeRule.getLabel(),
+ edgeRule.getDirection(),
+ edgeRule.getMultiplicityRule(),
+ edgeRule.getContains(),
+ edgeRule.getDeleteOtherV(),
+ edgeRule.getServiceInfrastructure());
+ edgeRulesFullHash.put(ruleKey,edgeRuleString);
+ String edgeLabel = edgeRule.getLabel();
+ if( edgeRuleLabelToKeyHash.containsKey(edgeLabel) ){
+ // This label maps to more than one edge rule - we'll have to figure out
+ // which rule applies when we look at each edge that uses this label.
+ // So we take it out of mapping hash and add it to the list of ones that
+ // we'll need to look up later.
+ edgeRuleLabelToKeyHash.remove(edgeLabel);
+ labelMapsToMultipleKeys.add(edgeLabel);
+ }
+ else {
+ edgeRuleLabelToKeyHash.put(edgeLabel, ruleKey);
+ }
+ }
+ }
+
+ if( ! edgeRuleKeyVal.equals( "all" ) ){
+ // If they passed in a (non-"all") argument, that is the single edgeRule that they want to update.
+ // Note - the key looks like "nodeA|nodeB" as it appears in DbEdgeRules.EdgeRules
+ Collection <EdgeRule> edRuleColl = edgeRuleMultimap.get(edgeRuleKeyVal);
+ Iterator <EdgeRule> ruleItr = edRuleColl.iterator();
+ if( ruleItr.hasNext() ){
+ // For now, we only look for one type of edge between two nodes (Ie. for one key).
+ EdgeRule edRule = ruleItr.next();
+ edgeRuleHash.put(edgeRuleKeyVal, edRule);
+ System.out.println("Adding this rule to list of rules to do: key = " + edgeRuleKeyVal + ", rule = [" + edRule + "]");
+ }
+ else {
+ String msg = " Error - Unrecognized edgeRuleKey: [" + edgeRuleKeyVal + "]. ";
+ System.out.println(msg);
+ System.exit(0);
+ }
+ }
+ else {
+ // They didn't pass a target ruleKey in, so we'll work on all types of edges
+ edgeRuleHash.putAll(edgeRulesFullHash);
+ }
+
+ try {
+ AAIConfig.init();
+ System.out.println(" ---- NOTE --- about to open graph (takes a little while)--------\n");
+ ErrorLogHelper.loadProperties();
+
+ graph = AAIGraph.getInstance().getGraph();
+
+ if( graph == null ){
+ String emsg = "null graph object in updateEdgeTags() \n";
+ System.out.println(emsg);
+ System.exit(0);
+ }
+ }
+ catch (AAIException e1) {
+ String msg = e1.getErrorObject().toString();
+ System.out.println(msg);
+ System.exit(0);
+ }
+ catch (Exception e2) {
+ String msg = e2.toString();
+ System.out.println(msg);
+ e2.printStackTrace();
+ System.exit(0);
+ }
+
+ Graph g = graph.newTransaction();
+ try {
+ Iterator<Edge> edgeItr = graph.traversal().E();
+
+ // Loop through all edges and update their tags if they are a type we are interested in.
+ // Sorry about looping over everything, but for now, I can't find a way to just select one type of edge at a time...!?
+ StringBuffer sb;
+ boolean missingEdge = false;
+ while( edgeItr != null && edgeItr.hasNext() ){
+ Edge tmpEd = edgeItr.next();
+ String edLab = tmpEd.label().toString();
+
+ // Since we have edgeLabels that can be used for different pairs of node-types, we have to
+ // look to see what nodeTypes this edge is connecting (if it is a label that could do this).
+ String derivedEdgeKey = "";
+ if( labelMapsToMultipleKeys.contains(edLab) ){
+ // need to figure out which key is right for this edge
+ derivedEdgeKey = deriveEdgeRuleKeyForThisEdge( TRANSID, FROMAPPID, g, tmpEd );
+ }
+ else {
+ // This kind of label only maps to one key -- so we can just look it up.
+ if ( edgeRuleLabelToKeyHash.get(edLab) == null ) {
+ if ( !missingEdge ) {
+ System.out.print("DEBUG - missing edge(s) in edgeRuleLabelToKeyHash " + edgeRuleLabelToKeyHash.toString());
+ missingEdge = true;
+ }
+ sb = new StringBuffer();
+ Vertex vIn = null;
+ Vertex vOut = null;
+ Object obj = null;
+ vIn = tmpEd.inVertex();
+ if ( vIn != null ){
+ obj = vIn.<String>property("aai-node-type").orElse(null);
+ if ( obj != null ) {
+ sb.append("from node-type " + obj.toString());
+
+ obj = vIn.id();
+ sb.append(" id " + obj.toString());
+ } else {
+ sb.append(" missing from node-type ");
+ }
+ } else {
+ sb.append(" missing inbound vertex ");
+ }
+ vOut = tmpEd.outVertex();
+ if ( vOut != null ) {
+ obj = vOut.<String>property("aai-node-type").orElse(null);
+ if ( obj != null ) {
+ sb.append(" to node-type " + obj.toString());
+ obj = vOut.id();
+ sb.append(" id " + obj.toString());
+ } else {
+ sb.append(" missing to node-type ");
+ }
+ } else {
+ sb.append(" missing to vertex ");
+ }
+ System.out.println("DEBUG - null entry for [" + edLab + "] between " + sb.toString());
+ continue;
+ }
+ derivedEdgeKey = edgeRuleLabelToKeyHash.get(edLab).toString();
+ }
+
+ if( edgeRuleHash.containsKey(derivedEdgeKey) ){
+ // this is an edge that we want to update
+ System.out.print("DEBUG - key = " + derivedEdgeKey + ", label = " + edLab
+ + ", for id = " + tmpEd.id().toString() + ", set: ");
+ Map<String,EdgeRule> edgeRules = getEdgeTagPropPutHash(TRANSID, FROMAPPID, derivedEdgeKey);
+ for (String key : edgeRules.keySet()) {
+ if (tmpEd.label().equals(key)) {
+ EdgeRules.getInstance().addProperties(tmpEd, edgeRules.get(key));
+ }
+ }
+ System.out.print("\n");
+ }
+ } // End of looping over all edges
+ graph.tx().commit();
+ System.out.println("DEBUG - committed updates for listed edges " );
+ }
+ catch (Exception e2) {
+ String msg = e2.toString();
+ System.out.println(msg);
+ e2.printStackTrace();
+ if( graph != null ){
+ graph.tx().rollback();
+ }
+ System.exit(0);
+ }
+
+ System.exit(0);
+
+ }// end of main()
+
+
+ /**
+ * 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, Graph graph,
+ Edge tEdge ) throws AAIException {
+
+ Vertex fromVtx = tEdge.outVertex();
+ Vertex 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()
+
+
+ /**
+ * 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()
+
+
+
+}
+
+
+
diff --git a/aai-resources/src/main/java/org/onap/aai/interceptors/AAIHeaderProperties.java b/aai-resources/src/main/java/org/onap/aai/interceptors/AAIHeaderProperties.java
new file mode 100644
index 0000000..733383a
--- /dev/null
+++ b/aai-resources/src/main/java/org/onap/aai/interceptors/AAIHeaderProperties.java
@@ -0,0 +1,27 @@
+/**
+ * ============LICENSE_START=======================================================
+ * org.onap.aai
+ * ================================================================================
+ * Copyright © 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END=========================================================
+ *
+ * ECOMP is a trademark and service mark of AT&T Intellectual Property.
+ */
+package org.onap.aai.interceptors;
+
+public class AAIHeaderProperties {
+
+ public static final String REQUEST_CONTEXT = "aai-request-context";
+}
diff --git a/aai-resources/src/main/java/org/onap/aai/interceptors/AAILogJAXRSInInterceptor.java b/aai-resources/src/main/java/org/onap/aai/interceptors/AAILogJAXRSInInterceptor.java
new file mode 100644
index 0000000..7d8112d
--- /dev/null
+++ b/aai-resources/src/main/java/org/onap/aai/interceptors/AAILogJAXRSInInterceptor.java
@@ -0,0 +1,285 @@
+/**
+ * ============LICENSE_START=======================================================
+ * org.onap.aai
+ * ================================================================================
+ * Copyright © 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END=========================================================
+ *
+ * ECOMP is a trademark and service mark of AT&T Intellectual Property.
+ */
+package org.onap.aai.interceptors;
+
+import java.io.InputStream;
+import java.util.ArrayList;
+import java.util.Collections;
+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.onap.aai.exceptions.AAIException;
+import org.onap.aai.logging.ErrorLogHelper;
+import org.onap.aai.rest.util.EchoResponse;
+import org.onap.aai.util.AAIConfig;
+import org.onap.aai.util.AAIConstants;
+import org.onap.aai.util.FormatDate;
+import org.onap.aai.util.HbaseSaltPrefixer;
+
+import com.att.eelf.configuration.EELFLogger;
+import com.att.eelf.configuration.EELFManager;
+import org.slf4j.MDC;
+
+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;
+ }
+ MDC.put("RequestId",newTransId);
+ }
+ else {
+ MDC.put("RequestId",transId);
+ }
+
+ List<String> fromAppIdList = headersList.get("X-FromAppId");
+ if (fromAppIdList != null) {
+ String fromAppId = null;
+ for (String fromAppIdValue : fromAppIdList) {
+ fromAppId = fromAppIdValue;
+ }
+ MDC.put("PartnerName",fromAppId);
+ }
+
+ 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() {
+ FormatDate fd = new FormatDate( "YYMMdd-HH:mm:ss:SSS");
+ return fd.getDateTime();
+ }
+
+}
diff --git a/aai-resources/src/main/java/org/onap/aai/interceptors/AAILogJAXRSOutInterceptor.java b/aai-resources/src/main/java/org/onap/aai/interceptors/AAILogJAXRSOutInterceptor.java
new file mode 100644
index 0000000..3b1f50c
--- /dev/null
+++ b/aai-resources/src/main/java/org/onap/aai/interceptors/AAILogJAXRSOutInterceptor.java
@@ -0,0 +1,303 @@
+/**
+ * ============LICENSE_START=======================================================
+ * org.onap.aai
+ * ================================================================================
+ * Copyright © 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END=========================================================
+ *
+ * ECOMP is a trademark and service mark of AT&T Intellectual Property.
+ */
+package org.onap.aai.interceptors;
+
+import java.io.OutputStream;
+import java.util.Collections;
+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.onap.aai.exceptions.AAIException;
+import org.onap.aai.logging.ErrorLogHelper;
+import org.onap.aai.util.AAIConfig;
+import org.onap.aai.util.AAIConstants;
+import org.onap.aai.util.FormatDate;
+
+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() {
+ FormatDate fd = new FormatDate( "YYMMdd-HH:mm:ss:SSS");
+ return fd.getDateTime();
+ }
+
+ 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;
+
+ if (tid == null || "".equals(tid)) {
+ tm = this.genDate();
+ 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-resources/src/main/java/org/onap/aai/interceptors/PostAaiAjscInterceptor.java b/aai-resources/src/main/java/org/onap/aai/interceptors/PostAaiAjscInterceptor.java
new file mode 100644
index 0000000..30382e4
--- /dev/null
+++ b/aai-resources/src/main/java/org/onap/aai/interceptors/PostAaiAjscInterceptor.java
@@ -0,0 +1,64 @@
+/**
+ * ============LICENSE_START=======================================================
+ * org.onap.aai
+ * ================================================================================
+ * Copyright © 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END=========================================================
+ *
+ * ECOMP is a trademark and service mark of AT&T Intellectual Property.
+ */
+package org.onap.aai.interceptors;
+
+import java.util.Map;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.onap.aai.logging.LoggingContext;
+import org.onap.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-resources/src/main/java/org/onap/aai/interceptors/PreAaiAjscInterceptor.java b/aai-resources/src/main/java/org/onap/aai/interceptors/PreAaiAjscInterceptor.java
new file mode 100644
index 0000000..7d1ae73
--- /dev/null
+++ b/aai-resources/src/main/java/org/onap/aai/interceptors/PreAaiAjscInterceptor.java
@@ -0,0 +1,55 @@
+/**
+ * ============LICENSE_START=======================================================
+ * org.onap.aai
+ * ================================================================================
+ * Copyright © 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END=========================================================
+ *
+ * ECOMP is a trademark and service mark of AT&T Intellectual Property.
+ */
+package org.onap.aai.interceptors;
+
+import java.util.Map;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.onap.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-resources/src/main/java/org/onap/aai/migration/EdgeMigrator.java b/aai-resources/src/main/java/org/onap/aai/migration/EdgeMigrator.java
new file mode 100644
index 0000000..4e2fde4
--- /dev/null
+++ b/aai-resources/src/main/java/org/onap/aai/migration/EdgeMigrator.java
@@ -0,0 +1,163 @@
+/**
+ * ============LICENSE_START=======================================================
+ * org.onap.aai
+ * ================================================================================
+ * Copyright © 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END=========================================================
+ *
+ * ECOMP is a trademark and service mark of AT&T Intellectual Property.
+ */
+package org.onap.aai.migration;
+
+import java.util.Map;
+import java.util.List;
+import java.util.ArrayList;
+import org.javatuples.Pair;
+
+import org.apache.tinkerpop.gremlin.structure.Edge;
+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.Vertex;
+import org.onap.aai.db.props.AAIProperties;
+import org.onap.aai.serialization.engines.TransactionalGraphEngine;
+import org.onap.aai.serialization.db.EdgeRule;
+import org.onap.aai.serialization.db.EdgeRules;
+
+/**
+ * A migration template for migrating all edge properties between "from" and "to" node from the DbedgeRules.json
+ *
+ */
+public abstract class EdgeMigrator extends Migrator {
+
+ private boolean success = true;
+ private EdgeRules rules;
+
+ public EdgeMigrator() {
+ // used for not great reflection implementation
+ super();
+ }
+
+ public EdgeMigrator(TransactionalGraphEngine engine) {
+ super(engine);
+ rules = EdgeRules.getInstance();
+ }
+
+ public EdgeMigrator(TransactionalGraphEngine engine, List<Pair<String, String>> nodePairList) {
+ super(engine);
+ rules = EdgeRules.getInstance();
+ }
+
+
+ /**
+ * Do not override this method as an inheritor of this class
+ */
+ @Override
+ public void run() {
+
+ executeModifyOperation();
+
+ }
+
+ /**
+ * This is where inheritors should add their logic
+ */
+ protected void executeModifyOperation() {
+
+ changeEdgeProperties();
+
+ }
+
+ protected void changeEdgeLabels() {
+ //TODO: when json file has edge label as well as edge property changes
+ }
+
+
+
+ protected void changeEdgeProperties() {
+ try {
+ List<Pair<String, String>> nodePairList = this.getAffectedNodePairTypes();
+ for (Pair<String, String> nodePair : nodePairList) {
+
+ String NODE_A = nodePair.getValue0();
+ String NODE_B = nodePair.getValue1();
+ Map<String, EdgeRule> result = rules.getEdgeRules(NODE_A, NODE_B);
+
+ GraphTraversal<Vertex, Vertex> g = this.engine.asAdmin().getTraversalSource().V();
+ /*
+ * Find Out-Edges from Node A to Node B and change them
+ * Also Find Out-Edges from Node B to Node A and change them
+ */
+ g.union(__.has(AAIProperties.NODE_TYPE, NODE_A).outE().where(__.inV().has(AAIProperties.NODE_TYPE, NODE_B)),
+ __.has(AAIProperties.NODE_TYPE, NODE_B).outE().where(__.inV().has(AAIProperties.NODE_TYPE, NODE_A)))
+ .sideEffect(t -> {
+ Edge e = t.get();
+ try {
+ Vertex out = e.outVertex();
+ Vertex in = e.inVertex();
+ if (out == null || in == null) {
+ logger.error(
+ e.id() + " invalid because one vertex was null: out=" + out + " in=" + in);
+ } else {
+ if (result.containsKey(e.label())) {
+ EdgeRule rule = result.get(e.label());
+ e.properties().forEachRemaining(prop -> prop.remove());
+ rules.addProperties(e, rule);
+ } else {
+ logger.info("found vertices connected by unkwown label: out=" + out + " label="
+ + e.label() + " in=" + in);
+ }
+ }
+ } catch (Exception e1) {
+ throw new RuntimeException(e1);
+ }
+ }).iterate();
+ }
+
+ } catch (Exception e) {
+ logger.error("error encountered", e);
+ success = false;
+ }
+ }
+
+ @Override
+ public Status getStatus() {
+ if (success) {
+ return Status.SUCCESS;
+ } else {
+ return Status.FAILURE;
+ }
+ }
+
+ @Override
+ public int getPriority() {
+ return 0;
+ }
+
+ /*
+ * Higher danger rating of 10 only for all edge property changes
+ * or when a quorum of edges change which can be overridden by inheritors
+ */
+ @Override
+ public int getDangerRating() {
+ return 1;
+ }
+
+ /**
+ * List of node pairs("from" and "to"), you would like EdgeMigrator to migrate from json files
+ * @return
+ */
+ public abstract List<Pair<String, String>> getAffectedNodePairTypes() ;
+
+}
diff --git a/aai-resources/src/main/java/org/onap/aai/migration/Enabled.java b/aai-resources/src/main/java/org/onap/aai/migration/Enabled.java
new file mode 100644
index 0000000..47a7c6d
--- /dev/null
+++ b/aai-resources/src/main/java/org/onap/aai/migration/Enabled.java
@@ -0,0 +1,37 @@
+/**
+ * ============LICENSE_START=======================================================
+ * org.onap.aai
+ * ================================================================================
+ * Copyright © 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END=========================================================
+ *
+ * ECOMP is a trademark and service mark of AT&T Intellectual Property.
+ */
+package org.onap.aai.migration;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+
+/**
+ * Used to enable a migration to be picked up by the {@link com.openecomp.aai.migration.MigrationControllerInternal MigrationController}
+ */
+@Target(ElementType.TYPE)
+@Retention(value = RetentionPolicy.RUNTIME)
+public @interface Enabled {
+
+}
diff --git a/aai-resources/src/main/java/org/onap/aai/migration/EventAction.java b/aai-resources/src/main/java/org/onap/aai/migration/EventAction.java
new file mode 100644
index 0000000..76d99be
--- /dev/null
+++ b/aai-resources/src/main/java/org/onap/aai/migration/EventAction.java
@@ -0,0 +1,31 @@
+/**
+ * ============LICENSE_START=======================================================
+ * org.onap.aai
+ * ================================================================================
+ * Copyright © 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END=========================================================
+ *
+ * ECOMP is a trademark and service mark of AT&T Intellectual Property.
+ */
+package org.onap.aai.migration;
+
+/**
+ * Used to describe the type of DMaaP event you would like to create
+ */
+public enum EventAction {
+ CREATE,
+ UPDATE,
+ DELETE
+}
diff --git a/aai-resources/src/main/java/org/onap/aai/migration/MigrationController.java b/aai-resources/src/main/java/org/onap/aai/migration/MigrationController.java
new file mode 100644
index 0000000..93d58b3
--- /dev/null
+++ b/aai-resources/src/main/java/org/onap/aai/migration/MigrationController.java
@@ -0,0 +1,50 @@
+/**
+ * ============LICENSE_START=======================================================
+ * org.onap.aai
+ * ================================================================================
+ * Copyright © 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END=========================================================
+ *
+ * ECOMP is a trademark and service mark of AT&T Intellectual Property.
+ */
+package org.onap.aai.migration;
+
+import org.onap.aai.dbmap.AAIGraph;
+
+/**
+ * Wrapper class to allow {@link com.openecomp.aai.migration.MigrationControllerInternal MigrationControllerInternal}
+ * to be run from a shell script
+ */
+public class MigrationController {
+
+ /**
+ * The main method.
+ *
+ * @param args
+ * the arguments
+ */
+ public static void main(String[] args) {
+
+ MigrationControllerInternal internal = new MigrationControllerInternal();
+
+ try {
+ internal.run(args);
+ } catch (Exception e) {
+ //ignore
+ }
+ AAIGraph.getInstance().getGraph().close();
+ System.exit(0);
+ }
+}
diff --git a/aai-resources/src/main/java/org/onap/aai/migration/MigrationControllerInternal.java b/aai-resources/src/main/java/org/onap/aai/migration/MigrationControllerInternal.java
new file mode 100644
index 0000000..6da9321
--- /dev/null
+++ b/aai-resources/src/main/java/org/onap/aai/migration/MigrationControllerInternal.java
@@ -0,0 +1,424 @@
+/**
+ * ============LICENSE_START=======================================================
+ * org.onap.aai
+ * ================================================================================
+ * Copyright © 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END=========================================================
+ *
+ * ECOMP is a trademark and service mark of AT&T Intellectual Property.
+ */
+package org.onap.aai.migration;
+
+import java.io.File;
+import java.io.IOException;
+import java.lang.reflect.InvocationTargetException;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.List;
+import java.util.Properties;
+import java.util.Set;
+
+import org.apache.activemq.broker.BrokerService;
+import org.apache.commons.configuration.ConfigurationException;
+import org.apache.commons.configuration.PropertiesConfiguration;
+import org.apache.commons.lang.exception.ExceptionUtils;
+import org.apache.tinkerpop.gremlin.structure.Graph;
+import org.apache.tinkerpop.gremlin.structure.io.IoCore;
+import org.onap.aai.db.props.AAIProperties;
+import org.onap.aai.dbmap.AAIGraph;
+import org.onap.aai.dbmap.DBConnectionType;
+import org.onap.aai.exceptions.AAIException;
+import org.onap.aai.introspection.Loader;
+import org.onap.aai.introspection.LoaderFactory;
+import org.onap.aai.introspection.ModelType;
+import org.onap.aai.introspection.Version;
+import org.onap.aai.serialization.engines.QueryStyle;
+import org.onap.aai.serialization.engines.TitanDBEngine;
+import org.onap.aai.serialization.engines.TransactionalGraphEngine;
+import org.onap.aai.util.AAIConstants;
+import org.onap.aai.util.FormatDate;
+import org.reflections.Reflections;
+import org.slf4j.MDC;
+
+import com.att.eelf.configuration.Configuration;
+import com.att.eelf.configuration.EELFLogger;
+import com.att.eelf.configuration.EELFManager;
+import com.beust.jcommander.JCommander;
+import com.beust.jcommander.Parameter;
+
+/**
+ * Runs a series of migrations from a defined directory based on the presence of
+ * the {@link com.openecomp.aai.migration.Enabled Enabled} annotation
+ *
+ * It will also write a record of the migrations run to the database.
+ */
+public class MigrationControllerInternal {
+
+ private EELFLogger logger;
+ private final int DANGER_ZONE = 10;
+ private final String vertexType = "migration-list-1707";
+ private final List<String> resultsSummary = new ArrayList<>();
+ private BrokerService broker;
+ private final List<NotificationHelper> notifications = new ArrayList<>();
+ private final String snapshotLocation = AAIConstants.AAI_HOME + AAIConstants.AAI_FILESEP + "logs" + AAIConstants.AAI_FILESEP + "data" + AAIConstants.AAI_FILESEP + "migrationSnapshots";
+ /**
+ * The main method.
+ *
+ * @param args
+ * the arguments
+ */
+ public void run(String[] args) {
+ // Set the logging file properties to be used by EELFManager
+ Properties props = System.getProperties();
+ props.setProperty(Configuration.PROPERTY_LOGGING_FILE_NAME, "migration-logback.xml");
+ props.setProperty(Configuration.PROPERTY_LOGGING_FILE_PATH, AAIConstants.AAI_HOME_ETC_APP_PROPERTIES);
+
+ logger = EELFManager.getInstance().getLogger(MigrationControllerInternal.class.getSimpleName());
+ MDC.put("logFilenameAppender", MigrationController.class.getSimpleName());
+
+ boolean loadSnapshot = false;
+
+ CommandLineArgs cArgs = new CommandLineArgs();
+
+ JCommander jCommander = new JCommander(cArgs, args);
+ jCommander.setProgramName(MigrationController.class.getSimpleName());
+ // Set flag to load from snapshot based on the presence of snapshot and
+ // graph storage backend of inmemory
+ if (cArgs.dataSnapshot != null && !cArgs.dataSnapshot.isEmpty()) {
+ try {
+ PropertiesConfiguration config = new PropertiesConfiguration(cArgs.config);
+ if (config.getString("storage.backend").equals("inmemory")) {
+ loadSnapshot = true;
+ System.setProperty("load.snapshot.file", "true");
+ System.setProperty("snapshot.location", cArgs.dataSnapshot);
+ }
+ } catch (ConfigurationException e) {
+ logAndPrint("ERROR: Could not load titan configuration.\n" + ExceptionUtils.getFullStackTrace(e));
+ return;
+ }
+ }
+ System.setProperty("realtime.db.config", cArgs.config);
+ logAndPrint("\n\n---------- Connecting to Graph ----------");
+ AAIGraph.getInstance();
+
+ logAndPrint("---------- Connection Established ----------");
+ Version version = AAIProperties.LATEST;
+ QueryStyle queryStyle = QueryStyle.TRAVERSAL;
+ ModelType introspectorFactoryType = ModelType.MOXY;
+ Loader loader = LoaderFactory.createLoaderForVersion(introspectorFactoryType, version);
+ TransactionalGraphEngine engine = new TitanDBEngine(queryStyle, DBConnectionType.REALTIME, loader);
+
+ if (cArgs.help) {
+ jCommander.usage();
+ engine.rollback();
+ return;
+ } else if (cArgs.list) {
+ Reflections reflections = new Reflections("org.onap.aai.migration");
+ Set<Class<? extends Migrator>> migratorClasses = findClasses(reflections);
+ List<Migrator> migratorList = createMigratorList(cArgs, migratorClasses);
+
+ sortList(migratorList);
+ engine.startTransaction();
+ System.out.println("---------- List of all migrations ----------");
+ migratorList.forEach(migrator -> {
+ boolean enabledAnnotation = migrator.getClass().isAnnotationPresent(Enabled.class);
+ String enabled = enabledAnnotation ? "Enabled" : "Disabled";
+ StringBuilder sb = new StringBuilder();
+ sb.append(migrator.getClass().getSimpleName() + " " + enabled);
+ sb.append(" ");
+ sb.append("[" + getDbStatus(migrator.getClass().getSimpleName(), engine) + "]");
+ System.out.println(sb.toString());
+ });
+ engine.rollback();
+ System.out.println("---------- Done ----------");
+ return;
+ }
+
+
+ Reflections reflections = new Reflections("org.onap.aai.migration");
+
+ logAndPrint("---------- Looking for migration scripts to be executed. ----------");
+ Set<Class<? extends Migrator>> migratorClasses = findClasses(reflections);
+ List<Migrator> migratorList = createMigratorList(cArgs, migratorClasses);
+
+ sortList(migratorList);
+
+ if (!cArgs.scripts.isEmpty() && migratorList.size() == 0) {
+ logAndPrint("\tERROR: Failed to find migrations " + cArgs.scripts + ".");
+ logAndPrint("---------- Done ----------");
+ }
+
+ logAndPrint("\tFound " + migratorList.size() + " migration scripts.");
+ logAndPrint("---------- Executing Migration Scripts ----------");
+
+
+
+ takeSnapshotIfRequired(engine, cArgs, migratorList);
+
+ for (Migrator migratorClass : migratorList) {
+ String name = migratorClass.getClass().getSimpleName();
+ Migrator migrator;
+ if (migratorClass.getClass().isAnnotationPresent(Enabled.class)) {
+
+ try {
+ engine.startTransaction();
+ if (!cArgs.forced && hasAlreadyRun(name, engine)) {
+ logAndPrint("Migration " + name + " has already been run on this database and will not be executed again. Use -f to force execution");
+ continue;
+ }
+ migrator = migratorClass.getClass().getConstructor(TransactionalGraphEngine.class).newInstance(engine);
+ } catch (InstantiationException | IllegalAccessException | IllegalArgumentException | InvocationTargetException | NoSuchMethodException | SecurityException e) {
+ logAndPrint("EXCEPTION caught initalizing migration class " + migratorClass.getClass().getSimpleName() + ".\n" + ExceptionUtils.getFullStackTrace(e));
+ engine.rollback();
+ continue;
+ }
+ logAndPrint("\tRunning " + migratorClass.getClass().getSimpleName() + " migration script.");
+ logAndPrint("\t\t See " + System.getProperty("AJSC_HOME") + "/logs/migration/" + migratorClass.getClass().getSimpleName() + "/* for logs.");
+ MDC.put("logFilenameAppender", migratorClass.getClass().getSimpleName() + "/" + migratorClass.getClass().getSimpleName());
+
+ migrator.run();
+
+ commitChanges(engine, migrator, cArgs);
+ } else {
+ logAndPrint("\tSkipping " + migratorClass.getClass().getSimpleName() + " migration script because it has been disabled.");
+ }
+ }
+ MDC.put("logFilenameAppender", MigrationController.class.getSimpleName());
+ for (NotificationHelper notificationHelper : notifications) {
+ try {
+ notificationHelper.triggerEvents();
+ } catch (AAIException e) {
+ logAndPrint("\tcould not event");
+ logger.error("could not event", e);
+ }
+ }
+ logAndPrint("---------- Done ----------");
+
+ // Save post migration snapshot if snapshot was loaded
+ generateSnapshot(engine, "post");
+
+ outputResultsSummary();
+ }
+
+ private String getDbStatus(String name, TransactionalGraphEngine engine) {
+ if (hasAlreadyRun(name, engine)) {
+ return "Already executed in this env";
+ }
+ return "Will be run on next execution";
+ }
+
+ private boolean hasAlreadyRun(String name, TransactionalGraphEngine engine) {
+ return engine.asAdmin().getReadOnlyTraversalSource().V().has(AAIProperties.NODE_TYPE, vertexType).has(name, true).hasNext();
+ }
+ private Set<Class<? extends Migrator>> findClasses(Reflections reflections) {
+ Set<Class<? extends Migrator>> migratorClasses = reflections.getSubTypesOf(Migrator.class);
+ /*
+ * TODO- Change this to make sure only classes in the specific $release are added in the runList
+ * Or add a annotation like exclude which folks again need to remember to add ??
+ */
+
+ migratorClasses.remove(PropertyMigrator.class);
+ migratorClasses.remove(EdgeMigrator.class);
+ return migratorClasses;
+ }
+
+
+ private void takeSnapshotIfRequired(TransactionalGraphEngine engine, CommandLineArgs cArgs, List<Migrator> migratorList) {
+
+ /*int sum = 0;
+ for (Migrator migrator : migratorList) {
+ if (migrator.getClass().isAnnotationPresent(Enabled.class)) {
+ sum += migrator.getDangerRating();
+ }
+ }
+
+ if (sum >= DANGER_ZONE) {
+
+ logAndPrint("Entered Danger Zone. Taking snapshot.");
+ }*/
+
+ //always take snapshot for now
+ generateSnapshot(engine, "pre");
+
+ }
+
+
+ private List<Migrator> createMigratorList(CommandLineArgs cArgs,
+ Set<Class<? extends Migrator>> migratorClasses) {
+ List<Migrator> migratorList = new ArrayList<>();
+
+ for (Class<? extends Migrator> migratorClass : migratorClasses) {
+ if (!cArgs.scripts.isEmpty() && !cArgs.scripts.contains(migratorClass.getSimpleName())) {
+ continue;
+ } else {
+ Migrator migrator;
+ try {
+
+ migrator = migratorClass.getConstructor().newInstance();
+ } catch (InstantiationException | IllegalAccessException | IllegalArgumentException | InvocationTargetException | NoSuchMethodException | SecurityException e) {
+ logAndPrint("EXCEPTION caught initalizing migration class " + migratorClass.getSimpleName() + ".\n" + ExceptionUtils.getFullStackTrace(e));
+ continue;
+ }
+ migratorList.add(migrator);
+ }
+ }
+ return migratorList;
+ }
+
+
+ private void sortList(List<Migrator> migratorList) {
+ Collections.sort(migratorList, new Comparator<Migrator>() {
+ public int compare(Migrator m1, Migrator m2) {
+ try {
+
+ if (m1.getPriority() > m2.getPriority()) {
+ return 1;
+ } else if (m1.getPriority() < m2.getPriority()) {
+ return -1;
+ } else {
+ return m1.getClass().getSimpleName().compareTo(m2.getClass().getSimpleName());
+ }
+ } catch (Exception e) {
+ return 0;
+ }
+ }
+ });
+ }
+
+
+ private void generateSnapshot(TransactionalGraphEngine engine, String phase) {
+
+ FormatDate fd = new FormatDate("yyyyMMddHHmm", "GMT");
+ String dateStr= fd.getDateTime();
+ String fileName = snapshotLocation + File.separator + phase + "Migration." + dateStr + ".graphson";
+ logAndPrint("Saving snapshot of inmemory graph " + phase + " migration to " + fileName);
+ Graph transaction = null;
+ try {
+
+ Path pathToFile = Paths.get(fileName);
+ if (!pathToFile.toFile().exists()) {
+ Files.createDirectories(pathToFile.getParent());
+ }
+ transaction = engine.startTransaction();
+ transaction.io(IoCore.graphson()).writeGraph(fileName);
+ engine.rollback();
+ } catch (IOException e) {
+ logAndPrint("ERROR: Could not write in memory graph to " + phase + "Migration file. \n" + ExceptionUtils.getFullStackTrace(e));
+ engine.rollback();
+ }
+
+ logAndPrint( phase + " migration snapshot saved to " + fileName);
+ }
+ /**
+ * Log and print.
+ *
+ * @param logger
+ * the logger
+ * @param msg
+ * the msg
+ */
+ protected void logAndPrint(String msg) {
+ System.out.println(msg);
+ logger.info(msg);
+ }
+
+ /**
+ * Commit changes.
+ *
+ * @param g
+ * the g
+ * @param migrator
+ * the migrator
+ * @param logger
+ * the logger
+ */
+ protected void commitChanges(TransactionalGraphEngine engine, Migrator migrator, CommandLineArgs cArgs) {
+
+ String simpleName = migrator.getClass().getSimpleName();
+ String message;
+ if (migrator.getStatus().equals(Status.FAILURE)) {
+ message = "Migration " + simpleName + " Failed. Rolling back.";
+ logAndPrint("\t" + message);
+ migrator.rollback();
+ } else if (migrator.getStatus().equals(Status.CHECK_LOGS)) {
+ message = "Migration " + simpleName + " encountered an anomily, check logs. Rolling back.";
+ logAndPrint("\t" + message);
+ migrator.rollback();
+ } else {
+ MDC.put("logFilenameAppender", simpleName + "/" + migrator.getClass().getSimpleName());
+
+ if (cArgs.commit) {
+ if (!engine.asAdmin().getTraversalSource().V().has(AAIProperties.NODE_TYPE, vertexType).hasNext()) {
+ engine.asAdmin().getTraversalSource().addV(AAIProperties.NODE_TYPE, vertexType).iterate();
+ }
+ engine.asAdmin().getTraversalSource().V().has(AAIProperties.NODE_TYPE, vertexType)
+ .property(simpleName, true).iterate();
+ MDC.put("logFilenameAppender", MigrationController.class.getSimpleName());
+ notifications.add(migrator.getNotificationHelper());
+ migrator.commit();
+ message = "Migration " + simpleName + " Succeeded. Changes Committed.";
+ logAndPrint("\t"+ message +"\t");
+ } else {
+ message = "--commit not specified. Not committing changes for " + simpleName + " to database.";
+ logAndPrint("\t" + message);
+ migrator.rollback();
+ }
+
+ }
+
+ resultsSummary.add(message);
+
+ }
+
+ private void outputResultsSummary() {
+ logAndPrint("---------------------------------");
+ logAndPrint("-------------Summary-------------");
+ for (String result : resultsSummary) {
+ logAndPrint(result);
+ }
+ logAndPrint("---------------------------------");
+ logAndPrint("---------------------------------");
+ }
+
+}
+
+class CommandLineArgs {
+
+ @Parameter(names = "--help", help = true)
+ public boolean help;
+
+ @Parameter(names = "-c", description = "location of configuration file")
+ public String config;
+
+ @Parameter(names = "-m", description = "names of migration scripts")
+ public List<String> scripts = new ArrayList<>();
+
+ @Parameter(names = "-l", description = "list the status of migrations")
+ public boolean list = false;
+
+ @Parameter(names = "-d", description = "location of data snapshot", hidden = true)
+ public String dataSnapshot;
+
+ @Parameter(names = "-f", description = "force migrations to be rerun")
+ public boolean forced = false;
+
+ @Parameter(names = "--commit", description = "commit changes to graph")
+ public boolean commit = false;
+
+}
diff --git a/aai-resources/src/main/java/org/onap/aai/migration/Migrator.java b/aai-resources/src/main/java/org/onap/aai/migration/Migrator.java
new file mode 100644
index 0000000..900c914
--- /dev/null
+++ b/aai-resources/src/main/java/org/onap/aai/migration/Migrator.java
@@ -0,0 +1,263 @@
+/**
+ * ============LICENSE_START=======================================================
+ * org.onap.aai
+ * ================================================================================
+ * Copyright © 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END=========================================================
+ *
+ * ECOMP is a trademark and service mark of AT&T Intellectual Property.
+ */
+package org.onap.aai.migration;
+
+import java.util.Iterator;
+import java.util.Optional;
+
+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.Property;
+import org.apache.tinkerpop.gremlin.structure.Vertex;
+import org.apache.tinkerpop.gremlin.structure.VertexProperty;
+import org.json.JSONException;
+import org.json.JSONObject;
+import org.onap.aai.db.props.AAIProperties;
+import org.onap.aai.exceptions.AAIException;
+import org.onap.aai.introspection.Loader;
+import org.onap.aai.introspection.LoaderFactory;
+import org.onap.aai.introspection.ModelType;
+import org.onap.aai.introspection.Version;
+import org.onap.aai.serialization.db.DBSerializer;
+import org.onap.aai.serialization.db.EdgeRules;
+import org.onap.aai.serialization.db.EdgeType;
+import org.onap.aai.serialization.db.exceptions.NoEdgeRuleFoundException;
+import org.onap.aai.serialization.engines.TransactionalGraphEngine;
+
+import com.att.eelf.configuration.EELFLogger;
+import com.att.eelf.configuration.EELFManager;
+
+/**
+ * This class defines an A&AI Migration
+ */
+public abstract class Migrator implements Runnable {
+
+ protected EELFLogger logger = null;
+
+ protected DBSerializer serializer = null;
+ protected Loader loader = null;
+
+ protected TransactionalGraphEngine engine;
+ protected NotificationHelper notificationHelper;
+
+ public Migrator() {
+ //used for not great reflection implementation
+ }
+ /**
+ * Instantiates a new migrator.
+ *
+ * @param g the g
+ */
+ public Migrator(TransactionalGraphEngine engine){
+ this.engine = engine;
+ initDBSerializer();
+ this.notificationHelper = new NotificationHelper(loader, serializer, engine, "AAI-MIGRATION", this.getMigrationName());
+ logger = EELFManager.getInstance().getLogger(this.getClass().getSimpleName());
+ logger.info("\tInitilization of " + this.getClass().getSimpleName() + " migration script complete.");
+ }
+
+ /**
+ * Gets the status.
+ *
+ * @return the status
+ */
+ public abstract Status getStatus();
+
+ /**
+ * Rollback.
+ */
+ public void rollback() {
+ engine.rollback();
+ }
+
+ /**
+ * Commit.
+ */
+ public void commit() {
+ engine.commit();
+ }
+
+ /**
+ * Gets the priority.
+ *
+ * Lower number has higher priority
+ *
+ * @return the priority
+ */
+ public abstract int getPriority();
+
+ /**
+ * The larger the number, the more danger
+ *
+ * Range is 0-10
+ *
+ * @return danger rating
+ */
+ public abstract int getDangerRating();
+ /**
+ * As string.
+ *
+ * @param v the v
+ * @return the string
+ */
+ protected String asString(Vertex v) {
+ final JSONObject result = new JSONObject();
+ Iterator<VertexProperty<Object>> properties = v.properties();
+ Property<Object> pk = null;
+ try {
+ while (properties.hasNext()) {
+ pk = properties.next();
+ result.put(pk.key(), pk.value());
+ }
+ } catch (JSONException e) {
+ logger.error("Warning error reading vertex: " + e);
+ }
+
+ return result.toString();
+ }
+
+ /**
+ * As string.
+ *
+ * @param edge the edge
+ * @return the string
+ */
+ protected String asString(Edge edge) {
+ final JSONObject result = new JSONObject();
+ Iterator<Property<Object>> properties = edge.properties();
+ Property<Object> pk = null;
+ try {
+ while (properties.hasNext()) {
+ pk = properties.next();
+ result.put(pk.key(), pk.value());
+ }
+ } catch (JSONException e) {
+ logger.error("Warning error reading edge: " + e);
+ }
+
+ return result.toString();
+ }
+ /**
+ * Checks for edge between.
+ *
+ * @param vertex a
+ * @param vertex b
+ * @param direction d
+ * @param edgeLabel the edge label
+ * @return true, if successful
+ */
+ protected boolean hasEdgeBetween(Vertex a, Vertex b, Direction d, String edgeLabel) {
+
+ if (d.equals(Direction.OUT)) {
+ return engine.asAdmin().getReadOnlyTraversalSource().V(a).out(edgeLabel).where(__.otherV().hasId(b)).hasNext();
+ } else {
+ return engine.asAdmin().getReadOnlyTraversalSource().V(a).in(edgeLabel).where(__.otherV().hasId(b)).hasNext();
+ }
+
+ }
+
+ /**
+ * Creates the edge
+ *
+ * @param edgeType the edge type - COUSIN or TREE
+ * @param out the out
+ * @param in the in
+ * @return the edge
+ */
+ protected Edge createEdge(EdgeType type, Vertex out, Vertex in) throws AAIException {
+ Edge newEdge = null;
+ try {
+ if (type.equals(EdgeType.COUSIN)){
+ newEdge = EdgeRules.getInstance().addEdge(this.engine.asAdmin().getTraversalSource(), out, in);
+ } else {
+ newEdge = EdgeRules.getInstance().addTreeEdge(this.engine.asAdmin().getTraversalSource(), out, in);
+ }
+ } catch (NoEdgeRuleFoundException e) {
+ throw new AAIException("AAI_6129", e);
+ }
+ return newEdge;
+ }
+
+ /**
+ * Creates the TREE edge
+ *
+ * @param out the out
+ * @param in the in
+ * @return the edge
+ */
+ protected Edge createTreeEdge(Vertex out, Vertex in) throws AAIException {
+ Edge newEdge = createEdge(EdgeType.TREE, out, in);
+ return newEdge;
+ }
+
+ /**
+ * Creates the COUSIN edge
+ *
+ * @param out the out
+ * @param in the in
+ * @return the edge
+ */
+ protected Edge createCousinEdge(Vertex out, Vertex in) throws AAIException {
+ Edge newEdge = createEdge(EdgeType.COUSIN, out, in);
+ return newEdge;
+ }
+
+ protected Edge createCousinEdgeBestEffort(Vertex out, Vertex in) throws AAIException {
+ return EdgeRules.getInstance().addEdgeIfPossible(this.engine.asAdmin().getTraversalSource(), out, in);
+ }
+ private void initDBSerializer() {
+ Version version = AAIProperties.LATEST;
+ ModelType introspectorFactoryType = ModelType.MOXY;
+ loader = LoaderFactory.createLoaderForVersion(introspectorFactoryType, version);
+ try {
+ this.serializer = new DBSerializer(version, this.engine, introspectorFactoryType, this.getMigrationName());
+ } catch (AAIException e) {
+ throw new RuntimeException("could not create seralizer", e);
+ }
+ }
+
+ /**
+ * These are the node types you would like your traversal to process
+ * @return
+ */
+ public abstract Optional<String[]> getAffectedNodeTypes();
+
+ /**
+ * used as the "fromAppId" when modifying vertices
+ * @return
+ */
+ public abstract String getMigrationName();
+
+ /**
+ * updates all internal vertex properties
+ * @param v
+ * @param isNewVertex
+ */
+ protected void touchVertexProperties(Vertex v, boolean isNewVertex) {
+ this.serializer.touchStandardVertexProperties(v, isNewVertex);
+ }
+
+ public NotificationHelper getNotificationHelper() {
+ return this.notificationHelper;
+ }
+}
diff --git a/aai-resources/src/main/java/org/onap/aai/migration/NotificationHelper.java b/aai-resources/src/main/java/org/onap/aai/migration/NotificationHelper.java
new file mode 100644
index 0000000..6835945
--- /dev/null
+++ b/aai-resources/src/main/java/org/onap/aai/migration/NotificationHelper.java
@@ -0,0 +1,107 @@
+/**
+ * ============LICENSE_START=======================================================
+ * org.onap.aai
+ * ================================================================================
+ * Copyright © 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END=========================================================
+ *
+ * ECOMP is a trademark and service mark of AT&T Intellectual Property.
+ */
+package org.onap.aai.migration;
+
+import java.io.UnsupportedEncodingException;
+import java.net.URI;
+import java.util.HashMap;
+import java.util.List;
+
+import javax.ws.rs.core.Response.Status;
+
+import org.apache.tinkerpop.gremlin.structure.Vertex;
+import org.onap.aai.exceptions.AAIException;
+import org.onap.aai.introspection.Introspector;
+import org.onap.aai.introspection.Loader;
+import org.onap.aai.introspection.exceptions.AAIUnknownObjectException;
+import org.onap.aai.rest.ueb.UEBNotification;
+import org.onap.aai.serialization.db.DBSerializer;
+import org.onap.aai.serialization.engines.TransactionalGraphEngine;
+import org.onap.aai.serialization.engines.query.QueryEngine;
+
+import com.att.eelf.configuration.EELFLogger;
+import com.att.eelf.configuration.EELFManager;
+
+/**
+ * Allows for DMaaP notifications from Migrations
+ */
+public class NotificationHelper {
+
+ private static final EELFLogger LOGGER = EELFManager.getInstance().getLogger(NotificationHelper.class);
+ protected final DBSerializer serializer;
+ protected final Loader loader;
+ protected final TransactionalGraphEngine engine;
+ protected final String transactionId;
+ protected final String sourceOfTruth;
+ protected final UEBNotification notification;
+
+ public NotificationHelper(Loader loader, DBSerializer serializer, TransactionalGraphEngine engine, String transactionId, String sourceOfTruth) {
+ this.loader = loader;
+ this.serializer = serializer;
+ this.engine = engine;
+ this.transactionId = transactionId;
+ this.sourceOfTruth = sourceOfTruth;
+ this.notification = new UEBNotification(loader);
+ }
+
+ public void addEvent(Vertex v, Introspector obj, EventAction action, URI uri) throws UnsupportedEncodingException, AAIException {
+ HashMap<String, Introspector> relatedObjects = new HashMap<>();
+ Status status = mapAction(action);
+ if (!obj.isTopLevel()) {
+ relatedObjects = this.getRelatedObjects(serializer, engine.getQueryEngine(), v);
+ }
+ notification.createNotificationEvent(transactionId, sourceOfTruth, status, uri, obj, relatedObjects);
+
+ }
+
+ private HashMap<String, Introspector> getRelatedObjects(DBSerializer serializer, QueryEngine queryEngine, Vertex v) throws AAIException {
+ 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 | UnsupportedEncodingException e) {
+ LOGGER.warn("Unable to get vertex properties, partial list of related vertices returned");
+ }
+
+ }
+
+ return relatedVertices;
+ }
+
+ private Status mapAction(EventAction action) {
+ if (EventAction.CREATE.equals(action)) {
+ return Status.CREATED;
+ } else if (EventAction.UPDATE.equals(action)) {
+ return Status.OK;
+ } else if (EventAction.DELETE.equals(action)) {
+ return Status.NO_CONTENT;
+ } else {
+ return Status.OK;
+ }
+ }
+
+ public void triggerEvents() throws AAIException {
+ notification.triggerEvents();
+ }
+}
diff --git a/aai-resources/src/main/java/org/onap/aai/migration/PropertyMigrator.java b/aai-resources/src/main/java/org/onap/aai/migration/PropertyMigrator.java
new file mode 100644
index 0000000..c42862a
--- /dev/null
+++ b/aai-resources/src/main/java/org/onap/aai/migration/PropertyMigrator.java
@@ -0,0 +1,150 @@
+/**
+ * ============LICENSE_START=======================================================
+ * org.onap.aai
+ * ================================================================================
+ * Copyright © 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END=========================================================
+ *
+ * ECOMP is a trademark and service mark of AT&T Intellectual Property.
+ */
+package org.onap.aai.migration;
+
+import java.util.Optional;
+
+import org.apache.tinkerpop.gremlin.process.traversal.P;
+import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversal;
+import org.apache.tinkerpop.gremlin.structure.Vertex;
+import org.onap.aai.db.props.AAIProperties;
+import org.onap.aai.serialization.engines.TransactionalGraphEngine;
+
+import com.thinkaurelius.titan.core.Cardinality;
+import com.thinkaurelius.titan.core.PropertyKey;
+import com.thinkaurelius.titan.core.schema.TitanManagement;
+
+/**
+ * A migration template for migrating a property from one name to another
+ */
+public abstract class PropertyMigrator extends Migrator {
+
+ protected final String OLD_FIELD;
+ protected final String NEW_FIELD;
+ protected final Class<?> fieldType;
+ protected final Cardinality cardinality;
+ protected final TitanManagement graphMgmt;
+ public PropertyMigrator() {
+ //used for not great reflection implementation
+ super();
+ this.OLD_FIELD = null;
+ this.NEW_FIELD = null;
+ this.fieldType = null;
+ this.cardinality = null;
+ this.graphMgmt = null;
+ }
+ public PropertyMigrator(TransactionalGraphEngine engine, String oldName, String newName, Class<?> type, Cardinality cardinality) {
+ super(engine);
+ this.OLD_FIELD = oldName;
+ this.NEW_FIELD = newName;
+ this.fieldType = type;
+ this.cardinality = cardinality;
+ this.graphMgmt = engine.asAdmin().getManagementSystem();
+ }
+
+ /**
+ * Do not override this method as an inheritor of this class
+ */
+ @Override
+ public void run() {
+
+ modifySchema();
+ executeModifyOperation();
+
+ }
+
+ protected void modifySchema() {
+ this.addIndex(this.addProperty());
+ graphMgmt.commit();
+ }
+
+ /**
+ * This is where inheritors should add their logic
+ */
+ protected void executeModifyOperation() {
+ changePropertyName();
+ }
+
+ protected void changePropertyName() {
+ GraphTraversal<Vertex, Vertex> g = this.engine.asAdmin().getTraversalSource().V();
+ if (this.getAffectedNodeTypes().isPresent()) {
+ g.has(AAIProperties.NODE_TYPE, P.within(this.getAffectedNodeTypes().get()));
+ }
+ g.has(OLD_FIELD).sideEffect(t -> {
+ final Vertex v = t.get();
+ final String value = v.value(OLD_FIELD);
+ v.property(OLD_FIELD).remove();
+ v.property(NEW_FIELD, value);
+ this.touchVertexProperties(v, false);
+ }).iterate();
+ }
+
+ @Override
+ public Status getStatus() {
+ GraphTraversal<Vertex, Vertex> g = this.engine.asAdmin().getTraversalSource().V();
+ if (this.getAffectedNodeTypes().isPresent()) {
+ g.has(AAIProperties.NODE_TYPE, P.within(this.getAffectedNodeTypes().get()));
+ }
+ long result = g.has(OLD_FIELD).count().next();
+ if (result == 0) {
+ return Status.SUCCESS;
+ } else {
+ return Status.FAILURE;
+ }
+ }
+
+ @Override
+ public int getPriority() {
+ return 0;
+ }
+
+ @Override
+ public int getDangerRating() {
+ return 1;
+ }
+
+ protected Optional<PropertyKey> addProperty() {
+
+ if (!graphMgmt.containsPropertyKey(this.NEW_FIELD)) {
+ logger.info(" PropertyKey [" + this.NEW_FIELD + "] created in the DB. ");
+ return Optional.of(graphMgmt.makePropertyKey(this.NEW_FIELD).dataType(this.fieldType).cardinality(this.cardinality)
+ .make());
+ } else {
+ logger.info(" PropertyKey [" + this.NEW_FIELD + "] already existed in the DB. ");
+ return Optional.empty();
+ }
+
+ }
+
+ protected void addIndex(Optional<PropertyKey> key) {
+ if (isIndexed() && key.isPresent()) {
+ if (graphMgmt.containsGraphIndex(key.get().name())) {
+ logger.debug(" Index [" + key.get().name() + "] already existed in the DB. ");
+ } else {
+ logger.info("Add index for PropertyKey: [" + key.get().name() + "]");
+ graphMgmt.buildIndex(key.get().name(), Vertex.class).addKey(key.get()).buildCompositeIndex();
+ }
+ }
+ }
+ public abstract boolean isIndexed();
+
+}
diff --git a/aai-resources/src/main/java/org/onap/aai/migration/Status.java b/aai-resources/src/main/java/org/onap/aai/migration/Status.java
new file mode 100644
index 0000000..eb08597
--- /dev/null
+++ b/aai-resources/src/main/java/org/onap/aai/migration/Status.java
@@ -0,0 +1,31 @@
+/**
+ * ============LICENSE_START=======================================================
+ * org.onap.aai
+ * ================================================================================
+ * Copyright © 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END=========================================================
+ *
+ * ECOMP is a trademark and service mark of AT&T Intellectual Property.
+ */
+package org.onap.aai.migration;
+
+/**
+ * Defines the status of the completed migration
+ */
+public enum Status {
+ SUCCESS,
+ CHECK_LOGS,
+ FAILURE
+}
diff --git a/aai-resources/src/main/java/org/onap/aai/migration/VertexMerge.java b/aai-resources/src/main/java/org/onap/aai/migration/VertexMerge.java
new file mode 100644
index 0000000..a01e026
--- /dev/null
+++ b/aai-resources/src/main/java/org/onap/aai/migration/VertexMerge.java
@@ -0,0 +1,246 @@
+/**
+ * ============LICENSE_START=======================================================
+ * org.onap.aai
+ * ================================================================================
+ * Copyright © 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END=========================================================
+ *
+ * ECOMP is a trademark and service mark of AT&T Intellectual Property.
+ */
+package org.onap.aai.migration;
+
+import java.io.UnsupportedEncodingException;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.Optional;
+import java.util.Set;
+
+import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversalSource;
+import org.apache.tinkerpop.gremlin.structure.Vertex;
+
+import org.onap.aai.db.props.AAIProperties;
+import org.onap.aai.exceptions.AAIException;
+import org.onap.aai.introspection.Introspector;
+import org.onap.aai.introspection.Loader;
+import org.onap.aai.introspection.exceptions.AAIUnknownObjectException;
+import org.onap.aai.serialization.db.DBSerializer;
+import org.onap.aai.serialization.db.EdgeRules;
+import org.onap.aai.serialization.db.EdgeType;
+import org.onap.aai.serialization.engines.TransactionalGraphEngine;
+import com.att.eelf.configuration.EELFLogger;
+import com.att.eelf.configuration.EELFManager;
+
+/**
+ * This class recursively merges two vertices passed in.
+ * <br>
+ * You can start with any two vertices, but after the vertices are merged based off the equality of their keys
+ *
+ */
+public class VertexMerge {
+
+ private final EELFLogger logger = EELFManager.getInstance().getLogger(this.getClass().getSimpleName());
+
+ private final GraphTraversalSource g;
+ private final TransactionalGraphEngine engine;
+ private final DBSerializer serializer;
+ private final EdgeRules rules;
+ private final Loader loader;
+ private final NotificationHelper notificationHelper;
+ private final boolean hasNotifications;
+ private VertexMerge(Builder builder) {
+ this.engine = builder.getEngine();
+ this.serializer = builder.getSerializer();
+ this.g = engine.asAdmin().getTraversalSource();
+ this.rules = EdgeRules.getInstance();
+ this.loader = builder.getLoader();
+ this.notificationHelper = builder.getHelper();
+ this.hasNotifications = builder.isHasNotifications();
+ }
+
+ /**
+ * Merges vertices. forceCopy is a map of the form [{aai-node-type}:{set of properties}]
+ * @param primary
+ * @param secondary
+ * @param forceCopy
+ * @throws AAIException
+ * @throws UnsupportedEncodingException
+ */
+ public void performMerge(Vertex primary, Vertex secondary, Map<String, Set<String>> forceCopy) throws AAIException, UnsupportedEncodingException {
+ final Optional<Introspector> secondarySnapshot;
+ if (this.hasNotifications) {
+ secondarySnapshot = Optional.of(serializer.getLatestVersionView(secondary));
+ } else {
+ secondarySnapshot = Optional.empty();
+ }
+ mergeProperties(primary, secondary, forceCopy);
+
+ Collection<Vertex> secondaryChildren = this.engine.getQueryEngine().findChildren(secondary);
+ Collection<Vertex> primaryChildren = this.engine.getQueryEngine().findChildren(primary);
+
+ mergeChildren(primary, secondary, primaryChildren, secondaryChildren, forceCopy);
+
+ Collection<Vertex> secondaryCousins = this.engine.getQueryEngine().findCousinVertices(secondary);
+ Collection<Vertex> primaryCousins = this.engine.getQueryEngine().findCousinVertices(primary);
+
+ secondaryCousins.removeAll(primaryCousins);
+ logger.info("removing vertex after merge: " + secondary );
+ if (this.hasNotifications && secondarySnapshot.isPresent()) {
+ this.notificationHelper.addEvent(secondary, secondarySnapshot.get(), EventAction.DELETE, this.serializer.getURIForVertex(secondary, false));
+ }
+ secondary.remove();
+ for (Vertex v : secondaryCousins) {
+ this.rules.addEdgeIfPossible(g, v, primary);
+ }
+ if (this.hasNotifications) {
+ final Introspector primarySnapshot = serializer.getLatestVersionView(primary);
+ this.notificationHelper.addEvent(primary, primarySnapshot, EventAction.UPDATE, this.serializer.getURIForVertex(primary, false));
+ }
+ }
+
+ /**
+ * This method may go away if we choose to event on each modification performed
+ * @param primary
+ * @param secondary
+ * @param forceCopy
+ * @throws AAIException
+ * @throws UnsupportedEncodingException
+ */
+ protected void performMergeHelper(Vertex primary, Vertex secondary, Map<String, Set<String>> forceCopy) throws AAIException, UnsupportedEncodingException {
+ mergeProperties(primary, secondary, forceCopy);
+
+ Collection<Vertex> secondaryChildren = this.engine.getQueryEngine().findChildren(secondary);
+ Collection<Vertex> primaryChildren = this.engine.getQueryEngine().findChildren(primary);
+
+ mergeChildren(primary, secondary, primaryChildren, secondaryChildren, forceCopy);
+
+ Collection<Vertex> secondaryCousins = this.engine.getQueryEngine().findCousinVertices(secondary);
+ Collection<Vertex> primaryCousins = this.engine.getQueryEngine().findCousinVertices(primary);
+
+ secondaryCousins.removeAll(primaryCousins);
+ secondary.remove();
+ for (Vertex v : secondaryCousins) {
+ this.rules.addEdgeIfPossible(g, v, primary);
+ }
+ }
+
+ private String getURI(Vertex v) throws UnsupportedEncodingException, AAIException {
+ Introspector obj = loader.introspectorFromName(v.<String>property(AAIProperties.NODE_TYPE).orElse(""));
+ this.serializer.dbToObject(Collections.singletonList(v), obj, 0, true, "false");
+ return obj.getURI();
+
+ }
+ private void mergeChildren(Vertex primary, Vertex secondary, Collection<Vertex> primaryChildren, Collection<Vertex> secondaryChildren, Map<String, Set<String>> forceCopy) throws UnsupportedEncodingException, AAIException {
+ Map<String, Vertex> primaryMap = uriMap(primaryChildren);
+ Map<String, Vertex> secondaryMap = uriMap(secondaryChildren);
+ Set<String> primaryKeys = new HashSet<>(primaryMap.keySet());
+ Set<String> secondaryKeys = new HashSet<>(secondaryMap.keySet());
+ primaryKeys.retainAll(secondaryKeys);
+ final Set<String> mergeItems = new HashSet<>(primaryKeys);
+ primaryKeys = new HashSet<>(primaryMap.keySet());
+ secondaryKeys = new HashSet<>(secondaryMap.keySet());
+ secondaryKeys.removeAll(primaryKeys);
+ final Set<String> copyItems = new HashSet<>(secondaryKeys);
+
+ for (String key : mergeItems) {
+ this.performMergeHelper(primaryMap.get(key), secondaryMap.get(key), forceCopy);
+ }
+
+ for (String key : copyItems) {
+ this.rules.addTreeEdgeIfPossible(g, secondaryMap.get(key), primary);
+ this.serializer.getEdgeBetween(EdgeType.TREE, secondary, secondaryMap.get(key)).remove();
+ }
+
+ }
+
+ private Map<String, Vertex> uriMap(Collection<Vertex> vertices) throws UnsupportedEncodingException, AAIException {
+ final Map<String, Vertex> result = new HashMap<>();
+ for (Vertex v : vertices) {
+ result.put(getURI(v), v);
+ }
+ return result;
+ }
+
+ private void mergeProperties(Vertex primary, Vertex secondary, Map<String, Set<String>> forceCopy) throws AAIUnknownObjectException {
+ final String primaryType = primary.<String>property(AAIProperties.NODE_TYPE).orElse("");
+ final String secondaryType = secondary.<String>property(AAIProperties.NODE_TYPE).orElse("");
+
+ final Introspector secondaryObj = loader.introspectorFromName(secondaryType);
+ secondary.properties().forEachRemaining(prop -> {
+ if (!primary.property(prop.key()).isPresent() || forceCopy.getOrDefault(primaryType, new HashSet<String>()).contains(prop.key())) {
+ primary.property(prop.key(), prop.value());
+ }
+ if (primary.property(prop.key()).isPresent() && secondary.property(prop.key()).isPresent() && secondaryObj.isListType(prop.key())) {
+ mergeCollection(primary, prop.key(), secondary.values(prop.key()));
+ }
+ });
+ }
+ private void mergeCollection(Vertex primary, String propName, Iterator<Object> secondaryValues) {
+ secondaryValues.forEachRemaining(item -> {
+ primary.property(propName, item);
+ });
+ }
+
+
+ public static class Builder {
+ private final TransactionalGraphEngine engine;
+
+ private final DBSerializer serializer;
+ private final Loader loader;
+ private NotificationHelper helper = null;
+ private boolean hasNotifications = false;
+ public Builder(Loader loader, TransactionalGraphEngine engine, DBSerializer serializer) {
+ this.loader = loader;
+ this.engine = engine;
+ this.serializer = serializer;
+ }
+
+ public Builder addNotifications(NotificationHelper helper) {
+ this.helper = helper;
+ this.hasNotifications = true;
+ return this;
+ }
+
+
+ public VertexMerge build() {
+ return new VertexMerge(this);
+ }
+
+ protected TransactionalGraphEngine getEngine() {
+ return engine;
+ }
+
+ protected DBSerializer getSerializer() {
+ return serializer;
+ }
+
+ protected Loader getLoader() {
+ return loader;
+ }
+
+ protected NotificationHelper getHelper() {
+ return helper;
+ }
+
+ protected boolean isHasNotifications() {
+ return hasNotifications;
+ }
+
+ }
+
+}
diff --git a/aai-resources/src/main/java/org/onap/aai/rest/BulkAddConsumer.java b/aai-resources/src/main/java/org/onap/aai/rest/BulkAddConsumer.java
new file mode 100644
index 0000000..b81c42c
--- /dev/null
+++ b/aai-resources/src/main/java/org/onap/aai/rest/BulkAddConsumer.java
@@ -0,0 +1,43 @@
+/**
+ * ============LICENSE_START=======================================================
+ * org.onap.aai
+ * ================================================================================
+ * Copyright © 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END=========================================================
+ *
+ * ECOMP is a trademark and service mark of AT&T Intellectual Property.
+ */
+package org.onap.aai.rest;
+
+import javax.ws.rs.Path;
+
+import org.onap.aai.restcore.HttpMethod;
+
+@Path("{version: v[8-9]|v1[01]}/bulkadd")
+public class BulkAddConsumer extends BulkConsumer {
+
+ @Override
+ protected boolean functionAllowed(HttpMethod method) {
+
+ return method.equals(HttpMethod.PUT);
+
+ }
+
+ @Override
+ protected boolean enableResourceVersion() {
+ return true;
+ }
+
+}
diff --git a/aai-resources/src/main/java/org/onap/aai/rest/BulkConsumer.java b/aai-resources/src/main/java/org/onap/aai/rest/BulkConsumer.java
new file mode 100644
index 0000000..fa74f7b
--- /dev/null
+++ b/aai-resources/src/main/java/org/onap/aai/rest/BulkConsumer.java
@@ -0,0 +1,485 @@
+/**
+ * ============LICENSE_START=======================================================
+ * org.onap.aai
+ * ================================================================================
+ * Copyright © 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END=========================================================
+ *
+ * ECOMP is a trademark and service mark of AT&T Intellectual Property.
+ */
+package org.onap.aai.rest;
+
+import java.io.UnsupportedEncodingException;
+import java.net.URI;
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.ws.rs.Consumes;
+import javax.ws.rs.PUT;
+import javax.ws.rs.PathParam;
+import javax.ws.rs.Produces;
+import javax.ws.rs.core.Context;
+import javax.ws.rs.core.HttpHeaders;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+import javax.ws.rs.core.Response.Status;
+import javax.ws.rs.core.UriBuilder;
+import javax.ws.rs.core.UriInfo;
+
+import org.javatuples.Pair;
+import org.javatuples.Triplet;
+
+import org.onap.aai.dbmap.DBConnectionType;
+import org.onap.aai.exceptions.AAIException;
+import org.onap.aai.introspection.Introspector;
+import org.onap.aai.introspection.Loader;
+import org.onap.aai.introspection.ModelType;
+import org.onap.aai.introspection.Version;
+import org.onap.aai.introspection.exceptions.AAIUnmarshallingException;
+import org.onap.aai.logging.ErrorObjectNotFoundException;
+import org.onap.aai.parsers.query.QueryParser;
+import org.onap.aai.rest.db.DBRequest;
+import org.onap.aai.rest.db.HttpEntry;
+import org.onap.aai.rest.util.ValidateEncoding;
+import org.onap.aai.restcore.HttpMethod;
+import org.onap.aai.restcore.RESTAPI;
+import org.onap.aai.serialization.engines.QueryStyle;
+import org.onap.aai.serialization.engines.TransactionalGraphEngine;
+import com.google.gson.Gson;
+import com.google.gson.GsonBuilder;
+import com.google.gson.JsonArray;
+import com.google.gson.JsonElement;
+import com.google.gson.JsonObject;
+import com.google.gson.JsonParser;
+import com.google.gson.JsonSyntaxException;
+
+/**
+ * The Class BulkAddConsumer.
+ */
+/*
+ * The purpose of this endpoint is to allow a client to add
+ * multiple objects with one request. It may take
+ * one or more transaction objects containing one or more
+ * objects to add.
+ * The transactions are independent of each other -
+ * if one fails, its effects are rolled back, but the others' aren't.
+ * Within a single transaction, if adding one object fails, all the others'
+ * changes are rolled back.
+ */
+public abstract class BulkConsumer extends RESTAPI {
+
+ /** The introspector factory type. */
+ private ModelType introspectorFactoryType = ModelType.MOXY;
+
+ /** The query style. */
+ private QueryStyle queryStyle = QueryStyle.TRAVERSAL;
+
+ /**
+ * Bulk add.
+ *
+ * @param content the content
+ * @param versionParam the version param
+ * @param uri the uri
+ * @param headers the headers
+ * @param info the info
+ * @param req the req
+ * @return the response
+ */
+ @PUT
+ @Consumes({ MediaType.APPLICATION_JSON})
+ @Produces({ MediaType.APPLICATION_JSON})
+ public Response bulkAdd(String content, @PathParam("version")String versionParam, @Context HttpHeaders headers, @Context UriInfo info, @Context HttpServletRequest req){
+
+ String transId = headers.getRequestHeaders().getFirst("X-TransactionId");
+ String sourceOfTruth = headers.getRequestHeaders().getFirst("X-FromAppId");
+ String realTime = headers.getRequestHeaders().getFirst("Real-Time");
+ String outputMediaType = getMediaType(headers.getAcceptableMediaTypes());
+ Version version = Version.valueOf(versionParam);
+ DBConnectionType type = this.determineConnectionType(sourceOfTruth, realTime);
+
+ Response response = null;
+
+ /* A Response will be generated for each object in each transaction.
+ * To keep track of what came from where to give organized feedback to the client,
+ * we keep responses from a given transaction together in one list (hence all being a list of lists)
+ * and pair each response with its matching URI (which will be null if there wasn't one).
+ */
+ List<List<Pair<URI, Response>>> allResponses = new ArrayList<List<Pair<URI, Response>>>();
+
+ try {
+ //TODO add auth check when this endpoint added to that auth properties files
+
+
+ JsonArray transactions = getTransactions(content);
+
+ for (int i = 0; i < transactions.size(); i++){
+ HttpEntry httpEntry = new HttpEntry(version, introspectorFactoryType, queryStyle, type);
+ Loader loader = httpEntry.getLoader();
+ TransactionalGraphEngine dbEngine = httpEntry.getDbEngine();
+ URI thisUri = null;
+ List<Triplet<URI, Introspector,HttpMethod>> triplet = new ArrayList<Triplet<URI, Introspector,HttpMethod>>();
+ HttpMethod method = null;
+ try {
+ JsonElement transObj = transactions.get(i);
+ if (!(transObj instanceof JsonObject)) {
+ throw new AAIException("AAI_6111", "input payload does not follow bulk add interface");
+ }
+ //JsonObject transaction = transObj.getAsJsonObject();
+
+ fillObjectTuplesFromTransaction(triplet, transObj.getAsJsonObject(), loader, dbEngine, outputMediaType);
+ if (triplet.size() == 0) {
+ //case where user sends a validly formatted transactions object but
+ //which has no actual things in it for A&AI to do anything with
+ //assuming we should count this as a user error
+ throw new AAIException("AAI_6118", "payload had no objects to operate on");
+ }
+
+ List<DBRequest> requests = new ArrayList<>();
+ for (Triplet<URI, Introspector, HttpMethod> tuple : triplet){
+ thisUri = tuple.getValue0();
+ method = tuple.getValue2();
+ QueryParser uriQuery = dbEngine.getQueryBuilder().createQueryFromURI(thisUri);
+ DBRequest request = new DBRequest.Builder(method, thisUri, uriQuery, tuple.getValue1(), headers, info, transId).build();
+ requests.add(request);
+ }
+
+ Pair<Boolean, List<Pair<URI, Response>>> results = httpEntry.process(requests, sourceOfTruth, this.enableResourceVersion());
+ List<Pair<URI, Response>> responses = results.getValue1();
+ allResponses.add(responses);
+ if (results.getValue0()) { //everything was processed without error
+ dbEngine.commit();
+ } else { //something failed
+ dbEngine.rollback();
+ }
+ } catch (Exception e) {
+ /* While httpEntry.process handles its exceptions, exceptions thrown in earlier helpers
+ * bubbles up to here. As we want to tie error messages to the URI of the object that caused
+ * them, we catch here, generate a Response, bundle it with that URI, and move on.
+ */
+ method = HttpMethod.PUT;
+ if (triplet.size() != 0) { //failed somewhere in the middle of tuple-filling
+ Triplet<URI, Introspector, HttpMethod> lastTuple = triplet.get(triplet.size()-1); //last one in there was the problem
+ if (lastTuple.getValue1() == null){
+ //failed out before thisUri could be set but after tuples started being filled
+ thisUri = lastTuple.getValue0();
+ method = lastTuple.getValue2();
+ }
+ } //else failed out on empty payload so tuples never filled (or failed out even earlier than tuple-filling)
+ addExceptionCaseFailureResponse(allResponses, e, i, thisUri, headers, info, method);
+ dbEngine.rollback();
+ continue; /* if an exception gets thrown within a transaction we want to keep going to
+ the next transaction, not break out of the whole request */
+ }
+ }
+
+ String returnPayload = generateResponsePayload(allResponses);
+
+ //unless a top level error gets thrown, we want to 201 bc the client wanted a "fire and forget" kind of setup
+ response = Response
+ .status(Status.CREATED)
+ .entity(returnPayload)
+ .build();
+ } catch (AAIException e) { //these catches needed for handling top level errors in payload parsing where the whole request must fail out
+ response = consumerExceptionResponseGenerator(headers, info, HttpMethod.PUT, e);
+ } catch(JsonSyntaxException e) {
+ AAIException ex = new AAIException("AAI_6111");
+ response = consumerExceptionResponseGenerator(headers, info, HttpMethod.PUT, ex);
+ } catch (Exception e ) {
+ AAIException ex = new AAIException("AAI_4000", e);
+ response = consumerExceptionResponseGenerator(headers, info, HttpMethod.PUT, ex);
+ }
+
+ return response;
+ }
+
+
+ /**
+ * Gets the transactions.
+ *
+ * @param content - input JSON payload string
+ * @return JsonArray - the array of transactions
+ * @throws AAIException the AAI exception
+ * @throws JsonSyntaxException Parses and breaks the single payload into an array of individual transaction
+ * bodies to be processed.
+ */
+ private JsonArray getTransactions(String content) throws AAIException, JsonSyntaxException {
+ JsonParser parser = new JsonParser();
+
+ JsonObject input = parser.parse(content).getAsJsonObject();
+
+ if (!(input.has("transactions"))) {
+ throw new AAIException("AAI_6118", "input payload does not follow bulk add interface - missing \"transactions\"");
+ }
+ JsonElement transactionsObj = input.get("transactions");
+
+ if (!(transactionsObj.isJsonArray())){
+ throw new AAIException("AAI_6111", "input payload does not follow bulk add interface");
+ }
+ JsonArray transactions = transactionsObj.getAsJsonArray();
+ if (transactions.size() == 0) {
+ //case where user sends a validly formatted transactions object but
+ //which has no actual things in it for A&AI to do anything with
+ //assuming we should count this as a user error
+ throw new AAIException("AAI_6118", "payload had no objects to operate on");
+ }
+ return transactions;
+ }
+
+ /**
+ * Fill object tuples from transaction.
+ *
+ * @param tuples the tuples
+ * @param transaction - JSON body containing the objects to be added
+ * each object must have a URI and an object body
+ * @param loader the loader
+ * @param dbEngine the db engine
+ * @param inputMediaType the input media type
+ * @return list of tuples containing each introspector-wrapped object and its given URI
+ * @throws AAIException the AAI exception
+ * @throws JsonSyntaxException the json syntax exception
+ * @throws UnsupportedEncodingException Walks through the given transaction and unmarshals each object in it, then bundles each
+ * with its URI.
+ */
+ private void fillObjectTuplesFromTransaction(List<Triplet<URI, Introspector, HttpMethod>> triplet,
+ JsonObject transaction, Loader loader, TransactionalGraphEngine dbEngine, String inputMediaType)
+ throws AAIException, JsonSyntaxException, UnsupportedEncodingException {
+
+
+ if (transaction.has("put") && this.functionAllowed(HttpMethod.PUT)) {
+ pairUp(triplet, transaction, loader, dbEngine, inputMediaType, HttpMethod.PUT);
+ }
+ else if (transaction.has("delete") && this.functionAllowed(HttpMethod.DELETE)) {
+ pairUp(triplet, transaction, loader, dbEngine, inputMediaType, HttpMethod.DELETE);
+ }
+ else if (transaction.has("patch") && this.functionAllowed(HttpMethod.MERGE_PATCH)) {
+ pairUp(triplet, transaction, loader, dbEngine, inputMediaType, HttpMethod.MERGE_PATCH);
+ }
+
+ else{
+
+ throw new AAIException("AAI_6118", "input payload does not follow bulk add interface - missing put delete or patch");
+ }
+
+
+
+ }
+
+
+
+ private void pairUp(List<Triplet<URI, Introspector, HttpMethod>> triplet, JsonObject item, Loader loader, TransactionalGraphEngine dbEngine, String inputMediaType, HttpMethod method) throws AAIException, JsonSyntaxException, UnsupportedEncodingException{
+
+
+ for (int i=0; i<item.size(); i++) {
+ Triplet<URI, Introspector, HttpMethod> tuple = Triplet.with(null, null,null);
+
+ tuple = tuple.setAt2(method);
+ try {
+ if (!(item.isJsonObject())) {
+ throw new AAIException("AAI_6111", "input payload does not follow bulk add interface");
+ }
+
+
+ JsonElement actionElement = null;
+
+ if(item.has("put")){
+ actionElement = item.get("put");
+ } else if(item.has("patch")){
+ actionElement = item.get("patch");
+ } else if(item.has("delete")){
+ actionElement = item.get("delete");
+ }
+
+ if ((actionElement == null) || !actionElement.isJsonArray()) {
+ throw new AAIException("AAI_6111", "input payload does not follow bulk add interface");
+ }
+ JsonArray httpArray = actionElement.getAsJsonArray();
+ for(int j = 0; j < httpArray.size(); ++j){
+ JsonObject it = httpArray.get(j).getAsJsonObject();
+ JsonElement itemURIfield = it.get("uri");
+ if (itemURIfield == null) {
+ throw new AAIException("AAI_6118", "must include object uri");
+ }
+ String uriStr = itemURIfield.getAsString();
+ if (uriStr.endsWith("/relationship-list/relationship")) {
+ if (method.equals(HttpMethod.PUT)) {
+ tuple = tuple.setAt2(HttpMethod.PUT_EDGE);
+ } else if (method.equals(HttpMethod.DELETE)) {
+ tuple = tuple.setAt2(HttpMethod.DELETE_EDGE);
+ }
+ } else {
+ tuple = tuple.setAt2(method);
+ }
+
+ URI uri = UriBuilder.fromPath(uriStr).build();
+
+ /* adding the uri as soon as we have one (valid or not) lets us
+ * keep any errors with their corresponding uris for client feedback
+ */
+ tuple = tuple.setAt0(uri);
+
+ if (!ValidateEncoding.getInstance().validate(uri)) {
+ throw new AAIException("AAI_3008", "uri=" + uri.getPath());
+ }
+
+ if (!(it.has("body"))){
+ throw new AAIException("AAI_6118", "input payload does not follow bulk add interface - missing \"body\"");
+ }
+ JsonElement bodyObj = it.get("body");
+ if (!(bodyObj.isJsonObject())) {
+ throw new AAIException("AAI_6111", "input payload does not follow bulk add interface");
+ }
+
+ Gson gson = new Gson();
+
+ String bodyStr = gson.toJson(bodyObj);
+
+ if (tuple.getValue2().equals(HttpMethod.PUT_EDGE)) {
+ Introspector obj;
+ try {
+ obj = loader.unmarshal("relationship", bodyStr, org.onap.aai.restcore.MediaType.getEnum(inputMediaType));
+ } catch (AAIUnmarshallingException e) {
+ throw new AAIException("AAI_3000", "object could not be unmarshalled:" + bodyStr);
+
+ }
+
+
+ tuple = tuple.setAt1(obj);
+
+ } else {
+ QueryParser uriQuery = dbEngine.getQueryBuilder().createQueryFromURI(uri);
+ String objName = uriQuery.getResultType();
+
+ Introspector obj;
+ try {
+ obj = loader.unmarshal(objName, bodyStr, org.onap.aai.restcore.MediaType.getEnum(inputMediaType));
+ } catch (AAIUnmarshallingException e) {
+ throw new AAIException("AAI_3000", "object could not be unmarshalled:" + bodyStr);
+
+ }
+
+ this.validateIntrospector(obj, loader, uri, tuple.getValue2());
+ tuple = tuple.setAt1(obj);
+ }
+ triplet.add(tuple);
+ }
+// JsonElement itemURIfield = item.get("uri");
+
+ } catch (AAIException e) {
+ // even if tuple doesn't have a uri or body, this way we keep all information associated with this error together
+ // even if both are null, that indicates how the input was messed up, so still useful to carry around like this
+ triplet.add(tuple);
+ throw e; //rethrow so the right response is generated on the level above
+ }
+ }
+ }
+
+
+
+ /**
+ * Generate response payload.
+ *
+ * @param allResponses - the list of the lists of responses from every action in every transaction requested
+ * @return A json string of similar format to the bulk add interface which for each response includes
+ * the original URI and a body with the status code of the response and the error message.
+ *
+ * Creates the payload for a single unified response from all responses generated
+ */
+ private String generateResponsePayload(List<List<Pair<URI,Response>>> allResponses){
+ JsonObject ret = new JsonObject();
+ JsonArray retArr = new JsonArray();
+
+ for(List<Pair<URI,Response>> responses : allResponses){
+ JsonObject tResp = new JsonObject();
+ JsonArray tArrResp = new JsonArray();
+
+ for (Pair<URI,Response> r : responses) {
+ JsonObject indPayload = new JsonObject();
+
+ URI origURI = r.getValue0();
+ if (origURI != null) {
+ indPayload.addProperty("uri", origURI.getPath());
+ } else {
+ indPayload.addProperty("uri", (String)null);
+ }
+
+ JsonObject body = new JsonObject();
+
+ int rStatus = r.getValue1().getStatus();
+ String rContents = null;
+
+ rContents = (String)r.getValue1().getEntity();
+
+ body.addProperty(new Integer(rStatus).toString(), rContents);
+ indPayload.add("body", body);
+
+ tArrResp.add(indPayload);
+ }
+
+ tResp.add("put", tArrResp);
+ retArr.add(tResp);
+ }
+ ret.add("transaction", retArr);
+ Gson gson = new GsonBuilder().serializeNulls().create();
+ String jsonStr = gson.toJson(ret);
+ return jsonStr;
+ }
+
+ /**
+ * Adds the exception case failure response.
+ *
+ * @param allResponses the all responses
+ * @param e the e
+ * @param index - index of which transaction was being processed when the exception was thrown
+ * @param thisUri the this uri
+ * @param headers the headers
+ * @param info the info
+ * @param templateAction the template action
+ * @param logline Generates a Response based on the given exception and adds it to the collection of responses for this request.
+ * @throws ErrorObjectNotFoundException
+ */
+ private void addExceptionCaseFailureResponse(List<List<Pair<URI, Response>>> allResponses, Exception e, int index, URI thisUri, HttpHeaders headers, UriInfo info, HttpMethod templateAction) {
+ AAIException ex = null;
+
+ if (!(e instanceof AAIException)){
+ ex = new AAIException("AAI_4000", e);
+ } else {
+ ex = (AAIException)e;
+ }
+
+ if (allResponses.size() != (index+1)) {
+ //index+1 bc if all transactions thus far have had a response list added
+ //the size will be one more than the current index (since those are offset by 1)
+
+ //this transaction doesn't have a response list yet, so create one
+ Response failResp = consumerExceptionResponseGenerator(headers, info, templateAction, ex);
+ Pair<URI, Response> uriResp = Pair.with(thisUri, failResp);
+ List<Pair<URI, Response>> transRespList = new ArrayList<Pair<URI,Response>>();
+ transRespList.add(uriResp);
+ allResponses.add(transRespList);
+ } else {
+ //this transaction already has a response list, so add this failure response to it
+ Response failResp = consumerExceptionResponseGenerator(headers, info, templateAction, ex);
+ Pair<URI, Response> uriResp = Pair.with(thisUri, failResp);
+ List<Pair<URI, Response>> tResps = allResponses.get(index);
+ tResps.add(uriResp);
+ }
+ }
+
+ protected abstract boolean functionAllowed(HttpMethod method);
+
+ protected abstract boolean enableResourceVersion();
+
+}
diff --git a/aai-resources/src/main/java/org/onap/aai/rest/BulkProcessConsumer.java b/aai-resources/src/main/java/org/onap/aai/rest/BulkProcessConsumer.java
new file mode 100644
index 0000000..d22fe21
--- /dev/null
+++ b/aai-resources/src/main/java/org/onap/aai/rest/BulkProcessConsumer.java
@@ -0,0 +1,43 @@
+/**
+ * ============LICENSE_START=======================================================
+ * org.onap.aai
+ * ================================================================================
+ * Copyright © 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END=========================================================
+ *
+ * ECOMP is a trademark and service mark of AT&T Intellectual Property.
+ */
+package org.onap.aai.rest;
+
+import javax.ws.rs.Path;
+
+import org.onap.aai.restcore.HttpMethod;
+
+@Path("{version: v[2789]|v1[01]}/bulkprocess")
+public class BulkProcessConsumer extends BulkConsumer {
+
+ @Override
+ protected boolean functionAllowed(HttpMethod method) {
+
+ return method.equals(HttpMethod.PUT) || method.equals(HttpMethod.DELETE) || method.equals(HttpMethod.MERGE_PATCH);
+ }
+
+ @Override
+ protected boolean enableResourceVersion() {
+ // TODO Auto-generated method stub
+ return true;
+ }
+
+}
diff --git a/aai-resources/src/main/java/org/onap/aai/rest/ExampleConsumer.java b/aai-resources/src/main/java/org/onap/aai/rest/ExampleConsumer.java
new file mode 100644
index 0000000..c942258
--- /dev/null
+++ b/aai-resources/src/main/java/org/onap/aai/rest/ExampleConsumer.java
@@ -0,0 +1,105 @@
+/**
+ * ============LICENSE_START=======================================================
+ * org.onap.aai
+ * ================================================================================
+ * Copyright © 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END=========================================================
+ *
+ * ECOMP is a trademark and service mark of AT&T Intellectual Property.
+ */
+package org.onap.aai.rest;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.ws.rs.GET;
+import javax.ws.rs.Path;
+import javax.ws.rs.PathParam;
+import javax.ws.rs.Produces;
+import javax.ws.rs.core.Context;
+import javax.ws.rs.core.HttpHeaders;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+import javax.ws.rs.core.Response.Status;
+import javax.ws.rs.core.UriInfo;
+
+import org.onap.aai.exceptions.AAIException;
+import org.onap.aai.introspection.Introspector;
+import org.onap.aai.introspection.Loader;
+import org.onap.aai.introspection.LoaderFactory;
+import org.onap.aai.introspection.MarshallerProperties;
+import org.onap.aai.introspection.ModelType;
+import org.onap.aai.introspection.Version;
+import org.onap.aai.introspection.generator.CreateExample;
+import org.onap.aai.restcore.HttpMethod;
+import org.onap.aai.restcore.RESTAPI;
+
+/**
+ * The Class ExampleConsumer.
+ */
+@Path("/{version: v[2789]|v1[01]}/examples")
+public class ExampleConsumer extends RESTAPI {
+
+
+ /**
+ * Gets the example.
+ *
+ * @param versionParam the version param
+ * @param type the type
+ * @param headers the headers
+ * @param info the info
+ * @param req the req
+ * @return the example
+ */
+ @GET
+ @Path("/{objectType: [^\\/]+}")
+ @Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
+ public Response getExample(@PathParam("version")String versionParam, @PathParam("objectType")String type, @Context HttpHeaders headers, @Context UriInfo info, @Context HttpServletRequest req) {
+
+ Status status = Status.INTERNAL_SERVER_ERROR;
+ Response response = null;
+
+ try {
+ String mediaType = getMediaType(headers.getAcceptableMediaTypes());
+ org.onap.aai.restcore.MediaType outputMediaType = org.onap.aai.restcore.MediaType.getEnum(mediaType);
+
+ Version version = Version.valueOf(versionParam);
+ Loader loader = LoaderFactory.createLoaderForVersion(ModelType.MOXY, version);
+
+ CreateExample example = new CreateExample(loader, type);
+
+ Introspector obj = example.getExampleObject();
+ String result = "";
+ if (obj != null) {
+ status = Status.OK;
+ MarshallerProperties properties =
+ new MarshallerProperties.Builder(outputMediaType).build();
+ result = obj.marshal(properties);
+ } else {
+
+ }
+ response = Response
+ .ok(obj)
+ .entity(result)
+ .status(status)
+ .type(outputMediaType.toString()).build();
+ } catch (AAIException e) {
+ //TODO check that the details here are sensible
+ response = consumerExceptionResponseGenerator(headers, info, HttpMethod.GET, e);
+ } catch (Exception e) {
+ AAIException ex = new AAIException("AAI_4000", e);
+ response = consumerExceptionResponseGenerator(headers, info, HttpMethod.GET, ex);
+ }
+ return response;
+ }
+}
diff --git a/aai-resources/src/main/java/org/onap/aai/rest/ExceptionHandler.java b/aai-resources/src/main/java/org/onap/aai/rest/ExceptionHandler.java
new file mode 100644
index 0000000..c20a370
--- /dev/null
+++ b/aai-resources/src/main/java/org/onap/aai/rest/ExceptionHandler.java
@@ -0,0 +1,130 @@
+/**
+ * ============LICENSE_START=======================================================
+ * org.onap.aai
+ * ================================================================================
+ * Copyright © 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END=========================================================
+ *
+ * ECOMP is a trademark and service mark of AT&T Intellectual Property.
+ */
+package org.onap.aai.rest;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.ws.rs.WebApplicationException;
+import javax.ws.rs.core.Context;
+import javax.ws.rs.core.HttpHeaders;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+import javax.ws.rs.ext.ExceptionMapper;
+import javax.ws.rs.ext.Provider;
+
+import org.onap.aai.exceptions.AAIException;
+import org.onap.aai.logging.ErrorLogHelper;
+import com.fasterxml.jackson.core.JsonParseException;
+import com.fasterxml.jackson.databind.JsonMappingException;
+import com.sun.istack.SAXParseException2;
+
+/**
+ * The Class ExceptionHandler.
+ */
+@Provider
+public class ExceptionHandler implements ExceptionMapper<Exception> {
+
+ @Context
+ private HttpServletRequest request;
+
+ @Context
+ private HttpHeaders headers;
+
+ /**
+ * @{inheritDoc}
+ */
+ @Override
+ public Response toResponse(Exception exception) {
+
+ Response response = null;
+ ArrayList<String> templateVars = new ArrayList<String>();
+
+ //the general case is that cxf will give us a WebApplicationException
+ //with a linked exception
+ if (exception instanceof WebApplicationException) {
+ WebApplicationException e = (WebApplicationException) exception;
+ if (e.getCause() != null) {
+ if (e.getCause() instanceof SAXParseException2) {
+ templateVars.add("UnmarshalException");
+ AAIException ex = new AAIException("AAI_4007", exception);
+ response = Response
+ .status(400)
+ .entity(ErrorLogHelper.getRESTAPIErrorResponse(headers.getAcceptableMediaTypes(), ex, templateVars))
+ .build();
+ }
+ }
+ } else if (exception instanceof JsonParseException) {
+ //jackson does it differently so we get the direct JsonParseException
+ templateVars.add("JsonParseException");
+ AAIException ex = new AAIException("AAI_4007", exception);
+ response = Response
+ .status(400)
+ .entity(ErrorLogHelper.getRESTAPIErrorResponse(headers.getAcceptableMediaTypes(), ex, templateVars))
+ .build();
+ } else if (exception instanceof JsonMappingException) {
+ //jackson does it differently so we get the direct JsonParseException
+ templateVars.add("JsonMappingException");
+ AAIException ex = new AAIException("AAI_4007", exception);
+ response = Response
+ .status(400)
+ .entity(ErrorLogHelper.getRESTAPIErrorResponse(headers.getAcceptableMediaTypes(), ex, templateVars))
+ .build();
+ }
+
+ // it didn't get set above, we wrap a general fault here
+ if (response == null) {
+
+ Exception actual_e = exception;
+ if (exception instanceof WebApplicationException) {
+ WebApplicationException e = (WebApplicationException) exception;
+ response = e.getResponse();
+ } else {
+ templateVars.add(request.getMethod());
+ templateVars.add("unknown");
+ AAIException ex = new AAIException("AAI_4000", actual_e);
+ List<MediaType> mediaTypes = headers.getAcceptableMediaTypes();
+ int setError = 0;
+
+ for (MediaType mediaType : mediaTypes) {
+ if (MediaType.APPLICATION_XML_TYPE.isCompatible(mediaType)) {
+ response = Response
+ .status(400)
+ .type(MediaType.APPLICATION_XML_TYPE)
+ .entity(ErrorLogHelper.getRESTAPIErrorResponse(headers.getAcceptableMediaTypes(), ex, templateVars))
+ .build();
+ setError = 1;
+ }
+ }
+ if (setError == 0) {
+ response = Response
+ .status(400)
+ .type(MediaType.APPLICATION_JSON_TYPE)
+ .entity(ErrorLogHelper.getRESTAPIErrorResponse(headers.getAcceptableMediaTypes(), ex, templateVars))
+ .build();
+ }
+ }
+ }
+ return response;
+ }
+}
diff --git a/aai-resources/src/main/java/org/onap/aai/rest/LegacyMoxyConsumer.java b/aai-resources/src/main/java/org/onap/aai/rest/LegacyMoxyConsumer.java
new file mode 100644
index 0000000..a68d8f2
--- /dev/null
+++ b/aai-resources/src/main/java/org/onap/aai/rest/LegacyMoxyConsumer.java
@@ -0,0 +1,597 @@
+/**
+ * ============LICENSE_START=======================================================
+ * org.onap.aai
+ * ================================================================================
+ * Copyright © 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END=========================================================
+ *
+ * ECOMP is a trademark and service mark of AT&T Intellectual Property.
+ */
+package org.onap.aai.rest;
+
+import java.io.UnsupportedEncodingException;
+import java.net.URI;
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.ws.rs.Consumes;
+import javax.ws.rs.DELETE;
+import javax.ws.rs.DefaultValue;
+import javax.ws.rs.Encoded;
+import javax.ws.rs.GET;
+import javax.ws.rs.PUT;
+import javax.ws.rs.Path;
+import javax.ws.rs.PathParam;
+import javax.ws.rs.Produces;
+import javax.ws.rs.QueryParam;
+import javax.ws.rs.core.Context;
+import javax.ws.rs.core.HttpHeaders;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.MultivaluedMap;
+import javax.ws.rs.core.Response;
+import javax.ws.rs.core.UriBuilder;
+import javax.ws.rs.core.UriInfo;
+
+import org.apache.cxf.jaxrs.ext.PATCH;
+import org.javatuples.Pair;
+import org.onap.aai.dbmap.DBConnectionType;
+import org.onap.aai.exceptions.AAIException;
+import org.onap.aai.introspection.Introspector;
+import org.onap.aai.introspection.Loader;
+import org.onap.aai.introspection.ModelType;
+import org.onap.aai.introspection.Version;
+import org.onap.aai.parsers.query.QueryParser;
+import org.onap.aai.rest.db.DBRequest;
+import org.onap.aai.rest.db.HttpEntry;
+import org.onap.aai.rest.exceptions.AAIInvalidXMLNamespace;
+import org.onap.aai.rest.util.ValidateEncoding;
+import org.onap.aai.restcore.HttpMethod;
+import org.onap.aai.restcore.RESTAPI;
+import org.onap.aai.serialization.engines.QueryStyle;
+import org.onap.aai.serialization.engines.TransactionalGraphEngine;
+import org.onap.aai.workarounds.RemoveDME2QueryParams;
+
+import com.att.eelf.configuration.EELFLogger;
+import com.att.eelf.configuration.EELFManager;
+import com.google.common.base.Joiner;
+
+
+/**
+ * The Class LegacyMoxyConsumer.
+ */
+@Path("{version: v[2789]|v1[01]}")
+public class LegacyMoxyConsumer extends RESTAPI {
+
+ private static final EELFLogger LOGGER = EELFManager.getInstance().getLogger(LegacyMoxyConsumer.class.getName());
+ protected static String authPolicyFunctionName = "REST";
+ private ModelType introspectorFactoryType = ModelType.MOXY;
+ private QueryStyle queryStyle = QueryStyle.TRAVERSAL;
+
+ /**
+ * Update.
+ *
+ * @param content the content
+ * @param versionParam the version param
+ * @param uri the uri
+ * @param headers the headers
+ * @param info the info
+ * @param req the req
+ * @return the response
+ */
+ @PUT
+ @Path("/{uri: .+}")
+ @Consumes({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
+ @Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
+ public Response update (String content, @PathParam("version")String versionParam, @PathParam("uri") @Encoded String uri, @Context HttpHeaders headers, @Context UriInfo info, @Context HttpServletRequest req) {
+
+ MediaType mediaType = headers.getMediaType();
+
+ return this.handleWrites(mediaType, HttpMethod.PUT, content, versionParam, uri, headers, info);
+ }
+
+ /**
+ * Update relationship.
+ *
+ * @param content the content
+ * @param versionParam the version param
+ * @param uri the uri
+ * @param headers the headers
+ * @param info the info
+ * @param req the req
+ * @return the response
+ */
+ @PUT
+ @Path("/{uri: .+}/relationship-list/relationship")
+ @Consumes({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
+ @Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
+ public Response updateRelationship (String content, @PathParam("version")String versionParam, @PathParam("uri") @Encoded String uri, @Context HttpHeaders headers, @Context UriInfo info, @Context HttpServletRequest req) {
+
+ String sourceOfTruth = headers.getRequestHeaders().getFirst("X-FromAppId");
+ String transId = headers.getRequestHeaders().getFirst("X-TransactionId");
+ String realTime = headers.getRequestHeaders().getFirst("Real-Time");
+ MediaType inputMediaType = headers.getMediaType();
+ Response response = null;
+ Loader loader = null;
+ TransactionalGraphEngine dbEngine = null;
+ boolean success = true;
+
+ try {
+ validateRequest(info);
+ Version version = Version.valueOf(versionParam);
+ version = Version.valueOf(versionParam);
+ DBConnectionType type = this.determineConnectionType(sourceOfTruth, realTime);
+ HttpEntry httpEntry = new HttpEntry(version, introspectorFactoryType, queryStyle, type);
+ loader = httpEntry.getLoader();
+ dbEngine = httpEntry.getDbEngine();
+
+ URI uriObject = UriBuilder.fromPath(uri).build();
+ this.validateURI(uriObject);
+
+ QueryParser uriQuery = dbEngine.getQueryBuilder().createQueryFromURI(uriObject);
+
+ Introspector wrappedEntity = loader.unmarshal("relationship", content, org.onap.aai.restcore.MediaType.getEnum(this.getInputMediaType(inputMediaType)));
+
+ DBRequest request = new DBRequest.Builder(HttpMethod.PUT_EDGE, uriObject, uriQuery, wrappedEntity, headers, info, transId).build();
+ List<DBRequest> requests = new ArrayList<>();
+ requests.add(request);
+ Pair<Boolean, List<Pair<URI, Response>>> responsesTuple = httpEntry.process(requests, sourceOfTruth);
+
+ response = responsesTuple.getValue1().get(0).getValue1();
+ success = responsesTuple.getValue0();
+
+ } catch (AAIException e) {
+ response = consumerExceptionResponseGenerator(headers, info, HttpMethod.PUT, e);
+ success = false;
+ } catch (Exception e) {
+ AAIException aaiException = new AAIException("AAI_4000", e);
+ response = consumerExceptionResponseGenerator(headers, info, HttpMethod.PUT, aaiException);
+ success = false;
+ } finally {
+ if (dbEngine != null) {
+ if (success) {
+ dbEngine.commit();
+ } else {
+ LOGGER.warn("Rolling back Titan transaction");
+ dbEngine.rollback();
+ }
+ }
+
+ }
+
+ return response;
+ }
+
+ /**
+ * Patch.
+ *
+ * @param content the content
+ * @param versionParam the version param
+ * @param uri the uri
+ * @param headers the headers
+ * @param info the info
+ * @param req the req
+ * @return the response
+ */
+ @PATCH
+ @Path("/{uri: .+}")
+ @Consumes({ "application/merge-patch+json" })
+ @Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
+ public Response patch (String content, @PathParam("version")String versionParam, @PathParam("uri") @Encoded String uri, @Context HttpHeaders headers, @Context UriInfo info, @Context HttpServletRequest req) {
+
+ MediaType mediaType = MediaType.APPLICATION_JSON_TYPE;
+
+ return this.handleWrites(mediaType, HttpMethod.MERGE_PATCH, content, versionParam, uri, headers, info);
+
+ }
+
+ /**
+ * Gets the legacy.
+ *
+ * @param content the content
+ * @param versionParam the version param
+ * @param uri the uri
+ * @param depthParam the depth param
+ * @param cleanUp the clean up
+ * @param headers the headers
+ * @param info the info
+ * @param req the req
+ * @return the legacy
+ */
+ @GET
+ @Path("/{uri: .+}")
+ @Consumes({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
+ @Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
+ public Response getLegacy (String content, @PathParam("version")String versionParam, @PathParam("uri") @Encoded String uri, @DefaultValue("all") @QueryParam("depth") String depthParam, @DefaultValue("false") @QueryParam("cleanup") String cleanUp, @Context HttpHeaders headers, @Context UriInfo info, @Context HttpServletRequest req) {
+
+ return this.getLegacy(content, versionParam, uri, depthParam, cleanUp, headers, info, req, new HashSet<String>());
+ }
+
+ /**
+ * This method exists as a workaround for filtering out undesired query params while routing between REST consumers
+ *
+ * @param content
+ * @param versionParam
+ * @param uri
+ * @param depthParam
+ * @param cleanUp
+ * @param headers
+ * @param info
+ * @param req
+ * @param removeQueryParams
+ * @return
+ */
+ public Response getLegacy(String content, String versionParam, String uri, String depthParam, String cleanUp, HttpHeaders headers, UriInfo info, HttpServletRequest req, Set<String> removeQueryParams) {
+ String sourceOfTruth = headers.getRequestHeaders().getFirst("X-FromAppId");
+ String transId = headers.getRequestHeaders().getFirst("X-TransactionId");
+ String realTime = headers.getRequestHeaders().getFirst("Real-Time");
+ Response response = null;
+ TransactionalGraphEngine dbEngine = null;
+ Loader loader = null;
+
+ try {
+ validateRequest(info);
+ Version version = Version.valueOf(versionParam);
+ DBConnectionType type = this.determineConnectionType(sourceOfTruth, realTime);
+ final HttpEntry httpEntry = new HttpEntry(version, introspectorFactoryType, queryStyle, type);
+ dbEngine = httpEntry.getDbEngine();
+ loader = httpEntry.getLoader();
+ MultivaluedMap<String, String> params = info.getQueryParameters();
+
+ RemoveDME2QueryParams dme2Workaround = new RemoveDME2QueryParams();
+ //clear out all params not used for filtering
+ params.remove("depth");
+ params.remove("cleanup");
+ params.remove("nodes-only");
+ for (String queryParam : removeQueryParams) {
+ params.remove(queryParam);
+ }
+ if (dme2Workaround.shouldRemoveQueryParams(params)) {
+ dme2Workaround.removeQueryParams(params);
+ }
+
+ uri = uri.split("\\?")[0];
+
+ URI uriObject = UriBuilder.fromPath(uri).build();
+
+ QueryParser uriQuery = dbEngine.getQueryBuilder().createQueryFromURI(uriObject, params);
+
+ String objType = "";
+ if (!uriQuery.getContainerType().equals("")) {
+ objType = uriQuery.getContainerType();
+ } else {
+ objType = uriQuery.getResultType();
+ }
+ Introspector obj = loader.introspectorFromName(objType);
+ DBRequest request =
+ new DBRequest.Builder(HttpMethod.GET, uriObject, uriQuery, obj, headers, info, transId).build();
+ List<DBRequest> requests = new ArrayList<>();
+ requests.add(request);
+ Pair<Boolean, List<Pair<URI, Response>>> responsesTuple = httpEntry.process(requests, sourceOfTruth);
+
+ response = responsesTuple.getValue1().get(0).getValue1();
+
+ } catch (AAIException e) {
+ response = consumerExceptionResponseGenerator(headers, info, HttpMethod.GET, e);
+ } catch (Exception e ) {
+ AAIException ex = new AAIException("AAI_4000", e);
+
+ response = consumerExceptionResponseGenerator(headers, info, HttpMethod.GET, ex);
+ } finally {
+ if (dbEngine != null) {
+ if (cleanUp.equals("true")) {
+ dbEngine.commit();
+ } else {
+ dbEngine.rollback();
+ }
+ }
+ }
+
+ return response;
+ }
+ /**
+ * Delete.
+ *
+ * @param versionParam the version param
+ * @param uri the uri
+ * @param headers the headers
+ * @param info the info
+ * @param resourceVersion the resource version
+ * @param req the req
+ * @return the response
+ */
+ @DELETE
+ @Path("/{uri: .+}")
+ @Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
+ public Response delete (@PathParam("version")String versionParam, @PathParam("uri") @Encoded String uri, @Context HttpHeaders headers, @Context UriInfo info, @QueryParam("resource-version")String resourceVersion, @Context HttpServletRequest req) {
+
+
+ String outputMediaType = getMediaType(headers.getAcceptableMediaTypes());
+ String sourceOfTruth = headers.getRequestHeaders().getFirst("X-FromAppId");
+ String transId = headers.getRequestHeaders().getFirst("X-TransactionId");
+ String realTime = headers.getRequestHeaders().getFirst("Real-Time");
+
+ TransactionalGraphEngine dbEngine = null;
+ Response response = Response.status(404)
+ .type(outputMediaType).build();
+
+ boolean success = true;
+
+ try {
+
+ validateRequest(info);
+ Version version = Version.valueOf(versionParam);
+ DBConnectionType type = this.determineConnectionType(sourceOfTruth, realTime);
+ HttpEntry httpEntry = new HttpEntry(version, introspectorFactoryType, queryStyle, type);
+
+ dbEngine = httpEntry.getDbEngine();
+ Loader loader = httpEntry.getLoader();
+
+ URI uriObject = UriBuilder.fromPath(uri).build();
+
+ QueryParser uriQuery = dbEngine.getQueryBuilder().createQueryFromURI(uriObject);
+ String objType = uriQuery.getResultType();
+ Introspector obj = loader.introspectorFromName(objType);
+
+ DBRequest request = new DBRequest.Builder(HttpMethod.DELETE, uriObject, uriQuery, obj, headers, info, transId).build();
+ List<DBRequest> requests = new ArrayList<>();
+ requests.add(request);
+ Pair<Boolean, List<Pair<URI, Response>>> responsesTuple = httpEntry.process(requests, sourceOfTruth);
+
+ response = responsesTuple.getValue1().get(0).getValue1();
+ success = responsesTuple.getValue0();
+
+ } catch (AAIException e) {
+ response = consumerExceptionResponseGenerator(headers, info, HttpMethod.DELETE, e);
+ success = false;
+ } catch (Exception e) {
+ AAIException ex = new AAIException("AAI_4000", e);
+ response = consumerExceptionResponseGenerator(headers, info, HttpMethod.DELETE, ex);
+ success = false;
+ } finally {
+ if (dbEngine != null) {
+ if (success) {
+ dbEngine.commit();
+ } else {
+ LOGGER.warn("Rolling back Titan transaction");
+ dbEngine.rollback();
+ }
+ }
+ }
+
+ return response;
+ }
+
+ /**
+ * This whole method does nothing because the body is being dropped while fielding the request.
+ *
+ * @param content the content
+ * @param versionParam the version param
+ * @param uri the uri
+ * @param headers the headers
+ * @param info the info
+ * @param req the req
+ * @return the response
+ */
+ @DELETE
+ @Path("/{uri: .+}/relationship-list/relationship")
+ @Consumes({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
+ @Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
+ public Response deleteRelationship (String content, @PathParam("version")String versionParam, @PathParam("uri") @Encoded String uri, @Context HttpHeaders headers, @Context UriInfo info, @Context HttpServletRequest req) {
+
+ MediaType inputMediaType = headers.getMediaType();
+
+ String outputMediaType = getMediaType(headers.getAcceptableMediaTypes());
+ String sourceOfTruth = headers.getRequestHeaders().getFirst("X-FromAppId");
+ String transId = headers.getRequestHeaders().getFirst("X-TransactionId");
+ String realTime = headers.getRequestHeaders().getFirst("Real-Time");
+
+ Loader loader = null;
+ TransactionalGraphEngine dbEngine = null;
+ Response response = Response.status(404)
+ .type(outputMediaType).build();
+
+ boolean success = true;
+
+ try {
+ this.validateRequest(info);
+ Version version = Version.valueOf(versionParam);
+ DBConnectionType type = this.determineConnectionType(sourceOfTruth, realTime);
+ HttpEntry httpEntry = new HttpEntry(version, introspectorFactoryType, queryStyle, type);
+ loader = httpEntry.getLoader();
+ dbEngine = httpEntry.getDbEngine();
+
+ if (content.equals("")) {
+ throw new AAIException("AAI_3102", "You must supply a relationship");
+ }
+ URI uriObject = UriBuilder.fromPath(uri).build();
+ this.validateURI(uriObject);
+
+ QueryParser uriQuery = dbEngine.getQueryBuilder().createQueryFromURI(uriObject);
+
+ Introspector wrappedEntity = loader.unmarshal("relationship", content, org.onap.aai.restcore.MediaType.getEnum(this.getInputMediaType(inputMediaType)));
+
+ DBRequest request = new DBRequest.Builder(HttpMethod.DELETE_EDGE, uriObject, uriQuery, wrappedEntity, headers, info, transId).build();
+ List<DBRequest> requests = new ArrayList<>();
+ requests.add(request);
+ Pair<Boolean, List<Pair<URI, Response>>> responsesTuple = httpEntry.process(requests, sourceOfTruth);
+
+ response = responsesTuple.getValue1().get(0).getValue1();
+ success = responsesTuple.getValue0();
+ } catch (AAIException e) {
+ response = consumerExceptionResponseGenerator(headers, info, HttpMethod.DELETE, e);
+ success = false;
+ } catch (Exception e) {
+ AAIException ex = new AAIException("AAI_4000", e);
+ response = consumerExceptionResponseGenerator(headers, info, HttpMethod.DELETE, ex);
+ success = false;
+ } finally {
+ if (dbEngine != null) {
+ if (success) {
+ dbEngine.commit();
+ } else {
+ LOGGER.warn("Rolling back Titan transaction");
+ dbEngine.rollback();
+ }
+ }
+ }
+
+ return response;
+ }
+
+ /**
+ * Validate request.
+ *
+ * @param uri the uri
+ * @param headers the headers
+ * @param req the req
+ * @param action the action
+ * @param info the info
+ * @throws AAIException the AAI exception
+ * @throws UnsupportedEncodingException the unsupported encoding exception
+ */
+ private void validateRequest(UriInfo info) throws AAIException, UnsupportedEncodingException {
+
+ if (!ValidateEncoding.getInstance().validate(info)) {
+ throw new AAIException("AAI_3008", "uri=" + getPath(info));
+ }
+ }
+
+ /**
+ * Gets the path.
+ *
+ * @param info the info
+ * @return the path
+ */
+ private String getPath(UriInfo info) {
+ String path = info.getPath(false);
+ MultivaluedMap<String, String> map = info.getQueryParameters(false);
+ String params = "?";
+ List<String> parmList = new ArrayList<>();
+ for (String key : map.keySet()) {
+ for (String value : map.get(key)) {
+ parmList.add(key + "=" + value);
+ }
+ }
+ String queryParams = Joiner.on("&").join(parmList);
+ if (map.keySet().size() > 0) {
+ path += params + queryParams;
+ }
+
+ return path;
+
+ }
+
+ /**
+ * Handle writes.
+ *
+ * @param aaiAction the aai action
+ * @param mediaType the media type
+ * @param method the method
+ * @param content the content
+ * @param versionParam the version param
+ * @param uri the uri
+ * @param headers the headers
+ * @param info the info
+ * @param req the req
+ * @return the response
+ */
+ private Response handleWrites(MediaType mediaType, HttpMethod method, String content, String versionParam, String uri, HttpHeaders headers, UriInfo info) {
+
+ Response response = null;
+ TransactionalGraphEngine dbEngine = null;
+ Loader loader = null;
+ Version version = null;
+ String sourceOfTruth = headers.getRequestHeaders().getFirst("X-FromAppId");
+ String transId = headers.getRequestHeaders().getFirst("X-TransactionId");
+ String realTime = headers.getRequestHeaders().getFirst("Real-Time");
+ Boolean success = true;
+
+ try {
+ validateRequest(info);
+
+ version = Version.valueOf(versionParam);
+ DBConnectionType type = this.determineConnectionType(sourceOfTruth, realTime);
+ HttpEntry httpEntry = new HttpEntry(version, introspectorFactoryType, queryStyle, type);
+ loader = httpEntry.getLoader();
+ dbEngine = httpEntry.getDbEngine();
+ URI uriObject = UriBuilder.fromPath(uri).build();
+ this.validateURI(uriObject);
+ QueryParser uriQuery = dbEngine.getQueryBuilder().createQueryFromURI(uriObject);
+ String objName = uriQuery.getResultType();
+ if (content.length() == 0) {
+ if (mediaType.toString().contains(MediaType.APPLICATION_JSON)) {
+ content = "{}";
+ } else {
+ content = "<empty/>";
+ }
+ }
+ Introspector obj = loader.unmarshal(objName, content, org.onap.aai.restcore.MediaType.getEnum(this.getInputMediaType(mediaType)));
+ if (obj == null) {
+ throw new AAIException("AAI_3000", "object could not be unmarshalled:" + content);
+ }
+
+ if (mediaType.toString().contains(MediaType.APPLICATION_XML) && !content.equals("<empty/>") && isEmptyObject(obj)) {
+ throw new AAIInvalidXMLNamespace(content);
+ }
+
+ this.validateIntrospector(obj, loader, uriObject, method);
+
+ DBRequest request =
+ new DBRequest.Builder(method, uriObject, uriQuery, obj, headers, info, transId)
+ .rawRequestContent(content).build();
+ List<DBRequest> requests = new ArrayList<>();
+ requests.add(request);
+ Pair<Boolean, List<Pair<URI, Response>>> responsesTuple = httpEntry.process(requests, sourceOfTruth);
+
+ response = responsesTuple.getValue1().get(0).getValue1();
+ success = responsesTuple.getValue0();
+ } catch (AAIException e) {
+ response = consumerExceptionResponseGenerator(headers, info, method, e);
+ success = false;
+ } catch (Exception e ) {
+ AAIException ex = new AAIException("AAI_4000", e);
+ response = consumerExceptionResponseGenerator(headers, info, method, ex);
+ success = false;
+ } finally {
+ if (dbEngine != null) {
+ if (success) {
+ dbEngine.commit();
+ } else {
+ LOGGER.warn("Rolling back Titan transaction");
+ dbEngine.rollback();
+ }
+ }
+ }
+
+ return response;
+ }
+
+ private void validateURI(URI uri) throws AAIException {
+ if (hasRelatedTo(uri)) {
+ throw new AAIException("AAI_3010");
+ }
+ }
+ private boolean hasRelatedTo(URI uri) {
+
+ return uri.toString().contains("/" + RestTokens.COUSIN + "/");
+ }
+
+ protected boolean isEmptyObject(Introspector obj) {
+ return "{}".equals(obj.marshal(false));
+ }
+}
diff --git a/aai-resources/src/main/java/org/onap/aai/rest/URLFromVertexIdConsumer.java b/aai-resources/src/main/java/org/onap/aai/rest/URLFromVertexIdConsumer.java
new file mode 100644
index 0000000..aa67557
--- /dev/null
+++ b/aai-resources/src/main/java/org/onap/aai/rest/URLFromVertexIdConsumer.java
@@ -0,0 +1,121 @@
+/**
+ * ============LICENSE_START=======================================================
+ * org.onap.aai
+ * ================================================================================
+ * Copyright © 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END=========================================================
+ *
+ * ECOMP is a trademark and service mark of AT&T Intellectual Property.
+ */
+package org.onap.aai.rest;
+
+import java.net.URI;
+import java.net.URL;
+import java.util.Iterator;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.ws.rs.GET;
+import javax.ws.rs.Path;
+import javax.ws.rs.PathParam;
+import javax.ws.rs.Produces;
+import javax.ws.rs.core.Context;
+import javax.ws.rs.core.HttpHeaders;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+import javax.ws.rs.core.Response.Status;
+import javax.ws.rs.core.UriInfo;
+
+import org.apache.tinkerpop.gremlin.structure.Vertex;
+
+import org.onap.aai.dbmap.DBConnectionType;
+import org.onap.aai.exceptions.AAIException;
+import org.onap.aai.introspection.ModelType;
+import org.onap.aai.introspection.Version;
+import org.onap.aai.rest.db.HttpEntry;
+import org.onap.aai.restcore.HttpMethod;
+import org.onap.aai.restcore.RESTAPI;
+import org.onap.aai.serialization.db.DBSerializer;
+import org.onap.aai.serialization.engines.QueryStyle;
+import org.onap.aai.serialization.engines.TransactionalGraphEngine;
+import org.onap.aai.util.AAIConfig;
+import org.onap.aai.workarounds.LegacyURITransformer;
+
+/**
+ * The Class URLFromVertexIdConsumer.
+ */
+@Path("{version: v[2789]|v1[01]}/generateurl")
+public class URLFromVertexIdConsumer extends RESTAPI {
+ private ModelType introspectorFactoryType = ModelType.MOXY;
+ private QueryStyle queryStyle = QueryStyle.TRAVERSAL;
+
+ private final String ID_ENDPOINT = "/id/{vertexid: \\d+}";
+
+ /**
+ * Generate url from vertex id.
+ *
+ * @param content the content
+ * @param versionParam the version param
+ * @param vertexid the vertexid
+ * @param headers the headers
+ * @param info the info
+ * @param req the req
+ * @return the response
+ */
+ @Path(ID_ENDPOINT)
+ @Produces({ MediaType.TEXT_PLAIN })
+ public Response generateUrlFromVertexId(String content, @PathParam("version")String versionParam, @PathParam("vertexid")long vertexid, @Context HttpHeaders headers, @Context UriInfo info, @Context HttpServletRequest req) {
+
+ String sourceOfTruth = headers.getRequestHeaders().getFirst("X-FromAppId");
+ String realTime = headers.getRequestHeaders().getFirst("Real-Time");
+
+ Version version = Version.valueOf(versionParam);
+ StringBuilder result = new StringBuilder();
+ Response response = null;
+ TransactionalGraphEngine dbEngine = null;
+ try {
+ DBConnectionType type = this.determineConnectionType(sourceOfTruth, realTime);
+ HttpEntry httpEntry = new HttpEntry(version, introspectorFactoryType, queryStyle, type);
+ dbEngine = httpEntry.getDbEngine();
+
+ DBSerializer serializer = new DBSerializer(version, dbEngine, introspectorFactoryType, sourceOfTruth);
+
+ Iterator<Vertex> thisVertex = dbEngine.asAdmin().getTraversalSource().V(vertexid);
+
+ if (!thisVertex.hasNext()) {
+ throw new AAIException("AAI_6114", "no node at that vertex id");
+ }
+ URI uri = serializer.getURIForVertex(thisVertex.next());
+
+ result.append(uri.getRawPath());
+ result.insert(0, version);
+ result.insert(0, AAIConfig.get("aai.server.url.base"));
+ LegacyURITransformer urlTransformer = LegacyURITransformer.getInstance();
+ URI output = new URI(result.toString());
+
+ response = Response.ok().entity(result.toString()).status(Status.OK).type(MediaType.TEXT_PLAIN).build();
+ } catch (AAIException e) {
+ //TODO check that the details here are sensible
+ response = consumerExceptionResponseGenerator(headers, info, HttpMethod.GET, e);
+ } catch (Exception e) {
+ AAIException ex = new AAIException("AAI_4000", e);
+ response = consumerExceptionResponseGenerator(headers, info, HttpMethod.GET, ex);
+ } finally { //to close the titan transaction (I think)
+ if (dbEngine != null) {
+ dbEngine.rollback();
+ }
+ }
+ return response;
+ }
+}
diff --git a/aai-resources/src/main/java/org/onap/aai/rest/VertexIdConsumer.java b/aai-resources/src/main/java/org/onap/aai/rest/VertexIdConsumer.java
new file mode 100644
index 0000000..68a72e6
--- /dev/null
+++ b/aai-resources/src/main/java/org/onap/aai/rest/VertexIdConsumer.java
@@ -0,0 +1,146 @@
+/**
+ * ============LICENSE_START=======================================================
+ * org.onap.aai
+ * ================================================================================
+ * Copyright © 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END=========================================================
+ *
+ * ECOMP is a trademark and service mark of AT&T Intellectual Property.
+ */
+package org.onap.aai.rest;
+
+import java.net.URI;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.ws.rs.DefaultValue;
+import javax.ws.rs.GET;
+import javax.ws.rs.Path;
+import javax.ws.rs.PathParam;
+import javax.ws.rs.Produces;
+import javax.ws.rs.QueryParam;
+import javax.ws.rs.core.Context;
+import javax.ws.rs.core.HttpHeaders;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+import javax.ws.rs.core.Response.Status;
+import javax.ws.rs.core.UriBuilder;
+import javax.ws.rs.core.UriInfo;
+
+import org.apache.tinkerpop.gremlin.structure.Vertex;
+import org.javatuples.Pair;
+
+import org.onap.aai.db.props.AAIProperties;
+import org.onap.aai.dbmap.DBConnectionType;
+import org.onap.aai.exceptions.AAIException;
+import org.onap.aai.introspection.Introspector;
+import org.onap.aai.introspection.Loader;
+import org.onap.aai.introspection.MarshallerProperties;
+import org.onap.aai.introspection.ModelType;
+import org.onap.aai.introspection.Version;
+import org.onap.aai.parsers.query.QueryParser;
+import org.onap.aai.rest.db.DBRequest;
+import org.onap.aai.rest.db.HttpEntry;
+import org.onap.aai.restcore.HttpMethod;
+import org.onap.aai.restcore.RESTAPI;
+import org.onap.aai.serialization.db.DBSerializer;
+import org.onap.aai.serialization.engines.QueryStyle;
+import org.onap.aai.serialization.engines.TransactionalGraphEngine;
+
+/**
+ * The Class VertexIdConsumer.
+ */
+@Path("{version: v[2789]|v1[01]}/resources")
+public class VertexIdConsumer extends RESTAPI {
+
+ private ModelType introspectorFactoryType = ModelType.MOXY;
+ private QueryStyle queryStyle = QueryStyle.TRAVERSAL;
+
+ private final String ID_ENDPOINT = "/id/{vertexid: \\d+}";
+
+ /**
+ * Gets the by vertex id.
+ *
+ * @param content the content
+ * @param versionParam the version param
+ * @param vertexid the vertexid
+ * @param depthParam the depth param
+ * @param headers the headers
+ * @param info the info
+ * @param req the req
+ * @return the by vertex id
+ */
+ @GET
+ @Path(ID_ENDPOINT)
+ @Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
+ public Response getByVertexId(String content, @PathParam("version")String versionParam, @PathParam("vertexid")long vertexid, @DefaultValue("all") @QueryParam("depth") String depthParam, @Context HttpHeaders headers, @Context UriInfo info, @Context HttpServletRequest req) {
+
+ String outputMediaType = getMediaType(headers.getAcceptableMediaTypes());
+ String sourceOfTruth = headers.getRequestHeaders().getFirst("X-FromAppId");
+ String transId = headers.getRequestHeaders().getFirst("X-TransactionId");
+ String realTime = headers.getRequestHeaders().getFirst("Real-Time");
+ Version version = Version.valueOf(versionParam);
+ Status status = Status.NOT_FOUND;
+ String result = "";
+ Response response = null;
+ TransactionalGraphEngine dbEngine = null;
+ try {
+ int depth = setDepth(depthParam);
+ DBConnectionType type = this.determineConnectionType(sourceOfTruth, realTime);
+ HttpEntry httpEntry = new HttpEntry(version, introspectorFactoryType, queryStyle, type);
+ dbEngine = httpEntry.getDbEngine();
+ Loader loader = httpEntry.getLoader();
+
+ DBSerializer serializer = new DBSerializer(version, dbEngine, introspectorFactoryType, sourceOfTruth);
+
+ //get type of the object represented by the given id
+ Vertex thisVertex = null;
+ Iterator<Vertex> itr = dbEngine.asAdmin().getTraversalSource().V(vertexid);
+
+ if (!itr.hasNext()) {
+ throw new AAIException("AAI_6114", "no node at that vertex id");
+ }
+ thisVertex = itr.next();
+ String objName = thisVertex.<String>property(AAIProperties.NODE_TYPE).orElse(null);
+
+ QueryParser query = dbEngine.getQueryBuilder(thisVertex).createQueryFromObjectName(objName);
+
+ Introspector obj = loader.introspectorFromName(query.getResultType());
+
+ URI uriObject = UriBuilder.fromPath(info.getPath()).build();
+
+ DBRequest request =
+ new DBRequest.Builder(HttpMethod.GET, uriObject, query, obj, headers, info, transId)
+ .customMarshaller(new MarshallerProperties.Builder(org.onap.aai.restcore.MediaType.getEnum(outputMediaType)).includeRoot(true).build()).build();
+
+ List<DBRequest> requests = new ArrayList<>();
+ requests.add(request);
+ Pair<Boolean, List<Pair<URI, Response>>> responsesTuple = httpEntry.process(requests, sourceOfTruth);
+ response = responsesTuple.getValue1().get(0).getValue1();
+ } catch (AAIException e){
+ response = consumerExceptionResponseGenerator(headers, info, HttpMethod.GET, e);
+ } catch (Exception e) {
+ AAIException ex = new AAIException("AAI_4000", e);
+ response = consumerExceptionResponseGenerator(headers, info, HttpMethod.GET, ex);
+ } finally { //to close the titan transaction (I think)
+ if (dbEngine != null) {
+ dbEngine.rollback();
+ }
+ }
+ return response;
+ }
+}
diff --git a/aai-resources/src/main/java/org/onap/aai/rest/exceptions/AAIInvalidXMLNamespace.java b/aai-resources/src/main/java/org/onap/aai/rest/exceptions/AAIInvalidXMLNamespace.java
new file mode 100644
index 0000000..b9a8176
--- /dev/null
+++ b/aai-resources/src/main/java/org/onap/aai/rest/exceptions/AAIInvalidXMLNamespace.java
@@ -0,0 +1,41 @@
+/**
+ * ============LICENSE_START=======================================================
+ * org.onap.aai
+ * ================================================================================
+ * Copyright © 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END=========================================================
+ *
+ * ECOMP is a trademark and service mark of AT&T Intellectual Property.
+ */
+package org.onap.aai.rest.exceptions;
+
+import org.onap.aai.exceptions.AAIException;
+
+public class AAIInvalidXMLNamespace extends AAIException {
+
+ private static final long serialVersionUID = 7487333042291858169L;
+
+ public AAIInvalidXMLNamespace(String message) {
+ super("AAI_3011", message);
+ }
+
+ public AAIInvalidXMLNamespace(Throwable cause) {
+ super("AAI_3011",cause);
+ }
+
+ public AAIInvalidXMLNamespace(String message, Throwable cause) {
+ super("AAI_3011", cause, message);
+ }
+}
diff --git a/aai-resources/src/main/java/org/onap/aai/rest/retired/RetiredConsumer.java b/aai-resources/src/main/java/org/onap/aai/rest/retired/RetiredConsumer.java
new file mode 100644
index 0000000..0188142
--- /dev/null
+++ b/aai-resources/src/main/java/org/onap/aai/rest/retired/RetiredConsumer.java
@@ -0,0 +1,144 @@
+/**
+ * ============LICENSE_START=======================================================
+ * org.onap.aai
+ * ================================================================================
+ * Copyright © 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END=========================================================
+ *
+ * ECOMP is a trademark and service mark of AT&T Intellectual Property.
+ */
+package org.onap.aai.rest.retired;
+
+import java.util.ArrayList;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.ws.rs.DELETE;
+import javax.ws.rs.GET;
+import javax.ws.rs.POST;
+import javax.ws.rs.PUT;
+import javax.ws.rs.Path;
+import javax.ws.rs.PathParam;
+import javax.ws.rs.core.Context;
+import javax.ws.rs.core.HttpHeaders;
+import javax.ws.rs.core.Response;
+import javax.ws.rs.core.UriInfo;
+
+import org.apache.cxf.jaxrs.ext.PATCH;
+
+import org.onap.aai.exceptions.AAIException;
+import org.onap.aai.logging.ErrorLogHelper;
+import org.onap.aai.restcore.RESTAPI;
+import org.onap.aai.util.AAIConfig;
+
+/**
+ * The Class RetiredConsumer.
+ */
+public abstract class RetiredConsumer extends RESTAPI {
+
+ /**
+ * Creates the message get.
+ *
+ * @param versionParam the version param
+ * @param headers the headers
+ * @param info the info
+ * @param req the req
+ * @return the response
+ */
+ @GET
+ @Path("/{uri:.*}")
+ public Response createMessageGet(@PathParam("version")String versionParam, @Context HttpHeaders headers, @Context UriInfo info, @Context HttpServletRequest req) {
+ return createMessage(versionParam, headers, info, req);
+ }
+
+ /**
+ * Creates the message delete.
+ *
+ * @param versionParam the version param
+ * @param headers the headers
+ * @param info the info
+ * @param req the req
+ * @return the response
+ */
+ @DELETE
+ @Path("/{uri:.*}")
+ public Response createMessageDelete(@PathParam("version")String versionParam, @Context HttpHeaders headers, @Context UriInfo info, @Context HttpServletRequest req) {
+ return createMessage(versionParam, headers, info, req);
+ }
+
+ /**
+ * Creates the message post.
+ *
+ * @param versionParam the version param
+ * @param headers the headers
+ * @param info the info
+ * @param req the req
+ * @return the response
+ */
+ @POST
+ @Path("/{uri:.*}")
+ public Response createMessagePost(@PathParam("version")String versionParam, @Context HttpHeaders headers, @Context UriInfo info, @Context HttpServletRequest req) {
+ return createMessage(versionParam, headers, info, req);
+ }
+
+ @PATCH
+ @Path("/{uri:.*}")
+ public Response createMessagePatch(@PathParam("version")String versionParam, @Context HttpHeaders headers, @Context UriInfo info, @Context HttpServletRequest req) {
+ return createMessage(versionParam, headers, info, req);
+ }
+ /**
+ * Creates the message put.
+ *
+ * @param versionParam the version param
+ * @param headers the headers
+ * @param info the info
+ * @param req the req
+ * @return the response
+ */
+ @PUT
+ @Path("/{uri:.*}")
+ public Response createMessagePut(@PathParam("version")String versionParam, @Context HttpHeaders headers, @Context UriInfo info, @Context HttpServletRequest req) {
+ return createMessage(versionParam, headers, info, req);
+ }
+
+
+ /**
+ * Creates the message.
+ *
+ * @param versionParam the version param
+ * @param headers the headers
+ * @param info the info
+ * @param req the req
+ * @return the response
+ */
+ private Response createMessage(String versionParam, HttpHeaders headers, UriInfo info, HttpServletRequest req) {
+ AAIException e = new AAIException("AAI_3007");
+
+ ArrayList<String> templateVars = new ArrayList<String>();
+
+ if (templateVars.size() == 0) {
+ templateVars.add("PUT");
+ templateVars.add(info.getPath().toString());
+ templateVars.add(versionParam);
+ templateVars.add(AAIConfig.get("aai.default.api.version", ""));
+ }
+
+ Response response = Response
+ .status(e.getErrorObject().getHTTPResponseCode())
+ .entity(ErrorLogHelper.getRESTAPIErrorResponse(headers.getAcceptableMediaTypes(), e,
+ templateVars)).build();
+
+ return response;
+ }
+}
diff --git a/aai-resources/src/main/java/org/onap/aai/rest/retired/V3ThroughV7Consumer.java b/aai-resources/src/main/java/org/onap/aai/rest/retired/V3ThroughV7Consumer.java
new file mode 100644
index 0000000..a43e5c2
--- /dev/null
+++ b/aai-resources/src/main/java/org/onap/aai/rest/retired/V3ThroughV7Consumer.java
@@ -0,0 +1,29 @@
+/**
+ * ============LICENSE_START=======================================================
+ * org.onap.aai
+ * ================================================================================
+ * Copyright © 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END=========================================================
+ *
+ * ECOMP is a trademark and service mark of AT&T Intellectual Property.
+ */
+package org.onap.aai.rest.retired;
+
+import javax.ws.rs.Path;
+
+@Path("{version: v[3-6]}") //TODO re-add v7 when we fix our env issues AAI-8567
+public class V3ThroughV7Consumer extends RetiredConsumer {
+
+}
diff --git a/aai-resources/src/main/java/org/onap/aai/rest/retired/V7V8Models.java b/aai-resources/src/main/java/org/onap/aai/rest/retired/V7V8Models.java
new file mode 100644
index 0000000..26dea02
--- /dev/null
+++ b/aai-resources/src/main/java/org/onap/aai/rest/retired/V7V8Models.java
@@ -0,0 +1,29 @@
+/**
+ * ============LICENSE_START=======================================================
+ * org.onap.aai
+ * ================================================================================
+ * Copyright © 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END=========================================================
+ *
+ * ECOMP is a trademark and service mark of AT&T Intellectual Property.
+ */
+package org.onap.aai.rest.retired;
+
+import javax.ws.rs.Path;
+
+@Path("{version: v[78]}/service-design-and-creation/models")
+public class V7V8Models extends RetiredConsumer {
+
+}
diff --git a/aai-resources/src/main/java/org/onap/aai/rest/retired/V7V8NamedQueries.java b/aai-resources/src/main/java/org/onap/aai/rest/retired/V7V8NamedQueries.java
new file mode 100644
index 0000000..98be455
--- /dev/null
+++ b/aai-resources/src/main/java/org/onap/aai/rest/retired/V7V8NamedQueries.java
@@ -0,0 +1,29 @@
+/**
+ * ============LICENSE_START=======================================================
+ * org.onap.aai
+ * ================================================================================
+ * Copyright © 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END=========================================================
+ *
+ * ECOMP is a trademark and service mark of AT&T Intellectual Property.
+ */
+package org.onap.aai.rest.retired;
+
+import javax.ws.rs.Path;
+
+@Path("{version: v[78]}/service-design-and-creation/named-queries")
+public class V7V8NamedQueries extends RetiredConsumer {
+
+}
diff --git a/aai-resources/src/main/java/org/onap/aai/rest/tools/ModelVersionTransformer.java b/aai-resources/src/main/java/org/onap/aai/rest/tools/ModelVersionTransformer.java
new file mode 100644
index 0000000..eeaaf6a
--- /dev/null
+++ b/aai-resources/src/main/java/org/onap/aai/rest/tools/ModelVersionTransformer.java
@@ -0,0 +1,410 @@
+/**
+ * ============LICENSE_START=======================================================
+ * org.onap.aai
+ * ================================================================================
+ * Copyright © 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END=========================================================
+ *
+ * ECOMP is a trademark and service mark of AT&T Intellectual Property.
+ */
+package org.onap.aai.rest.tools;
+
+import java.io.UnsupportedEncodingException;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.NoSuchElementException;
+import java.util.Set;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.ws.rs.Consumes;
+import javax.ws.rs.Encoded;
+import javax.ws.rs.POST;
+import javax.ws.rs.Path;
+import javax.ws.rs.PathParam;
+import javax.ws.rs.Produces;
+import javax.ws.rs.core.Context;
+import javax.ws.rs.core.HttpHeaders;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.MultivaluedMap;
+import javax.ws.rs.core.Response;
+import javax.ws.rs.core.Response.Status;
+import javax.ws.rs.core.UriInfo;
+
+import org.apache.tinkerpop.gremlin.structure.Vertex;
+import org.onap.aai.db.props.AAIProperties;
+import org.onap.aai.dbmap.DBConnectionType;
+import org.onap.aai.exceptions.AAIException;
+import org.onap.aai.introspection.Introspector;
+import org.onap.aai.introspection.Loader;
+import org.onap.aai.introspection.MarshallerProperties;
+import org.onap.aai.introspection.ModelType;
+import org.onap.aai.introspection.Version;
+import org.onap.aai.introspection.exceptions.AAIUnknownObjectException;
+import org.onap.aai.logging.ErrorLogHelper;
+import org.onap.aai.rest.db.HttpEntry;
+import org.onap.aai.rest.exceptions.AAIInvalidXMLNamespace;
+import org.onap.aai.rest.util.ValidateEncoding;
+import org.onap.aai.restcore.RESTAPI;
+import org.onap.aai.serialization.db.EdgeType;
+import org.onap.aai.serialization.db.exceptions.NoEdgeRuleFoundException;
+import org.onap.aai.serialization.engines.QueryStyle;
+import org.onap.aai.serialization.engines.TransactionalGraphEngine;
+
+import com.att.eelf.configuration.EELFLogger;
+import com.att.eelf.configuration.EELFManager;
+import com.google.common.base.Joiner;
+
+
+/**
+ * The Class ModelVersionTransformer.
+ */
+@Path("tools")
+public class ModelVersionTransformer extends RESTAPI {
+
+ private static final EELFLogger LOGGER = EELFManager.getInstance().getLogger(ModelVersionTransformer.class.getName());
+ protected static String authPolicyFunctionName = "REST";
+ private ModelType introspectorFactoryType = ModelType.MOXY;
+ private QueryStyle queryStyle = QueryStyle.TRAVERSAL;
+
+
+ /**
+ * POST for model transformation.
+ *
+ * @param content the content
+ * @param uri the uri
+ * @param headers the headers
+ * @param info the info
+ * @param req the req
+ * @return the transformed model
+ * @Path("/{uri: modeltransform}")
+ * @throws UnsupportedEncodingException
+ */
+ @POST
+ @Path("/{uri: modeltransform}")
+ @Consumes({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
+ @Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
+ public Response modelTransform (String content, @PathParam("uri") @Encoded String uri, @Context HttpHeaders headers, @Context UriInfo info, @Context HttpServletRequest req) throws UnsupportedEncodingException {
+ Response response = null;
+ TransactionalGraphEngine dbEngine = null;
+ Loader loader = null;
+ MediaType mediaType = headers.getMediaType();
+ String sourceOfTruth = headers.getRequestHeaders().getFirst("X-FromAppId");
+ String transId = headers.getRequestHeaders().getFirst("X-TransactionId");
+ String realTime = headers.getRequestHeaders().getFirst("Real-Time");
+ Boolean success = true;
+ AAIException ex;
+
+ try {
+ validateRequest(info);
+
+ DBConnectionType type = this.determineConnectionType(sourceOfTruth, realTime);
+ HttpEntry httpEntry = new HttpEntry(Version.v8, introspectorFactoryType, queryStyle, type);
+ loader = httpEntry.getLoader();
+ dbEngine = httpEntry.getDbEngine();
+ if (content.length() == 0) {
+ if (mediaType.toString().contains(MediaType.APPLICATION_JSON)) {
+ content = "{}";
+ } else {
+ content = "<empty/>";
+ }
+ }
+
+ //Unmarshall the received model and store properties and values in a map.
+ Introspector obj = loader.unmarshal("Model", content, org.onap.aai.restcore.MediaType.getEnum(this.getInputMediaType(mediaType)));
+ if (obj == null) {
+ throw new AAIException("AAI_3000", "object could not be unmarshalled:" + content);
+ }
+
+ if (mediaType.toString().contains(MediaType.APPLICATION_XML) && !content.equals("<empty/>") && isEmptyObject(obj)) {
+ throw new AAIInvalidXMLNamespace(content);
+ }
+
+ Set<String> properties = obj.getProperties();
+ java.util.Iterator<String> propItr = properties.iterator();
+
+ Map<String, Object> v8PropMap = new HashMap<String, Object>();
+ while (propItr.hasNext()){
+ String property = propItr.next();
+ Object propertyValue = obj.getValue(property);
+ if (propertyValue != null) {
+ v8PropMap.put(propItr.next(), propertyValue);
+ }
+ }
+ // Get the current models and create a map of model-ver to model keys, this allows us
+ // to easily figure out and construct the relationships on the supplied v8 model
+ Map<String,String> modelVersionIdToModelInvariantIdMap = getCurrentModelsFromGraph(headers, transId, info);
+
+ // Build the v10 - TODO
+ HttpEntry newHttpEntry = new HttpEntry(Version.v10, introspectorFactoryType, queryStyle, type);
+ Loader newLoader = newHttpEntry.getLoader();
+ Introspector newModelObj = newLoader.introspectorFromName("Model");
+
+ // pull the attributes we need to apply to the model + model-ver objects
+ // model specific attrs
+ String oldModelInvariantId = obj.getValue("model-id");
+ String oldModelType = obj.getValue("model-type");
+ // model-ver specific
+ String oldModelName = obj.getValue("model-name");
+ String oldModelVersionId = obj.getValue("model-name-version-id");
+ String oldModelVersion = obj.getValue("model-version");
+
+ // copy attributes from the v8 model object to the v10 model object
+ newModelObj.setValue("model-invariant-id", oldModelInvariantId);
+ newModelObj.setValue("model-type", oldModelType);
+
+ Introspector modelVersObj = newModelObj.newIntrospectorInstanceOfProperty("model-vers");
+
+ newModelObj.setValue("model-vers", modelVersObj.getUnderlyingObject());
+
+ List<Object> modelVerList = (List<Object>)modelVersObj.getValue("model-ver");
+
+ //create a model-ver object
+ Introspector modelVerObj = newLoader.introspectorFromName("ModelVer");
+ // load attributes from the v8 model object into the v10 model-ver object
+ modelVerObj.setValue("model-version-id", oldModelVersionId);
+ modelVerObj.setValue("model-name", oldModelName);
+ modelVerObj.setValue("model-version", oldModelVersion);
+
+
+ if (obj.hasProperty("model-elements")) {
+ Introspector oldModelElements = obj.getWrappedValue("model-elements");
+ if (oldModelElements != null) {
+ Introspector newModelElements = modelVerObj.newIntrospectorInstanceOfProperty("model-elements");
+ modelVerObj.setValue("model-elements", newModelElements.getUnderlyingObject());
+ repackModelElements(oldModelElements, newModelElements, modelVersionIdToModelInvariantIdMap);
+ }
+ }
+
+ modelVerList.add(modelVerObj.getUnderlyingObject());
+
+ String outputMediaType = getMediaType(headers.getAcceptableMediaTypes());
+ MarshallerProperties marshallerProperties =
+ new MarshallerProperties.Builder(org.onap.aai.restcore.MediaType.getEnum(outputMediaType)).build();
+
+ String result = newModelObj.marshal(marshallerProperties);
+ response = Response.ok(result).build();
+
+ } catch (AAIException e) {
+
+ ArrayList<String> templateVars = new ArrayList<String>(2);
+ templateVars.add("POST modeltransform");
+ templateVars.add("model-ver.model-version-id");
+ response = Response
+ .status(e.getErrorObject().getHTTPResponseCode())
+ .entity(ErrorLogHelper.getRESTAPIErrorResponse(
+ headers.getAcceptableMediaTypes(), e,
+ templateVars)).build();
+ success = false;
+ } catch (Exception e) {
+ ArrayList<String> templateVars = new ArrayList<String>(2);
+ templateVars.add("POST modeltransform");
+ templateVars.add("model-ver.model-version-id");
+ ex = new AAIException("AAI_4000", e);
+ response = Response
+ .status(Status.INTERNAL_SERVER_ERROR)
+ .entity(ErrorLogHelper.getRESTAPIErrorResponse(headers.getAcceptableMediaTypes(), ex, templateVars))
+ .build();
+ e.printStackTrace();
+ success = false;
+ } finally {
+ if (dbEngine != null) {
+ if (success) {
+ dbEngine.commit();
+ } else {
+ dbEngine.rollback();
+ }
+ }
+ }
+ return response;
+ }
+
+
+ private void repackModelElements(Introspector oldModelElements, Introspector newModelElements, Map<String, String> modelVersionIdToModelInvariantIdMap)
+ throws AAIUnknownObjectException, AAIException {
+
+ List<Introspector> oldModelElementList = oldModelElements.getWrappedListValue("model-element");
+ List<Object> newModelElementList = (List<Object>)newModelElements.getValue("model-element");
+
+ for (Introspector oldModelElement : oldModelElementList) {
+ Introspector newModelElement = newModelElements.getLoader().introspectorFromName("model-element");
+
+ ArrayList<String> attrs = new ArrayList<String>();
+
+ attrs.add("model-element-uuid");
+ attrs.add("new-data-del-flag");
+ attrs.add("cardinality");
+ attrs.add("linkage-points");
+
+ for (String attr : attrs) {
+ if (oldModelElement.hasProperty(attr)) {
+ newModelElement.setValue(attr, oldModelElement.getValue(attr));
+ }
+ }
+
+ if (oldModelElement.hasProperty("relationship-list")) {
+
+ Introspector oldRelationshipList = oldModelElement.getWrappedValue("relationship-list");
+ Introspector newRelationshipList = newModelElements.getLoader().introspectorFromName("relationship-list");
+ newModelElement.setValue("relationship-list", newRelationshipList.getUnderlyingObject());
+
+ List<Introspector> oldRelationshipListList = oldRelationshipList.getWrappedListValue("relationship");
+ List<Object> newRelationshipListList = (List<Object>)newRelationshipList.getValue("relationship");
+
+ for (Introspector oldRelationship : oldRelationshipListList) {
+
+ Introspector newRelationship = newModelElements.getLoader().introspectorFromName("relationship");
+ newRelationshipListList.add(newRelationship.getUnderlyingObject());
+
+ List<Introspector> oldRelationshipData = oldRelationship.getWrappedListValue("relationship-data");
+ List<Object> newRelationshipData = (List<Object>)newRelationship.getValue("relationship-data");
+
+ newRelationship.setValue("related-to", "model-ver");
+
+ for (Introspector oldRelationshipDatum : oldRelationshipData) {
+
+ String oldProp = null;
+ String oldVal = null;
+
+ if (oldRelationshipDatum.hasProperty("relationship-key")) {
+ oldProp = oldRelationshipDatum.getValue("relationship-key");
+ }
+ if (oldRelationshipDatum.hasProperty("relationship-value")) {
+ oldVal = oldRelationshipDatum.getValue("relationship-value");
+ }
+
+ if ("model.model-name-version-id".equals(oldProp)) {
+ // make two new relationshipDatum for use w/ the new style model
+
+ // you should have the model in the list of models we collected earlier
+ if (modelVersionIdToModelInvariantIdMap.containsKey(oldVal)) {
+ Introspector newRelationshipDatum1 = newModelElements.getLoader().introspectorFromName("relationship-data");
+ Introspector newRelationshipDatum2 = newModelElements.getLoader().introspectorFromName("relationship-data");
+
+ String modelId = modelVersionIdToModelInvariantIdMap.get(oldVal);
+
+ // the first one points at the model-invariant-id of found model
+ newRelationshipDatum1.setValue("relationship-key", "model.model-invariant-id");
+ newRelationshipDatum1.setValue("relationship-value", modelId);
+
+ // the second one points at the model-version-id which corresponds to the old model-name-version-id
+ newRelationshipDatum2.setValue("relationship-key", "model-ver.model-version-id");
+ newRelationshipDatum2.setValue("relationship-value", oldVal);
+
+ newRelationshipData.add(newRelationshipDatum1.getUnderlyingObject());
+ newRelationshipData.add(newRelationshipDatum2.getUnderlyingObject());
+ } else {
+ throw new AAIException("AAI_6114", "No model-ver found using model-ver.model-version-id=" + oldVal);
+ }
+ }
+ }
+
+ }
+ }
+
+ if (oldModelElement.hasProperty("model-elements")) {
+ Introspector nextOldModelElements = oldModelElement.getWrappedValue("model-elements");
+ if (nextOldModelElements != null) {
+ Introspector nextNewModelElements = newModelElement.newIntrospectorInstanceOfProperty("model-elements");
+ newModelElement.setValue("model-elements", nextNewModelElements.getUnderlyingObject());
+ repackModelElements(nextOldModelElements, nextNewModelElements, modelVersionIdToModelInvariantIdMap);
+ }
+ }
+ newModelElementList.add(newModelElement.getUnderlyingObject());
+ }
+ return;
+
+ }
+
+ private Map<String, String> getCurrentModelsFromGraph(HttpHeaders headers, String transactionId, UriInfo info) throws NoEdgeRuleFoundException, AAIException {
+
+ TransactionalGraphEngine dbEngine = null;
+ Map<String, String> modelVerModelMap = new HashMap<String,String>() ;
+ try {
+
+ Version version = AAIProperties.LATEST;
+ DBConnectionType type = DBConnectionType.REALTIME;
+
+ final HttpEntry httpEntry = new HttpEntry(version, introspectorFactoryType, queryStyle, type);
+ dbEngine = httpEntry.getDbEngine();
+
+ List<Vertex> modelVertices = dbEngine.asAdmin().getTraversalSource().V().has(AAIProperties.NODE_TYPE,"model").toList();
+ for (Vertex modelVtx : modelVertices) {
+
+ List<Vertex> modelVerVerts = dbEngine.getQueryBuilder(modelVtx).createEdgeTraversal(EdgeType.TREE, "model", "model-ver").toList();
+ for (Vertex v : modelVerVerts) {
+ modelVerModelMap.put(v.value("model-version-id"), modelVtx.value("model-invariant-id"));
+ }
+ }
+ } catch (NoSuchElementException e) {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ } catch (Exception e1) {
+ e1.printStackTrace();
+ }
+ return modelVerModelMap;
+
+ }
+
+ /**
+ * Validate request.
+ *
+ * @param uri the uri
+ * @param headers the headers
+ * @param req the req
+ * @param action the action
+ * @param info the info
+ * @throws AAIException the AAI exception
+ * @throws UnsupportedEncodingException the unsupported encoding exception
+ */
+ private void validateRequest(UriInfo info) throws AAIException, UnsupportedEncodingException {
+
+ if (!ValidateEncoding.getInstance().validate(info)) {
+ throw new AAIException("AAI_3008", "uri=" + getPath(info));
+ }
+ }
+
+ /**
+ * Gets the path.
+ *
+ * @param info the info
+ * @return the path
+ */
+ private String getPath(UriInfo info) {
+ String path = info.getPath(false);
+ MultivaluedMap<String, String> map = info.getQueryParameters(false);
+ String params = "?";
+ List<String> parmList = new ArrayList<>();
+ for (String key : map.keySet()) {
+ for (String value : map.get(key)) {
+ parmList.add(key + "=" + value);
+ }
+ }
+ String queryParams = Joiner.on("&").join(parmList);
+ if (map.keySet().size() > 0) {
+ path += params + queryParams;
+ }
+
+ return path;
+
+ }
+
+ protected boolean isEmptyObject(Introspector obj) {
+ return "{}".equals(obj.marshal(false));
+ }
+
+
+}
diff --git a/aai-resources/src/main/java/org/onap/aai/rest/util/EchoResponse.java b/aai-resources/src/main/java/org/onap/aai/rest/util/EchoResponse.java
new file mode 100644
index 0000000..55a07e4
--- /dev/null
+++ b/aai-resources/src/main/java/org/onap/aai/rest/util/EchoResponse.java
@@ -0,0 +1,122 @@
+/**
+ * ============LICENSE_START=======================================================
+ * org.onap.aai
+ * ================================================================================
+ * Copyright © 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END=========================================================
+ *
+ * ECOMP is a trademark and service mark of AT&T Intellectual Property.
+ */
+package org.onap.aai.rest.util;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.ws.rs.GET;
+import javax.ws.rs.Path;
+import javax.ws.rs.Produces;
+import javax.ws.rs.QueryParam;
+import javax.ws.rs.core.Context;
+import javax.ws.rs.core.HttpHeaders;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+import javax.ws.rs.core.Response.Status;
+
+import org.onap.aai.exceptions.AAIException;
+import org.onap.aai.logging.ErrorLogHelper;
+import org.onap.aai.restcore.RESTAPI;
+
+/**
+ * The Class EchoResponse.
+ */
+public class EchoResponse extends RESTAPI {
+
+ protected static String authPolicyFunctionName = "util";
+
+ public static final String echoPath = "/util/echo";
+
+ /**
+ * Simple health-check API that echos back the X-FromAppId and X-TransactionId to clients.
+ * If there is a query string, a transaction gets logged into hbase, proving the application is connected to the data store.
+ * If there is no query string, no transacction logging is done to hbase.
+ *
+ * @param headers the headers
+ * @param req the req
+ * @param myAction if exists will cause transaction to be logged to hbase
+ * @return the response
+ */
+ @GET
+ @Produces( { MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
+ @Path(echoPath)
+ public Response echoResult(@Context HttpHeaders headers, @Context HttpServletRequest req,
+ @QueryParam("action") String myAction) {
+ Response response = null;
+
+ AAIException ex = null;
+ String fromAppId = null;
+ String transId = null;
+
+ try {
+ fromAppId = getFromAppId(headers );
+ transId = getTransId(headers);
+ } catch (AAIException e) {
+ ArrayList<String> templateVars = new ArrayList<String>();
+ templateVars.add("PUT uebProvider");
+ templateVars.add("addTopic");
+ return Response
+ .status(e.getErrorObject().getHTTPResponseCode())
+ .entity(ErrorLogHelper.getRESTAPIErrorResponse(headers.getAcceptableMediaTypes(), e, templateVars))
+ .build();
+ }
+
+ try {
+
+ HashMap<AAIException, ArrayList<String>> exceptionList = new HashMap<AAIException, ArrayList<String>>();
+
+ ArrayList<String> templateVars = new ArrayList<String>();
+ templateVars.add(fromAppId);
+ templateVars.add(transId);
+
+ exceptionList.put(new AAIException("AAI_0002", "OK"), templateVars);
+
+ response = Response.status(Status.OK)
+ .entity(ErrorLogHelper.getRESTAPIInfoResponse(
+ headers.getAcceptableMediaTypes(), exceptionList))
+ .build();
+
+ } catch (Exception e) {
+ ex = new AAIException("AAI_4000", e);
+ ArrayList<String> templateVars = new ArrayList<String>();
+ templateVars.add(Action.GET.name());
+ templateVars.add(fromAppId +" "+transId);
+
+ response = Response
+ .status(Status.INTERNAL_SERVER_ERROR)
+ .entity(ErrorLogHelper.getRESTAPIErrorResponse(
+ headers.getAcceptableMediaTypes(), ex,
+ templateVars)).build();
+
+ } finally {
+ if (ex != null) {
+ ErrorLogHelper.logException(ex);
+ }
+
+ }
+
+ return response;
+ }
+
+}
diff --git a/aai-resources/src/main/java/org/onap/aai/rest/util/LogFormatTools.java b/aai-resources/src/main/java/org/onap/aai/rest/util/LogFormatTools.java
new file mode 100644
index 0000000..cfda0c3
--- /dev/null
+++ b/aai-resources/src/main/java/org/onap/aai/rest/util/LogFormatTools.java
@@ -0,0 +1,37 @@
+/**
+ * ============LICENSE_START=======================================================
+ * org.onap.aai
+ * ================================================================================
+ * Copyright © 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END=========================================================
+ *
+ * ECOMP is a trademark and service mark of AT&T Intellectual Property.
+ */
+package org.onap.aai.rest.util;
+
+import java.time.ZoneOffset;
+import java.time.ZonedDateTime;
+import java.time.format.DateTimeFormatter;
+
+public class LogFormatTools {
+
+ private static final String DATE_FORMAT = "yyyy-MM-dd'T'HH:mm:ss.SSSZ";
+ private static final DateTimeFormatter DTF = DateTimeFormatter.ofPattern(DATE_FORMAT)
+ .withZone(ZoneOffset.UTC);
+
+ public static String getCurrentDateTime() {
+ return DTF.format(ZonedDateTime.now());
+ }
+}
diff --git a/aai-resources/src/main/java/org/onap/aai/rest/util/ValidateEncoding.java b/aai-resources/src/main/java/org/onap/aai/rest/util/ValidateEncoding.java
new file mode 100644
index 0000000..7d4b314
--- /dev/null
+++ b/aai-resources/src/main/java/org/onap/aai/rest/util/ValidateEncoding.java
@@ -0,0 +1,161 @@
+/**
+ * ============LICENSE_START=======================================================
+ * org.onap.aai
+ * ================================================================================
+ * Copyright © 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END=========================================================
+ *
+ * ECOMP is a trademark and service mark of AT&T Intellectual Property.
+ */
+package org.onap.aai.rest.util;
+
+import java.io.UnsupportedEncodingException;
+import java.net.URI;
+
+import javax.ws.rs.core.MultivaluedMap;
+import javax.ws.rs.core.UriInfo;
+
+import org.springframework.web.util.UriUtils;
+
+/**
+ * The Class ValidateEncoding.
+ */
+public class ValidateEncoding {
+
+ private final String encoding = "UTF-8";
+
+ /**
+ * Instantiates a new validate encoding.
+ */
+ private ValidateEncoding() {
+
+ }
+
+ /**
+ * The Class Helper.
+ */
+ private static class Helper {
+
+ /** The Constant INSTANCE. */
+ private static final ValidateEncoding INSTANCE = new ValidateEncoding();
+ }
+
+ /**
+ * Gets the single instance of ValidateEncoding.
+ *
+ * @return single instance of ValidateEncoding
+ */
+ public static ValidateEncoding getInstance() {
+ return Helper.INSTANCE;
+ }
+
+ /**
+ * Validate.
+ *
+ * @param uri the uri
+ * @return true, if successful
+ * @throws UnsupportedEncodingException the unsupported encoding exception
+ */
+ public boolean validate(URI uri) throws UnsupportedEncodingException {
+ boolean result = true;
+ if (!validatePath(uri.getRawPath())) {
+ result = false;
+ }
+ /*if (!validateQueryParams(uri.getRawQuery())) {
+ result = false;
+ } //TODO
+ */
+
+ return result;
+ }
+
+ /**
+ * Validate.
+ *
+ * @param info the info
+ * @return true, if successful
+ * @throws UnsupportedEncodingException the unsupported encoding exception
+ */
+ public boolean validate(UriInfo info) throws UnsupportedEncodingException {
+ boolean result = true;
+ if (!validatePath(info.getPath(false))) {
+ result = false;
+ }
+ if (!validateQueryParams(info.getQueryParameters(false))) {
+ result = false;
+ }
+
+ return result;
+ }
+
+ /**
+ * Validate path.
+ *
+ * @param path the path
+ * @return true, if successful
+ * @throws UnsupportedEncodingException the unsupported encoding exception
+ */
+ private boolean validatePath(String path) throws UnsupportedEncodingException {
+ String[] segments = path.split("/");
+ boolean valid = true;
+ for (String segment : segments) {
+ if (!this.checkEncoding(segment)) {
+ valid = false;
+ }
+ }
+
+ return valid;
+
+ }
+
+ /**
+ * Validate query params.
+ *
+ * @param params the params
+ * @return true, if successful
+ * @throws UnsupportedEncodingException the unsupported encoding exception
+ */
+ private boolean validateQueryParams(MultivaluedMap<String, String> params) throws UnsupportedEncodingException {
+ boolean valid = true;
+
+ for (String key : params.keySet()) {
+ if (!this.checkEncoding(key)) {
+ valid = false;
+ }
+ for (String item : params.get(key)) {
+ if (!this.checkEncoding(item)) {
+ valid = false;
+ }
+ }
+ }
+ return valid;
+ }
+
+ /**
+ * Check encoding.
+ *
+ * @param segment the segment
+ * @return true, if successful
+ * @throws UnsupportedEncodingException the unsupported encoding exception
+ */
+ private boolean checkEncoding(String segment) throws UnsupportedEncodingException {
+ boolean result = false;
+ String decode = UriUtils.decode(segment, encoding);
+ String encode = UriUtils.encode(decode, encoding);
+ result = segment.equals(encode);
+
+ return result;
+ }
+}
diff --git a/aai-resources/src/main/java/org/onap/aai/transforms/Converter.java b/aai-resources/src/main/java/org/onap/aai/transforms/Converter.java
new file mode 100644
index 0000000..cb7525f
--- /dev/null
+++ b/aai-resources/src/main/java/org/onap/aai/transforms/Converter.java
@@ -0,0 +1,26 @@
+/**
+ * ============LICENSE_START=======================================================
+ * org.onap.aai
+ * ================================================================================
+ * Copyright © 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END=========================================================
+ *
+ * ECOMP is a trademark and service mark of AT&T Intellectual Property.
+ */
+package org.onap.aai.transforms;
+
+public interface Converter {
+ String convert(String input);
+}
diff --git a/aai-resources/src/main/java/org/onap/aai/transforms/LowerCamelToLowerHyphenConverter.java b/aai-resources/src/main/java/org/onap/aai/transforms/LowerCamelToLowerHyphenConverter.java
new file mode 100644
index 0000000..df9ccc5
--- /dev/null
+++ b/aai-resources/src/main/java/org/onap/aai/transforms/LowerCamelToLowerHyphenConverter.java
@@ -0,0 +1,35 @@
+/**
+ * ============LICENSE_START=======================================================
+ * org.onap.aai
+ * ================================================================================
+ * Copyright © 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END=========================================================
+ *
+ * ECOMP is a trademark and service mark of AT&T Intellectual Property.
+ */
+package org.onap.aai.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-resources/src/main/java/org/onap/aai/transforms/LowerHyphenToLowerCamelConverter.java b/aai-resources/src/main/java/org/onap/aai/transforms/LowerHyphenToLowerCamelConverter.java
new file mode 100644
index 0000000..e983dfb
--- /dev/null
+++ b/aai-resources/src/main/java/org/onap/aai/transforms/LowerHyphenToLowerCamelConverter.java
@@ -0,0 +1,82 @@
+/**
+ * ============LICENSE_START=======================================================
+ * org.onap.aai
+ * ================================================================================
+ * Copyright © 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END=========================================================
+ *
+ * ECOMP is a trademark and service mark of AT&T Intellectual Property.
+ */
+package org.onap.aai.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-resources/src/main/java/org/onap/aai/transforms/MapTraverser.java b/aai-resources/src/main/java/org/onap/aai/transforms/MapTraverser.java
new file mode 100644
index 0000000..983602e
--- /dev/null
+++ b/aai-resources/src/main/java/org/onap/aai/transforms/MapTraverser.java
@@ -0,0 +1,88 @@
+/**
+ * ============LICENSE_START=======================================================
+ * org.onap.aai
+ * ================================================================================
+ * Copyright © 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END=========================================================
+ *
+ * ECOMP is a trademark and service mark of AT&T Intellectual Property.
+ */
+package org.onap.aai.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-resources/src/main/java/org/onap/aai/util/AAIAppServletContextListener.java b/aai-resources/src/main/java/org/onap/aai/util/AAIAppServletContextListener.java
new file mode 100644
index 0000000..58dc29b
--- /dev/null
+++ b/aai-resources/src/main/java/org/onap/aai/util/AAIAppServletContextListener.java
@@ -0,0 +1,94 @@
+/**
+ * ============LICENSE_START=======================================================
+ * org.onap.aai
+ * ================================================================================
+ * Copyright © 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END=========================================================
+ *
+ * ECOMP is a trademark and service mark of AT&T Intellectual Property.
+ */
+package org.onap.aai.util;
+
+import java.io.IOException;
+
+import javax.servlet.ServletContextEvent;
+import javax.servlet.ServletContextListener;
+
+import org.onap.aai.dbmap.AAIGraph;
+import org.onap.aai.exceptions.AAIException;
+import org.onap.aai.introspection.ModelInjestor;
+import org.onap.aai.logging.ErrorLogHelper;
+import org.onap.aai.migration.MigrationControllerInternal;
+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());
+
+ /**
+ * Destroys Context
+ *
+ * @param arg0 the ServletContextEvent
+ */
+ public void contextDestroyed(ServletContextEvent arg0) {
+ LOGGER.info("AAIGraph shutting down");
+ AAIGraph.getInstance().graphShutdown();
+ LOGGER.info("AAIGraph shutdown");
+ }
+
+ /**
+ * Initializes Context
+ *
+ * @param arg0 the ServletContextEvent
+ */
+ public void contextInitialized(ServletContextEvent arg0) {
+ System.setProperty("org.onap.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();
+
+ LOGGER.info("A&AI Server initialization succcessful.");
+ System.setProperty("org.onap.aai.serverStarted", "true");
+ if ("true".equals(AAIConfig.get("aai.run.migrations", "false"))) {
+ MigrationControllerInternal migrations = new MigrationControllerInternal();
+ migrations.run(new String[]{"--commit"});
+ }
+ } 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);
+ }
+
+ LOGGER.info("Resources MicroService Started");
+ LOGGER.error("Resources MicroService Started");
+ LOGGER.debug("Resources MicroService Started");
+ }
+}
diff --git a/aai-resources/src/main/java/org/onap/aai/util/DataConversionHelper.java b/aai-resources/src/main/java/org/onap/aai/util/DataConversionHelper.java
new file mode 100644
index 0000000..3094889
--- /dev/null
+++ b/aai-resources/src/main/java/org/onap/aai/util/DataConversionHelper.java
@@ -0,0 +1,64 @@
+/**
+ * ============LICENSE_START=======================================================
+ * org.onap.aai
+ * ================================================================================
+ * Copyright © 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END=========================================================
+ *
+ * ECOMP is a trademark and service mark of AT&T Intellectual Property.
+ */
+package org.onap.aai.util;
+
+
+/**
+ * Utility to convert data from one form to another
+ *
+ */
+public class DataConversionHelper {
+
+ public static final String IPVERSION_IPV4 = "ipv4";
+ public static final String IPVERSION_IPV6 = "ipv6";
+ public static final String IPVERSION_UNKNOWN = "unknown";
+
+ /**
+ * Instantiates a new data conversion helper.
+ */
+ public DataConversionHelper() { }
+
+ /**
+ * Convert from 4 or 6 to ipv4 or ipv6. Returns unknown if 4 or 6 not passed.
+ * @param numVal expects good input but won't error if that's not what's passed
+ * @return IPVERSION constant, .
+ * @see org.onap.aai.domain.yang.IpVersion
+ */
+ public static String convertIPVersionNumToString(String numVal) {
+ if ("4".equals(numVal)) return IPVERSION_IPV4;
+ else if ("6".equals(numVal))return IPVERSION_IPV6;
+ else return IPVERSION_UNKNOWN;
+ }
+
+ /**
+ * Convert from ipv4 or ipv6 to 4 or 6. Returns 0 on bad input.
+ * @param stringVal expects good input but won't error if that's not what's passed
+ * @return 4 or 6, or 0 if a bad string is sent.
+ * @see org.onap.aai.domain.yang.IpVersion
+ */
+ public static String convertIPVersionStringToNum(String stringVal) {
+ if (IPVERSION_IPV4.equals(stringVal)) return "4";
+ else if (IPVERSION_IPV6.equals(stringVal)) return "6";
+ else return "0";
+ }
+
+}
diff --git a/aai-resources/src/main/java/org/onap/aai/util/JettyObfuscationConversionCommandLineUtil.java b/aai-resources/src/main/java/org/onap/aai/util/JettyObfuscationConversionCommandLineUtil.java
new file mode 100644
index 0000000..4903640
--- /dev/null
+++ b/aai-resources/src/main/java/org/onap/aai/util/JettyObfuscationConversionCommandLineUtil.java
@@ -0,0 +1,100 @@
+/**
+ * ============LICENSE_START=======================================================
+ * org.onap.aai
+ * ================================================================================
+ * Copyright © 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END=========================================================
+ *
+ * ECOMP is a trademark and service mark of AT&T Intellectual Property.
+ */
+package org.onap.aai.util;
+
+import org.apache.commons.cli.BasicParser;
+import org.apache.commons.cli.CommandLine;
+import org.apache.commons.cli.CommandLineParser;
+import org.apache.commons.cli.Options;
+import org.apache.commons.cli.ParseException;
+import org.eclipse.jetty.util.security.Password;
+
+import org.onap.aai.exceptions.AAIException;
+
+/*
+ * The purpose of this class is to be a tool for
+ * manually applying jetty obfuscation/deobfuscation
+ * so that one can obfuscate the various passwords/secrets
+ * in aaiconfig.properties.
+ *
+ * Originally, they were being encrypted by a similar
+ * command line utility, however the encryption key
+ * was being hardcoded in the src package
+ * which is a security violation.
+ * Since this ultimately just moved the problem of how
+ * to hide secrets to a different secret in a different file,
+ * and since that encryption was really just being done to
+ * obfuscate those values in case someone needed to look at
+ * properties with others looking at their screen,
+ * we decided that jetty obfuscation would be adequate
+ * for that task as well as
+ * removing the "turtles all the way down" secret-to-hide-
+ * the-secret-to-hide-the-secret problem.
+ */
+public class JettyObfuscationConversionCommandLineUtil {
+
+ /**
+ * The main method.
+ *
+ * @param args the arguments
+ */
+ public static void main(String[] args){
+ Options options = new Options();
+ options.addOption("e", true, "obfuscate the given string");
+ options.addOption("d", true, "deobfuscate the given string");
+
+ CommandLineParser parser = new BasicParser();
+
+ try {
+ CommandLine cmd = parser.parse(options, args);
+ String toProcess = null;
+
+ if (cmd.hasOption("e")){
+ toProcess = cmd.getOptionValue("e");
+ String encoded = Password.obfuscate(toProcess);
+ System.out.println(encoded);
+ } else if (cmd.hasOption("d")) {
+ toProcess = cmd.getOptionValue("d");
+ String decoded_str = Password.deobfuscate(toProcess);
+ System.out.println(decoded_str);
+ } else {
+ usage();
+ }
+ } catch (ParseException e) {
+ System.out.println("failed to parse input");
+ System.out.println(e.toString());
+ usage();
+ } catch (Exception e) {
+ System.out.println("exception:" + e.toString());
+ }
+ }
+
+ /**
+ * Usage.
+ */
+ private static void usage(){
+ System.out.println("usage:");;
+ System.out.println("-e [string] to obfuscate");
+ System.out.println("-d [string] to deobfuscate");
+ System.out.println("-h help");
+ }
+}