diff options
author | Venkata Harish K Kajur <vk250x@att.com> | 2017-05-12 17:28:40 -0400 |
---|---|---|
committer | Venkata Harish K Kajur <vk250x@att.com> | 2017-05-12 17:30:49 -0400 |
commit | c0e8c47e202ef604b449e72556c8757764744f7d (patch) | |
tree | 9c67ffb0bf962850999e42cae909a31b2b725c7d /aai-resources/src/main/java/org | |
parent | 2801d04f58b28ed4bc94cd1263bad7b6784c895e (diff) |
Add all of the resources repo
Change-Id: If2a9c584621f6d01eb70e9c51e05e054ef3486c4
Signed-off-by: Venkata Harish K Kajur <vk250x@att.com>
Diffstat (limited to 'aai-resources/src/main/java/org')
41 files changed, 6851 insertions, 0 deletions
diff --git a/aai-resources/src/main/java/org/openecomp/aai/ajsc_aai/JaxrsErrorMessageLookupService.java b/aai-resources/src/main/java/org/openecomp/aai/ajsc_aai/JaxrsErrorMessageLookupService.java new file mode 100644 index 0000000..30dfced --- /dev/null +++ b/aai-resources/src/main/java/org/openecomp/aai/ajsc_aai/JaxrsErrorMessageLookupService.java @@ -0,0 +1,98 @@ +/*- + * ============LICENSE_START======================================================= + * org.openecomp.aai + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.aai.ajsc_aai; + +//import java.util.HashMap; +//import java.util.Map; + +//import javax.ws.rs.GET; +//import javax.ws.rs.HeaderParam; +//import javax.ws.rs.Path; +//import javax.ws.rs.PathParam; +//import javax.ws.rs.Produces; + +//import org.slf4j.Logger; +//import org.slf4j.LoggerFactory; +//import org.springframework.web.context.ContextLoader; +//import org.springframework.web.context.WebApplicationContext; + +//import ajsc.ErrorMessageLookupService; + +//@Path("/errormessage") +//public class JaxrsErrorMessageLookupService { + + //private final static Logger logger = LoggerFactory + //.getLogger(ErrorMessageLookupService.class); + + /** + * Gets the message. + * + * @param input the input + * @param errorCode the error code + * @param appId the app id + * @param operation the operation + * @param messageText the message text + * @param isRESTService the is REST service + * @param faultEntity the fault entity + * @param ConvID the conv ID + * @return the message + */ + //@GET + //@Path("/emls") + //@Produces("text/plain") + //public String getMessage(@PathParam("input") String input, + //@HeaderParam("errorCode") String errorCode, + //@HeaderParam("appId") String appId, + //@HeaderParam("operation") String operation, + //@HeaderParam("messageText") String messageText, + //@HeaderParam("isRESTService") String isRESTService, + //@HeaderParam("faultEntity") String faultEntity, + //@HeaderParam("ConvID") String ConvID) { + + //Map<String, String> headers = new HashMap<String, String>(); + //headers.put(errorCode, errorCode); + //headers.put(appId, appId); + //headers.put(operation, operation); + //headers.put(messageText, messageText); + //headers.put(isRESTService, isRESTService); + //headers.put(faultEntity, faultEntity); + //headers.put(ConvID, ConvID); + + //WebApplicationContext applicationContext = ContextLoader + //.getCurrentWebApplicationContext(); + + //ErrorMessageLookupService e = (ErrorMessageLookupService) applicationContext + //.getBean("errorMessageLookupService"); + + //String message = e.getExceptionDetails(appId, operation, errorCode, + //messageText,isRESTService, faultEntity, ConvID); + + //System.out.println("Error code = " + errorCode); + //System.out.println("appId = " + appId); + //System.out.println("operation = " + operation); + //System.out.println("messageText = " + messageText); + //System.out.println("isRESTService = " + isRESTService); + //System.out.println("faultEntity = " + faultEntity); + //System.out.println("ConvID = " + ConvID); + //return "The exception message is:\n " + message; + //} + +//} diff --git a/aai-resources/src/main/java/org/openecomp/aai/ajsc_aai/JaxrsUserService.java b/aai-resources/src/main/java/org/openecomp/aai/ajsc_aai/JaxrsUserService.java new file mode 100644 index 0000000..39c78f6 --- /dev/null +++ b/aai-resources/src/main/java/org/openecomp/aai/ajsc_aai/JaxrsUserService.java @@ -0,0 +1,54 @@ +/*- + * ============LICENSE_START======================================================= + * org.openecomp.aai + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.aai.ajsc_aai; + +import javax.ws.rs.GET; +import javax.ws.rs.Path; +import javax.ws.rs.PathParam; +import javax.ws.rs.Produces; +import java.util.Map; +import java.util.HashMap; + +@Path("/user") +public class JaxrsUserService { + + private static final Map<String,String> userIdToNameMap; + static { + userIdToNameMap = new HashMap<String,String>(); + userIdToNameMap.put("userID1","Name1"); + userIdToNameMap.put("userID2","Name2"); + } + + /** + * Lookup user. + * + * @param userId the user id + * @return the string + */ + @GET + @Path("/{userId}") + @Produces("text/plain") + public String lookupUser(@PathParam("userId") String userId) { + String name = userIdToNameMap.get(userId); + return name != null ? name : "unknown id"; + } + +} diff --git a/aai-resources/src/main/java/org/openecomp/aai/ajsc_aai/filemonitor/ServicePropertiesListener.java b/aai-resources/src/main/java/org/openecomp/aai/ajsc_aai/filemonitor/ServicePropertiesListener.java new file mode 100644 index 0000000..1520722 --- /dev/null +++ b/aai-resources/src/main/java/org/openecomp/aai/ajsc_aai/filemonitor/ServicePropertiesListener.java @@ -0,0 +1,37 @@ +/*- + * ============LICENSE_START======================================================= + * org.openecomp.aai + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.aai.ajsc_aai.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/openecomp/aai/ajsc_aai/filemonitor/ServicePropertiesMap.java b/aai-resources/src/main/java/org/openecomp/aai/ajsc_aai/filemonitor/ServicePropertiesMap.java new file mode 100644 index 0000000..656b290 --- /dev/null +++ b/aai-resources/src/main/java/org/openecomp/aai/ajsc_aai/filemonitor/ServicePropertiesMap.java @@ -0,0 +1,126 @@ +/*- + * ============LICENSE_START======================================================= + * org.openecomp.aai + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.aai.ajsc_aai.filemonitor; + +import java.io.File; +import java.io.FileInputStream; +import java.util.HashMap; +import java.util.Map; +import java.util.Properties; + +import com.att.eelf.configuration.EELFLogger; +import com.att.eelf.configuration.EELFManager; +import com.fasterxml.jackson.core.type.TypeReference; +import com.fasterxml.jackson.databind.ObjectMapper; + +public class ServicePropertiesMap +{ + private static HashMap<String, HashMap<String, String>> mapOfMaps = new HashMap<String, HashMap<String, String>>(); + private static final EELFLogger LOGGER = EELFManager.getInstance().getLogger(ServicePropertiesMap.class); + + /** + * Refresh. + * + * @param file the file + * @throws Exception the exception + */ + public static void refresh(File file) throws Exception + { + try + { + LOGGER.info("Loading properties - " + (file != null?file.getName():"")); + + //Store .json & .properties files into map of maps + String filePath = file.getPath(); + + if(filePath.lastIndexOf(".json")>0){ + + ObjectMapper om = new ObjectMapper(); + TypeReference<HashMap<String, String>> typeRef = new TypeReference<HashMap<String, String>>() {}; + HashMap<String, String> propMap = om.readValue(file, typeRef); + HashMap<String, String> lcasePropMap = new HashMap<String, String>(); + for (String key : propMap.keySet() ) + { + String lcaseKey = ifNullThenEmpty(key); + lcasePropMap.put(lcaseKey, propMap.get(key)); + } + + mapOfMaps.put(file.getName(), lcasePropMap); + + + }else if(filePath.lastIndexOf(".properties")>0){ + Properties prop = new Properties(); + FileInputStream fis = new FileInputStream(file); + prop.load(fis); + + @SuppressWarnings("unchecked") + HashMap<String, String> propMap = new HashMap<String, String>((Map)prop); + + mapOfMaps.put(file.getName(), propMap); + } + + LOGGER.info("File - " + file.getName() + " is loaded into the map and the corresponding system properties have been refreshed"); + } + catch (Exception e) + { + LOGGER.error("File " + (file != null?file.getName():"") + " cannot be loaded into the map ", e); + throw new Exception("Error reading map file " + (file != null?file.getName():""), e); + } + } + + /** + * Gets the property. + * + * @param fileName the file name + * @param propertyKey the property key + * @return the property + */ + public static String getProperty(String fileName, String propertyKey) + { + HashMap<String, String> propMap = mapOfMaps.get(fileName); + return propMap!=null?propMap.get(ifNullThenEmpty(propertyKey)):""; + } + + /** + * Gets the properties. + * + * @param fileName the file name + * @return the properties + */ + public static HashMap<String, String> getProperties(String fileName){ + return mapOfMaps.get(fileName); + } + + /** + * If null then empty. + * + * @param key the key + * @return the string + */ + private static String ifNullThenEmpty(String key) { + if (key == null) { + return ""; + } else { + return key; + } + } + +} diff --git a/aai-resources/src/main/java/org/openecomp/aai/ajsc_aai/filemonitor/ServicePropertyService.java b/aai-resources/src/main/java/org/openecomp/aai/ajsc_aai/filemonitor/ServicePropertyService.java new file mode 100644 index 0000000..98426ad --- /dev/null +++ b/aai-resources/src/main/java/org/openecomp/aai/ajsc_aai/filemonitor/ServicePropertyService.java @@ -0,0 +1,218 @@ +/*- + * ============LICENSE_START======================================================= + * org.openecomp.aai + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.aai.ajsc_aai.filemonitor; + +//import java.io.File; +//import java.io.FileInputStream; +//import java.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/openecomp/aai/ajsc_aai/util/ServicePropertiesMapBean.java b/aai-resources/src/main/java/org/openecomp/aai/ajsc_aai/util/ServicePropertiesMapBean.java new file mode 100644 index 0000000..7577de7 --- /dev/null +++ b/aai-resources/src/main/java/org/openecomp/aai/ajsc_aai/util/ServicePropertiesMapBean.java @@ -0,0 +1,37 @@ +/*- + * ============LICENSE_START======================================================= + * org.openecomp.aai + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.aai.ajsc_aai.util; + +import org.openecomp.aai.ajsc_aai.filemonitor.ServicePropertiesMap; + +public class ServicePropertiesMapBean { + + /** + * Gets the property. + * + * @param propFileName the prop file name + * @param propertyKey the property key + * @return the property + */ + public static String getProperty(String propFileName, String propertyKey) { + return ServicePropertiesMap.getProperty(propFileName, propertyKey); + } +} diff --git a/aai-resources/src/main/java/org/openecomp/aai/db/schema/ScriptDriver.java b/aai-resources/src/main/java/org/openecomp/aai/db/schema/ScriptDriver.java new file mode 100644 index 0000000..458c4c9 --- /dev/null +++ b/aai-resources/src/main/java/org/openecomp/aai/db/schema/ScriptDriver.java @@ -0,0 +1,95 @@ +/*- + * ============LICENSE_START======================================================= + * org.openecomp.aai + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.aai.db.schema; + +import java.io.IOException; + +import org.codehaus.jackson.JsonGenerationException; +import org.codehaus.jackson.map.JsonMappingException; +import org.codehaus.jackson.map.ObjectMapper; + +import org.openecomp.aai.exceptions.AAIException; +import org.openecomp.aai.introspection.Version; +import org.openecomp.aai.util.AAIConfig; +import com.beust.jcommander.JCommander; +import com.beust.jcommander.Parameter; +import com.thinkaurelius.titan.core.TitanFactory; +import com.thinkaurelius.titan.core.TitanGraph; + +public class ScriptDriver { + + + /** + * The main method. + * + * @param args the arguments + * @throws AAIException the AAI exception + * @throws JsonGenerationException the json generation exception + * @throws JsonMappingException the json mapping exception + * @throws IOException Signals that an I/O exception has occurred. + */ + public static void main (String[] args) throws AAIException, JsonGenerationException, JsonMappingException, IOException { + CommandLineArgs cArgs = new CommandLineArgs(); + + new JCommander(cArgs, args); + + if (cArgs.help) { + System.out.println("-c [path to graph configuration] -type [what you want to audit - oxm or graph]"); + } + String config = cArgs.config; + AAIConfig.init(); + TitanGraph graph = TitanFactory.open(config); + if (!(cArgs.type.equals("oxm") || cArgs.type.equals("graph"))) { + System.out.println("type: " + cArgs.type + " not recognized."); + System.exit(1); + } + + Auditor a = null; + if (cArgs.type.equals("oxm")) { + a = AuditorFactory.getOXMAuditor(Version.v8); + } else if (cArgs.type.equals("graph")) { + a = AuditorFactory.getGraphAuditor(graph); + } + + AuditDoc doc = a.getAuditDoc(); + + ObjectMapper mapper = new ObjectMapper(); + + String json = mapper.writerWithDefaultPrettyPrinter().writeValueAsString(doc); + System.out.println(json); + + } + +} + +class CommandLineArgs { + + @Parameter(names = "--help", description = "Help") + public boolean help = false; + + @Parameter(names = "-c", description = "Configuration", required=true) + public String config; + + @Parameter(names = "-type", description = "Type", required=true) + public String type = "graph"; + + +} diff --git a/aai-resources/src/main/java/org/openecomp/aai/dmaap/AAIDmaapEventJMSConsumer.java b/aai-resources/src/main/java/org/openecomp/aai/dmaap/AAIDmaapEventJMSConsumer.java new file mode 100644 index 0000000..fc11e5d --- /dev/null +++ b/aai-resources/src/main/java/org/openecomp/aai/dmaap/AAIDmaapEventJMSConsumer.java @@ -0,0 +1,198 @@ +/*- + * ============LICENSE_START======================================================= + * org.openecomp.aai + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.aai.dmaap; + +import java.io.File; +import java.io.FileReader; +import java.io.IOException; +import java.util.Properties; + +import javax.jms.JMSException; +import javax.jms.Message; +import javax.jms.MessageListener; +import javax.jms.TextMessage; +import javax.ws.rs.core.MediaType; + +import org.apache.log4j.MDC; +import org.eclipse.jetty.util.security.Password; +import org.json.JSONException; +import org.json.JSONObject; + +import org.openecomp.aai.logging.ErrorLogHelper; +import org.openecomp.aai.util.AAIConstants; +import com.att.eelf.configuration.EELFLogger; +import com.att.eelf.configuration.EELFManager; +//import com.att.nsa.mr.client.MRBatchingPublisher; +//import com.att.nsa.mr.client.MRClientFactory; +import com.sun.jersey.api.client.Client; +import com.sun.jersey.api.client.ClientResponse; +import com.sun.jersey.api.client.WebResource; +import com.sun.jersey.api.client.filter.HTTPBasicAuthFilter; + +public class AAIDmaapEventJMSConsumer implements MessageListener { + + private static final EELFLogger LOGGER = EELFManager.getInstance().getLogger(AAIDmaapEventJMSConsumer.class); + + private Client httpClient; + + //private MRBatchingPublisher aaiEventPublisher = null; + private Properties aaiEventProps; + private String aaiEventUrl = ""; + + //private MRBatchingPublisher aaiVceEventPublisher = null; + private Properties aaiVceEventProps; + private String aaiVceEventUrl = ""; + + public AAIDmaapEventJMSConsumer() throws org.apache.commons.configuration.ConfigurationException { + //super(); + //try { + + //if (this.aaiEventPublisher == null) { + //FileReader reader = new FileReader(new File(AAIConstants.AAI_EVENT_DMAAP_PROPS)); + //aaiEventProps = new Properties(); + //aaiEventProps.load(reader); + //reader.close(); + //aaiEventProps.setProperty("DME2preferredRouterFilePath", + //AAIConstants.AAI_HOME_ETC_APP_PROPERTIES + "preferredRoute.txt"); + //if (aaiEventProps.getProperty("password") != null + //&& aaiEventProps.getProperty("password").startsWith("OBF:")) { + //aaiEventProps.setProperty("password", Password.deobfuscate(aaiEventProps.getProperty("password"))); + //} + + //this.aaiEventPublisher = MRClientFactory.createBatchingPublisher(aaiEventProps); + + //String host = aaiEventProps.getProperty("host"); + //String topic = aaiEventProps.getProperty("topic"); + //String protocol = aaiEventProps.getProperty("Protocol"); + + //String username = aaiEventProps.getProperty("username"); + //String password = aaiEventProps.getProperty("password"); + + //aaiEventUrl = protocol + "://" + host + "/events/" + topic; + //httpClient = Client.create(); + //httpClient.addFilter(new HTTPBasicAuthFilter(username, password)); + //} + + //if (this.aaiVceEventProps == null) { + //FileReader reader = new FileReader(new File(AAIConstants.AAI_EVENT_DMAAP_PROPS)); + //aaiVceEventProps = new Properties(); + //aaiVceEventProps.load(reader); + //reader.close(); + //aaiVceEventProps.setProperty("DME2preferredRouterFilePath", + //AAIConstants.AAI_HOME_ETC_APP_PROPERTIES + "preferredRoute.txt"); + //if (aaiVceEventProps.getProperty("password") != null + //&& aaiVceEventProps.getProperty("password").startsWith("OBF:")) { + //aaiVceEventProps.setProperty("password", + //Password.deobfuscate(aaiVceEventProps.getProperty("password"))); + //} + //aaiVceEventProps.setProperty("topic", "AAI-VCE-INTERFACE-DATA"); + //this.aaiVceEventPublisher = MRClientFactory.createBatchingPublisher(aaiVceEventProps); + + //String host = aaiVceEventProps.getProperty("host"); + //String topic = aaiVceEventProps.getProperty("topic"); + //String protocol = aaiVceEventProps.getProperty("Protocol"); + + //aaiVceEventUrl = protocol + "://" + host + "/events/" + topic; + + //} + //} catch (IOException e) { + //ErrorLogHelper.logError("AAI_4000", "Error updating dmaap config file for aai event."); + //} + + } + + @Override + public void onMessage(Message message) { + + //String jsmMessageTxt = ""; + //String aaiEvent = ""; + //String eventName = ""; + + + //String environment = ""; + + //if (message instanceof TextMessage) { + //try { + //jsmMessageTxt = ((TextMessage) message).getText(); + //JSONObject jo = new JSONObject(jsmMessageTxt); + + //if (jo.has("aaiEventPayload")) { + //aaiEvent = jo.getJSONObject("aaiEventPayload").toString(); + //} else { + //return; + //} + //if (jo.getString("transId") != null) { + //MDC.put("requestId", jo.getString("transId")); + //} + //if (jo.getString("fromAppId") != null) { + //MDC.put("partnerName", jo.getString("fromAppId")); + //} + //if (jo.getString("event-topic") != null) { + //eventName = jo.getString("event-topic"); + //} + + //LOGGER.info(eventName + "|" + aaiEvent); + //if (eventName.equals("AAI-EVENT")) { + //if (!this.sentWithHttp(environment, this.httpClient, this.aaiEventUrl, aaiEvent)) { + //this.aaiEventPublisher.send(aaiEvent); + //} + //LOGGER.info(eventName + "|Event sent."); + //} else if (eventName.equals("AAI-VCE-INTERFACE-DATA")) { + //String msg = ""; + //if (!this.sentWithHttp(environment, this.httpClient, this.aaiVceEventUrl, aaiEvent)) { + //this.aaiVceEventPublisher.send(aaiEvent); + //msg = this.aaiVceEventPublisher.sendBatchWithResponse().getResponseMessage(); + //} + //LOGGER.info(eventName + "|Event sent. " + msg); + //} else { + //LOGGER.error(eventName + "|Event Topic invalid."); + //} + //} catch (java.net.SocketException e) { + //if (!e.getMessage().contains("Connection reset")) { + //LOGGER.error("AAI_7304 Error reaching DMaaP to send event. " + aaiEvent, e); + //} + //} catch (IOException e) { + //LOGGER.error("AAI_7304 Error reaching DMaaP to send event. " + aaiEvent, e); + //} catch (JMSException | JSONException e) { + //LOGGER.error("AAI_7350 Error parsing aaievent jsm message for sending to dmaap. " + jsmMessageTxt, e); + //} catch (Exception e) { + //LOGGER.error("AAI_7350 Error sending message to dmaap. " + jsmMessageTxt, e); + //} + //} + + } + + private boolean sentWithHttp(String environment, Client client, String url, String aaiEvent) throws IOException { + //if (environment.startsWith("dev") || environment.startsWith("testINT") || environment.startsWith("testEXT")) { + + //WebResource webResource = client.resource(url); + //ClientResponse response = webResource.accept(MediaType.APPLICATION_JSON).type(MediaType.APPLICATION_JSON) + //.post(ClientResponse.class, aaiEvent); + //if (response.getStatus() != 200) { + //LOGGER.info("Failed : HTTP error code : " + response.getStatus()); + //return false; + //} + //} else { + //return false; + //} + return true; + } +} diff --git a/aai-resources/src/main/java/org/openecomp/aai/dmaap/AAIDmaapEventJMSProducer.java b/aai-resources/src/main/java/org/openecomp/aai/dmaap/AAIDmaapEventJMSProducer.java new file mode 100644 index 0000000..eef852a --- /dev/null +++ b/aai-resources/src/main/java/org/openecomp/aai/dmaap/AAIDmaapEventJMSProducer.java @@ -0,0 +1,44 @@ +/*- + * ============LICENSE_START======================================================= + * org.openecomp.aai + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.aai.dmaap; + +import org.apache.activemq.ActiveMQConnectionFactory; +import org.apache.activemq.command.ActiveMQQueue; +import org.json.JSONObject; +import org.springframework.jms.connection.CachingConnectionFactory; +import org.springframework.jms.core.JmsTemplate; + +public class AAIDmaapEventJMSProducer { + + private JmsTemplate jmsTemplate; + + public AAIDmaapEventJMSProducer() { + //this.jmsTemplate = new JmsTemplate(); + //this.jmsTemplate.setConnectionFactory(new CachingConnectionFactory(new ActiveMQConnectionFactory("tcp://localhost:61447"))); + //this.jmsTemplate.setDefaultDestination(new ActiveMQQueue("IN_QUEUE")); + } + + public void sendMessageToDefaultDestination(JSONObject finalJson) { + //jmsTemplate.convertAndSend(finalJson.toString()); + //CachingConnectionFactory ccf = (CachingConnectionFactory)this.jmsTemplate.getConnectionFactory(); + //ccf.destroy(); + } +} diff --git a/aai-resources/src/main/java/org/openecomp/aai/interceptors/AAIHeaderProperties.java b/aai-resources/src/main/java/org/openecomp/aai/interceptors/AAIHeaderProperties.java new file mode 100644 index 0000000..4798d90 --- /dev/null +++ b/aai-resources/src/main/java/org/openecomp/aai/interceptors/AAIHeaderProperties.java @@ -0,0 +1,26 @@ +/*- + * ============LICENSE_START======================================================= + * org.openecomp.aai + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.aai.interceptors; + +public class AAIHeaderProperties { + + public static final String REQUEST_CONTEXT = "aai-request-context"; +} diff --git a/aai-resources/src/main/java/org/openecomp/aai/interceptors/AAILogJAXRSInInterceptor.java b/aai-resources/src/main/java/org/openecomp/aai/interceptors/AAILogJAXRSInInterceptor.java new file mode 100644 index 0000000..80127d0 --- /dev/null +++ b/aai-resources/src/main/java/org/openecomp/aai/interceptors/AAILogJAXRSInInterceptor.java @@ -0,0 +1,283 @@ +/*- + * ============LICENSE_START======================================================= + * org.openecomp.aai + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.aai.interceptors; + +import java.io.InputStream; +import java.text.DateFormat; +import java.text.SimpleDateFormat; +import java.util.ArrayList; +import java.util.Collections; +import java.util.Date; +import java.util.List; +import java.util.Map; +import java.util.UUID; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import javax.ws.rs.core.MediaType; + +import org.apache.commons.io.IOUtils; +import org.apache.cxf.helpers.CastUtils; +import org.apache.cxf.interceptor.LoggingMessage; +import org.apache.cxf.jaxrs.interceptor.JAXRSInInterceptor; +import org.apache.cxf.message.Message; + +import org.openecomp.aai.exceptions.AAIException; +import org.openecomp.aai.logging.ErrorLogHelper; +import org.openecomp.aai.rest.util.EchoResponse; +import org.openecomp.aai.util.AAIConfig; +import org.openecomp.aai.util.AAIConstants; +import org.openecomp.aai.util.HbaseSaltPrefixer; +import com.att.eelf.configuration.EELFLogger; +import com.att.eelf.configuration.EELFManager; + +public class AAILogJAXRSInInterceptor extends JAXRSInInterceptor { + + protected final String COMPONENT = "aairest"; + protected final String CAMEL_REQUEST ="CamelHttpUrl"; + private static final Pattern uuidPattern = Pattern.compile("^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$"); + private static final EELFLogger LOGGER = EELFManager.getInstance().getLogger(AAILogJAXRSInInterceptor.class); + + /** + * {@inheritDoc} + */ + public void handleMessage(Message message) { + + boolean go = false; + String uri = null; + String query = null; + try { + + uri = (String)message.get(CAMEL_REQUEST); + if (uri != null) { + query = (String)message.get(Message.QUERY_STRING); + } + + if (AAIConfig.get(AAIConstants.AAI_LOGGING_HBASE_INTERCEPTOR).equalsIgnoreCase("true") && + AAIConfig.get(AAIConstants.AAI_LOGGING_HBASE_ENABLED).equalsIgnoreCase("true")) { + go = true; + message.getExchange().put("AAI_LOGGING_HBASE_ENABLED", 1); + if (AAIConfig.get(AAIConstants.AAI_LOGGING_HBASE_LOGREQUEST).equalsIgnoreCase("true") ) { + message.getExchange().put("AAI_LOGGING_HBASE_LOGREQUEST", 1); + } + if (AAIConfig.get(AAIConstants.AAI_LOGGING_HBASE_LOGRESPONSE).equalsIgnoreCase("true") ) { + message.getExchange().put("AAI_LOGGING_HBASE_LOGRESPONSE", 1); + } + } + if (AAIConfig.get(AAIConstants.AAI_LOGGING_TRACE_ENABLED).equalsIgnoreCase("true") ) { + go = true; + message.getExchange().put("AAI_LOGGING_TRACE_ENABLED", 1); + if (AAIConfig.get(AAIConstants.AAI_LOGGING_TRACE_LOGREQUEST).equalsIgnoreCase("true") ) { + message.getExchange().put("AAI_LOGGING_TRACE_LOGREQUEST", 1); + } + if (AAIConfig.get(AAIConstants.AAI_LOGGING_TRACE_LOGRESPONSE).equalsIgnoreCase("true") ) { + message.getExchange().put("AAI_LOGGING_TRACE_LOGRESPONSE", 1); + } + } + } catch (AAIException e1) { + ErrorLogHelper.logException(e1); + } + + if (uri.contains(EchoResponse.echoPath)) { + // if it's a health check, we don't want to log ANYTHING if it's a lightweight one + if (query == null) { + if (message.getExchange().containsKey("AAI_LOGGING_HBASE_ENABLED")) { + message.getExchange().remove("AAI_LOGGING_HBASE_ENABLED"); + } + if (message.getExchange().containsKey("AAI_LOGGING_TRACE_ENABLED")) { + message.getExchange().remove("AAI_LOGGING_TRACE_ENABLED"); + } + go = false; + } + } + else if (uri.contains("/translog/")) { + // if it's a translog query, we don't want to log the responses + if (message.getExchange().containsKey("AAI_LOGGING_HBASE_LOGRESPONSE")) { + message.getExchange().remove("AAI_LOGGING_HBASE_LOGRESPONSE"); + } + if (message.getExchange().containsKey("AAI_LOGGING_TRACE_LOGRESPONSE")) { + message.getExchange().remove("AAI_LOGGING_TRACE_LOGRESPONSE"); + } + } + + if (go == false) { // there's nothing to do + return; + } + + // DONE: get a TXID based on hostname, time (YYYYMMDDHHMMSSMILLIS, and LoggingMessage.nextId(); 20150326145301-1 + String now = genDate(); + + message.getExchange().put("AAI_RQST_TM", now); + + String id = (String)message.getExchange().get(LoggingMessage.ID_KEY); + + String fullId = null; + try { + if (id == null) { + id = LoggingMessage.nextId(); + } + fullId = AAIConfig.get(AAIConstants.AAI_NODENAME) + "-" + now + "-" + id; + fullId = HbaseSaltPrefixer.getInstance().prependSalt(fullId); + message.getExchange().put(LoggingMessage.ID_KEY, fullId); + } catch (AAIException e1) { + LOGGER.debug("config problem", e1); + } + + if (fullId == null) { + fullId = now + "-" + id; + fullId = HbaseSaltPrefixer.getInstance().prependSalt(fullId); + } + message.put(LoggingMessage.ID_KEY, fullId); + final LoggingMessage buffer = new LoggingMessage("Message", fullId); + + Integer responseCode = (Integer)message.get(Message.RESPONSE_CODE); + if (responseCode != null) { + buffer.getResponseCode().append(responseCode); + } + + String encoding = (String)message.get(Message.ENCODING); + + if (encoding != null) { + buffer.getEncoding().append(encoding); + } + String httpMethod = (String)message.get(Message.HTTP_REQUEST_METHOD); + if (httpMethod != null) { + buffer.getHttpMethod().append(httpMethod); + } + + String ct = (String)message.get(Message.CONTENT_TYPE); + if (ct != null) { + if ("*/*".equals(ct)) { + message.put(Message.CONTENT_TYPE, MediaType.APPLICATION_JSON); + ct = MediaType.APPLICATION_JSON; + } + buffer.getContentType().append(ct); + + } + Object headers = message.get(Message.PROTOCOL_HEADERS); + if (headers != null) { + buffer.getHeader().append(headers); + + Map<String, List<String>> headersList = CastUtils.cast((Map<?, ?>)message.get(Message.PROTOCOL_HEADERS)); + String transId = ""; + List<String> xt = headersList.get("X-TransactionId"); + String newTransId = transId; + boolean missingTransId = false; + boolean replacedTransId = false; + String logMsg = null; + if (xt != null) { + for (String transIdValue : xt) { + transId = transIdValue; + } + Matcher matcher = uuidPattern.matcher(transId); + if (!matcher.find()) { + replacedTransId = true; + // check if there's a colon, and check the first group? + if (transId.contains(":")) { + String[] uuidParts = transId.split(":"); + Matcher matcher2 = uuidPattern.matcher(uuidParts[0]); + if (matcher2.find()) { + newTransId = uuidParts[0]; + } else { + // punt, we tried to find it, it has a colon but no UUID-1 + newTransId = UUID.randomUUID().toString(); + } + } else { + newTransId = UUID.randomUUID().toString(); + } + } + } else { + newTransId = UUID.randomUUID().toString(); + missingTransId = true; + } + + if (missingTransId || replacedTransId) { + List<String> txList = new ArrayList<String>(); + txList.add(newTransId); + headersList.put("X-TransactionId", txList); + if (missingTransId) { + logMsg = "Missing requestID. Assigned " + newTransId; + } else if (replacedTransId) { + logMsg = "Replaced invalid requestID of " + transId + " Assigned " + newTransId; + } + } + + List<String> contentType = headersList.get("Content-Type"); + if (contentType == null) { + ct = (String)message.get(Message.CONTENT_TYPE); + headersList.put(Message.CONTENT_TYPE, Collections.singletonList(ct)); + } + + LOGGER.auditEvent("REST " + httpMethod + " " + ((query != null)? uri+"?"+query : uri) + " HbaseTxId=" + fullId); + LOGGER.info(logMsg); + } + + + if (uri != null) { + buffer.getAddress().append(uri); + if (query != null) { + buffer.getAddress().append("?").append(query); + } + } + + InputStream is = message.getContent(InputStream.class); + if (is != null) { + try { + String currentPayload = IOUtils.toString(is, "UTF-8"); + IOUtils.closeQuietly(is); + buffer.getPayload().append(currentPayload); + is = IOUtils.toInputStream(currentPayload, "UTF-8"); + message.setContent(InputStream.class, is); + IOUtils.closeQuietly(is); + } catch (Exception e) { + // It's ok to not have request input content + // throw new Fault(e); + } + } + + // this will be saved in the message exchange, and can be pulled out later... + message.getExchange().put(fullId + "_REQUEST", buffer.toString()); + } + + /** + * Gen date. + * + * @param aaiLogger the aai logger + * @param logline the logline + * @return the string + */ + protected String genDate() { + Date date = new Date(); + DateFormat formatter = null; + try { + formatter = new SimpleDateFormat(AAIConfig.get(AAIConstants.HBASE_TABLE_TIMESTAMP_FORMAT)); + } catch (AAIException ex) { + ErrorLogHelper.logException(ex); + } finally { + if (formatter == null) { + formatter = new SimpleDateFormat("YYMMdd-HH:mm:ss:SSS"); + } + } + + return formatter.format(date); + } + +} diff --git a/aai-resources/src/main/java/org/openecomp/aai/interceptors/AAILogJAXRSOutInterceptor.java b/aai-resources/src/main/java/org/openecomp/aai/interceptors/AAILogJAXRSOutInterceptor.java new file mode 100644 index 0000000..0f5e457 --- /dev/null +++ b/aai-resources/src/main/java/org/openecomp/aai/interceptors/AAILogJAXRSOutInterceptor.java @@ -0,0 +1,323 @@ +/*- + * ============LICENSE_START======================================================= + * org.openecomp.aai + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.aai.interceptors; + +import java.io.OutputStream; +import java.text.DateFormat; +import java.text.SimpleDateFormat; +import java.util.Collections; +import java.util.Date; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import org.apache.cxf.helpers.CastUtils; +import org.apache.cxf.interceptor.LoggingMessage; +import org.apache.cxf.io.CacheAndWriteOutputStream; +import org.apache.cxf.io.CachedOutputStream; +import org.apache.cxf.io.CachedOutputStreamCallback; +import org.apache.cxf.jaxrs.interceptor.JAXRSOutInterceptor; +import org.apache.cxf.message.Message; + +import org.openecomp.aai.exceptions.AAIException; +import org.openecomp.aai.logging.ErrorLogHelper; +import org.openecomp.aai.util.AAIConfig; +import org.openecomp.aai.util.AAIConstants; +import com.att.eelf.configuration.EELFLogger; +import com.att.eelf.configuration.EELFManager; + +// right after the request is complete, there may be content +public class AAILogJAXRSOutInterceptor extends JAXRSOutInterceptor { + + private static final EELFLogger LOGGER = EELFManager.getInstance().getLogger(AAILogJAXRSOutInterceptor.class); + + protected final String COMPONENT = "aairest"; + protected final String CAMEL_REQUEST = "CamelHttpUrl"; + + /** + * {@inheritDoc} + */ + public void handleMessage(Message message) { + + String fullId = (String) message.getExchange().get(LoggingMessage.ID_KEY); + + Map<String, List<String>> headers = CastUtils.cast((Map<?, ?>) message.get(Message.PROTOCOL_HEADERS)); + if (headers == null) { + headers = new HashMap<String, List<String>>(); + } + + headers.put("X-AAI-TXID", Collections.singletonList(fullId)); + message.put(Message.PROTOCOL_HEADERS, headers); + + Message outMessage = message.getExchange().getOutMessage(); + final OutputStream os = outMessage.getContent(OutputStream.class); + if (os == null) { + return; + } + + // we only want to register the callback if there is good reason for it. + if (message.getExchange().containsKey("AAI_LOGGING_HBASE_ENABLED") || message.getExchange().containsKey("AAI_LOGGING_TRACE_ENABLED")) { + + final CacheAndWriteOutputStream newOut = new CacheAndWriteOutputStream(os); + message.setContent(OutputStream.class, newOut); + newOut.registerCallback(new LoggingCallback(message, os)); + } + + } + + class LoggingCallback implements CachedOutputStreamCallback { + + private final Message message; + private final OutputStream origStream; + + public LoggingCallback(final Message msg, final OutputStream os) { + this.message = msg; + this.origStream = os; + } + + public void onFlush(CachedOutputStream cos) { + + } + + public void onClose(CachedOutputStream cos) { + + String getValue = ""; + String postValue = ""; + String logValue = ""; + + try { + logValue = AAIConfig.get("aai.transaction.logging"); + getValue = AAIConfig.get("aai.transaction.logging.get"); + postValue = AAIConfig.get("aai.transaction.logging.post"); + } catch (AAIException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + + if (!message.getExchange().containsKey("AAI_LOGGING_HBASE_ENABLED") && !message.getExchange().containsKey("AAI_LOGGING_TRACE_ENABLED")) { + return; + } + + String fullId = (String) message.getExchange().get(LoggingMessage.ID_KEY); + + Message inMessage = message.getExchange().getInMessage(); + String transId = null; + String fromAppId = null; + + Map<String, List<String>> headersList = CastUtils.cast((Map<?, ?>) inMessage.get(Message.PROTOCOL_HEADERS)); + if (headersList != null) { + List<String> xt = headersList.get("X-TransactionId"); + if (xt != null) { + for (String transIdValue : xt) { + transId = transIdValue; + } + } + List<String> fa = headersList.get("X-FromAppId"); + if (fa != null) { + for (String fromAppIdValue : fa) { + + fromAppId = fromAppIdValue; + } + } + } + + String httpMethod = (String) inMessage.get(Message.HTTP_REQUEST_METHOD); + + String uri = (String) inMessage.get(CAMEL_REQUEST); + String fullUri = uri; + if (uri != null) { + String query = (String) message.get(Message.QUERY_STRING); + if (query != null) { + fullUri = uri + "?" + query; + } + } + + String request = (String) message.getExchange().get(fullId + "_REQUEST"); + + Message outMessage = message.getExchange().getOutMessage(); + + final LoggingMessage buffer = new LoggingMessage("OUTMessage", fullId); + + // should we check this, and make sure it's not an error? + Integer responseCode = (Integer) outMessage.get(Message.RESPONSE_CODE); + if (responseCode == null) { + responseCode = 200; // this should never happen, but just in + // case we don't get one + } + buffer.getResponseCode().append(responseCode); + + String encoding = (String) outMessage.get(Message.ENCODING); + + if (encoding != null) { + buffer.getEncoding().append(encoding); + } + + String ct = (String) outMessage.get(Message.CONTENT_TYPE); + if (ct != null) { + buffer.getContentType().append(ct); + } + + Object headers = outMessage.get(Message.PROTOCOL_HEADERS); + if (headers != null) { + buffer.getHeader().append(headers); + } + + Boolean ss = false; + if (responseCode >= 200 && responseCode <= 299) { + ss = true; + } + String response = buffer.toString(); + + // this should have been set by the in interceptor + String rqstTm = (String) message.getExchange().get("AAI_RQST_TM"); + + // just in case it wasn't, we'll put this here. not great, but it'll + // have a val. + if (rqstTm == null) { + rqstTm = genDate(); + } + + + String respTm = genDate(); + + try { + String actualRequest = request; + StringBuilder builder = new StringBuilder(); + cos.writeCacheTo(builder, 100000); + // here comes my xml: + String payload = builder.toString(); + + String actualResponse = response; + if (payload == null) { + + } else { + actualResponse = response + payload; + } + + // we only log to AAI log if it's eanbled in the config props + // file + if (message.getExchange().containsKey("AAI_LOGGING_TRACE_ENABLED")) { + + if (message.getExchange().containsKey("AAI_LOGGING_TRACE_LOGREQUEST")) { + + // strip newlines from request + String traceRequest = actualRequest; + traceRequest = traceRequest.replace("\n", " "); + traceRequest = traceRequest.replace("\r", ""); + traceRequest = traceRequest.replace("\t", ""); + LOGGER.debug(traceRequest); + } + if (message.getExchange().containsKey("AAI_LOGGING_TRACE_LOGRESPONSE")) { + // strip newlines from response + String traceResponse = actualResponse; + traceResponse = traceResponse.replace("\n", " "); + traceResponse = traceResponse.replace("\r", ""); + traceResponse = traceResponse.replace("\t", ""); + + LOGGER.debug(traceResponse); + } + } + + // we only log to HBASE if it's enabled in the config props file + // TODO: pretty print XML/JSON. we might need to get the payload + // and envelope seperately + if (message.getExchange().containsKey("AAI_LOGGING_HBASE_ENABLED")) { + if (!message.getExchange().containsKey("AAI_LOGGING_HBASE_LOGREQUEST")) { + actualRequest = "loggingDisabled"; + } + if (!message.getExchange().containsKey("AAI_LOGGING_HBASE_LOGRESPONSE")) { + actualResponse = "loggingDisabled"; + } + + LOGGER.debug("action={}, urlin={}, HbTransId={}", httpMethod, fullUri, fullId); + + if (logValue.equals("false")) { + } else if (getValue.equals("false") && httpMethod.equals("GET")) { + } else if (postValue.equals("false") && httpMethod.equals("POST")) { + } else { + putTransaction(transId, responseCode.toString(), rqstTm, respTm, fromAppId + ":" + transId, fullUri, httpMethod, request, response, actualResponse); + + } + } + } catch (Exception ex) { + // ignore + } + + message.setContent(OutputStream.class, origStream); + + LOGGER.auditEvent("HTTP Response Code: {}", responseCode.toString()); + } + + } + + protected String genDate() { + Date date = new Date(); + DateFormat formatter = null; + try { + formatter = new SimpleDateFormat(AAIConfig.get(AAIConstants.HBASE_TABLE_TIMESTAMP_FORMAT)); + } catch (AAIException ex) { + ErrorLogHelper.logException(ex); + } finally { + if (formatter == null) { + formatter = new SimpleDateFormat("YYMMdd-HH:mm:ss:SSS"); + } + } + return formatter.format(date); + } + + public String putTransaction(String tid, String status, String rqstTm, String respTm, String srcId, String rsrcId, String rsrcType, String rqstBuf, String respBuf, String actualResponse) { + String tm = null; + String fromAppId = srcId.substring(0, srcId.indexOf(':')); + String transId = srcId.substring(srcId.indexOf(':') + 1); + + if (tid == null || "".equals(tid)) { + Date date = new Date(); + DateFormat formatter = null; + try { + formatter = new SimpleDateFormat(AAIConfig.get(AAIConstants.HBASE_TABLE_TIMESTAMP_FORMAT)); + } catch (Exception e) { + formatter = new SimpleDateFormat("YYYYMMdd-HH:mm:ss:SSS"); + } + tm = formatter.format(date); + tid = tm + "-"; + } + + String htid = tid; + + if (rqstTm == null || "".equals(rqstTm)) { + rqstTm = tm; + } + + if (respTm == null || "".equals(respTm)) { + respTm = tm; + } + + try { + LOGGER.debug(" transactionId:" + tid + " status: " + status + " rqstDate: " + rqstTm + " respDate: " + respTm + " sourceId: " + srcId + " resourceId: " + + rsrcId + " resourceType: " + rsrcType + " payload rqstBuf: " + rqstBuf + " payload respBuf: " + respBuf + " Payload Error Messages: " + actualResponse); + return htid; + } catch (Exception e) { + ErrorLogHelper.logError("AAI_4000", "Exception updating HBase:"); + return htid; + } + + } +} diff --git a/aai-resources/src/main/java/org/openecomp/aai/interceptors/PostAaiAjscInterceptor.java b/aai-resources/src/main/java/org/openecomp/aai/interceptors/PostAaiAjscInterceptor.java new file mode 100644 index 0000000..3a4f899 --- /dev/null +++ b/aai-resources/src/main/java/org/openecomp/aai/interceptors/PostAaiAjscInterceptor.java @@ -0,0 +1,63 @@ +/*- + * ============LICENSE_START======================================================= + * org.openecomp.aai + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.aai.interceptors; + +import java.util.Map; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import org.openecomp.aai.logging.LoggingContext; +import org.openecomp.aai.logging.LoggingContext.StatusCode; +import com.att.eelf.configuration.EELFLogger; +import com.att.eelf.configuration.EELFManager; + +import ajsc.beans.interceptors.AjscInterceptor; + +public class PostAaiAjscInterceptor implements AjscInterceptor { + + private static final EELFLogger LOGGER = EELFManager.getInstance().getLogger(PostAaiAjscInterceptor.class); + + private static class LazyAaiAjscInterceptor { + public static final PostAaiAjscInterceptor INSTANCE = new PostAaiAjscInterceptor(); + } + + public static PostAaiAjscInterceptor getInstance() { + return LazyAaiAjscInterceptor.INSTANCE; + } + + @Override + public boolean allowOrReject(HttpServletRequest req, HttpServletResponse resp, Map<?, ?> paramMap) + throws Exception { + final String responseCode = LoggingContext.responseCode(); + + if (responseCode != null && responseCode.startsWith("ERR.")) { + LoggingContext.statusCode(StatusCode.ERROR); + LOGGER.error(req.getRequestURL() + " call failed with responseCode=" + responseCode); + } else { + LoggingContext.statusCode(StatusCode.COMPLETE); + LOGGER.info(req.getRequestURL() + " call succeeded"); + } + + LoggingContext.clear(); + return true; + } +} diff --git a/aai-resources/src/main/java/org/openecomp/aai/interceptors/PreAaiAjscInterceptor.java b/aai-resources/src/main/java/org/openecomp/aai/interceptors/PreAaiAjscInterceptor.java new file mode 100644 index 0000000..a2c56d0 --- /dev/null +++ b/aai-resources/src/main/java/org/openecomp/aai/interceptors/PreAaiAjscInterceptor.java @@ -0,0 +1,54 @@ +/*- + * ============LICENSE_START======================================================= + * org.openecomp.aai + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.aai.interceptors; + +import java.util.Map; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import org.openecomp.aai.logging.LoggingContext; + +import ajsc.beans.interceptors.AjscInterceptor; + +public class PreAaiAjscInterceptor implements AjscInterceptor { + + private static class LazyAaiAjscInterceptor { + public static final PreAaiAjscInterceptor INSTANCE = new PreAaiAjscInterceptor(); + } + + public static PreAaiAjscInterceptor getInstance() { + return LazyAaiAjscInterceptor.INSTANCE; + } + + @Override + public boolean allowOrReject(HttpServletRequest req, HttpServletResponse resp, Map<?, ?> paramMap) + throws Exception { + + LoggingContext.init(); + + LoggingContext.requestId(req.getHeader("X-TransactionId")); + LoggingContext.partnerName(req.getHeader("X-FromAppId")); + LoggingContext.serviceName(req.getMethod() + " " + req.getRequestURI().toString()); + + return true; + } +} diff --git a/aai-resources/src/main/java/org/openecomp/aai/rest/BulkAddConsumer.java b/aai-resources/src/main/java/org/openecomp/aai/rest/BulkAddConsumer.java new file mode 100644 index 0000000..f8c34c2 --- /dev/null +++ b/aai-resources/src/main/java/org/openecomp/aai/rest/BulkAddConsumer.java @@ -0,0 +1,42 @@ +/*- + * ============LICENSE_START======================================================= + * org.openecomp.aai + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.aai.rest; + +import javax.ws.rs.Path; + +import org.openecomp.aai.restcore.HttpMethod; + +@Path("{version: v[8-9]|v1[0]}/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/openecomp/aai/rest/BulkConsumer.java b/aai-resources/src/main/java/org/openecomp/aai/rest/BulkConsumer.java new file mode 100644 index 0000000..951c9ff --- /dev/null +++ b/aai-resources/src/main/java/org/openecomp/aai/rest/BulkConsumer.java @@ -0,0 +1,484 @@ +/*- + * ============LICENSE_START======================================================= + * org.openecomp.aai + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.aai.rest; + +import java.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.openecomp.aai.dbmap.DBConnectionType; +import org.openecomp.aai.exceptions.AAIException; +import org.openecomp.aai.introspection.Introspector; +import org.openecomp.aai.introspection.Loader; +import org.openecomp.aai.introspection.ModelType; +import org.openecomp.aai.introspection.Version; +import org.openecomp.aai.introspection.exceptions.AAIUnmarshallingException; +import org.openecomp.aai.logging.ErrorObjectNotFoundException; +import org.openecomp.aai.parsers.query.QueryParser; +import org.openecomp.aai.rest.db.DBRequest; +import org.openecomp.aai.rest.db.HttpEntry; +import org.openecomp.aai.rest.util.ValidateEncoding; +import org.openecomp.aai.restcore.HttpMethod; +import org.openecomp.aai.restcore.RESTAPI; +import org.openecomp.aai.serialization.engines.QueryStyle; +import org.openecomp.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.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.openecomp.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.openecomp.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/openecomp/aai/rest/BulkProcessConsumer.java b/aai-resources/src/main/java/org/openecomp/aai/rest/BulkProcessConsumer.java new file mode 100644 index 0000000..91867ef --- /dev/null +++ b/aai-resources/src/main/java/org/openecomp/aai/rest/BulkProcessConsumer.java @@ -0,0 +1,42 @@ +/*- + * ============LICENSE_START======================================================= + * org.openecomp.aai + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.aai.rest; + +import javax.ws.rs.Path; + +import org.openecomp.aai.restcore.HttpMethod; + +@Path("{version: v[2789]|v1[0]}/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/openecomp/aai/rest/ExampleConsumer.java b/aai-resources/src/main/java/org/openecomp/aai/rest/ExampleConsumer.java new file mode 100644 index 0000000..de59955 --- /dev/null +++ b/aai-resources/src/main/java/org/openecomp/aai/rest/ExampleConsumer.java @@ -0,0 +1,104 @@ +/*- + * ============LICENSE_START======================================================= + * org.openecomp.aai + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.aai.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.openecomp.aai.exceptions.AAIException; +import org.openecomp.aai.introspection.Introspector; +import org.openecomp.aai.introspection.Loader; +import org.openecomp.aai.introspection.LoaderFactory; +import org.openecomp.aai.introspection.MarshallerProperties; +import org.openecomp.aai.introspection.ModelType; +import org.openecomp.aai.introspection.Version; +import org.openecomp.aai.introspection.generator.CreateExample; +import org.openecomp.aai.restcore.HttpMethod; +import org.openecomp.aai.restcore.RESTAPI; + +/** + * The Class ExampleConsumer. + */ +@Path("/{version: v[2789]|v1[0]}/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.openecomp.aai.restcore.MediaType outputMediaType = org.openecomp.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/openecomp/aai/rest/ExceptionHandler.java b/aai-resources/src/main/java/org/openecomp/aai/rest/ExceptionHandler.java new file mode 100644 index 0000000..f1a6f47 --- /dev/null +++ b/aai-resources/src/main/java/org/openecomp/aai/rest/ExceptionHandler.java @@ -0,0 +1,129 @@ +/*- + * ============LICENSE_START======================================================= + * org.openecomp.aai + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.aai.rest; + +import java.util.ArrayList; +import java.util.List; + +import javax.servlet.http.HttpServletRequest; +import javax.ws.rs.WebApplicationException; +import javax.ws.rs.core.Context; +import javax.ws.rs.core.HttpHeaders; +import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.Response; +import javax.ws.rs.ext.ExceptionMapper; +import javax.ws.rs.ext.Provider; + +import org.openecomp.aai.exceptions.AAIException; +import org.openecomp.aai.logging.ErrorLogHelper; +import com.fasterxml.jackson.core.JsonParseException; +import com.fasterxml.jackson.databind.JsonMappingException; +import com.sun.istack.SAXParseException2; + +/** + * The Class ExceptionHandler. + */ +@Provider +public class ExceptionHandler implements ExceptionMapper<Exception> { + + @Context + private HttpServletRequest request; + + @Context + private HttpHeaders headers; + + /** + * @{inheritDoc} + */ + @Override + public Response toResponse(Exception exception) { + + Response response = null; + ArrayList<String> templateVars = new ArrayList<String>(); + + //the general case is that cxf will give us a WebApplicationException + //with a linked exception + if (exception instanceof WebApplicationException) { + WebApplicationException e = (WebApplicationException) exception; + if (e.getCause() != null) { + if (e.getCause() instanceof SAXParseException2) { + templateVars.add("UnmarshalException"); + AAIException ex = new AAIException("AAI_4007", exception); + response = Response + .status(400) + .entity(ErrorLogHelper.getRESTAPIErrorResponse(headers.getAcceptableMediaTypes(), ex, templateVars)) + .build(); + } + } + } else if (exception instanceof JsonParseException) { + //jackson does it differently so we get the direct JsonParseException + templateVars.add("JsonParseException"); + AAIException ex = new AAIException("AAI_4007", exception); + response = Response + .status(400) + .entity(ErrorLogHelper.getRESTAPIErrorResponse(headers.getAcceptableMediaTypes(), ex, templateVars)) + .build(); + } else if (exception instanceof JsonMappingException) { + //jackson does it differently so we get the direct JsonParseException + templateVars.add("JsonMappingException"); + AAIException ex = new AAIException("AAI_4007", exception); + response = Response + .status(400) + .entity(ErrorLogHelper.getRESTAPIErrorResponse(headers.getAcceptableMediaTypes(), ex, templateVars)) + .build(); + } + + // it didn't get set above, we wrap a general fault here + if (response == null) { + + Exception actual_e = exception; + if (exception instanceof WebApplicationException) { + WebApplicationException e = (WebApplicationException) exception; + response = e.getResponse(); + } else { + templateVars.add(request.getMethod()); + templateVars.add("unknown"); + AAIException ex = new AAIException("AAI_4000", actual_e); + List<MediaType> mediaTypes = headers.getAcceptableMediaTypes(); + int setError = 0; + + for (MediaType mediaType : mediaTypes) { + if (MediaType.APPLICATION_XML_TYPE.isCompatible(mediaType)) { + response = Response + .status(400) + .type(MediaType.APPLICATION_XML_TYPE) + .entity(ErrorLogHelper.getRESTAPIErrorResponse(headers.getAcceptableMediaTypes(), ex, templateVars)) + .build(); + setError = 1; + } + } + if (setError == 0) { + response = Response + .status(400) + .type(MediaType.APPLICATION_JSON_TYPE) + .entity(ErrorLogHelper.getRESTAPIErrorResponse(headers.getAcceptableMediaTypes(), ex, templateVars)) + .build(); + } + } + } + return response; + } +} diff --git a/aai-resources/src/main/java/org/openecomp/aai/rest/LegacyMoxyConsumer.java b/aai-resources/src/main/java/org/openecomp/aai/rest/LegacyMoxyConsumer.java new file mode 100644 index 0000000..7af432d --- /dev/null +++ b/aai-resources/src/main/java/org/openecomp/aai/rest/LegacyMoxyConsumer.java @@ -0,0 +1,583 @@ +/*- + * ============LICENSE_START======================================================= + * org.openecomp.aai + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.aai.rest; + +import java.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.openecomp.aai.dbmap.DBConnectionType; +import org.openecomp.aai.exceptions.AAIException; +import org.openecomp.aai.introspection.Introspector; +import org.openecomp.aai.introspection.Loader; +import org.openecomp.aai.introspection.ModelType; +import org.openecomp.aai.introspection.Version; +import org.openecomp.aai.parsers.query.QueryParser; +import org.openecomp.aai.rest.db.DBRequest; +import org.openecomp.aai.rest.db.HttpEntry; +import org.openecomp.aai.rest.util.ValidateEncoding; +import org.openecomp.aai.restcore.HttpMethod; +import org.openecomp.aai.restcore.RESTAPI; +import org.openecomp.aai.serialization.engines.QueryStyle; +import org.openecomp.aai.serialization.engines.TransactionalGraphEngine; +import org.openecomp.aai.workarounds.RemoveDME2QueryParams; +import com.att.eelf.configuration.EELFLogger; +import com.att.eelf.configuration.EELFManager; +import com.google.common.base.Joiner; +import com.thinkaurelius.titan.core.TitanTransaction; + + +/** + * The Class LegacyMoxyConsumer. + */ +@Path("{version: v[2789]|v1[0]}") +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(Action.PUT, mediaType, HttpMethod.PUT, content, versionParam, uri, headers, info, req); + } + + /** + * 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; + TitanTransaction g = 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(); + + QueryParser uriQuery = dbEngine.getQueryBuilder().createQueryFromURI(uriObject); + + Introspector wrappedEntity = loader.unmarshal("relationship", content, org.openecomp.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(Action.PUT, mediaType, HttpMethod.MERGE_PATCH, content, versionParam, uri, headers, info, req); + + } + + /** + * 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; + TitanTransaction g = 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(); + + TitanTransaction g = null; + 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(); + + TitanTransaction g = null; + 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(); + + QueryParser uriQuery = dbEngine.getQueryBuilder().createQueryFromURI(uriObject); + + Introspector wrappedEntity = loader.unmarshal("relationship", content, org.openecomp.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(Action aaiAction, MediaType mediaType, HttpMethod method, String content, String versionParam, String uri, HttpHeaders headers, UriInfo info, HttpServletRequest req) { + + 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"); + TitanTransaction g = null; + 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(); + + 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.openecomp.aai.restcore.MediaType.getEnum(this.getInputMediaType(mediaType))); + if (obj == null) { + throw new AAIException("AAI_3000", "object could not be unmarshalled:" + 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; + } + +} diff --git a/aai-resources/src/main/java/org/openecomp/aai/rest/URLFromVertexIdConsumer.java b/aai-resources/src/main/java/org/openecomp/aai/rest/URLFromVertexIdConsumer.java new file mode 100644 index 0000000..d67a008 --- /dev/null +++ b/aai-resources/src/main/java/org/openecomp/aai/rest/URLFromVertexIdConsumer.java @@ -0,0 +1,120 @@ +/*- + * ============LICENSE_START======================================================= + * org.openecomp.aai + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.aai.rest; + +import java.net.URI; +import java.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.openecomp.aai.dbmap.DBConnectionType; +import org.openecomp.aai.exceptions.AAIException; +import org.openecomp.aai.introspection.ModelType; +import org.openecomp.aai.introspection.Version; +import org.openecomp.aai.rest.db.HttpEntry; +import org.openecomp.aai.restcore.HttpMethod; +import org.openecomp.aai.restcore.RESTAPI; +import org.openecomp.aai.serialization.db.DBSerializer; +import org.openecomp.aai.serialization.engines.QueryStyle; +import org.openecomp.aai.serialization.engines.TransactionalGraphEngine; +import org.openecomp.aai.util.AAIConfig; +import org.openecomp.aai.workarounds.LegacyURITransformer; + +/** + * The Class URLFromVertexIdConsumer. + */ +@Path("{version: v[2789]|v1[0]}/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/openecomp/aai/rest/VertexIdConsumer.java b/aai-resources/src/main/java/org/openecomp/aai/rest/VertexIdConsumer.java new file mode 100644 index 0000000..9e1dcfc --- /dev/null +++ b/aai-resources/src/main/java/org/openecomp/aai/rest/VertexIdConsumer.java @@ -0,0 +1,145 @@ +/*- + * ============LICENSE_START======================================================= + * org.openecomp.aai + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.aai.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.openecomp.aai.db.props.AAIProperties; +import org.openecomp.aai.dbmap.DBConnectionType; +import org.openecomp.aai.exceptions.AAIException; +import org.openecomp.aai.introspection.Introspector; +import org.openecomp.aai.introspection.Loader; +import org.openecomp.aai.introspection.MarshallerProperties; +import org.openecomp.aai.introspection.ModelType; +import org.openecomp.aai.introspection.Version; +import org.openecomp.aai.parsers.query.QueryParser; +import org.openecomp.aai.rest.db.DBRequest; +import org.openecomp.aai.rest.db.HttpEntry; +import org.openecomp.aai.restcore.HttpMethod; +import org.openecomp.aai.restcore.RESTAPI; +import org.openecomp.aai.serialization.db.DBSerializer; +import org.openecomp.aai.serialization.engines.QueryStyle; +import org.openecomp.aai.serialization.engines.TransactionalGraphEngine; + +/** + * The Class VertexIdConsumer. + */ +@Path("{version: v[2789]|v1[0]}/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.openecomp.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/openecomp/aai/rest/db/DBRequest.java b/aai-resources/src/main/java/org/openecomp/aai/rest/db/DBRequest.java new file mode 100644 index 0000000..e7b6858 --- /dev/null +++ b/aai-resources/src/main/java/org/openecomp/aai/rest/db/DBRequest.java @@ -0,0 +1,251 @@ +/*- + * ============LICENSE_START======================================================= + * org.openecomp.aai + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.aai.rest.db; + +import java.net.URI; +import java.util.Optional; + +import javax.ws.rs.core.HttpHeaders; +import javax.ws.rs.core.UriInfo; + +import org.openecomp.aai.introspection.Introspector; +import org.openecomp.aai.introspection.MarshallerProperties; +import org.openecomp.aai.parsers.query.QueryParser; +import org.openecomp.aai.restcore.HttpMethod; + +/** + * The Class DBRequest. + */ +public class DBRequest { + + private final QueryParser parser; + + private final Introspector introspector; + + private final HttpHeaders headers; + + private final String transactionId; + + private final UriInfo info; + + private final HttpMethod method; + + private final URI uri; + + private final Optional<String> rawRequestContent; + + private final Optional<MarshallerProperties> marshallerProperties; + + + /** + * Instantiates a new DB request. + * + * @param method the method + * @param uri the uri + * @param parser the parser + * @param obj the obj + * @param headers the headers + * @param info the info + * @param transactionId the transaction id + */ + private DBRequest(Builder builder) { + this.method = builder.getMethod(); + this.parser = builder.getParser(); + this.introspector = builder.getIntrospector(); + this.headers = builder.getHeaders(); + this.transactionId = builder.getTransactionId(); + this.info = builder.getInfo(); + this.uri = builder.getUri(); + this.marshallerProperties = builder.getMarshallerProperties(); + this.rawRequestContent = builder.getRawRequestContent(); + } + + /** + * Gets the headers. + * + * @return the headers + */ + public HttpHeaders getHeaders() { + return headers; + } + + + /** + * Gets the transaction id. + * + * @return the transaction id + */ + public String getTransactionId() { + return transactionId; + } + + /** + * Gets the info. + * + * @return the info + */ + public UriInfo getInfo() { + return info; + } + + /** + * Gets the parser. + * + * @return the parser + */ + public QueryParser getParser() { + return parser; + } + + /** + * Gets the introspector. + * + * @return the introspector + */ + public Introspector getIntrospector() { + return introspector; + } + + /** + * Gets the method. + * + * @return the method + */ + public HttpMethod getMethod() { + return method; + } + + /** + * Gets the uri. + * + * @return the uri + */ + public URI getUri() { + return uri; + } + + /** + * Gets the raw content. + * + * @return the raw content + */ + public Optional<String> getRawRequestContent() { + return rawRequestContent; + } + + public Optional<MarshallerProperties> getMarshallerProperties() { + return marshallerProperties; + } + + + + public static class Builder { + + private QueryParser parser = null; + + private Introspector introspector = null; + + private HttpHeaders headers = null; + + private String transactionId = null; + + private UriInfo info = null; + + private HttpMethod method = null; + + private URI uri = null; + + private Optional<MarshallerProperties> marshallerProperties = Optional.empty(); + + private Optional<String> rawRequestContent = Optional.empty(); + /** + * Instantiates a new DB request. + * + * @param method the method + * @param uri the uri + * @param parser the parser + * @param obj the obj + * @param headers the headers + * @param info the info + * @param transactionId the transaction id + */ + public Builder(HttpMethod method, URI uri, QueryParser parser, Introspector obj, HttpHeaders headers, UriInfo info, String transactionId) { + this.method = method; + this.parser = parser; + this.introspector = obj; + this.headers = headers; + this.transactionId = transactionId; + this.info = info; + this.uri = uri; + + } + + public QueryParser getParser() { + return parser; + } + + public Introspector getIntrospector() { + return introspector; + } + + public HttpHeaders getHeaders() { + return headers; + } + + public String getTransactionId() { + return transactionId; + } + + public UriInfo getInfo() { + return info; + } + + public HttpMethod getMethod() { + return method; + } + + public URI getUri() { + return uri; + } + + public Builder customMarshaller(MarshallerProperties properties) { + this.marshallerProperties = Optional.of(properties); + return this; + } + + public Builder rawRequestContent(String content) { + this.rawRequestContent = Optional.of(content); + return this; + } + protected Optional<MarshallerProperties> getMarshallerProperties() { + return marshallerProperties; + } + protected Optional<String> getRawRequestContent() { + return rawRequestContent; + } + public DBRequest build() { + + return new DBRequest(this); + } + + + } +} diff --git a/aai-resources/src/main/java/org/openecomp/aai/rest/db/HttpEntry.java b/aai-resources/src/main/java/org/openecomp/aai/rest/db/HttpEntry.java new file mode 100644 index 0000000..ef305b0 --- /dev/null +++ b/aai-resources/src/main/java/org/openecomp/aai/rest/db/HttpEntry.java @@ -0,0 +1,570 @@ +/*- + * ============LICENSE_START======================================================= + * org.openecomp.aai + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.aai.rest.db; + +import java.io.IOException; +import java.io.UnsupportedEncodingException; +import java.lang.reflect.InvocationTargetException; +import java.net.MalformedURLException; +import java.net.URI; +import java.net.URISyntaxException; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Set; + +import javax.ws.rs.core.HttpHeaders; +import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.MultivaluedMap; +import javax.ws.rs.core.Response; +import javax.ws.rs.core.Response.Status; +import javax.ws.rs.core.UriBuilder; + +import org.apache.commons.lang.StringUtils; +import org.apache.tinkerpop.gremlin.structure.Vertex; +import org.javatuples.Pair; + +import org.openecomp.aai.db.props.AAIProperties; +import org.openecomp.aai.dbmap.DBConnectionType; +import org.openecomp.aai.domain.responseMessage.AAIResponseMessage; +import org.openecomp.aai.domain.responseMessage.AAIResponseMessageDatum; +import org.openecomp.aai.exceptions.AAIException; +import org.openecomp.aai.introspection.Introspector; +import org.openecomp.aai.introspection.Loader; +import org.openecomp.aai.introspection.LoaderFactory; +import org.openecomp.aai.introspection.MarshallerProperties; +import org.openecomp.aai.introspection.ModelInjestor; +import org.openecomp.aai.introspection.ModelType; +import org.openecomp.aai.introspection.Version; +import org.openecomp.aai.introspection.exceptions.AAIUnknownObjectException; +import org.openecomp.aai.logging.ErrorLogHelper; +import org.openecomp.aai.parsers.query.QueryParser; +import org.openecomp.aai.parsers.uri.URIToExtensionInformation; +import org.openecomp.aai.rest.ueb.UEBNotification; +import org.openecomp.aai.restcore.HttpMethod; +import org.openecomp.aai.schema.enums.ObjectMetadata; +import org.openecomp.aai.serialization.db.DBSerializer; +import org.openecomp.aai.serialization.engines.QueryStyle; +import org.openecomp.aai.serialization.engines.TitanDBEngine; +import org.openecomp.aai.serialization.engines.TransactionalGraphEngine; +import org.openecomp.aai.serialization.engines.query.QueryEngine; +import com.att.eelf.configuration.EELFLogger; +import com.att.eelf.configuration.EELFManager; +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.github.fge.jsonpatch.JsonPatchException; +import com.github.fge.jsonpatch.mergepatch.JsonMergePatch; +import com.thinkaurelius.titan.core.TitanException; +import com.thinkaurelius.titan.core.TitanTransaction; + +/** + * The Class HttpEntry. + */ +public class HttpEntry { + + private static final EELFLogger LOGGER = EELFManager.getInstance().getLogger(HttpEntry.class); + + private final ModelType introspectorFactoryType; + + private final QueryStyle queryStyle; + + private final Version version; + + private final Loader loader; + + private final TransactionalGraphEngine dbEngine; + + private boolean processSingle = true; + + /** + * Instantiates a new http entry. + * + * @param version the version + * @param modelType the model type + * @param queryStyle the query style + * @param llBuilder the ll builder + */ + public HttpEntry(Version version, ModelType modelType, QueryStyle queryStyle, DBConnectionType connectionType) { + this.introspectorFactoryType = modelType; + this.queryStyle = queryStyle; + this.version = version; + this.loader = LoaderFactory.createLoaderForVersion(introspectorFactoryType, version); + this.dbEngine = new TitanDBEngine( + queryStyle, + connectionType, + loader); + //start transaction on creation + dbEngine.startTransaction(); + + } + + /** + * Gets the introspector factory type. + * + * @return the introspector factory type + */ + public ModelType getIntrospectorFactoryType() { + return introspectorFactoryType; + } + + /** + * Gets the query style. + * + * @return the query style + */ + public QueryStyle getQueryStyle() { + return queryStyle; + } + + /** + * Gets the version. + * + * @return the version + */ + public Version getVersion() { + return version; + } + + /** + * Gets the loader. + * + * @return the loader + */ + public Loader getLoader() { + return loader; + } + + /** + * Gets the db engine. + * + * @return the db engine + */ + public TransactionalGraphEngine getDbEngine() { + return dbEngine; + } + + public Pair<Boolean, List<Pair<URI, Response>>> process (List<DBRequest> requests, String sourceOfTruth) throws AAIException { + return this.process(requests, sourceOfTruth, true); + } + /** + * Process. + * @param requests the requests + * @param sourceOfTruth the source of truth + * + * @return the pair + * @throws AAIException the AAI exception + */ + public Pair<Boolean, List<Pair<URI, Response>>> process (List<DBRequest> requests, String sourceOfTruth, boolean enableResourceVersion) throws AAIException { + DBSerializer serializer = new DBSerializer(version, dbEngine, introspectorFactoryType, sourceOfTruth); + Response response = null; + Status status = Status.NOT_FOUND; + Introspector obj = null; + QueryParser query = null; + URI uri = null; + String transactionId = null; + UEBNotification notification = new UEBNotification(loader); + int depth = AAIProperties.MAXIMUM_DEPTH; + List<Pair<URI,Response>> responses = new ArrayList<>(); + MultivaluedMap<String, String> params = null; + HttpMethod method = null; + String uriTemp = ""; + Boolean success = true; + QueryEngine queryEngine = dbEngine.getQueryEngine(); + int maxRetries = 10; + int retry = 0; + for (DBRequest request : requests) { + try { + for (retry = 0; retry < maxRetries; ++retry) { + try { + method = request.getMethod(); + obj = request.getIntrospector(); + query = request.getParser(); + transactionId = request.getTransactionId(); + uriTemp = request.getUri().getRawPath().replaceFirst("^v\\d+/", ""); + uri = UriBuilder.fromPath(uriTemp).build(); + List<Vertex> vertices = query.getQueryBuilder().toList(); + boolean isNewVertex = false; + String outputMediaType = getMediaType(request.getHeaders().getAcceptableMediaTypes()); + String result = null; + params = request.getInfo().getQueryParameters(false); + depth = setDepth(obj, params.getFirst("depth")); + String cleanUp = params.getFirst("cleanup"); + String requestContext = ""; + List<String> requestContextList = request.getHeaders().getRequestHeader("aai-request-context"); + if (requestContextList != null) { + requestContext = requestContextList.get(0); + } + + if (cleanUp == null) { + cleanUp = "false"; + } + if (vertices.size() > 1 && processSingle && !method.equals(HttpMethod.GET)) { + if (method.equals(HttpMethod.DELETE)) { + throw new AAIException("AAI_6138"); + } else { + throw new AAIException("AAI_6137"); + } + } + if (method.equals(HttpMethod.PUT)) { + String resourceVersion = (String)obj.getValue("resource-version"); + if (vertices.size() == 1) { + if (enableResourceVersion) { + serializer.verifyResourceVersion("update", query.getResultType(), (String)vertices.get(0).<String>property("resource-version").orElse(null), resourceVersion, obj.getURI()); + } + isNewVertex = false; + } else { + if (enableResourceVersion) { + serializer.verifyResourceVersion("create", query.getResultType(), "", resourceVersion, obj.getURI()); + } + isNewVertex = true; + } + } else { + if (vertices.size() == 0) { + String msg = createNotFoundMessage(query.getResultType(), request.getUri()); + throw new AAIException("AAI_6114", msg); + } else { + isNewVertex = false; + } + } + Vertex v = null; + if (!isNewVertex) { + v = vertices.get(0); + } + HashMap<String, Introspector> relatedObjects = new HashMap<>(); + switch (method) { + case GET: + String nodeOnly = params.getFirst("nodes-only"); + boolean isNodeOnly = nodeOnly != null; + + obj = this.getObjectFromDb(vertices, serializer, query, obj, request.getUri(), depth, isNodeOnly, cleanUp); + if (obj != null) { + status = Status.OK; + MarshallerProperties properties; + if (!request.getMarshallerProperties().isPresent()) { + properties = + new MarshallerProperties.Builder(org.openecomp.aai.restcore.MediaType.getEnum(outputMediaType)).build(); + } else { + properties = request.getMarshallerProperties().get(); + } + result = obj.marshal(properties); + } + + break; + case PUT: + if (isNewVertex) { + v = serializer.createNewVertex(obj); + } else { + serializer.touchStandardVertexProperties(v, false); + } + serializer.serializeToDb(obj, v, query, uri.getRawPath(), requestContext); + status = Status.OK; + if (isNewVertex) { + status = Status.CREATED; + } + obj = serializer.getLatestVersionView(v); + if (query.isDependent()) { + relatedObjects = this.getRelatedObjects(serializer, queryEngine, v); + } + notification.createNotificationEvent(transactionId, sourceOfTruth, status, uri, obj, relatedObjects); + + break; + case PUT_EDGE: + serializer.touchStandardVertexProperties(v, false); + serializer.createEdge(obj, v); + status = Status.OK; + break; + case MERGE_PATCH: + Introspector existingObj = (Introspector) obj.clone(); + existingObj = this.getObjectFromDb(vertices, serializer, query, existingObj, request.getUri(), 0, false, cleanUp); + String existingJson = existingObj.marshal(false); + String newJson; + + if (request.getRawRequestContent().isPresent()) { + newJson = request.getRawRequestContent().get(); + } else { + newJson = ""; + } + Object relationshipList = request.getIntrospector().getValue("relationship-list"); + ObjectMapper mapper = new ObjectMapper(); + try { + JsonNode existingNode = mapper.readTree(existingJson); + JsonNode newNode = mapper.readTree(newJson); + JsonMergePatch patch = JsonMergePatch.fromJson(newNode); + JsonNode completed = patch.apply(existingNode); + String patched = mapper.writeValueAsString(completed); + Introspector patchedObj = loader.unmarshal(existingObj.getName(), patched); + if (relationshipList == null) { + //if the caller didn't touch the relationship-list, we shouldn't either + patchedObj.setValue("relationship-list", null); + } + serializer.touchStandardVertexProperties(v, false); + serializer.serializeToDb(patchedObj, v, query, uri.getRawPath(), requestContext); + status = Status.OK; + patchedObj = serializer.getLatestVersionView(v); + if (query.isDependent()) { + relatedObjects = this.getRelatedObjects(serializer, queryEngine, v); + } + notification.createNotificationEvent(transactionId, sourceOfTruth, status, uri, patchedObj, relatedObjects); + } catch (IOException | JsonPatchException e) { + throw new AAIException("AAI_3000", "could not perform patch operation"); + } + break; + case DELETE: + String resourceVersion = params.getFirst("resource-version"); + obj = serializer.getLatestVersionView(v); + if (query.isDependent()) { + relatedObjects = this.getRelatedObjects(serializer, queryEngine, v); + } + serializer.delete(v, resourceVersion, enableResourceVersion); + status = Status.NO_CONTENT; + notification.createNotificationEvent(transactionId, sourceOfTruth, status, uri, obj, relatedObjects); + break; + case DELETE_EDGE: + serializer.touchStandardVertexProperties(v, false); + serializer.deleteEdge(obj, v); + status = Status.NO_CONTENT; + break; + default: + break; + } + + + /* temporarily adding vertex id to the headers + * to be able to use for testing the vertex id endpoint functionality + * since we presently have no other way of generating those id urls + */ + if (response == null && v != null && ( + method.equals(HttpMethod.PUT) + || method.equals(HttpMethod.GET) + || method.equals(HttpMethod.MERGE_PATCH)) + ) { + String myvertid = v.id().toString(); + response = Response.status(status) + .header("vertex-id", myvertid) + .entity(result) + .type(outputMediaType).build(); + } else if (response == null) { + response = Response.status(status) + .type(outputMediaType).build(); + } else { + //response already set to something + } + Pair<URI,Response> pairedResp = Pair.with(request.getUri(), response); + responses.add(pairedResp); + //break out of retry loop + break; + } catch (TitanException e) { + this.dbEngine.rollback(); + AAIException ex = new AAIException("AAI_6142", e); + ErrorLogHelper.logException(ex); + Thread.sleep((retry + 1) * 20); + this.dbEngine.startTransaction(); + queryEngine = dbEngine.getQueryEngine(); + serializer = new DBSerializer(version, dbEngine, introspectorFactoryType, sourceOfTruth); + } + + if (retry == maxRetries) { + throw new AAIException("AAI_6134"); + } + } + } catch (AAIException e) { + success = false; + ArrayList<String> templateVars = new ArrayList<String>(); + templateVars.add(request.getMethod().toString()); //GET, PUT, etc + templateVars.add(request.getUri().getPath().toString()); + templateVars.addAll(e.getTemplateVars()); + + response = Response + .status(e.getErrorObject().getHTTPResponseCode()) + .entity(ErrorLogHelper.getRESTAPIErrorResponse(request.getHeaders().getAcceptableMediaTypes(), e, templateVars)) + .build(); + Pair<URI,Response> pairedResp = Pair.with(request.getUri(), response); + responses.add(pairedResp); + continue; + } catch (Exception e) { + success = false; + e.printStackTrace(); + AAIException ex = new AAIException("AAI_4000", e); + ArrayList<String> templateVars = new ArrayList<String>(); + templateVars.add(request.getMethod().toString()); //GET, PUT, etc + templateVars.add(request.getUri().getPath().toString()); + + response = Response + .status(ex.getErrorObject().getHTTPResponseCode()) + .entity(ErrorLogHelper.getRESTAPIErrorResponse(request.getHeaders().getAcceptableMediaTypes(), ex, templateVars)) + .build(); + Pair<URI, Response> pairedResp = Pair.with(request.getUri(), response); + responses.add(pairedResp); + continue; + } + } + + notification.triggerEvents(); + Pair<Boolean, List<Pair<URI, Response>>> tuple = Pair.with(success, responses); + return tuple; + } + + /** + * Gets the media type. + * + * @param mediaTypeList the media type list + * @return the media type + */ + private String getMediaType(List <MediaType> mediaTypeList) { + String mediaType = MediaType.APPLICATION_JSON; // json is the default + for (MediaType mt : mediaTypeList) { + if (MediaType.APPLICATION_XML_TYPE.isCompatible(mt)) { + mediaType = MediaType.APPLICATION_XML; + } + } + return mediaType; + } + + /** + * Gets the object from db. + * + * @param serializer the serializer + * @param g the g + * @param query the query + * @param obj the obj + * @param uri the uri + * @param depth the depth + * @param cleanUp the clean up + * @return the object from db + * @throws AAIException the AAI exception + * @throws IllegalAccessException the illegal access exception + * @throws IllegalArgumentException the illegal argument exception + * @throws InvocationTargetException the invocation target exception + * @throws SecurityException the security exception + * @throws InstantiationException the instantiation exception + * @throws NoSuchMethodException the no such method exception + * @throws UnsupportedEncodingException the unsupported encoding exception + * @throws MalformedURLException the malformed URL exception + * @throws AAIUnknownObjectException + * @throws URISyntaxException + */ + private Introspector getObjectFromDb(List<Vertex> results, DBSerializer serializer, QueryParser query, Introspector obj, URI uri, int depth, boolean nodeOnly, String cleanUp) throws AAIException, IllegalAccessException, IllegalArgumentException, InvocationTargetException, SecurityException, InstantiationException, NoSuchMethodException, UnsupportedEncodingException, AAIUnknownObjectException, URISyntaxException { + + //nothing found + if (results.size() == 0) { + String msg = createNotFoundMessage(query.getResultType(), uri); + throw new AAIException("AAI_6114", msg); + } + + obj = serializer.dbToObject(results, obj, depth, nodeOnly, cleanUp); + + return obj; + } + + + /** + * Creates the not found message. + * + * @param resultType the result type + * @param uri the uri + * @return the string + */ + private String createNotFoundMessage(String resultType, URI uri) { + + String msg = "No Node of type " + resultType + " found at: " + uri.getPath(); + + return msg; + } + + /** + * Sets the depth. + * + * @param depthParam the depth param + * @return the int + * @throws AAIException the AAI exception + */ + protected int setDepth(Introspector obj, String depthParam) throws AAIException { + int depth = AAIProperties.MAXIMUM_DEPTH; + + if(depthParam == null){ + if(this.version.compareTo(Version.v9) >= 0){ + depth = 0; + } else { + depth = AAIProperties.MAXIMUM_DEPTH; + } + } else { + if (depthParam.length() > 0 && !depthParam.equals("all")){ + try { + depth = Integer.valueOf(depthParam); + } catch (Exception e) { + throw new AAIException("AAI_4016"); + } + + } + } + String maxDepth = obj.getMetadata(ObjectMetadata.MAXIMUM_DEPTH); + + int maximumDepth = AAIProperties.MAXIMUM_DEPTH; + + if(maxDepth != null){ + try { + maximumDepth = Integer.parseInt(maxDepth); + } catch(Exception ex){ + throw new AAIException("AAI_4018"); + } + } + + if(depth > maximumDepth){ + throw new AAIException("AAI_3303"); + } + + return depth; + } + + /** + * Checks if is modification method. + * + * @param method the method + * @return true, if is modification method + */ + private boolean isModificationMethod(HttpMethod method) { + boolean result = false; + + if (method.equals(HttpMethod.PUT) || method.equals(HttpMethod.PUT_EDGE) || method.equals(HttpMethod.DELETE_EDGE) || method.equals(HttpMethod.MERGE_PATCH)) { + result = true; + } + + return result; + + } + + private HashMap<String, Introspector> getRelatedObjects(DBSerializer serializer, QueryEngine queryEngine, Vertex v) throws IllegalAccessException, IllegalArgumentException, InvocationTargetException, SecurityException, InstantiationException, NoSuchMethodException, UnsupportedEncodingException, AAIException, URISyntaxException { + HashMap<String, Introspector> relatedVertices = new HashMap<>(); + List<Vertex> vertexChain = queryEngine.findParents(v); + for (Vertex vertex : vertexChain) { + try { + final Introspector vertexObj = serializer.getVertexProperties(vertex); + relatedVertices.put(vertexObj.getObjectId(), vertexObj); + } catch (AAIUnknownObjectException e) { + LOGGER.warn("Unable to get vertex properties, partial list of related vertices returned"); + } + + } + + return relatedVertices; + } + +} diff --git a/aai-resources/src/main/java/org/openecomp/aai/rest/retired/RetiredConsumer.java b/aai-resources/src/main/java/org/openecomp/aai/rest/retired/RetiredConsumer.java new file mode 100644 index 0000000..99974ef --- /dev/null +++ b/aai-resources/src/main/java/org/openecomp/aai/rest/retired/RetiredConsumer.java @@ -0,0 +1,143 @@ +/*- + * ============LICENSE_START======================================================= + * org.openecomp.aai + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.aai.rest.retired; + +import java.util.ArrayList; + +import javax.servlet.http.HttpServletRequest; +import javax.ws.rs.DELETE; +import javax.ws.rs.GET; +import javax.ws.rs.POST; +import javax.ws.rs.PUT; +import javax.ws.rs.Path; +import javax.ws.rs.PathParam; +import javax.ws.rs.core.Context; +import javax.ws.rs.core.HttpHeaders; +import javax.ws.rs.core.Response; +import javax.ws.rs.core.UriInfo; + +import org.apache.cxf.jaxrs.ext.PATCH; + +import org.openecomp.aai.exceptions.AAIException; +import org.openecomp.aai.logging.ErrorLogHelper; +import org.openecomp.aai.restcore.RESTAPI; +import org.openecomp.aai.util.AAIConfig; + +/** + * The Class RetiredConsumer. + */ +public abstract class RetiredConsumer extends RESTAPI { + + /** + * Creates the message get. + * + * @param versionParam the version param + * @param headers the headers + * @param info the info + * @param req the req + * @return the response + */ + @GET + @Path("/{uri:.*}") + public Response createMessageGet(@PathParam("version")String versionParam, @Context HttpHeaders headers, @Context UriInfo info, @Context HttpServletRequest req) { + return createMessage(versionParam, headers, info, req); + } + + /** + * Creates the message delete. + * + * @param versionParam the version param + * @param headers the headers + * @param info the info + * @param req the req + * @return the response + */ + @DELETE + @Path("/{uri:.*}") + public Response createMessageDelete(@PathParam("version")String versionParam, @Context HttpHeaders headers, @Context UriInfo info, @Context HttpServletRequest req) { + return createMessage(versionParam, headers, info, req); + } + + /** + * Creates the message post. + * + * @param versionParam the version param + * @param headers the headers + * @param info the info + * @param req the req + * @return the response + */ + @POST + @Path("/{uri:.*}") + public Response createMessagePost(@PathParam("version")String versionParam, @Context HttpHeaders headers, @Context UriInfo info, @Context HttpServletRequest req) { + return createMessage(versionParam, headers, info, req); + } + + @PATCH + @Path("/{uri:.*}") + public Response createMessagePatch(@PathParam("version")String versionParam, @Context HttpHeaders headers, @Context UriInfo info, @Context HttpServletRequest req) { + return createMessage(versionParam, headers, info, req); + } + /** + * Creates the message put. + * + * @param versionParam the version param + * @param headers the headers + * @param info the info + * @param req the req + * @return the response + */ + @PUT + @Path("/{uri:.*}") + public Response createMessagePut(@PathParam("version")String versionParam, @Context HttpHeaders headers, @Context UriInfo info, @Context HttpServletRequest req) { + return createMessage(versionParam, headers, info, req); + } + + + /** + * Creates the message. + * + * @param versionParam the version param + * @param headers the headers + * @param info the info + * @param req the req + * @return the response + */ + private Response createMessage(String versionParam, HttpHeaders headers, UriInfo info, HttpServletRequest req) { + AAIException e = new AAIException("AAI_3007"); + + ArrayList<String> templateVars = new ArrayList<String>(); + + if (templateVars.size() == 0) { + templateVars.add("PUT"); + templateVars.add(info.getPath().toString()); + templateVars.add(versionParam); + templateVars.add(AAIConfig.get("aai.default.api.version", "")); + } + + Response response = Response + .status(e.getErrorObject().getHTTPResponseCode()) + .entity(ErrorLogHelper.getRESTAPIErrorResponse(headers.getAcceptableMediaTypes(), e, + templateVars)).build(); + + return response; + } +} diff --git a/aai-resources/src/main/java/org/openecomp/aai/rest/retired/V3ThroughV7Consumer.java b/aai-resources/src/main/java/org/openecomp/aai/rest/retired/V3ThroughV7Consumer.java new file mode 100644 index 0000000..5572586 --- /dev/null +++ b/aai-resources/src/main/java/org/openecomp/aai/rest/retired/V3ThroughV7Consumer.java @@ -0,0 +1,28 @@ +/*- + * ============LICENSE_START======================================================= + * org.openecomp.aai + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.aai.rest.retired; + +import javax.ws.rs.Path; + +@Path("{version: v[3-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/openecomp/aai/rest/ueb/NotificationEvent.java b/aai-resources/src/main/java/org/openecomp/aai/rest/ueb/NotificationEvent.java new file mode 100644 index 0000000..389d296 --- /dev/null +++ b/aai-resources/src/main/java/org/openecomp/aai/rest/ueb/NotificationEvent.java @@ -0,0 +1,96 @@ +/*- + * ============LICENSE_START======================================================= + * org.openecomp.aai + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.aai.rest.ueb; + +import org.openecomp.aai.exceptions.AAIException; +import org.openecomp.aai.introspection.Introspector; +import org.openecomp.aai.introspection.Loader; +import org.openecomp.aai.introspection.Version; +import org.openecomp.aai.util.StoreNotificationEvent; + +/** + * The Class NotificationEvent. + */ +public class NotificationEvent { + + private Loader loader = null; + + private Introspector eventHeader = null; + + private Introspector obj = null; + + /** + * Instantiates a new notification event. + * + * @param version the version + * @param eventHeader the event header + * @param obj the obj + */ + public NotificationEvent (Loader loader, Introspector eventHeader, Introspector obj) { + this.loader = loader; + this.eventHeader = eventHeader; + this.obj = obj; + } + + /** + * Trigger. + * + * @throws AAIException the AAI exception + */ + public void trigger() throws AAIException { + + StoreNotificationEvent sne = new StoreNotificationEvent(); + + sne.storeEvent(loader, eventHeader, obj); + + } + + /** + * Gets the notification version. + * + * @return the notification version + */ + public Version getNotificationVersion() { + return loader.getVersion(); + } + + /** + * Gets the event header. + * + * @return the event header + */ + public Introspector getEventHeader() { + return eventHeader; + } + + /** + * Gets the obj. + * + * @return the obj + */ + public Introspector getObj() { + return obj; + } + + + + +} diff --git a/aai-resources/src/main/java/org/openecomp/aai/rest/ueb/UEBNotification.java b/aai-resources/src/main/java/org/openecomp/aai/rest/ueb/UEBNotification.java new file mode 100644 index 0000000..397082f --- /dev/null +++ b/aai-resources/src/main/java/org/openecomp/aai/rest/ueb/UEBNotification.java @@ -0,0 +1,178 @@ +/*- + * ============LICENSE_START======================================================= + * org.openecomp.aai + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.aai.rest.ueb; + +import java.io.UnsupportedEncodingException; +import java.net.URI; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; + +import javax.ws.rs.core.Response.Status; + +import org.openecomp.aai.db.props.AAIProperties; +import org.openecomp.aai.exceptions.AAIException; +import org.openecomp.aai.introspection.Introspector; +import org.openecomp.aai.introspection.Loader; +import org.openecomp.aai.introspection.LoaderFactory; +import org.openecomp.aai.introspection.Version; +import org.openecomp.aai.introspection.exceptions.AAIUnknownObjectException; +import org.openecomp.aai.introspection.exceptions.AAIUnmarshallingException; +import org.openecomp.aai.parsers.uri.URIToObject; +import org.openecomp.aai.util.AAIConfig; +import com.att.eelf.configuration.EELFLogger; +import com.att.eelf.configuration.EELFManager; + +/** + * The Class UEBNotification. + */ +public class UEBNotification { + + private static final EELFLogger LOGGER = EELFManager.getInstance().getLogger(UEBNotification.class); + + private Loader currentVersionLoader = null; + protected List<NotificationEvent> events = null; + private String urlBase = null; + private Version notificationVersion = null; + + /** + * Instantiates a new UEB notification. + * + * @param loader the loader + */ + public UEBNotification(Loader loader) { + events = new ArrayList<>(); + currentVersionLoader = LoaderFactory.createLoaderForVersion(loader.getModelType(), AAIProperties.LATEST); + urlBase = AAIConfig.get("aai.server.url.base",""); + notificationVersion = Version.valueOf(AAIConfig.get("aai.notification.current.version","v10")); + } + + + /** + * Creates the notification event. + * + * @param transactionId the X-TransactionId + * @param sourceOfTruth + * @param status the status + * @param uri the uri + * @param obj the obj + * @throws AAIException the AAI exception + * @throws IllegalArgumentException the illegal argument exception + * @throws UnsupportedEncodingException the unsupported encoding exception + */ + public void createNotificationEvent(String transactionId, String sourceOfTruth, Status status, URI uri, Introspector obj, HashMap<String, Introspector> relatedObjects) throws AAIException, IllegalArgumentException, UnsupportedEncodingException { + + String action = "UPDATE"; + + if (status.equals(Status.CREATED)) { + action = "CREATE"; + } else if (status.equals(Status.OK)) { + action = "UPDATE"; + } else if (status.equals(Status.NO_CONTENT)) { + action = "DELETE"; + } + + try { + Introspector eventHeader = currentVersionLoader.introspectorFromName("notification-event-header"); + URIToObject parser = new URIToObject(currentVersionLoader, uri, relatedObjects); + + String entityLink = ""; + if (uri.toString().startsWith("/")) { + entityLink = urlBase + notificationVersion + uri; + } else { + entityLink = urlBase + notificationVersion + "/" + uri; + } + + + eventHeader.setValue("entity-link", entityLink); + eventHeader.setValue("action", action); + eventHeader.setValue("entity-type", obj.getDbName()); + eventHeader.setValue("top-entity-type", parser.getTopEntityName()); + eventHeader.setValue("source-name", sourceOfTruth); + eventHeader.setValue("version", notificationVersion.toString()); + eventHeader.setValue("id", transactionId); + + List<Object> parentList = parser.getParentList(); + parentList.clear(); + + if (!parser.getTopEntity().equals(parser.getEntity())) { + Introspector child = obj; + if (!parser.getLoader().getVersion().equals(obj.getVersion())) { + String json = obj.marshal(false); + child = parser.getLoader().unmarshal(parser.getEntity().getName(), json); + } + + //wrap the child object in its parents + parentList.add(child.getUnderlyingObject()); + } + + final Introspector eventObject; + + //convert to most resent version + if (!parser.getLoader().getVersion().equals(currentVersionLoader.getVersion())) { + String json = ""; + if (parser.getTopEntity().equals(parser.getEntity())) { + //convert the parent object passed in + json = obj.marshal(false); + eventObject = currentVersionLoader.unmarshal(obj.getName(), json); + } else { + //convert the object created in the parser + json = parser.getTopEntity().marshal(false); + eventObject = currentVersionLoader.unmarshal(parser.getTopEntity().getName(), json); + } + } else { + if (parser.getTopEntity().equals(parser.getEntity())) { + //take the top level parent object passed in + eventObject = obj; + } else { + //take the wrapped child objects (ogres are like onions) + eventObject = parser.getTopEntity(); + } + } + + final NotificationEvent event = new NotificationEvent(currentVersionLoader, eventHeader, eventObject); + events.add(event); + } catch (AAIUnknownObjectException e) { + throw new RuntimeException("Fatal error - notification-event-header object not found!"); + } catch (AAIUnmarshallingException e) { + LOGGER.error("Unmarshalling error occurred while generating UEBNotification", e); + } + } + + /** + * Trigger events. + * + * @throws AAIException the AAI exception + */ + public void triggerEvents() throws AAIException { + for (NotificationEvent event : events) { + event.trigger(); + } + events.clear(); + } + + public List<NotificationEvent> getEvents() { + return this.events; + } + + + +} diff --git a/aai-resources/src/main/java/org/openecomp/aai/rest/util/EchoResponse.java b/aai-resources/src/main/java/org/openecomp/aai/rest/util/EchoResponse.java new file mode 100644 index 0000000..6d01435 --- /dev/null +++ b/aai-resources/src/main/java/org/openecomp/aai/rest/util/EchoResponse.java @@ -0,0 +1,121 @@ +/*- + * ============LICENSE_START======================================================= + * org.openecomp.aai + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.aai.rest.util; + +import java.util.ArrayList; +import java.util.HashMap; + +import javax.servlet.http.HttpServletRequest; +import javax.ws.rs.GET; +import javax.ws.rs.Path; +import javax.ws.rs.Produces; +import javax.ws.rs.QueryParam; +import javax.ws.rs.core.Context; +import javax.ws.rs.core.HttpHeaders; +import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.Response; +import javax.ws.rs.core.Response.Status; + +import org.openecomp.aai.exceptions.AAIException; +import org.openecomp.aai.logging.ErrorLogHelper; +import org.openecomp.aai.restcore.RESTAPI; + +/** + * The Class EchoResponse. + */ +public class EchoResponse extends RESTAPI { + + protected static String authPolicyFunctionName = "util"; + + public static final String echoPath = "/util/echo"; + + /** + * Simple health-check API that echos back the X-FromAppId and X-TransactionId to clients. + * If there is a query string, a transaction gets logged into hbase, proving the application is connected to the data store. + * If there is no query string, no transacction logging is done to hbase. + * + * @param headers the headers + * @param req the req + * @param myAction if exists will cause transaction to be logged to hbase + * @return the response + */ + @GET + @Produces( { MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON }) + @Path(echoPath) + public Response echoResult(@Context HttpHeaders headers, @Context HttpServletRequest req, + @QueryParam("action") String myAction) { + Response response = null; + + AAIException ex = null; + String fromAppId = null; + String transId = null; + + try { + fromAppId = getFromAppId(headers ); + transId = getTransId(headers); + } catch (AAIException e) { + ArrayList<String> templateVars = new ArrayList<String>(); + templateVars.add("PUT uebProvider"); + templateVars.add("addTopic"); + return Response + .status(e.getErrorObject().getHTTPResponseCode()) + .entity(ErrorLogHelper.getRESTAPIErrorResponse(headers.getAcceptableMediaTypes(), e, templateVars)) + .build(); + } + + try { + + HashMap<AAIException, ArrayList<String>> exceptionList = new HashMap<AAIException, ArrayList<String>>(); + + ArrayList<String> templateVars = new ArrayList<String>(); + templateVars.add(fromAppId); + templateVars.add(transId); + + exceptionList.put(new AAIException("AAI_0002", "OK"), templateVars); + + response = Response.status(Status.OK) + .entity(ErrorLogHelper.getRESTAPIInfoResponse( + headers.getAcceptableMediaTypes(), exceptionList)) + .build(); + + } catch (Exception e) { + ex = new AAIException("AAI_4000", e); + ArrayList<String> templateVars = new ArrayList<String>(); + templateVars.add(Action.GET.name()); + templateVars.add(fromAppId +" "+transId); + + response = Response + .status(Status.INTERNAL_SERVER_ERROR) + .entity(ErrorLogHelper.getRESTAPIErrorResponse( + headers.getAcceptableMediaTypes(), ex, + templateVars)).build(); + + } finally { + if (ex != null) { + ErrorLogHelper.logException(ex); + } + + } + + return response; + } + +} diff --git a/aai-resources/src/main/java/org/openecomp/aai/rest/util/LogFormatTools.java b/aai-resources/src/main/java/org/openecomp/aai/rest/util/LogFormatTools.java new file mode 100644 index 0000000..d6fcd67 --- /dev/null +++ b/aai-resources/src/main/java/org/openecomp/aai/rest/util/LogFormatTools.java @@ -0,0 +1,36 @@ +/*- + * ============LICENSE_START======================================================= + * org.openecomp.aai + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.aai.rest.util; + +import java.time.ZoneOffset; +import java.time.ZonedDateTime; +import java.time.format.DateTimeFormatter; + +public class LogFormatTools { + + private static final String DATE_FORMAT = "yyyy-MM-dd'T'HH:mm:ss.SSSZ"; + private static final DateTimeFormatter DTF = DateTimeFormatter.ofPattern(DATE_FORMAT) + .withZone(ZoneOffset.UTC); + + public static String getCurrentDateTime() { + return DTF.format(ZonedDateTime.now()); + } +} diff --git a/aai-resources/src/main/java/org/openecomp/aai/rest/util/ValidateEncoding.java b/aai-resources/src/main/java/org/openecomp/aai/rest/util/ValidateEncoding.java new file mode 100644 index 0000000..a09a317 --- /dev/null +++ b/aai-resources/src/main/java/org/openecomp/aai/rest/util/ValidateEncoding.java @@ -0,0 +1,160 @@ +/*- + * ============LICENSE_START======================================================= + * org.openecomp.aai + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.aai.rest.util; + +import java.io.UnsupportedEncodingException; +import java.net.URI; + +import javax.ws.rs.core.MultivaluedMap; +import javax.ws.rs.core.UriInfo; + +import org.springframework.web.util.UriUtils; + +/** + * The Class ValidateEncoding. + */ +public class ValidateEncoding { + + private final String encoding = "UTF-8"; + + /** + * Instantiates a new validate encoding. + */ + private ValidateEncoding() { + + } + + /** + * The Class Helper. + */ + private static class Helper { + + /** The Constant INSTANCE. */ + private static final ValidateEncoding INSTANCE = new ValidateEncoding(); + } + + /** + * Gets the single instance of ValidateEncoding. + * + * @return single instance of ValidateEncoding + */ + public static ValidateEncoding getInstance() { + return Helper.INSTANCE; + } + + /** + * Validate. + * + * @param uri the uri + * @return true, if successful + * @throws UnsupportedEncodingException the unsupported encoding exception + */ + public boolean validate(URI uri) throws UnsupportedEncodingException { + boolean result = true; + if (!validatePath(uri.getRawPath())) { + result = false; + } + /*if (!validateQueryParams(uri.getRawQuery())) { + result = false; + } //TODO + */ + + return result; + } + + /** + * Validate. + * + * @param info the info + * @return true, if successful + * @throws UnsupportedEncodingException the unsupported encoding exception + */ + public boolean validate(UriInfo info) throws UnsupportedEncodingException { + boolean result = true; + if (!validatePath(info.getPath(false))) { + result = false; + } + if (!validateQueryParams(info.getQueryParameters(false))) { + result = false; + } + + return result; + } + + /** + * Validate path. + * + * @param path the path + * @return true, if successful + * @throws UnsupportedEncodingException the unsupported encoding exception + */ + private boolean validatePath(String path) throws UnsupportedEncodingException { + String[] segments = path.split("/"); + boolean valid = true; + for (String segment : segments) { + if (!this.checkEncoding(segment)) { + valid = false; + } + } + + return valid; + + } + + /** + * Validate query params. + * + * @param params the params + * @return true, if successful + * @throws UnsupportedEncodingException the unsupported encoding exception + */ + private boolean validateQueryParams(MultivaluedMap<String, String> params) throws UnsupportedEncodingException { + boolean valid = true; + + for (String key : params.keySet()) { + if (!this.checkEncoding(key)) { + valid = false; + } + for (String item : params.get(key)) { + if (!this.checkEncoding(item)) { + valid = false; + } + } + } + return valid; + } + + /** + * Check encoding. + * + * @param segment the segment + * @return true, if successful + * @throws UnsupportedEncodingException the unsupported encoding exception + */ + private boolean checkEncoding(String segment) throws UnsupportedEncodingException { + boolean result = false; + String decode = UriUtils.decode(segment, encoding); + String encode = UriUtils.encode(decode, encoding); + result = segment.equals(encode); + + return result; + } +} diff --git a/aai-resources/src/main/java/org/openecomp/aai/transforms/Converter.java b/aai-resources/src/main/java/org/openecomp/aai/transforms/Converter.java new file mode 100644 index 0000000..44a0222 --- /dev/null +++ b/aai-resources/src/main/java/org/openecomp/aai/transforms/Converter.java @@ -0,0 +1,25 @@ +/*- + * ============LICENSE_START======================================================= + * org.openecomp.aai + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.aai.transforms; + +public interface Converter { + String convert(String input); +} diff --git a/aai-resources/src/main/java/org/openecomp/aai/transforms/LowerCamelToLowerHyphenConverter.java b/aai-resources/src/main/java/org/openecomp/aai/transforms/LowerCamelToLowerHyphenConverter.java new file mode 100644 index 0000000..a31da05 --- /dev/null +++ b/aai-resources/src/main/java/org/openecomp/aai/transforms/LowerCamelToLowerHyphenConverter.java @@ -0,0 +1,34 @@ +/*- + * ============LICENSE_START======================================================= + * org.openecomp.aai + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.aai.transforms; + +import com.google.common.base.CaseFormat; + +public class LowerCamelToLowerHyphenConverter implements Converter { + + @Override + public String convert(String input) { + if(input == null){ + return null; + } + return CaseFormat.LOWER_CAMEL.to(CaseFormat.LOWER_HYPHEN, input); + } +} diff --git a/aai-resources/src/main/java/org/openecomp/aai/transforms/LowerHyphenToLowerCamelConverter.java b/aai-resources/src/main/java/org/openecomp/aai/transforms/LowerHyphenToLowerCamelConverter.java new file mode 100644 index 0000000..784adbe --- /dev/null +++ b/aai-resources/src/main/java/org/openecomp/aai/transforms/LowerHyphenToLowerCamelConverter.java @@ -0,0 +1,81 @@ +/*- + * ============LICENSE_START======================================================= + * org.openecomp.aai + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.aai.transforms; + +/** + * <b>LowerHyphenToLowerCamelConverter</b> is the converter to use + * for converting from the lower hyphen to lower camel case + * <p> + * Examples: + * lower-test => lowerTest + * lower-Test => lowerTest + * lowerTest => lowerTest + * lower-test-val => lowerTestVal + * <p> + * + */ +public class LowerHyphenToLowerCamelConverter implements Converter { + + /** + * Converts the dash formatted string into a camel case string + * Ensure that the capitalization is not lost during this conversion + * <p> + * Loops through each character in the string + * checks if the current character is '-' and if it is then sets the + * boolean isPreviousCharDash to true and continues to the next iteration + * If the character is not '-', then checks if the previous character is dash + * If it is, then it will upper case the current character and appends to the builder + * Otherwise, it will just append the current character without any modification + * + * @param input the input string to convert to camel case + * @return a string that is converted to camel case + * if the input is null, then it returns null + */ + @Override + public String convert(String input) { + if(input == null){ + return null; + } + + int size = input.length(); + StringBuilder builder = new StringBuilder(size); + + boolean isPreviousCharDash = false; + + for(int index = 0; index < size; ++index){ + char ch = input.charAt(index); + + if(ch == '-'){ + isPreviousCharDash = true; + continue; + } + if(isPreviousCharDash){ + builder.append(Character.toUpperCase(ch)); + isPreviousCharDash = false; + } else{ + builder.append(ch); + } + } + + return builder.toString(); + } + +} diff --git a/aai-resources/src/main/java/org/openecomp/aai/transforms/MapTraverser.java b/aai-resources/src/main/java/org/openecomp/aai/transforms/MapTraverser.java new file mode 100644 index 0000000..7695240 --- /dev/null +++ b/aai-resources/src/main/java/org/openecomp/aai/transforms/MapTraverser.java @@ -0,0 +1,87 @@ +/*- + * ============LICENSE_START======================================================= + * org.openecomp.aai + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.aai.transforms; + + +import joptsimple.internal.Objects; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +public class MapTraverser { + + private Converter converter; + + public MapTraverser(Converter converter){ + this.converter = converter; + } + + public Map<String, Object> convertKeys(Map<String, Object> map){ + + Objects.ensureNotNull(map); + + Map<String, Object> modifiedMap = new HashMap<String, Object>(); + convertKeys(map, modifiedMap); + + return modifiedMap; + } + + private Map<String, Object> convertKeys(Map<String, Object> original, Map<String, Object> modified){ + + for(Map.Entry<String, Object> entry : original.entrySet()){ + String key = entry.getKey(); + key = converter.convert(key); + Object value = entry.getValue(); + if(value instanceof Map){ + modified.put(key, convertKeys((Map<String, Object>)value, new HashMap<String, Object>())); + } else if(value instanceof List){ + modified.put(key, convertKeys((List<Object>) value)); + } else { + modified.put(key, value); + } + } + + return modified; + } + + public List<Object> convertKeys(List<Object> list){ + + List<Object> modifiedList = new ArrayList<Object>(); + if(list != null && list.size() > 0){ + + for(Object o : list){ + if(o instanceof Map){ + Map<String, Object> map = (Map<String, Object>) o; + modifiedList.add(convertKeys(map)); + } else if(o instanceof List){ + List<Object> l = (List<Object>) o; + modifiedList.add(convertKeys(l)); + } else { + modifiedList.add(o); + } + } + } + + return modifiedList; + } +} diff --git a/aai-resources/src/main/java/org/openecomp/aai/util/AAIAppServletContextListener.java b/aai-resources/src/main/java/org/openecomp/aai/util/AAIAppServletContextListener.java new file mode 100644 index 0000000..773b4a6 --- /dev/null +++ b/aai-resources/src/main/java/org/openecomp/aai/util/AAIAppServletContextListener.java @@ -0,0 +1,104 @@ +/*- + * ============LICENSE_START======================================================= + * org.openecomp.aai + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.aai.util; + +import java.io.IOException; + +import javax.servlet.ServletContextEvent; +import javax.servlet.ServletContextListener; + +//import org.apache.activemq.broker.BrokerService; + +import org.openecomp.aai.dbmap.AAIGraph; +import org.openecomp.aai.exceptions.AAIException; +import org.openecomp.aai.introspection.ModelInjestor; +import org.openecomp.aai.logging.ErrorLogHelper; +import com.att.eelf.configuration.EELFLogger; +import com.att.eelf.configuration.EELFManager; + +public class AAIAppServletContextListener implements ServletContextListener { + + private static final EELFLogger LOGGER = EELFManager.getInstance().getLogger(AAIAppServletContextListener.class.getName()); + + //private BrokerService broker = new BrokerService(); + + /** + * Destroys Context + * + * @param arg0 the ServletContextEvent + */ + public void contextDestroyed(ServletContextEvent arg0) { + LOGGER.info("AAIGraph shutting down"); + AAIGraph.getInstance().graphShutdown(); + LOGGER.info("AAIGraph shutdown"); + + try { +// broker.stop(); + } catch (Exception e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + } + + /** + * Initializes Context + * + * @param arg0 the ServletContextEvent + */ + public void contextInitialized(ServletContextEvent arg0) { + System.setProperty("org.openecomp.aai.serverStarted", "false"); + LOGGER.info("***AAI Server initialization started..."); + + try { + LOGGER.info("Loading aaiconfig.properties"); + AAIConfig.init(); + + LOGGER.info("Loading error.properties"); + ErrorLogHelper.loadProperties(); + + LOGGER.info("Loading graph database"); + + AAIGraph.getInstance(); + ModelInjestor.getInstance(); + + // Jsm internal broker for aai events + //broker = new BrokerService(); + //broker.addConnector("tcp://localhost:61447"); + //broker.setPersistent(false); + //broker.setUseJmx(false); + //broker.setSchedulerSupport(false); + //broker.start(); + + LOGGER.info("A&AI Server initialization succcessful."); + System.setProperty("org.openecomp.aai.serverStarted", "true"); + + } catch (AAIException e) { + ErrorLogHelper.logException(e); + throw new RuntimeException("AAIException caught while initializing A&AI server", e); + } catch (IOException e) { + ErrorLogHelper.logError("AAI_4000", e.getMessage()); + throw new RuntimeException("IOException caught while initializing A&AI server", e); + } catch (Exception e) { + LOGGER.error("Unknown failure while initializing A&AI Server", e); + throw new RuntimeException("Unknown failure while initializing A&AI server", e); + } + } +} diff --git a/aai-resources/src/main/java/org/openecomp/aai/util/GenerateMethodMapper.java b/aai-resources/src/main/java/org/openecomp/aai/util/GenerateMethodMapper.java new file mode 100644 index 0000000..dd72530 --- /dev/null +++ b/aai-resources/src/main/java/org/openecomp/aai/util/GenerateMethodMapper.java @@ -0,0 +1,142 @@ +/*- + * ============LICENSE_START======================================================= + * org.openecomp.aai + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.aai.util; + +import java.io.FileWriter; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.Map; + +import org.json.JSONArray; +import org.json.JSONException; +import org.json.JSONObject; + +import org.openecomp.aai.audit.ListEndpoints; +import org.openecomp.aai.introspection.Version; + +public class GenerateMethodMapper { + + private final static String filePath = "bundleconfig-local/etc/appprops/methodMapper.properties"; + + /** + * The main method. + * + * @param args the arguments + * @throws Exception the exception + */ + public static void main(String[] args) throws Exception { + + ListEndpoints le = null; + JSONObject jo = new JSONObject(); + JSONArray ja = new JSONArray(); + + for (Version version : Version.values()) { + + le = new ListEndpoints(version); + Map<String, String> ln = le.getLogicalNames(); + List<String> keys = new ArrayList<String>(ln.keySet()); + Collections.sort(keys); + for (String key : keys) { + addEndpointToJsonArray(key, ln.get(key), ja, version.toString()); + } + + } + + addUniqueEndpoints(ja); + + jo.put("ActiveAndAvailableInventory-CloudNetwork", ja); + try (FileWriter file = new FileWriter(filePath)) { + file.write(jo.toString(4)); + } + + System.exit(0); + + } + + /** + * Adds the unique endpoints. + * + * @param ja the ja + * @throws JSONException the JSON exception + */ + private static void addUniqueEndpoints(JSONArray ja) throws JSONException { + JSONObject joItem = new JSONObject(); + joItem.put("url", "/aai/{version}/service-design-and-creation/models*"); + joItem.put("method", "get"); + joItem.put("logicalName", "GetModel"); + ja.put(joItem); + joItem = new JSONObject(); + joItem.put("url", "/aai/{version}/service-design-and-creation/models*"); + joItem.put("method", "put"); + joItem.put("logicalName", "PutModel"); + ja.put(joItem); + joItem = new JSONObject(); + joItem.put("url", "/aai/{version}/service-design-and-creation/models*"); + joItem.put("method", "delete"); + joItem.put("logicalName", "DeleteModel"); + ja.put(joItem); + joItem = new JSONObject(); + joItem.put("url", "/aai/{version}/service-design-and-creation/named-queries/*"); + joItem.put("method", "get"); + joItem.put("logicalName", "GetNamedQuery"); + ja.put(joItem); + } + + /** + * Adds the endpoint to json array. + * + * @param url the url + * @param name the name + * @param ja the ja + * @param apiVersion the api version + * @throws JSONException the JSON exception + */ + private static void addEndpointToJsonArray(String url, String name, JSONArray ja, String apiVersion) + throws JSONException { + + JSONObject joGet = new JSONObject(); + JSONObject joPut = new JSONObject(); + JSONObject joDel = new JSONObject(); + + if (!url.endsWith("relationship")) { + joGet.put("url", url); + joGet.put("method", "get"); + joGet.put("logicalName", apiVersion + "Get" + name); + ja.put(joGet); + } + + if (url.endsWith("}") || url.endsWith("relationship")) { + joPut.put("url", url); + joPut.put("method", "put"); + joPut.put("logicalName", apiVersion + "Put" + name); + ja.put(joPut); + + joDel.put("url", url); + joDel.put("method", "delete"); + joDel.put("logicalName", apiVersion + "Delete" + name); + ja.put(joDel); + + } + + } + +} diff --git a/aai-resources/src/main/java/org/openecomp/aai/util/MergeResource.java b/aai-resources/src/main/java/org/openecomp/aai/util/MergeResource.java new file mode 100644 index 0000000..427f65b --- /dev/null +++ b/aai-resources/src/main/java/org/openecomp/aai/util/MergeResource.java @@ -0,0 +1,205 @@ +/*- + * ============LICENSE_START======================================================= + * org.openecomp.aai + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.aai.util; + +import java.lang.reflect.Field; +import java.lang.reflect.Method; +import java.util.Date; + +import com.sun.tools.javac.util.List; + +//SWGK - 01/08/2016 - Helper function to deal with concurrency control +public class MergeResource { + + //Merge Assumptions: + //fromresource and toresource are the same resource type and same resource object + //fromresource is the latest version from the DB + //toresource is the version of the same resource with updates + //merging of child elements are complete overwrite of fromresource corresponding child element + //merging of relationshiplist is complete overwrite of fromresource corresponding releationship element + //In case of supplying the only specific child element update, please specify the child element type (need not be in canonical form) + //For parent only update (not involving child or relationship element update), then all the child elements and relationship list will be set as null in the merged object + //For setting null to primitive type (including String) you have to do it after the merge is called specifically for parent only copy + + + /** + * Merge. + * + * @param <T> the generic type + * @param fromresource the fromresource + * @param toresource the toresource + * @param bupdateChildren the bupdate children + * @param childNamelist the child namelist + * @param bupdateRelatedLink the bupdate related link + * @return the t + */ + public static <T> T merge(T fromresource, T toresource, boolean bupdateChildren, String childNamelist[], boolean bupdateRelatedLink) + { + Field[] fields = fromresource.getClass().getDeclaredFields(); + if (fields != null) + { + for (Field field : fields) + { + try + { + field.setAccessible(true); + if ( field.getName().equalsIgnoreCase("resourceVersion") ) + continue; + if ( isValidMergeType(field.getType()) ) + { + Object obj = field.get(toresource); + // If the updated resource's any property to be set null then one has to set it separately for the merged object + if (obj != null) + field.set(fromresource, obj); + continue; + } + else + // set the child list or relatedTo link to be null so no updates takes place + field.set(fromresource, null); + //override situation + if (bupdateChildren || bupdateRelatedLink) + { + if (bupdateRelatedLink && field.getName().equalsIgnoreCase("relationshipList")) + { + Object obj = field.get(toresource); + field.set(fromresource, obj); + continue; + } + if (field.getName().equalsIgnoreCase("relationshipList")) + if (!bupdateRelatedLink) + continue; + // not an efficient as it blindly updates all children - onus is on callee to nullify + // specific child(ren) that they don't want to update after the merge call. + // can be optimized to send a list of children class names in canonical form + // but deferring for next release so that only those children can be merged + if (bupdateChildren && (childNamelist != null)) + { + for (String classStringName : childNamelist) + { + if ( !classStringName.isEmpty() && field.getType().toString().toLowerCase().endsWith(classStringName.toLowerCase()) ) + { + Object obj = field.get(toresource); + field.set(fromresource, obj); + } + } + continue; + } + + if (bupdateChildren && (childNamelist == null)) + { + Object obj = field.get(toresource); + field.set(fromresource, obj); + + } + } + + } + catch (Exception e) + { + + } + + + } + } + return fromresource; + } + + + /** + * Merge. + * + * @param <T> the generic type + * @param fromresource the fromresource + * @param toresource the toresource + * @return the t + */ + public static <T> T merge(T fromresource, T toresource) + { + return merge(fromresource, toresource, false, false); + } + + /** + * Merge. + * + * @param <T> the generic type + * @param fromresource the fromresource + * @param toresource the toresource + * @param bupdateChildren the bupdate children + * @param bupdateRelatedLink the bupdate related link + * @return the t + */ + public static <T> T merge(T fromresource, T toresource, boolean bupdateChildren, boolean bupdateRelatedLink) + { + return merge(fromresource, toresource, bupdateChildren, null, bupdateRelatedLink); + } + + /** + * Checks if is valid merge type. + * + * @param fieldType the field type + * @return true, if is valid merge type + */ + public static boolean isValidMergeType(Class<?> fieldType) { + if (fieldType.equals(String.class)) { + return true; + } else if (Date.class.isAssignableFrom(fieldType)) { + return true; + } else if (Number.class.isAssignableFrom(fieldType)) { + return true; + } else if (fieldType.equals(Integer.TYPE)) { + return true; + } else if (fieldType.equals(Long.TYPE)) { + return true; + } else if (Enum.class.isAssignableFrom(fieldType)) { + return true; + } else if (Boolean.class.isAssignableFrom(fieldType)) { + return true; + } + else { + return false; + } + } + + /** + * Gets the child return type. + * + * @param classname the classname + * @param methodname the methodname + * @return the class + */ + public static Class<?> GetChildReturnType(String classname, String methodname) + { + try { + Class<?> c = Class.forName(classname); + Method[] allMethods = c.getDeclaredMethods(); + for (Method m : allMethods) { + if (!m.getName().equals(methodname)) { + return m.getReturnType(); + } + } + } catch (ClassNotFoundException x) { + + } + + return null; + } +} diff --git a/aai-resources/src/main/java/org/openecomp/aai/util/PojoUtils.java b/aai-resources/src/main/java/org/openecomp/aai/util/PojoUtils.java new file mode 100644 index 0000000..870ddec --- /dev/null +++ b/aai-resources/src/main/java/org/openecomp/aai/util/PojoUtils.java @@ -0,0 +1,738 @@ +/*- + * ============LICENSE_START======================================================= + * org.openecomp.aai + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.aai.util; + +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.core.JsonGenerationException; +import com.fasterxml.jackson.databind.DeserializationFeature; +import com.fasterxml.jackson.databind.JsonMappingException; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.SerializationFeature; +import com.fasterxml.jackson.module.jaxb.JaxbAnnotationModule; +import com.google.common.base.CaseFormat; +import com.google.common.collect.Multimap; +import com.thinkaurelius.titan.core.TitanVertex; +import org.apache.commons.io.output.ByteArrayOutputStream; +import org.eclipse.persistence.dynamic.DynamicEntity; +import org.eclipse.persistence.dynamic.DynamicType; +import org.eclipse.persistence.jaxb.MarshallerProperties; +import org.openecomp.aai.domain.model.AAIResource; +import org.openecomp.aai.exceptions.AAIException; + +import javax.xml.bind.JAXBContext; +import javax.xml.bind.JAXBException; +import javax.xml.bind.Marshaller; +import java.io.IOException; +import java.io.StringWriter; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.util.*; +import java.util.Map.Entry; + +public class PojoUtils { + + /** + * Gets the key value list. + * + * @param <T> the generic type + * @param e the e + * @param clazz the clazz + * @return the key value list + * @throws IllegalAccessException the illegal access exception + * @throws IllegalArgumentException the illegal argument exception + * @throws InvocationTargetException the invocation target exception + */ + public <T> List<KeyValueList> getKeyValueList(Entity e, T clazz) throws IllegalAccessException, IllegalArgumentException, InvocationTargetException { + List<KeyValueList> kvList = e.getKeyValueList(); + Object value = null; + Method[] methods = clazz.getClass().getDeclaredMethods(); + String propertyName = ""; + + for (Method method : methods) { + if (method.getName().startsWith("get")) { + propertyName = CaseFormat.UPPER_CAMEL.to(CaseFormat.LOWER_HYPHEN,method.getName().substring(3)); + if (!(method.getReturnType().getName().contains("aai")) || method.getReturnType().getName().contains("java.util.List")) { + value = method.invoke(clazz); + KeyValueList kv = new KeyValueList(); + kv.setKey(propertyName); + if (value != null) { + kv.setValue(value.toString()); + } else { + kv.setValue(""); + } + kvList.add(kv); + } + } + } + return kvList; + } + + /** + * Gets the json from object. + * + * @param <T> the generic type + * @param clazz the clazz + * @return the json from object + * @throws JsonGenerationException the json generation exception + * @throws JsonMappingException the json mapping exception + * @throws IOException Signals that an I/O exception has occurred. + */ + public <T> String getJsonFromObject(T clazz) throws JsonGenerationException, JsonMappingException, IOException { + return getJsonFromObject(clazz, false, true); + } + + /** + * Gets the json from object. + * + * @param <T> the generic type + * @param clazz the clazz + * @param wrapRoot the wrap root + * @param indent the indent + * @return the json from object + * @throws JsonGenerationException the json generation exception + * @throws JsonMappingException the json mapping exception + * @throws IOException Signals that an I/O exception has occurred. + */ + public <T> String getJsonFromObject(T clazz, boolean wrapRoot, boolean indent) throws JsonGenerationException, JsonMappingException, IOException { + ObjectMapper mapper = new ObjectMapper(); + + mapper.setSerializationInclusion(JsonInclude.Include.NON_NULL); + + mapper.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false); + mapper.configure(SerializationFeature.INDENT_OUTPUT, indent); + mapper.configure(SerializationFeature.WRAP_ROOT_VALUE, wrapRoot); + + mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); + mapper.configure(DeserializationFeature.UNWRAP_ROOT_VALUE, wrapRoot); + + mapper.registerModule(new JaxbAnnotationModule()); + + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + + mapper.writeValue(baos, clazz); + + return baos.toString(); + } + + /** + * Gets the json from dynamic object. + * + * @param ent the ent + * @param jaxbContext the jaxb context + * @param includeRoot the include root + * @return the json from dynamic object + * @throws JsonGenerationException the json generation exception + * @throws JsonMappingException the json mapping exception + * @throws IOException Signals that an I/O exception has occurred. + * @throws JAXBException the JAXB exception + */ + public String getJsonFromDynamicObject(DynamicEntity ent, org.eclipse.persistence.jaxb.JAXBContext jaxbContext, boolean includeRoot) throws JsonGenerationException, JsonMappingException, IOException, JAXBException { + org.eclipse.persistence.jaxb.JAXBMarshaller marshaller = jaxbContext.createMarshaller(); + + marshaller.setProperty(org.eclipse.persistence.jaxb.JAXBMarshaller.JAXB_FORMATTED_OUTPUT, false); + marshaller.setProperty(MarshallerProperties.JSON_MARSHAL_EMPTY_COLLECTIONS, Boolean.FALSE) ; + marshaller.setProperty("eclipselink.json.include-root", includeRoot); + marshaller.setProperty("eclipselink.media-type", "application/json"); + StringWriter writer = new StringWriter(); + marshaller.marshal(ent, writer); + + return writer.toString(); + } + + /** + * Gets the xml from object. + * + * @param <T> the generic type + * @param clazz the clazz + * @return the xml from object + * @throws JAXBException the JAXB exception + */ + public <T> String getXmlFromObject(T clazz) throws JAXBException { + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + JAXBContext jc = JAXBContext.newInstance(clazz.getClass().getPackage().getName()); + + Marshaller marshaller = jc.createMarshaller(); + marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true); + marshaller.marshal(clazz, baos); + + return baos.toString(); + } + + /** + * Gets the lookup key. + * + * @param baseKey the base key + * @param lookupHash the lookup hash + * @param keyProps the key props + * @return the lookup key + */ + public String getLookupKey (String baseKey, HashMap<String,Object> lookupHash, Collection<String> keyProps) { + int baseKeyLen = baseKey.length(); + StringBuffer newKey = new StringBuffer(); + if (baseKeyLen > 0) { + newKey.append(baseKey); + } + + Iterator <String> keyPropI = keyProps.iterator(); + while( keyPropI.hasNext() ){ + String keyProp = keyPropI.next(); + if (baseKeyLen > 0) { + newKey.append("&"); + } + newKey.append(keyProp + "=" + lookupHash.get(keyProp)); + } + return newKey.toString(); + } + + /** + * Gets the lookup keys. + * + * @param lookupHashes the lookup hashes + * @param _dbRulesNodeKeyProps the db rules node key props + * @return the lookup keys + */ + public String getLookupKeys (LinkedHashMap<String,HashMap<String,Object>> lookupHashes, Multimap<String, String> _dbRulesNodeKeyProps) { + Iterator<String> it = lookupHashes.keySet().iterator(); + String lookupKeys = ""; + while (it.hasNext()) { + String objectType = (String)it.next(); + HashMap<String,Object> lookupHash = lookupHashes.get(objectType); + + Collection<String> keyProps = _dbRulesNodeKeyProps.get(objectType); + Iterator <String> keyPropI = keyProps.iterator(); + while( keyPropI.hasNext() ){ + lookupKeys += lookupHash.get(keyPropI.next()); + } + } + return lookupKeys; + } + + /** + * Gets the example object. + * + * @param <T> the generic type + * @param clazz the clazz + * @param singleton the singleton + * @return the example object + * @throws IllegalAccessException the illegal access exception + * @throws IllegalArgumentException the illegal argument exception + * @throws InvocationTargetException the invocation target exception + * @throws NoSuchMethodException the no such method exception + * @throws SecurityException the security exception + * @throws AAIException the AAI exception + */ + public <T> void getExampleObject(T clazz, boolean singleton) throws IllegalAccessException, IllegalArgumentException, InvocationTargetException, NoSuchMethodException, SecurityException, AAIException { + Method[] methods = clazz.getClass().getDeclaredMethods(); + String dnHypPropertyName = ""; + String upCamPropertyName = ""; + Random rand = new Random(); + int randInt = rand.nextInt(10000000); + + for (Method method : methods) { + boolean go = false; + if (method.getName().startsWith("get")) { + dnHypPropertyName = CaseFormat.UPPER_CAMEL.to(CaseFormat.LOWER_HYPHEN,method.getName().substring(3)); + upCamPropertyName = CaseFormat.UPPER_CAMEL.to(CaseFormat.UPPER_CAMEL,method.getName().substring(3)); + go = true; + } else if (method.getName().startsWith("is")) { + dnHypPropertyName = CaseFormat.UPPER_CAMEL.to(CaseFormat.LOWER_HYPHEN,method.getName().substring(2)); + upCamPropertyName = CaseFormat.UPPER_CAMEL.to(CaseFormat.UPPER_CAMEL,method.getName().substring(2)); + go = true; + } + // don't return resource-version on a singleton + if (singleton && dnHypPropertyName.equals("resource-version")) { + go = false; + } + if (go) { + String retType = method.getReturnType().getName(); + if (!retType.contains("aai") && !retType.contains("java.util.List")) { + // get the setter + Method meth = clazz.getClass().getMethod("set" + upCamPropertyName, method.getReturnType()); + + if (retType.contains("String")) { + String val = "example-" + dnHypPropertyName + "-val-" + randInt; + if (val != null) { + meth.invoke(clazz, val); + } + } else if (retType.toLowerCase().contains("long")) { + Integer foo = rand.nextInt(100000); + meth.invoke(clazz, foo.longValue()); + } else if (retType.toLowerCase().contains("int")) { + meth.invoke(clazz, rand.nextInt(100000)); + } else if (retType.toLowerCase().contains("short")) { + Integer randShort = rand.nextInt(10000); + meth.invoke(clazz, randShort.shortValue()); + } else if (retType.toLowerCase().contains("boolean")) { + meth.invoke(clazz, true); + } + } + } + } + } + + + /** + * Gets the aai object from vertex. + * + * @param <T> the generic type + * @param clazz the clazz + * @param vert the vert + * @param _propertyDataTypeMap the property data type map + * @return the aai object from vertex + * @throws IllegalAccessException the illegal access exception + * @throws IllegalArgumentException the illegal argument exception + * @throws InvocationTargetException the invocation target exception + * @throws NoSuchMethodException the no such method exception + * @throws SecurityException the security exception + * @throws AAIException the AAI exception + */ + public <T> void getAaiObjectFromVertex(T clazz, TitanVertex vert, Map<String, String> _propertyDataTypeMap) throws IllegalAccessException, IllegalArgumentException, InvocationTargetException, NoSuchMethodException, SecurityException, AAIException { + Method[] methods = clazz.getClass().getDeclaredMethods(); + String dnHypPropertyName = ""; + String upCamPropertyName = ""; + for (Method method : methods) { + boolean go = false; + if (method.getName().startsWith("get")) { + dnHypPropertyName = CaseFormat.UPPER_CAMEL.to(CaseFormat.LOWER_HYPHEN,method.getName().substring(3)); + upCamPropertyName = CaseFormat.UPPER_CAMEL.to(CaseFormat.UPPER_CAMEL,method.getName().substring(3)); + go = true; + } else if (method.getName().startsWith("is")) { + dnHypPropertyName = CaseFormat.UPPER_CAMEL.to(CaseFormat.LOWER_HYPHEN,method.getName().substring(2)); + upCamPropertyName = CaseFormat.UPPER_CAMEL.to(CaseFormat.UPPER_CAMEL,method.getName().substring(2)); + go = true; + } + if (go) { + String retType = method.getReturnType().getName(); + if (!retType.contains("aai") && !retType.contains("java.util.List")) { + // get the setter + Method meth = clazz.getClass().getMethod("set" + upCamPropertyName, method.getReturnType()); + + if (retType.contains("String")) { + String val = (String)vert.<String>property(dnHypPropertyName).orElse(null); + if (val != null) { + meth.invoke(clazz, val); + } + } else if (retType.toLowerCase().contains("long")) { + String titanType = _propertyDataTypeMap.get(dnHypPropertyName); + + Long val = null; + // we have a case where the type in titan is "Integer" but in the POJO it's Long or long + if (titanType.toLowerCase().contains("int")) { + Integer intVal = (Integer)vert.<Integer>property(dnHypPropertyName).orElse(null); + if (intVal != null) { + val = intVal.longValue(); + } + } else { + val = (Long)vert.<Long>property(dnHypPropertyName).orElse(null); + } + if (val != null) { + meth.invoke(clazz, val); + } + } else if (retType.toLowerCase().contains("int")) { + Integer val = (Integer)vert.<Integer>property(dnHypPropertyName).orElse(null); + if (val != null) { + meth.invoke(clazz, val); + } + } else if (retType.toLowerCase().contains("short")) { + Short val = (Short)vert.<Short>property(dnHypPropertyName).orElse(null); + if (val != null) { + meth.invoke(clazz, val); + } + } else if (retType.toLowerCase().contains("boolean")) { + Boolean val = (Boolean)vert.<Boolean>property(dnHypPropertyName).orElse(null); + if (val != null) { + meth.invoke(clazz, val); + } + } + } + } + } + } + + /** + * Gets the topology object. + * + * @param <T> the generic type + * @param clazz the clazz + * @param _dbRulesNodeNameProps the db rules node name props + * @param _dbRulesNodeKeyProps the db rules node key props + * @param vert the vert + * @return the topology object + * @throws IllegalAccessException the illegal access exception + * @throws IllegalArgumentException the illegal argument exception + * @throws InvocationTargetException the invocation target exception + * @throws NoSuchMethodException the no such method exception + * @throws SecurityException the security exception + * @throws AAIException the AAI exception + */ + public <T> void getTopologyObject(T clazz, Multimap<String, String> _dbRulesNodeNameProps, Multimap<String, String> _dbRulesNodeKeyProps, TitanVertex vert) throws IllegalAccessException, IllegalArgumentException, InvocationTargetException, NoSuchMethodException, SecurityException, AAIException { + Method[] methods = clazz.getClass().getDeclaredMethods(); + String dnHypPropertyName = ""; +// Object value = null; + List<String> includeProps = new ArrayList<String>(); + + if ("false".equals(AAIConfig.get("aai.notification.topology.allAttrs", "false"))) { + for (Method method : methods) { + if (method.getName().startsWith("is")) { + dnHypPropertyName = CaseFormat.UPPER_CAMEL.to(CaseFormat.LOWER_HYPHEN,method.getName().substring(2)); + String upCamPropertyName = CaseFormat.UPPER_CAMEL.to(CaseFormat.UPPER_CAMEL,method.getName().substring(2)); + String retType = method.getReturnType().getName(); + if (retType.equals("java.lang.Boolean")) { + // get the setter + Method setterMeth = clazz.getClass().getMethod("set" + upCamPropertyName, method.getReturnType()); + setterMeth.invoke(clazz, (Boolean)null); + } + } + } + String dnHypClassName = CaseFormat.UPPER_CAMEL.to(CaseFormat.LOWER_HYPHEN,clazz.getClass().getSimpleName()); + Collection<String> keepProps = _dbRulesNodeNameProps.get(dnHypClassName); + Iterator <String> keepPropI = keepProps.iterator(); + while( keepPropI.hasNext() ){ + includeProps.add(keepPropI.next()); + } + Collection<String> keepProps2 = _dbRulesNodeKeyProps.get(dnHypClassName); + Iterator <String> keepPropI2 = keepProps2.iterator(); + while( keepPropI2.hasNext() ){ + includeProps.add(keepPropI2.next()); + } + } + + for (Method method : methods) { + if (method.getName().startsWith("get")) { + dnHypPropertyName = CaseFormat.UPPER_CAMEL.to(CaseFormat.LOWER_HYPHEN,method.getName().substring(3)); + if (includeProps.size() > 0) { + if (!includeProps.contains(dnHypPropertyName)) { + continue; + } + } + String upCamPropertyName = CaseFormat.UPPER_CAMEL.to(CaseFormat.UPPER_CAMEL,method.getName().substring(3)); + String retType = method.getReturnType().getName(); + if (!retType.contains("aai") && !retType.contains("java.util.List")) { + // get the setter + Method meth = clazz.getClass().getMethod("set" + upCamPropertyName, method.getReturnType()); + + if (retType.contains("String")) { + String val = (String)vert.<String>property(dnHypPropertyName).orElse(null); + if (val != null) { + meth.invoke(clazz, val); + } + } else if (retType.toLowerCase().contains("long")) { + Long val = (Long)vert.<Long>property(dnHypPropertyName).orElse(null); + if (val != null) { + meth.invoke(clazz, val); + } + } else if (retType.toLowerCase().contains("int")) { + Integer val = (Integer)vert.<Integer>property(dnHypPropertyName).orElse(null); + if (val != null) { + meth.invoke(clazz, val); + } + } else if (retType.toLowerCase().contains("short")) { + Short val = (Short)vert.<Short>property(dnHypPropertyName).orElse(null); + if (val != null) { + meth.invoke(clazz, val); + } + } + } + } + } + } + + /** + * Gets the dynamic topology object. + * + * @param aaiRes the aai res + * @param meObjectType the me object type + * @param _dbRulesNodeNameProps the db rules node name props + * @param _dbRulesNodeKeyProps the db rules node key props + * @param _propertyDataTypeMap the property data type map + * @param vert the vert + * @return the dynamic topology object + * @throws AAIException the AAI exception + */ + public DynamicEntity getDynamicTopologyObject(AAIResource aaiRes, DynamicType meObjectType, Multimap<String, String> _dbRulesNodeNameProps, + Multimap<String, String> _dbRulesNodeKeyProps, Map<String, String> _propertyDataTypeMap, TitanVertex vert) throws AAIException { + + DynamicEntity meObject = meObjectType.newDynamicEntity(); + + List<String> includeProps = new ArrayList<String>(); + + if ("false".equals(AAIConfig.get("aai.notification.topology.allAttrs", "false"))) { + String dnHypClassName = CaseFormat.UPPER_CAMEL.to(CaseFormat.LOWER_HYPHEN,meObjectType.getJavaClass().getSimpleName()); + Collection<String> keepProps = _dbRulesNodeNameProps.get(dnHypClassName); + Iterator <String> keepPropI = keepProps.iterator(); + while( keepPropI.hasNext() ){ + includeProps.add(keepPropI.next()); + } + Collection<String> keepProps2 = _dbRulesNodeKeyProps.get(dnHypClassName); + Iterator <String> keepPropI2 = keepProps2.iterator(); + while( keepPropI2.hasNext() ) { + includeProps.add(keepPropI2.next()); + } + } + + + + for (String attrName : aaiRes.getStringFields()) { + if (includeProps.contains(attrName)) { + meObject.set((CaseFormat.LOWER_HYPHEN.to(CaseFormat.LOWER_CAMEL,attrName)), vert.<String>property(attrName).orElse(null)); + } + } + // the attrName might need to be converted to camel case!!! + for (String attrName : aaiRes.getLongFields()) { + if (includeProps.contains(attrName)) { + String titanType = _propertyDataTypeMap.get(attrName); + + Long val = null; + // we have a case where the type in titan is "Integer" but in the POJO it's Long or long + if (titanType.toLowerCase().contains("int")) { + Integer intVal = (Integer)vert.<Integer>property(attrName).orElse(null); + if (intVal != null) { + val = intVal.longValue(); + } + } else { + val = (Long)vert.<Long>property(attrName).orElse(null); + } + meObject.set((CaseFormat.LOWER_HYPHEN.to(CaseFormat.LOWER_CAMEL,attrName)), val); + } + } + + for (String attrName : aaiRes.getIntFields()) { + if (includeProps.contains(attrName)) { + Integer val = (Integer)vert.<Integer>property(attrName).orElse(null); + meObject.set((CaseFormat.LOWER_HYPHEN.to(CaseFormat.LOWER_CAMEL,attrName)), val); + } + } + + for (String attrName : aaiRes.getShortFields()) { + if (includeProps.contains(attrName)) { + String titanType = _propertyDataTypeMap.get(attrName); + + Short val = null; + // we have a case where the type in titan is "Integer" but in the POJO it's Long or long + if (titanType.toLowerCase().contains("int")) { + Integer intVal = (Integer)vert.<Integer>property(attrName).orElse(null); + if (intVal != null) { + val = intVal.shortValue(); + } + } else { + val = (Short)vert.<Short>property(attrName).orElse(null); + } + meObject.set((CaseFormat.LOWER_HYPHEN.to(CaseFormat.LOWER_CAMEL,attrName)), val); + } + } + + for (String attrName : aaiRes.getBooleanFields()) { + if (includeProps.contains(attrName)) { + Boolean val = (Boolean)vert.<Boolean>property(attrName).orElse(null); + meObject.set((CaseFormat.LOWER_HYPHEN.to(CaseFormat.LOWER_CAMEL,attrName)), val); + } + } + return meObject; + } + + /** + * Gets the aai dynamic object from vertex. + * + * @param aaiRes the aai res + * @param meObject the me object + * @param vert the vert + * @param _propertyDataTypeMap the property data type map + * @return the aai dynamic object from vertex + */ + public void getAaiDynamicObjectFromVertex(AAIResource aaiRes, DynamicEntity meObject, TitanVertex vert, + Map<String, String> _propertyDataTypeMap) { + getAaiDynamicObjectFromVertex(aaiRes, meObject, vert, _propertyDataTypeMap, null); + } + + /** + * Gets the aai dynamic object from vertex. + * + * @param aaiRes the aai res + * @param meObject the me object + * @param vert the vert + * @param _propertyDataTypeMap the property data type map + * @param propertyOverRideHash the property over ride hash + * @return the aai dynamic object from vertex + */ + @SuppressWarnings("unchecked") + public void getAaiDynamicObjectFromVertex(AAIResource aaiRes, DynamicEntity meObject, TitanVertex vert, + Map<String, String> _propertyDataTypeMap, HashMap<String, Object> propertyOverRideHash) { + + for (String attrName : aaiRes.getStringFields()) { + if (propertyOverRideHash == null || (propertyOverRideHash != null && propertyOverRideHash.containsKey(attrName))) { + meObject.set((CaseFormat.LOWER_HYPHEN.to(CaseFormat.LOWER_CAMEL,attrName)), vert.<String>property(dbAliasWorkaround(attrName)).orElse(null)); + } + } + + for (String attrName : aaiRes.getStringListFields()) { + if (propertyOverRideHash == null || (propertyOverRideHash != null && propertyOverRideHash.containsKey(attrName))) { + meObject.set((CaseFormat.LOWER_HYPHEN.to(CaseFormat.LOWER_CAMEL,attrName)), vert.<ArrayList<String>>property(attrName).orElse(null)); + } + } + + // the attrName might need to be converted to camel case!!! + for (String attrName : aaiRes.getLongFields()) { + String titanType = _propertyDataTypeMap.get(attrName); + Long val = null; + // we have a case where the type in titan is "Integer" but in the POJO it's Long or long + if (titanType.toLowerCase().contains("int")) { + Object vertexVal = vert.property(attrName).orElse(null); + if (vertexVal != null) { + if (vertexVal instanceof Integer) { + val = ((Integer)vertexVal).longValue(); + + } else { + val = (Long)vert.<Long>property(attrName).orElse(null); + } + } + } else { + val = (Long)vert.<Long>property(attrName).orElse(null); + } + if (val != null) { + if (propertyOverRideHash == null || (propertyOverRideHash != null && propertyOverRideHash.containsKey(attrName))) { + meObject.set((CaseFormat.LOWER_HYPHEN.to(CaseFormat.LOWER_CAMEL,attrName)), val); + } + } + } + + for (String attrName : aaiRes.getIntFields()) { + Integer val = (Integer)vert.<Integer>property(attrName).orElse(null); + if (val != null) { + if (propertyOverRideHash == null || (propertyOverRideHash != null && propertyOverRideHash.containsKey(attrName))) { + meObject.set((CaseFormat.LOWER_HYPHEN.to(CaseFormat.LOWER_CAMEL,attrName)), val); + } + } + } + + for (String attrName : aaiRes.getShortFields()) { + String titanType = _propertyDataTypeMap.get(attrName); + Short val = null; + // we have a case where the type in titan is "Integer" but in the POJO it's Long or long + if (titanType.toLowerCase().contains("int")) { + Integer intVal = (Integer)vert.<Integer>property(attrName).orElse(null); + if (intVal != null) { + val = intVal.shortValue(); + } + } else { + val = (Short)vert.<Short>property(attrName).orElse(null); + } + if (val != null) { + if (propertyOverRideHash == null || (propertyOverRideHash != null && propertyOverRideHash.containsKey(attrName))) { + meObject.set((CaseFormat.LOWER_HYPHEN.to(CaseFormat.LOWER_CAMEL,attrName)), val); + } + } + } + + for (String attrName : aaiRes.getBooleanFields()) { + Boolean val = (Boolean)vert.<Boolean>property(attrName).orElse(null); + // This is not ideal, but moxy isn't marshalling these attributes. + // TODO: Figure out how to see the default-value from the OXM at startup (or at runtime). + String dnHypClassName = CaseFormat.UPPER_CAMEL.to(CaseFormat.LOWER_HYPHEN,aaiRes.getSimpleName()); + if (val == null && AAIConfig.getDefaultBools().containsKey(dnHypClassName)) { + if (AAIConfig.getDefaultBools().get(dnHypClassName).contains(attrName)) { + val = false; + } + } + if (val != null) { + if (propertyOverRideHash == null || (propertyOverRideHash != null && propertyOverRideHash.containsKey(attrName))) { + meObject.set((CaseFormat.LOWER_HYPHEN.to(CaseFormat.LOWER_CAMEL,attrName)), val); + } + } + } + + } + + private String dbAliasWorkaround(String propName) { + final String modelInvariantIdLocal = "model-invariant-id-local"; + final String modelVersionIdLocal = "model-version-id-local"; + final String modelInvariantId = "model-invariant-id"; + final String modelVersionId = "model-version-id"; + + if (propName.equals(modelInvariantId)) { + return modelInvariantIdLocal; + } + if (propName.equals(modelVersionId)) { + return modelVersionIdLocal; + } + + return propName; + + } + + /** + * Gets the dynamic example object. + * + * @param childObject the child object + * @param aaiRes the aai res + * @param singleton the singleton + * @return the dynamic example object + */ + public void getDynamicExampleObject(DynamicEntity childObject, AAIResource aaiRes, boolean singleton) { + // TODO Auto-generated method stub + + Random rand = new Random(); + Integer randInt = rand.nextInt(100000); + long range = 100000000L; + long randLong = (long)(rand.nextDouble()*range); + Integer randShrt = rand.nextInt(20000); + short randShort = randShrt.shortValue(); + + for (String dnHypAttrName : aaiRes.getStringFields()) { + + if (singleton && ("resource-version").equals(dnHypAttrName)) { + continue; + } + + String dnCamAttrName = CaseFormat.LOWER_HYPHEN.to(CaseFormat.LOWER_CAMEL,dnHypAttrName); + childObject.set(dnCamAttrName, "example-" + dnHypAttrName + "-val-" + randInt); + + } + + for (String dnHypAttrName : aaiRes.getStringListFields()) { + ArrayList<String> exampleList = new ArrayList<String>(); + exampleList.add("example-" + dnHypAttrName + "-val-" + randInt + "-" + 1); + exampleList.add("example-" + dnHypAttrName + "-val-" + randInt + "-" + 2); + String dnCamAttrName = CaseFormat.LOWER_HYPHEN.to(CaseFormat.LOWER_CAMEL,dnHypAttrName); + childObject.set(dnCamAttrName, exampleList); + } + + // the attrName might need to be converted to camel case!!! + for (String dnHypAttrName : aaiRes.getLongFields()) { + String dnCamAttrName = CaseFormat.LOWER_HYPHEN.to(CaseFormat.LOWER_CAMEL,dnHypAttrName); + childObject.set(dnCamAttrName, randLong); + } + + for (String dnHypAttrName : aaiRes.getIntFields()) { + String dnCamAttrName = CaseFormat.LOWER_HYPHEN.to(CaseFormat.LOWER_CAMEL,dnHypAttrName); + childObject.set(dnCamAttrName, randInt); + } + + for (String dnHypAttrName : aaiRes.getShortFields()) { + String dnCamAttrName = CaseFormat.LOWER_HYPHEN.to(CaseFormat.LOWER_CAMEL,dnHypAttrName); + childObject.set(dnCamAttrName, randShort); + } + + for (String dnHypAttrName : aaiRes.getBooleanFields()) { + String dnCamAttrName = CaseFormat.LOWER_HYPHEN.to(CaseFormat.LOWER_CAMEL,dnHypAttrName); + childObject.set(dnCamAttrName, Boolean.TRUE); + } + } +} diff --git a/aai-resources/src/main/java/org/openecomp/aai/util/StoreNotificationEvent.java b/aai-resources/src/main/java/org/openecomp/aai/util/StoreNotificationEvent.java new file mode 100644 index 0000000..ea674ed --- /dev/null +++ b/aai-resources/src/main/java/org/openecomp/aai/util/StoreNotificationEvent.java @@ -0,0 +1,283 @@ +/*- + * ============LICENSE_START======================================================= + * org.openecomp.aai + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.aai.util; + +import java.io.StringWriter; +import java.text.DateFormat; +import java.text.SimpleDateFormat; +import java.util.Date; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.UUID; + +import javax.xml.bind.Marshaller; + +import org.apache.cxf.helpers.CastUtils; +import org.apache.cxf.message.Message; +import org.apache.cxf.phase.PhaseInterceptorChain; +import org.eclipse.persistence.dynamic.DynamicEntity; +import org.eclipse.persistence.jaxb.dynamic.DynamicJAXBContext; +import org.json.JSONException; +import org.json.JSONObject; +import org.openecomp.aai.dmaap.AAIDmaapEventJMSProducer; +import org.openecomp.aai.exceptions.AAIException; +import org.openecomp.aai.introspection.Introspector; +import org.openecomp.aai.introspection.Loader; +import org.openecomp.aai.introspection.exceptions.AAIUnknownObjectException; + +public class StoreNotificationEvent { + + private AAIDmaapEventJMSProducer messageProducer; + private String fromAppId = ""; + private String transId = ""; + + /** + * Instantiates a new store notification event. + */ + public StoreNotificationEvent() { + this.messageProducer = new AAIDmaapEventJMSProducer(); + Message inMessage = PhaseInterceptorChain.getCurrentMessage().getExchange().getInMessage(); + Map<String, List<String>> headersList = CastUtils.cast((Map<?, ?>) inMessage.get(Message.PROTOCOL_HEADERS)); + if (headersList != null) { + List<String> xt = headersList.get("X-TransactionId"); + if (xt != null) { + for (String transIdValue : xt) { + transId = transIdValue; + } + } + List<String> fa = headersList.get("X-FromAppId"); + if (fa != null) { + for (String fromAppIdValue : fa) { + + fromAppId = fromAppIdValue; + } + } + } + } + + + /** + * Store dynamic event. + * + * @param notificationJaxbContext + * the notification jaxb context + * @param notificationVersion + * the notification version + * @param eventHeader + * the event header + * @param obj + * the obj + * @throws AAIException + * the AAI exception + */ + public void storeDynamicEvent(DynamicJAXBContext notificationJaxbContext, String notificationVersion, DynamicEntity eventHeader, DynamicEntity obj) throws AAIException { + + if (obj == null) { + throw new AAIException("AAI_7350"); + } + + DynamicEntity notificationEvent = notificationJaxbContext.getDynamicType("inventory.aai.openecomp.org." + notificationVersion + ".NotificationEvent").newDynamicEntity(); + + if (eventHeader.get("id") == null) { + eventHeader.set("id", genDate2() + "-" + UUID.randomUUID().toString()); + } + + if (eventHeader.get("timestamp") == null) { + eventHeader.set("timestamp", genDate()); + } + + if (eventHeader.get("entityLink") == null) { + eventHeader.set("entityLink", "UNK"); + } + + if (eventHeader.get("action") == null) { + eventHeader.set("action", "UNK"); + } + + if (eventHeader.get("eventType") == null) { + eventHeader.set("eventType", AAIConfig.get("aai.notificationEvent.default.eventType", "UNK")); + } + + if (eventHeader.get("domain") == null) { + eventHeader.set("domain", AAIConfig.get("aai.notificationEvent.default.domain", "UNK")); + } + + if (eventHeader.get("sourceName") == null) { + eventHeader.set("sourceName", AAIConfig.get("aai.notificationEvent.default.sourceName", "UNK")); + } + + if (eventHeader.get("sequenceNumber") == null) { + eventHeader.set("sequenceNumber", AAIConfig.get("aai.notificationEvent.default.sequenceNumber", "UNK")); + } + + if (eventHeader.get("severity") == null) { + eventHeader.set("severity", AAIConfig.get("aai.notificationEvent.default.severity", "UNK")); + } + + if (eventHeader.get("version") == null) { + eventHeader.set("version", AAIConfig.get("aai.notificationEvent.default.version", "UNK")); + } + + if (notificationEvent.get("cambriaPartition") == null) { + notificationEvent.set("cambriaPartition", AAIConstants.UEB_PUB_PARTITION_AAI); + } + + notificationEvent.set("eventHeader", eventHeader); + notificationEvent.set("entity", obj); + + try { + StringWriter result = new StringWriter(); + + Marshaller marshaller = notificationJaxbContext.createMarshaller(); + marshaller.setProperty(org.eclipse.persistence.jaxb.MarshallerProperties.MEDIA_TYPE, "application/json"); + marshaller.setProperty(org.eclipse.persistence.jaxb.MarshallerProperties.JSON_INCLUDE_ROOT, false); + marshaller.setProperty(org.eclipse.persistence.jaxb.MarshallerProperties.JSON_WRAPPER_AS_ARRAY_NAME, false); + marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, false); + marshaller.marshal(notificationEvent, result); + + this.sendToDmaapJmsQueue(result.toString()); + + } catch (Exception e) { + throw new AAIException("AAI_7350", e); + } + } + + public void storeEvent(Loader loader, Introspector eventHeader, Introspector obj) throws AAIException { + if (obj == null) { + throw new AAIException("AAI_7350"); + } + + try { + final Introspector notificationEvent = loader.introspectorFromName("notification-event"); + + if (eventHeader.getValue("id") == null) { + eventHeader.setValue("id", genDate2() + "-" + UUID.randomUUID().toString()); + } + + if (eventHeader.getValue("timestamp") == null) { + eventHeader.setValue("timestamp", genDate()); + } + + if (eventHeader.getValue("entity-link") == null) { + eventHeader.setValue("entity-link", "UNK"); + } + + if (eventHeader.getValue("action") == null) { + eventHeader.setValue("action", "UNK"); + } + + if (eventHeader.getValue("event-type") == null) { + eventHeader.setValue("event-type", AAIConfig.get("aai.notificationEvent.default.eventType", "UNK")); + } + + if (eventHeader.getValue("domain") == null) { + eventHeader.setValue("domain", AAIConfig.get("aai.notificationEvent.default.domain", "UNK")); + } + + if (eventHeader.getValue("source-name") == null) { + eventHeader.setValue("source-name", AAIConfig.get("aai.notificationEvent.default.sourceName", "UNK")); + } + + if (eventHeader.getValue("sequence-number") == null) { + eventHeader.setValue("sequence-number", AAIConfig.get("aai.notificationEvent.default.sequenceNumber", "UNK")); + } + + if (eventHeader.getValue("severity") == null) { + eventHeader.setValue("severity", AAIConfig.get("aai.notificationEvent.default.severity", "UNK")); + } + + if (eventHeader.getValue("version") == null) { + eventHeader.setValue("version", AAIConfig.get("aai.notificationEvent.default.version", "UNK")); + } + + if (notificationEvent.getValue("cambria-partition") == null) { + notificationEvent.setValue("cambria-partition", AAIConstants.UEB_PUB_PARTITION_AAI); + } + + notificationEvent.setValue("event-header", eventHeader.getUnderlyingObject()); + notificationEvent.setValue("entity", obj.getUnderlyingObject()); + + String entityJson = notificationEvent.marshal(false); + sendToDmaapJmsQueue(entityJson); + } catch (JSONException e) { + throw new AAIException("AAI_7350", e); + } catch (AAIUnknownObjectException e) { + throw new AAIException("AAI_7350", e); + } + } + + private void sendToDmaapJmsQueue(String entityString) throws JSONException { + + JSONObject entityJsonObject = new JSONObject(entityString); + + JSONObject entityJsonObjectUpdated = new JSONObject(); + JSONObject finalJson = new JSONObject(); + + JSONObject entityHeader = entityJsonObject.getJSONObject("event-header"); + String cambriaPartition = entityJsonObject.getString("cambria.partition"); + + entityJsonObject.remove("event-header"); + entityJsonObject.remove("cambria.partition"); + + entityJsonObjectUpdated.put("event-header", entityHeader); + entityJsonObjectUpdated.put("cambria.partition", cambriaPartition); + + Iterator<String> iter = entityJsonObject.keys(); + JSONObject entity = new JSONObject(); + if (iter.hasNext()) { + entity = entityJsonObject.getJSONObject(iter.next()); + } + + entityJsonObjectUpdated.put("entity", entity); + + finalJson.put("event-topic", "AAI-EVENT"); + finalJson.put("transId", transId); + finalJson.put("fromAppId", fromAppId); + finalJson.put("fullId", ""); + finalJson.put("aaiEventPayload", entityJsonObjectUpdated); + + messageProducer.sendMessageToDefaultDestination(finalJson); + } + + /** + * Gen date. + * + * @return the string + */ + public static String genDate() { + Date date = new Date(); + DateFormat formatter = new SimpleDateFormat("YYYYMMdd-HH:mm:ss:SSS"); + return formatter.format(date); + } + + /** + * Gen date 2. + * + * @return the string + */ + public static String genDate2() { + Date date = new Date(); + DateFormat formatter = new SimpleDateFormat("YYYYMMddHHmmss"); + return formatter.format(date); + } + +} diff --git a/aai-resources/src/main/java/org/openecomp/aai/util/UniquePropertyCheck.java b/aai-resources/src/main/java/org/openecomp/aai/util/UniquePropertyCheck.java new file mode 100644 index 0000000..b5c5cbc --- /dev/null +++ b/aai-resources/src/main/java/org/openecomp/aai/util/UniquePropertyCheck.java @@ -0,0 +1,264 @@ +/*- + * ============LICENSE_START======================================================= + * org.openecomp.aai + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.aai.util; +import java.util.HashMap; +import java.util.Iterator; +import java.util.Map; +import java.util.Properties; +import java.util.UUID; + +import org.apache.tinkerpop.gremlin.structure.Direction; +import org.apache.tinkerpop.gremlin.structure.Edge; +import org.apache.tinkerpop.gremlin.structure.VertexProperty; +import org.slf4j.MDC; + +import org.openecomp.aai.exceptions.AAIException; +import com.att.eelf.configuration.Configuration; +import com.att.eelf.configuration.EELFLogger; +import com.att.eelf.configuration.EELFManager; +import com.thinkaurelius.titan.core.TitanEdge; +import com.thinkaurelius.titan.core.TitanFactory; +import com.thinkaurelius.titan.core.TitanGraph; +import com.thinkaurelius.titan.core.TitanTransaction; +import com.thinkaurelius.titan.core.TitanVertex; + + + +public class UniquePropertyCheck { + + + private static final String FROMAPPID = "AAI-UTILS"; + private static final String TRANSID = UUID.randomUUID().toString(); + private static final String COMPONENT = "UniquePropertyCheck"; + + /** + * The main method. + * + * @param args the arguments + */ + public static void main(String[] args) { + + + Properties props = System.getProperties(); + props.setProperty(Configuration.PROPERTY_LOGGING_FILE_NAME, "uniquePropertyCheck-logback.xml"); + props.setProperty(Configuration.PROPERTY_LOGGING_FILE_PATH, AAIConstants.AAI_HOME_ETC_APP_PROPERTIES); + EELFLogger logger = EELFManager.getInstance().getLogger(UniquePropertyCheck.class.getSimpleName()); + MDC.put("logFilenameAppender", UniquePropertyCheck.class.getSimpleName()); + + if( args == null || args.length != 1 ){ + String msg = "usage: UniquePropertyCheck propertyName \n"; + System.out.println(msg); + logAndPrint(logger, msg ); + System.exit(1); + } + String propertyName = args[0]; + TitanTransaction graph = null; + + try { + AAIConfig.init(); + System.out.println(" ---- NOTE --- about to open graph (takes a little while)--------\n"); + TitanGraph tGraph = TitanFactory.open(AAIConstants.REALTIME_DB_CONFIG); + + if( tGraph == null ) { + logAndPrint(logger, " Error: Could not get TitanGraph "); + System.exit(1); + } + + graph = tGraph.newTransaction(); + if( graph == null ){ + logAndPrint(logger, "could not get graph object in UniquePropertyCheck() \n"); + System.exit(0); + } + } + catch (AAIException e1) { + String msg = "Threw Exception: [" + e1.toString() + "]"; + logAndPrint(logger, msg); + System.exit(0); + } + catch (Exception e2) { + String msg = "Threw Exception: [" + e2.toString() + "]"; + logAndPrint(logger, msg); + System.exit(0); + } + + runTheCheckForUniqueness( TRANSID, FROMAPPID, graph, propertyName, logger ); + System.exit(0); + + }// End main() + + + /** + * Run the check for uniqueness. + * + * @param transId the trans id + * @param fromAppId the from app id + * @param graph the graph + * @param propertyName the property name + * @param logger the logger + * @return the boolean + */ + public static Boolean runTheCheckForUniqueness( String transId, String fromAppId, TitanTransaction graph, + String propertyName, EELFLogger logger ){ + + // Note - property can be found in more than one nodetype + // our uniqueness constraints are always across the entire db - so this + // tool looks across all nodeTypes that the property is found in. + Boolean foundDupesFlag = false; + + HashMap <String,String> valuesAndVidHash = new HashMap <String, String> (); + HashMap <String,String> dupeHash = new HashMap <String, String> (); + + int propCount = 0; + int dupeCount = 0; + Iterable <?> vertItr = graph.query().has(propertyName).vertices(); + Iterator <?> vertItor = vertItr.iterator(); + while( vertItor.hasNext() ){ + propCount++; + TitanVertex v = (TitanVertex)vertItor.next(); + String thisVid = v.id().toString(); + Object val = (v.<Object>property(propertyName)).orElse(null); + if( valuesAndVidHash.containsKey(val) ){ + // We've seen this one before- track it in our dupe hash + dupeCount++; + if( dupeHash.containsKey(val) ){ + // This is not the first one being added to the dupe hash for this value + String updatedDupeList = dupeHash.get(val) + "|" + thisVid; + dupeHash.put(val.toString(), updatedDupeList); + } + else { + // This is the first time we see this value repeating + String firstTwoVids = valuesAndVidHash.get(val) + "|" + thisVid; + dupeHash.put(val.toString(), firstTwoVids); + } + } + else { + valuesAndVidHash.put(val.toString(), thisVid); + } + } + + + String info = "\n Found this property [" + propertyName + "] " + propCount + " times in our db."; + logAndPrint(logger, info); + info = " Found " + dupeCount + " cases of duplicate values for this property.\n\n"; + logAndPrint(logger, info); + + try { + if( ! dupeHash.isEmpty() ){ + Iterator <?> dupeItr = dupeHash.entrySet().iterator(); + while( dupeItr.hasNext() ){ + Map.Entry pair = (Map.Entry) dupeItr.next(); + String dupeValue = pair.getKey().toString();; + String vidsStr = pair.getValue().toString(); + String[] vidArr = vidsStr.split("\\|"); + logAndPrint(logger, "\n\n -------------- Found " + vidArr.length + + " nodes with " + propertyName + " of this value: [" + dupeValue + "]. Node details: "); + + for( int i = 0; i < vidArr.length; i++ ){ + String vidString = vidArr[i]; + Long idLong = Long.valueOf(vidString); + TitanVertex tvx = (TitanVertex)graph.getVertex(idLong); + showPropertiesAndEdges( TRANSID, FROMAPPID, tvx, logger ); + } + } + } + } + catch( Exception e2 ){ + logAndPrint(logger, "Threw Exception: [" + e2.toString() + "]"); + } + finally { + if( graph != null ){ + graph.rollback(); + } + } + + return foundDupesFlag; + + }// end of runTheCheckForUniqueness() + + + /** + * Show properties and edges. + * + * @param transId the trans id + * @param fromAppId the from app id + * @param tVert the t vert + * @param logger the logger + */ + private static void showPropertiesAndEdges( String transId, String fromAppId, TitanVertex tVert, + EELFLogger logger ){ + + if( tVert == null ){ + logAndPrint(logger, "Null node passed to showPropertiesAndEdges."); + } + else { + String nodeType = ""; + Object ob = tVert.<String>property("aai-node-type").orElse(null); + if( ob == null ){ + nodeType = "null"; + } + else{ + nodeType = ob.toString(); + } + + logAndPrint(logger, " AAINodeType/VtxID for this Node = [" + nodeType + "/" + tVert.id() + "]"); + logAndPrint(logger, " Property Detail: "); + Iterator<VertexProperty<Object>> pI = tVert.properties(); + while( pI.hasNext() ){ + VertexProperty<Object> tp = pI.next(); + Object val = tp.value(); + logAndPrint(logger, "Prop: [" + tp.key() + "], val = [" + val + "] "); + } + + Iterator <Edge> eI = tVert.edges(Direction.BOTH); + if( ! eI.hasNext() ){ + logAndPrint(logger, "No edges were found for this vertex. "); + } + while( eI.hasNext() ){ + TitanEdge ed = (TitanEdge) eI.next(); + String lab = ed.label(); + TitanVertex vtx = (TitanVertex) ed.otherVertex(tVert); + if( vtx == null ){ + logAndPrint(logger, " >>> COULD NOT FIND VERTEX on the other side of this edge edgeId = " + ed.id() + " <<< "); + } + else { + String nType = vtx.<String>property("aai-node-type").orElse(null); + String vid = vtx.id().toString(); + logAndPrint(logger, "Found an edge (" + lab + ") from this vertex to a [" + nType + "] node with VtxId = " + vid); + } + } + } + } // End of showPropertiesAndEdges() + + + /** + * Log and print. + * + * @param logger the logger + * @param msg the msg + */ + protected static void logAndPrint(EELFLogger logger, String msg) { + System.out.println(msg); + logger.info(msg); + } + +} + + |