From 2857310c33726032ce77449d91e87864e6bf4108 Mon Sep 17 00:00:00 2001 From: "Bansal, Nitin (nb121v)" Date: Tue, 3 Apr 2018 12:31:43 -0400 Subject: [PATCH] Moving Historical Queries to spring boot Change-Id: If4042f3b19b25b086e8f0c4b3723afe9839d994a Issue-ID: AAI-802 Signed-off-by: Bansal, Nitin (nb121v) --- pom.xml | 22 ++- .../java/org/onap/aai/datarouter/Application.java | 18 +- .../onap/aai/datarouter/JerseyConfiguration.java | 41 ++++ .../exception/BaseDataRouterException.java | 85 -------- .../aai/datarouter/exception/DataRouterError.java | 102 ---------- .../datarouter/exception/DataRouterException.java} | 108 +++++----- .../aai/datarouter/logging/DataRouterMsgs.java | 6 + .../onap/aai/datarouter/logging/LoggingUtil.java | 78 ++++++++ .../datarouter/query/ChameleonResponseBuiler.java | 21 +- .../onap/aai/datarouter/query/ChameleonRouter.java | 217 +++++++++++---------- .../org/onap/aai/datarouter/query/ChampRouter.java | 89 ++++++--- .../org/onap/aai/datarouter/query/QueryRouter.java | 47 +---- .../aai/datarouter/query/RestClientConfig.java | 87 +++++++++ .../onap/aai/datarouter/service/EchoService.java | 23 ++- .../datarouter/service/HistoricalQueryService.java | 107 ++++++++++ src/main/resources/application.properties | 15 +- .../resources/logging/DataRouterMsgs.properties | 5 +- .../aai/datarouter/query/ChameleonRouterTest.java | 104 ++++++++++ .../onap/aai/datarouter/query/ChampRouterTest.java | 94 +++++++++ src/test/resources/chameleon-response.json | 13 ++ src/test/resources/champ-response.json | 16 ++ 21 files changed, 860 insertions(+), 438 deletions(-) create mode 100644 src/main/java/org/onap/aai/datarouter/JerseyConfiguration.java delete mode 100644 src/main/java/org/onap/aai/datarouter/exception/BaseDataRouterException.java delete mode 100644 src/main/java/org/onap/aai/datarouter/exception/DataRouterError.java rename src/{test/java/org/onap/aai/datarouter/exception/DataRouterExceptionTest.java => main/java/org/onap/aai/datarouter/exception/DataRouterException.java} (52%) create mode 100644 src/main/java/org/onap/aai/datarouter/logging/LoggingUtil.java create mode 100644 src/main/java/org/onap/aai/datarouter/query/RestClientConfig.java create mode 100644 src/main/java/org/onap/aai/datarouter/service/HistoricalQueryService.java create mode 100644 src/test/java/org/onap/aai/datarouter/query/ChameleonRouterTest.java create mode 100644 src/test/java/org/onap/aai/datarouter/query/ChampRouterTest.java create mode 100644 src/test/resources/chameleon-response.json create mode 100644 src/test/resources/champ-response.json diff --git a/pom.xml b/pom.xml index 03c5d8d..fc5dd83 100644 --- a/pom.xml +++ b/pom.xml @@ -70,6 +70,10 @@ limitations under the License. + + org.springframework.boot + spring-boot-starter-jersey + ch.qos.logback logback-core @@ -89,11 +93,7 @@ limitations under the License. org.apache.camel camel-spring-boot-starter - - org.apache.camel - camel-core - 2.20.1 - + org.apache.camel camel-servlet-starter @@ -107,8 +107,7 @@ limitations under the License. org.springframework.boot spring-boot-starter-web - - + org.springframework.boot spring-boot-starter @@ -122,6 +121,11 @@ limitations under the License. javax.ws.rs-api 2.0.1 + + org.eclipse.jetty + jetty-security + 9.3.8.RC0 + org.powermock powermock-module-junit4 @@ -299,12 +303,12 @@ limitations under the License. - com.mycila license-maven-plugin 3.0
License.txt
src/main/java/** src/test/java/**
format - process-sources
--> + process-sources org.sonatype.plugins nexus-staging-maven-plugin diff --git a/src/main/java/org/onap/aai/datarouter/Application.java b/src/main/java/org/onap/aai/datarouter/Application.java index dfd8144..3ea6ab8 100644 --- a/src/main/java/org/onap/aai/datarouter/Application.java +++ b/src/main/java/org/onap/aai/datarouter/Application.java @@ -20,15 +20,27 @@ */ package org.onap.aai.datarouter; -import org.springframework.boot.SpringApplication; +import java.util.HashMap; + +import org.eclipse.jetty.util.security.Password; import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.boot.builder.SpringApplicationBuilder; +import org.springframework.boot.web.support.SpringBootServletInitializer; @SpringBootApplication -public class Application { +public class Application extends SpringBootServletInitializer{ public static void main(String[] args) { - SpringApplication.run(Application.class, args); + String keyStorePassword = System.getProperty("KEY_STORE_PASSWORD"); + if(keyStorePassword==null || keyStorePassword.isEmpty()){ + throw new RuntimeException("Env property KEY_STORE_PASSWORD not set"); + } + HashMap props = new HashMap<>(); + props.put("server.ssl.key-store-password", Password.deobfuscate(keyStorePassword)); + new Application().configure(new SpringApplicationBuilder(Application.class).properties(props)).run(args); + + } } \ No newline at end of file diff --git a/src/main/java/org/onap/aai/datarouter/JerseyConfiguration.java b/src/main/java/org/onap/aai/datarouter/JerseyConfiguration.java new file mode 100644 index 0000000..04e8cad --- /dev/null +++ b/src/main/java/org/onap/aai/datarouter/JerseyConfiguration.java @@ -0,0 +1,41 @@ +/** + * ============LICENSE_START======================================================= + * org.onap.aai + * ================================================================================ + * Copyright © 2017-2018 AT&T Intellectual Property. All rights reserved. + * Copyright © 2017-2018 Amdocs + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ +package org.onap.aai.datarouter; + +import javax.ws.rs.ApplicationPath; + +import org.glassfish.jersey.server.ResourceConfig; +import org.onap.aai.datarouter.service.EchoService; +import org.onap.aai.datarouter.service.HistoricalQueryService; +import org.springframework.stereotype.Component; + + +@Component +@ApplicationPath("/") +public class JerseyConfiguration extends ResourceConfig +{ + public JerseyConfiguration() + { + register(EchoService.class); + register(HistoricalQueryService.class); + + } +} \ No newline at end of file diff --git a/src/main/java/org/onap/aai/datarouter/exception/BaseDataRouterException.java b/src/main/java/org/onap/aai/datarouter/exception/BaseDataRouterException.java deleted file mode 100644 index c256da3..0000000 --- a/src/main/java/org/onap/aai/datarouter/exception/BaseDataRouterException.java +++ /dev/null @@ -1,85 +0,0 @@ -/** - * ============LICENSE_START======================================================= - * org.onap.aai - * ================================================================================ - * Copyright © 2017-2018 AT&T Intellectual Property. All rights reserved. - * Copyright © 2017-2018 Amdocs - * ================================================================================ - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * ============LICENSE_END========================================================= - */ -package org.onap.aai.datarouter.exception; - -/* - * COPYRIGHT NOTICE: Copyright (c) 2016 Team Pacifica (Amdocs & AT&T) The contents and intellectual - * property contained herein, remain the property of Team Pacifica (Amdocs & AT&T). - */ - -import java.util.Locale; - -/** - * Base SMAdaptor exception class. - */ -public class BaseDataRouterException extends Exception { - - /** Force serialVersionUID. */ - private static final long serialVersionUID = -6663403070792969748L; - - /** Default locale. */ - public static final Locale LOCALE = Locale.US; - - /** Exception id. */ - private final String id; - - /** - * Constructor. - * - * @param id the incoming id. - */ - public BaseDataRouterException(final String id) { - super(); - this.id = id; - } - - /** - * Constructor. - * - * @param id the incoming id - * @param message the incoming message - */ - public BaseDataRouterException(final String id, final String message) { - super(message); - this.id = id; - } - - /** - * Constructor. - * - * @param id the incoming id - * @param message the incoming message - * @param cause the incoming throwable - */ - public BaseDataRouterException(final String id, final String message, final Throwable cause) { - super(message, cause); - this.id = id; - } - - /** - * Get the exception id. - * - * @return the exception id - */ - public String getId() { - return this.id; - } -} diff --git a/src/main/java/org/onap/aai/datarouter/exception/DataRouterError.java b/src/main/java/org/onap/aai/datarouter/exception/DataRouterError.java deleted file mode 100644 index 6ca4bd8..0000000 --- a/src/main/java/org/onap/aai/datarouter/exception/DataRouterError.java +++ /dev/null @@ -1,102 +0,0 @@ -/** - * ============LICENSE_START======================================================= - * org.onap.aai - * ================================================================================ - * Copyright © 2017-2018 AT&T Intellectual Property. All rights reserved. - * Copyright © 2017-2018 Amdocs - * ================================================================================ - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * ============LICENSE_END========================================================= - */ -package org.onap.aai.datarouter.exception; - -/* - * COPYRIGHT NOTICE: Copyright (c) 2016 Team Pacifica (Amdocs & AT&T) The contents and intellectual - * property contained herein, remain the property of Team Pacifica (Amdocs & AT&T). - */ - -import java.text.MessageFormat; - -import javax.ws.rs.core.Response.Status; - -/** - * DL enum for error conditions. - */ -public enum DataRouterError { - - /** Parsing exceptions - Range 100..199. */ - DL_PARSE_100("DL-100", "Unable to find resource {0} in the model", Status.BAD_REQUEST), - DL_PARSE_101("DL-101", "Unable to parse ", Status.BAD_REQUEST), - DL_PARSE_102("DL-102", "Sot Filter error: {0} ", Status.INTERNAL_SERVER_ERROR), - DL_PARSE_103("DL-103", "URL Parsing error: {0} ", Status.BAD_REQUEST), - DL_PARSE_104("DL-104", "Missing Ids filter: {0} ", Status.BAD_REQUEST), - DL_PARSE_105("DL-105", "Invalid Ids filter: {0} ", Status.BAD_REQUEST), - - /** Validation exceptions - Range 200..299. */ - DL_VALIDATION_200("DL-200", "Missing X-TransactionId in header ", Status.BAD_REQUEST), - - /** Other components integration errors - Range 300..399. */ - DL_INTEGRATION_300("DL-300", "Unable to decorate Graph ", Status.INTERNAL_SERVER_ERROR), - - /** Environment related exceptions - Range 400..499. */ - DL_ENV_400("DL-400", "Unable to find file {0} ", Status.INTERNAL_SERVER_ERROR), - DL_ENV_401("DL-401", "Unable to Load OXM Models", Status.INTERNAL_SERVER_ERROR), - - /** Other components integration errors - Range 500..599. */ - DL_AUTH_500("DL-500", "Unable to authorize User ", Status.FORBIDDEN); - - /** The error id. */ - private String id; - /** The error message. */ - private String message; - /** The error http return code. */ - private Status status; - - /** - * Constructor. - * - * @param id the error id - * @param message the error message - */ - DataRouterError(final String id, final String message, final Status status) { - this.id = id; - this.message = message; - this.status = status; - } - - /** - * Get the id. - * - * @return the error id - */ - public String getId() { - return this.id; - } - - /** - * Get the message. - * - * @param args the error arguments - * @return the error message - */ - public String getMessage(final Object... args) { - final MessageFormat formatter = new MessageFormat(""); - formatter.applyPattern(this.message); - return formatter.format(args); - } - - public Status getHttpStatus() { - return this.status; - } - -} diff --git a/src/test/java/org/onap/aai/datarouter/exception/DataRouterExceptionTest.java b/src/main/java/org/onap/aai/datarouter/exception/DataRouterException.java similarity index 52% rename from src/test/java/org/onap/aai/datarouter/exception/DataRouterExceptionTest.java rename to src/main/java/org/onap/aai/datarouter/exception/DataRouterException.java index 9c16d14..46f0d58 100644 --- a/src/test/java/org/onap/aai/datarouter/exception/DataRouterExceptionTest.java +++ b/src/main/java/org/onap/aai/datarouter/exception/DataRouterException.java @@ -1,49 +1,59 @@ -/** - * ============LICENSE_START======================================================= - * org.onap.aai - * ================================================================================ - * Copyright © 2017-2018 AT&T Intellectual Property. All rights reserved. - * Copyright © 2017-2018 Amdocs - * ================================================================================ - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * ============LICENSE_END========================================================= - */ -package org.onap.aai.datarouter.exception; - -import org.junit.Assert; -import org.junit.Test; - -import javax.ws.rs.core.Response; - -public class DataRouterExceptionTest { - - @Test - public void testDataRouterError(){ - DataRouterError error1 = DataRouterError.DL_PARSE_100; - Assert.assertEquals("DL-100", error1.getId()); - Assert.assertNotNull(error1.getMessage()); - Assert.assertEquals(Response.Status.BAD_REQUEST, error1.getHttpStatus()); - } - - @Test - public void testBaseDataRouterException(){ - BaseDataRouterException exp1 = new BaseDataRouterException("id-1"); - Assert.assertEquals(exp1.getId(), "id-1"); - - BaseDataRouterException exp2 = new BaseDataRouterException("id-1", "test-error"); - Assert.assertEquals(exp2.getId(), "id-1"); - - BaseDataRouterException exp3 = new BaseDataRouterException("id-1", "test-error", new Throwable()); - Assert.assertEquals(exp3.getId(), "id-1"); - } -} +/** + * ============LICENSE_START======================================================= + * org.onap.aai + * ================================================================================ + * Copyright © 2017-2018 AT&T Intellectual Property. All rights reserved. + * Copyright © 2017-2018 Amdocs + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ +package org.onap.aai.datarouter.exception; + +import javax.ws.rs.core.Response.Status; + +public class DataRouterException extends Exception { + + private static final long serialVersionUID = 8162385108397238865L; + + private Status httpStatus; + + public DataRouterException() { + } + + public DataRouterException(String message, Status httpStatus) { + super(message); + this.setHttpStatus(httpStatus); + } + + public DataRouterException(Throwable cause) { + super(cause); + } + + public DataRouterException(String message, Throwable cause) { + super(message, cause); + } + + public DataRouterException(String message, Throwable cause, boolean enableSuppression, + boolean writableStackTrace) { + super(message, cause, enableSuppression, writableStackTrace); + } + + public Status getHttpStatus() { + return httpStatus; + } + + public void setHttpStatus(Status httpStatus) { + this.httpStatus = httpStatus; + } +} diff --git a/src/main/java/org/onap/aai/datarouter/logging/DataRouterMsgs.java b/src/main/java/org/onap/aai/datarouter/logging/DataRouterMsgs.java index 93f4c54..f0d6541 100644 --- a/src/main/java/org/onap/aai/datarouter/logging/DataRouterMsgs.java +++ b/src/main/java/org/onap/aai/datarouter/logging/DataRouterMsgs.java @@ -26,6 +26,12 @@ import org.onap.aai.cl.eelf.LogMessageEnum; public enum DataRouterMsgs implements LogMessageEnum { + + /** + * Arguments: {0} = HTTP request type, {1} = time to process in milliseconds + */ + PROCESSED_REQUEST, + /** Data Layer Service started. */ SERVICE_STARTED, diff --git a/src/main/java/org/onap/aai/datarouter/logging/LoggingUtil.java b/src/main/java/org/onap/aai/datarouter/logging/LoggingUtil.java new file mode 100644 index 0000000..e29af73 --- /dev/null +++ b/src/main/java/org/onap/aai/datarouter/logging/LoggingUtil.java @@ -0,0 +1,78 @@ +/** + * ============LICENSE_START======================================================= + * org.onap.aai + * ================================================================================ + * Copyright © 2017-2018 AT&T Intellectual Property. All rights reserved. + * Copyright © 2017-2018 Amdocs + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ +package org.onap.aai.datarouter.logging; + +import javax.servlet.http.HttpServletRequest; +import javax.ws.rs.core.HttpHeaders; +import javax.ws.rs.core.Response; + +import org.onap.aai.cl.api.LogFields; +import org.onap.aai.cl.api.LogLine; +import org.onap.aai.cl.api.Logger; +import org.onap.aai.cl.mdc.MdcContext; +import org.onap.aai.datarouter.util.DataRouterConstants; +import org.slf4j.MDC; + +public class LoggingUtil { + public static void initMdcContext(HttpServletRequest httpReq, HttpHeaders headers) { + String fromIp = httpReq.getRemoteAddr(); + String fromAppId = ""; + String transId = null; + + if (headers.getRequestHeaders().getFirst("X-FromAppId") != null) { + fromAppId = headers.getRequestHeaders().getFirst("X-FromAppId"); + } + + if ((headers.getRequestHeaders().getFirst("X-TransactionId") == null) + || headers.getRequestHeaders().getFirst("X-TransactionId").isEmpty()) { + transId = java.util.UUID.randomUUID().toString(); + } else { + transId = headers.getRequestHeaders().getFirst("X-TransactionId"); + } + + MdcContext.initialize(transId, DataRouterConstants.DATA_ROUTER_SERVICE_NAME, "", fromAppId, + fromIp); + } + + public static void logRestRequest(Logger logger, Logger auditLogger, HttpServletRequest req, Response response) { + String respStatusString = ""; + if (Response.Status.fromStatusCode(response.getStatus()) != null) { + respStatusString = Response.Status.fromStatusCode(response.getStatus()).toString(); + } + + // Generate error log + logger.info(DataRouterMsgs.PROCESS_REST_REQUEST, req.getMethod(), req.getRequestURL().toString(), + req.getRemoteHost(), Integer.toString(response.getStatus())); + + // Generate audit log. + auditLogger.info(DataRouterMsgs.PROCESS_REST_REQUEST, + new LogFields().setField(LogLine.DefinedFields.RESPONSE_CODE, response.getStatus()) + .setField(LogLine.DefinedFields.RESPONSE_DESCRIPTION, respStatusString), + (req != null) ? req.getMethod() : "Unknown", (req != null) ? req.getRequestURL().toString() : "Unknown", + (req != null) ? req.getRemoteHost() : "Unknown", Integer.toString(response.getStatus()) + " payload: " + + (response.getEntity() == null ? "" : response.getEntity().toString())); + MDC.clear(); + } + + public static String setDuration(long startTime, long stopTime) { + return String.valueOf(stopTime - startTime); + } +} diff --git a/src/main/java/org/onap/aai/datarouter/query/ChameleonResponseBuiler.java b/src/main/java/org/onap/aai/datarouter/query/ChameleonResponseBuiler.java index d319c48..502fbf2 100644 --- a/src/main/java/org/onap/aai/datarouter/query/ChameleonResponseBuiler.java +++ b/src/main/java/org/onap/aai/datarouter/query/ChameleonResponseBuiler.java @@ -24,7 +24,10 @@ import java.util.ArrayList; import java.util.List; import java.util.Map; +import javax.ws.rs.core.Response.Status; + import org.apache.camel.Exchange; +import org.onap.aai.datarouter.exception.DataRouterException; import com.google.gson.JsonElement; import com.google.gson.JsonObject; @@ -36,14 +39,13 @@ public class ChameleonResponseBuiler { private static final String TARGET = "target"; private static final String TYPE = "type"; - public static void buildEntity(Exchange exchange, String id){ - String response = exchange.getIn().getBody().toString(); + public static String buildEntity(String chameleonResponse, String id) throws DataRouterException{ + JsonParser parser = new JsonParser(); - JsonObject root = parser.parse(response).getAsJsonObject(); + JsonObject root = parser.parse(chameleonResponse).getAsJsonObject(); JsonObject champResponse = new JsonObject(); if (!root.has(TYPE)) { - exchange.getIn().setHeader(Exchange.HTTP_RESPONSE_CODE, 400); - return ; + throw new DataRouterException("Chameloen response does not have type : "+chameleonResponse , Status.BAD_REQUEST); } champResponse.addProperty("key", id); champResponse.addProperty(TYPE, root.get(TYPE).getAsString()); @@ -66,16 +68,19 @@ public class ChameleonResponseBuiler { champResponse.add("properties", props); - exchange.getIn().setBody(champResponse.toString()); + return champResponse.toString(); } - public static void buildObjectRelationship(Exchange exchange, String id){ + public static String buildObjectRelationship(String chameleonResponse, String id){ //TODO: implement when chameleon supports this query + return "[]"; } - public static void buildCollection(Exchange exchange){ + public static String buildCollection(String chameleonResponse){ //TODO: implement when chameleon supports this query + return "[]"; + } diff --git a/src/main/java/org/onap/aai/datarouter/query/ChameleonRouter.java b/src/main/java/org/onap/aai/datarouter/query/ChameleonRouter.java index 2df2524..4e9f75b 100644 --- a/src/main/java/org/onap/aai/datarouter/query/ChameleonRouter.java +++ b/src/main/java/org/onap/aai/datarouter/query/ChameleonRouter.java @@ -18,26 +18,40 @@ * limitations under the License. * ============LICENSE_END========================================================= */ -package org.onap.aai.datarouter.query; +package org.onap.aai.datarouter.query; import java.security.InvalidParameterException; +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; +import java.util.Map; import java.util.regex.Matcher; import java.util.regex.Pattern; -import javax.ws.rs.BadRequestException; +import javax.annotation.PostConstruct; +import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.Response.Status; -import org.apache.camel.Exchange; -import org.apache.camel.RuntimeCamelException; -import org.onap.aai.rest.RestClientEndpoint; +import org.eclipse.jetty.util.security.Password; import org.onap.aai.cl.api.Logger; import org.onap.aai.cl.eelf.LoggerFactory; +import org.onap.aai.datarouter.exception.DataRouterException; +import org.onap.aai.datarouter.util.DataRouterConstants; +import org.onap.aai.restclient.client.OperationResult; +import org.onap.aai.restclient.client.RestClient; +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.stereotype.Component; -public class ChameleonRouter extends QueryRouter { +@Component +@Qualifier("chameleon") +public class ChameleonRouter implements QueryRouter { Logger logger = LoggerFactory.getInstance().getLogger(ChameleonRouter.class.getName()); private String chameleonBaseURL; + private RestClient restClient ; + private enum ChameleonAction { GET_OBJECT_BY_ID, GET_REL_BY_ID, GET_OBJECT_RELS, GET_OBJECTS_BY_FILTER, GET_RELS_BY_FILTER }; @@ -48,13 +62,26 @@ public class ChameleonRouter extends QueryRouter { private static final Pattern QUERY_OBJECT_ID_URL_MATCH = Pattern.compile("/objects/(.*)"); private static final Pattern QUERY_REL_ID_URL_MATCH = Pattern.compile("/relationships/(.*)"); - private static final String ECOMP_QUERY_ID = "ECOMP_QUERY_ID"; - private static final String ECOMP_QUERY_TYPE = "ECOMP_QUERY_TYPE"; - public ChameleonRouter(String chameleonBaseURL) { + public ChameleonRouter(){} + + + public ChameleonRouter(String chameleonBaseURL, RestClientConfig config) { + this.chameleonBaseURL = chameleonBaseURL; + this.restClient = new RestClient().validateServerHostname(false).validateServerCertChain(true) + .clientCertFile(config.getCertPath()) + .clientCertPassword(Password.deobfuscate(config.getCertPassword())) + .trustStore(config.getTrustStorePath()) + .connectTimeoutMs(config.getConnectionTimeout()) + .readTimeoutMs(config.getReadTimeout()); + validate(); + } + + + public void validate() { String baseURL = chameleonBaseURL.endsWith("/") ? chameleonBaseURL.substring(0, chameleonBaseURL.length() - 1) : chameleonBaseURL; - if (checkRecursion(baseURL)) { + if (baseURL.contains(DATA_ROUTER_PORT)) { logger.error(QueryMsgs.QUERY_ERROR, "Invalid chameleonBaseURL : Can't re-route back to DataRouter " + chameleonBaseURL); throw new InvalidParameterException( @@ -63,17 +90,6 @@ public class ChameleonRouter extends QueryRouter { this.chameleonBaseURL = baseURL; } - public void setQueryRequest(Exchange exchange) { - setMDC(exchange); - ChameleonAction action = resolveChameleonAction(exchange); - String ecompUrl = buildUrl(exchange, action); - logger.info(QueryMsgs.QUERY_INFO, "Routing request to Chameleon service URL: " + ecompUrl); - exchange.getIn().setHeader(RestClientEndpoint.IN_HEADER_URL, ecompUrl); - exchange.getIn().setHeader("X-FromAppId", SERVICE_NAME); - exchange.getIn().setHeader("X-TransactionId", getTxId(exchange)); - - } - private boolean urlMatcher(Pattern p, String url) { Matcher m = p.matcher(url); if (m.matches() && !m.group(1).contains("/")) { @@ -83,40 +99,39 @@ public class ChameleonRouter extends QueryRouter { } } - private ChameleonAction resolveChameleonAction(Exchange exchange) { - String path = exchange.getIn().getHeader(Exchange.HTTP_PATH, String.class); - path = path.endsWith("/") ? path.substring(0, path.length() - 1) : path; + private ChameleonAction resolveChameleonAction(String urlContext) throws DataRouterException { + + urlContext = urlContext.endsWith("/") ? urlContext.substring(0, urlContext.length() - 1) : urlContext; ChameleonAction action; - if (urlMatcher(QUERY_OBJECT_FILTER_URL_MATCH, path)) { + if (urlMatcher(QUERY_OBJECT_FILTER_URL_MATCH, urlContext)) { action = ChameleonAction.GET_OBJECTS_BY_FILTER; - } else if (urlMatcher(QUERY_REL_FILTER_URL_MATCH, path)) { + } else if (urlMatcher(QUERY_REL_FILTER_URL_MATCH, urlContext)) { action = ChameleonAction.GET_RELS_BY_FILTER; - } else if (urlMatcher(QUERY_OBJECT_REL_URL_MATCH, path)) { + } else if (urlMatcher(QUERY_OBJECT_REL_URL_MATCH, urlContext)) { action = ChameleonAction.GET_OBJECT_RELS; - } else if (urlMatcher(QUERY_OBJECT_ID_URL_MATCH, path)) { + } else if (urlMatcher(QUERY_OBJECT_ID_URL_MATCH, urlContext)) { action = ChameleonAction.GET_OBJECT_BY_ID; - } else if (urlMatcher(QUERY_REL_ID_URL_MATCH, path)) { + } else if (urlMatcher(QUERY_REL_ID_URL_MATCH, urlContext)) { action = ChameleonAction.GET_REL_BY_ID; } else { - exchange.getIn().setHeader(ChameleonErrorProcessor.ECOMP_QUERY_ERROR_CODE, 404); - throw new RuntimeCamelException(); + + throw new DataRouterException("", Status.NOT_FOUND); } return action; } - private String buildUrl(Exchange exchange, ChameleonAction action) { - String path = exchange.getIn().getHeader(Exchange.HTTP_PATH, String.class); - path = path.endsWith("/") ? path.substring(0, path.length() - 1) : path; - String queryParams = exchange.getIn().getHeader(Exchange.HTTP_QUERY, String.class); + private String buildUrl(String urlContext, String queryParams, ChameleonAction action) { + + urlContext = urlContext.endsWith("/") ? urlContext.substring(0, urlContext.length() - 1) : urlContext; String ecompUrl = ""; String ID = ""; switch (action) { case GET_OBJECT_BY_ID: - ID = path.substring(path.lastIndexOf("/") + 1, path.length()); + ID = urlContext.substring(urlContext.lastIndexOf("/") + 1, urlContext.length()); if (ID == null || ID.isEmpty()) { - throw new IllegalArgumentException("Invalid URI path with no Object ID: " + path); + throw new IllegalArgumentException("Invalid URI path with no Object ID: " + urlContext); } else { if (queryParams != null && !queryParams.isEmpty()) { ecompUrl = chameleonBaseURL + "/" + ID + "?" + queryParams; @@ -125,14 +140,13 @@ public class ChameleonRouter extends QueryRouter { ecompUrl = chameleonBaseURL + "/" + ID; } } - exchange.getIn().setHeader(ECOMP_QUERY_ID, ID); - exchange.getIn().setHeader(ECOMP_QUERY_TYPE, ChameleonAction.GET_OBJECT_BY_ID); + break; case GET_REL_BY_ID: - ID = path.substring(path.lastIndexOf("/") + 1, path.length()); + ID = urlContext.substring(urlContext.lastIndexOf("/") + 1, urlContext.length()); if (ID == null || ID.isEmpty()) { - throw new IllegalArgumentException("Invalid URI path with no Relationship ID: " + path); + throw new IllegalArgumentException("Invalid URI path with no Relationship ID: " + urlContext); } else { if (queryParams != null && !queryParams.isEmpty()) { ecompUrl = chameleonBaseURL + "/" + ID + "?" + queryParams; @@ -141,14 +155,13 @@ public class ChameleonRouter extends QueryRouter { ecompUrl = chameleonBaseURL + "/" + ID; } } - exchange.getIn().setHeader(ECOMP_QUERY_ID, ID); - exchange.getIn().setHeader(ECOMP_QUERY_TYPE, ChameleonAction.GET_REL_BY_ID); + break; case GET_OBJECT_RELS: - ID = path.substring(path.lastIndexOf("/") + 1, path.length()); + ID = urlContext.substring(urlContext.lastIndexOf("/") + 1, urlContext.length()); if (ID == null || ID.isEmpty()) { - throw new IllegalArgumentException("Invalid URI path with no Object ID: " + path); + throw new IllegalArgumentException("Invalid URI path with no Object ID: " + urlContext); } else { if (queryParams != null && !queryParams.isEmpty()) { // TODO: Fix the URL for getting object relations when Chameloen @@ -159,8 +172,7 @@ public class ChameleonRouter extends QueryRouter { ecompUrl = chameleonBaseURL + "/relations" + ID; } } - exchange.getIn().setHeader(ECOMP_QUERY_ID, ID); - exchange.getIn().setHeader(ECOMP_QUERY_TYPE, ChameleonAction.GET_OBJECT_RELS); + break; case GET_OBJECTS_BY_FILTER: @@ -171,7 +183,7 @@ public class ChameleonRouter extends QueryRouter { } else { ecompUrl = chameleonBaseURL + "/filter"; } - exchange.getIn().setHeader(ECOMP_QUERY_TYPE, ChameleonAction.GET_OBJECTS_BY_FILTER); + break; case GET_RELS_BY_FILTER: @@ -182,7 +194,7 @@ public class ChameleonRouter extends QueryRouter { } else { ecompUrl = chameleonBaseURL + "/filter"; } - exchange.getIn().setHeader(ECOMP_QUERY_TYPE, ChameleonAction.GET_RELS_BY_FILTER); + break; } @@ -190,86 +202,83 @@ public class ChameleonRouter extends QueryRouter { return ecompUrl; } - public void setQueryResponse(Exchange exchange) { - parseResponse(exchange); - adjustHeaders(exchange); - } - - private void adjustHeaders(Exchange exchange) { - // Remove the internal heders - exchange.getIn().removeHeader(ECOMP_QUERY_ID); - exchange.getIn().removeHeader(ECOMP_QUERY_TYPE); - } + private String parseResponse(String urlContext, OperationResult result, ChameleonAction action) + throws DataRouterException { - private void parseResponse(Exchange exchange) throws BadRequestException { - - ChameleonAction action = exchange.getIn().getHeader(ECOMP_QUERY_TYPE, ChameleonAction.class); - Integer httpResponseCode = exchange.getIn().getHeader(RestClientEndpoint.OUT_HEADER_RESPONSE_CODE, Integer.class); - String ID = ""; + Integer httpResponseCode = result.getResultCode(); + String ID = urlContext.substring(urlContext.lastIndexOf("/") + 1, urlContext.length()); switch (action) { case GET_OBJECT_BY_ID: if (httpResponseCode >= 200 && httpResponseCode <= 299) { - ID = exchange.getIn().getHeader(ECOMP_QUERY_ID, String.class); if (ID == null || ID.isEmpty()) { - exchange.getIn().setHeader(Exchange.HTTP_RESPONSE_CODE, 400); + throw new DataRouterException("", Status.BAD_REQUEST); } else { - ChameleonResponseBuiler.buildEntity(exchange, ID); + return ChameleonResponseBuiler.buildEntity(result.getResult(), ID); } } else { - exchange.getIn().setHeader(Exchange.HTTP_RESPONSE_CODE, httpResponseCode); + throw new DataRouterException("", Status.fromStatusCode(httpResponseCode)); } - break; + case GET_REL_BY_ID: if (httpResponseCode >= 200 && httpResponseCode <= 299) { - ID = exchange.getIn().getHeader(ECOMP_QUERY_ID, String.class); + if (ID == null || ID.isEmpty()) { - exchange.getIn().setHeader(Exchange.HTTP_RESPONSE_CODE, 400); + throw new DataRouterException("", Status.BAD_REQUEST); } else { - ChameleonResponseBuiler.buildEntity(exchange, ID); + return ChameleonResponseBuiler.buildEntity(result.getResult(), ID); } } else { - exchange.getIn().setHeader(Exchange.HTTP_RESPONSE_CODE, httpResponseCode); + throw new DataRouterException("", Status.fromStatusCode(httpResponseCode)); } - break; + case GET_OBJECT_RELS: - if (httpResponseCode >= 200 && httpResponseCode <= 299) { - ID = exchange.getIn().getHeader(ECOMP_QUERY_ID, String.class); - if (ID == null || ID.isEmpty()) { - exchange.getIn().setHeader(Exchange.HTTP_RESPONSE_CODE, 400); - } else { - ChameleonResponseBuiler.buildObjectRelationship(exchange, ID); - } + + // TODO:Return 200 with empty body for now until chameleon supports this + // query + if (ID == null || ID.isEmpty()) { + throw new DataRouterException("", Status.BAD_REQUEST); } else { - // TODO:Return 200 with empty body for now until chameleon supports this - // query - exchange.getIn().setHeader(Exchange.HTTP_RESPONSE_CODE, 200); - exchange.getIn().setBody("[]"); + return ChameleonResponseBuiler.buildObjectRelationship(result.getResult(), ID); } - break; + case GET_OBJECTS_BY_FILTER: - if (httpResponseCode >= 200 && httpResponseCode <= 299) { - ChameleonResponseBuiler.buildCollection(exchange); - } else { - // TODO:Return 200 with empty body for now until chameleon supports this - // query - exchange.getIn().setHeader(Exchange.HTTP_RESPONSE_CODE, 200); - exchange.getIn().setBody("[]"); - } - break; + // TODO:Return 200 with empty body for now until chameleon supports this + // query + return ChameleonResponseBuiler.buildCollection(result.getResult()); + case GET_RELS_BY_FILTER: - if (httpResponseCode >= 200 && httpResponseCode <= 299) { - ChameleonResponseBuiler.buildCollection(exchange); - } else { - // TODO:Return 200 with empty body for now until chameleon supports this - // query - exchange.getIn().setHeader(Exchange.HTTP_RESPONSE_CODE, 200); - exchange.getIn().setBody("[]"); - } - break; + // TODO:Return 200 with empty body for now until chameleon supports this + // query + return ChameleonResponseBuiler.buildCollection(result.getResult()); + default: + throw new DataRouterException("", Status.NOT_FOUND); + + } + + } + @Override + public String process(String urlContext, String queryParams, Map> headers) + throws DataRouterException { + String response; + ChameleonAction action = resolveChameleonAction(urlContext); + String chameleonURL = buildUrl(urlContext, queryParams, action); + logger.info(QueryMsgs.QUERY_INFO, "Routing request to Chameleon service URL: " + chameleonURL); + + headers = headers == null ? new HashMap>() : headers; + headers.put("X-FromAppId", Arrays.asList(DataRouterConstants.DATA_ROUTER_SERVICE_NAME)); + OperationResult result = restClient.get(chameleonURL, headers, MediaType.APPLICATION_JSON_TYPE); + + try { + response = parseResponse(urlContext, result, action); + } catch (DataRouterException ex) { + logger.info(QueryMsgs.QUERY_ERROR, + "Error while calling Chameleon service URL: " + chameleonURL + " failure cause: " + result.getFailureCause()); + throw ex; } + return response; } } diff --git a/src/main/java/org/onap/aai/datarouter/query/ChampRouter.java b/src/main/java/org/onap/aai/datarouter/query/ChampRouter.java index a120f89..7e63869 100644 --- a/src/main/java/org/onap/aai/datarouter/query/ChampRouter.java +++ b/src/main/java/org/onap/aai/datarouter/query/ChampRouter.java @@ -21,50 +21,87 @@ package org.onap.aai.datarouter.query; import java.security.InvalidParameterException; +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; +import java.util.Map; -import org.apache.camel.Exchange; -import org.onap.aai.rest.RestClientEndpoint; +import javax.annotation.PostConstruct; +import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.Response.Status; + +import org.eclipse.jetty.util.security.Password; import org.onap.aai.cl.api.Logger; import org.onap.aai.cl.eelf.LoggerFactory; +import org.onap.aai.datarouter.exception.DataRouterException; +import org.onap.aai.datarouter.util.DataRouterConstants; +import org.onap.aai.restclient.client.OperationResult; +import org.onap.aai.restclient.client.RestClient; +import org.onap.aai.restclient.rest.HttpUtil; +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.stereotype.Component; + -public class ChampRouter extends QueryRouter { +@Component +@Qualifier("champ") +public class ChampRouter implements QueryRouter { Logger logger = LoggerFactory.getInstance().getLogger(ChampRouter.class.getName()); private String champBaseURL; + + private RestClient restClient ; + public ChampRouter(){} + + public ChampRouter(String champBaseURL, RestClientConfig config) { + this.champBaseURL = champBaseURL; + this.restClient = new RestClient().validateServerHostname(false).validateServerCertChain(true) + .clientCertFile(config.getCertPath()) + .clientCertPassword(Password.deobfuscate(config.getCertPassword())) + .trustStore(config.getTrustStorePath()) + .connectTimeoutMs(config.getConnectionTimeout()) + .readTimeoutMs(config.getReadTimeout()); + validate(); + } - public ChampRouter(String champBaseURL) { - String baseURL = champBaseURL.endsWith("/") ? champBaseURL.substring(0, champBaseURL.length() - 1) - : champBaseURL; - if(checkRecursion(baseURL)){ - logger.info(QueryMsgs.QUERY_INFO, "Invalid champBaseURL : Can't re-route back to DataRouter "+ champBaseURL); - throw new InvalidParameterException("Invalid champBaseURL : Can't re-route back to DataRouter "+ champBaseURL); + + public void validate(){ + String baseURL = champBaseURL.endsWith("/") ? champBaseURL.substring(0, champBaseURL.length() - 1) : champBaseURL; + if (baseURL.contains(DATA_ROUTER_PORT)) { + logger.info(QueryMsgs.QUERY_INFO, "Invalid champBaseURL : Can't re-route back to DataRouter " + champBaseURL); + throw new InvalidParameterException("Invalid champBaseURL : Can't re-route back to DataRouter " + champBaseURL); } - this.champBaseURL = baseURL; + this.champBaseURL = baseURL; } - public void setQueryRequest(Exchange exchange) { - setMDC(exchange); - String path = exchange.getIn().getHeader(Exchange.HTTP_PATH, String.class); - String queryParams = exchange.getIn().getHeader(Exchange.HTTP_QUERY, String.class); - String ecompUrl; + @Override + public String process(String urlContext, String queryParams, Map> headers) + throws DataRouterException { + String champURL; + String response; if (queryParams != null && !queryParams.isEmpty()) { - ecompUrl = champBaseURL + path + "?" + queryParams; + champURL = champBaseURL + urlContext + "?" + queryParams; } else { - ecompUrl = champBaseURL + path; + champURL = champBaseURL + urlContext; } - logger.info(QueryMsgs.QUERY_INFO, "Routing request to Champ service URL: " + ecompUrl); - exchange.getIn().setHeader(RestClientEndpoint.IN_HEADER_URL, ecompUrl); - exchange.getIn().setHeader("X-FromAppId", SERVICE_NAME); - exchange.getIn().setHeader("X-TransactionId", getTxId(exchange)); + logger.info(QueryMsgs.QUERY_INFO, "Routing request to Champ service URL: " + champURL); - } + headers = headers == null ? new HashMap>() : headers; + headers.put("X-FromAppId", Arrays.asList(DataRouterConstants.DATA_ROUTER_SERVICE_NAME)); + OperationResult result = restClient.get(champURL, headers, MediaType.APPLICATION_JSON_TYPE); + + if (HttpUtil.isHttpResponseClassSuccess(result.getResultCode())) { + response = result.getResult(); + } else { + logger.info(QueryMsgs.QUERY_ERROR, + "Error while calling Champ service URL: " + champURL + " failure cause: " + result.getFailureCause()); + throw new DataRouterException( + "Error while calling Champ service URL: " + champURL + " failure cause: " + result.getFailureCause(), + Status.fromStatusCode(result.getResultCode())); + } - public void setQueryResponse(Exchange exchange) { - Integer httpResponseCode = exchange.getIn().getHeader(RestClientEndpoint.OUT_HEADER_RESPONSE_CODE, Integer.class); - // Object httpBody = exchange.getIn().getBody(); - exchange.getIn().setHeader(Exchange.HTTP_RESPONSE_CODE, httpResponseCode); + return response; } diff --git a/src/main/java/org/onap/aai/datarouter/query/QueryRouter.java b/src/main/java/org/onap/aai/datarouter/query/QueryRouter.java index aabeac2..07b4e79 100644 --- a/src/main/java/org/onap/aai/datarouter/query/QueryRouter.java +++ b/src/main/java/org/onap/aai/datarouter/query/QueryRouter.java @@ -20,55 +20,22 @@ */ package org.onap.aai.datarouter.query; +import java.util.List; import java.util.Map; -import java.util.UUID; -import org.apache.camel.Exchange; import org.onap.aai.cl.api.Logger; import org.onap.aai.cl.eelf.LoggerFactory; -import org.onap.aai.cl.mdc.MdcContext; +import org.onap.aai.datarouter.exception.DataRouterException; - -public abstract class QueryRouter { +public interface QueryRouter { Logger logger = LoggerFactory.getInstance().getLogger(QueryRouter.class.getName()); - protected static final String SERVICE_NAME = "DATA-ROUTER"; - /** HTTP header containing the ECOMP Request Id */ - protected static final String HEADER_TRANS_ID = "X-TransactionId"; - - /** HTTP header containing the calling application Id */ - protected static final String HEADER_FROM_APP_ID = "X-FromAppId"; - - /** HTTP header containing the calling host details */ - protected static final String HEADER_FROM_HOST = "Host"; - - /** HTTP header containing the calling host details */ - protected static final String DATA_ROUTER_PORT = "9502"; - - public abstract void setQueryRequest(Exchange exchange) ; - - public abstract void setQueryResponse(Exchange exchange); - - protected String getTxId(final Exchange exchange){ - String txId = exchange.getIn().getHeader("X-TransactionId",String.class); - return ((txId==null||txId.isEmpty())?UUID.randomUUID().toString():txId); - } - - protected boolean checkRecursion(String url){ - return url.contains(DATA_ROUTER_PORT); - } - - protected void setMDC(final Exchange exchange) { - String transId = exchange.getIn().getHeader(HEADER_TRANS_ID, String.class); - String appId = exchange.getIn().getHeader(HEADER_FROM_APP_ID, String.class); - String hostId = exchange.getIn().getHeader(HEADER_FROM_HOST, String.class); + /** HTTP header containing the calling host details */ + static final String DATA_ROUTER_PORT = "9502"; - // Set MDC transaction id, calling service name, calling service id, - // partner name, client address - MdcContext.initialize(transId, "DataRouter", "", appId, hostId); - } - + public String process(String urlContext, String queryParams, Map> headers) + throws DataRouterException; } diff --git a/src/main/java/org/onap/aai/datarouter/query/RestClientConfig.java b/src/main/java/org/onap/aai/datarouter/query/RestClientConfig.java new file mode 100644 index 0000000..96a61ba --- /dev/null +++ b/src/main/java/org/onap/aai/datarouter/query/RestClientConfig.java @@ -0,0 +1,87 @@ +/** + * ============LICENSE_START======================================================= + * org.onap.aai + * ================================================================================ + * Copyright © 2017-2018 AT&T Intellectual Property. All rights reserved. + * Copyright © 2017-2018 Amdocs + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ +package org.onap.aai.datarouter.query; + +public class RestClientConfig { + + private String certPath; + private String certPassword; + private String trustStorePath; + private String connectionTimeout; + private String readTimeout; + + public String getCertPath() { + return certPath; + } + + public void setCertPath(String certPath) { + this.certPath = certPath; + } + + public String getCertPassword() { + return certPassword; + } + + public void setCertPassword(String certPassword) { + this.certPassword = certPassword; + } + + public String getTrustStorePath() { + return trustStorePath; + } + + public void setTrustStorePath(String trustStorePath) { + this.trustStorePath = trustStorePath; + } + + public int getConnectionTimeout() { + return parseInt(connectionTimeout,10000); + } + + public void setConnectionTimeout(String connectionTimeout) { + this.connectionTimeout = connectionTimeout; + } + + public int getReadTimeout() { + return parseInt(connectionTimeout,10000); + } + + public void setReadTimeout(String readTimeout) { + this.readTimeout = readTimeout; + } + + + private int parseInt(String config, int defaultValue) { + int intVal = defaultValue; // Default delay of half a sec + try { + intVal = Integer.parseInt(config); + } catch (Exception e) { + // Ignore the parsing error and use the default + } + return intVal; + } + @Override + public String toString() { + return "RestClientConfig [certPath=" + certPath + ", certPassword=" + certPassword + ", trustStorePath=" + + trustStorePath + ", connectionTimeout=" + connectionTimeout + ", readTimeout=" + readTimeout + "]"; + } + +} diff --git a/src/main/java/org/onap/aai/datarouter/service/EchoService.java b/src/main/java/org/onap/aai/datarouter/service/EchoService.java index 8192935..70bc129 100644 --- a/src/main/java/org/onap/aai/datarouter/service/EchoService.java +++ b/src/main/java/org/onap/aai/datarouter/service/EchoService.java @@ -20,15 +20,6 @@ */ package org.onap.aai.datarouter.service; -import org.onap.aai.cl.api.LogFields; -import org.onap.aai.cl.api.LogLine; -import org.onap.aai.cl.api.Logger; -import org.onap.aai.cl.eelf.LoggerFactory; -import org.onap.aai.cl.mdc.MdcContext; -import org.onap.aai.datarouter.logging.DataRouterMsgs; -import org.onap.aai.datarouter.util.DataRouterConstants; -import org.slf4j.MDC; - import javax.servlet.http.HttpServletRequest; import javax.ws.rs.GET; import javax.ws.rs.Path; @@ -39,6 +30,18 @@ import javax.ws.rs.core.HttpHeaders; import javax.ws.rs.core.Response; import javax.ws.rs.core.UriInfo; +import org.onap.aai.cl.api.LogFields; +import org.onap.aai.cl.api.LogLine; +import org.onap.aai.cl.api.Logger; +import org.onap.aai.cl.eelf.LoggerFactory; +import org.onap.aai.cl.mdc.MdcContext; +import org.onap.aai.datarouter.logging.DataRouterMsgs; +import org.onap.aai.datarouter.util.DataRouterConstants; +import org.slf4j.MDC; +import org.springframework.stereotype.Component; + +@Component +@Path("/data-router/v1") public class EchoService { private static Logger logger = LoggerFactory.getInstance().getLogger(EchoService.class.getName()); @@ -48,7 +51,7 @@ public class EchoService { private static final String XTRANSACTIONID = "X-TransactionId"; @GET - @Path("echo/{input}") + @Path("/echo/{input}") @Produces("text/plain") public String ping(@PathParam("input") String input, @Context HttpHeaders headers, @Context UriInfo info, @Context HttpServletRequest req) { diff --git a/src/main/java/org/onap/aai/datarouter/service/HistoricalQueryService.java b/src/main/java/org/onap/aai/datarouter/service/HistoricalQueryService.java new file mode 100644 index 0000000..2b401b0 --- /dev/null +++ b/src/main/java/org/onap/aai/datarouter/service/HistoricalQueryService.java @@ -0,0 +1,107 @@ +/** + * ============LICENSE_START======================================================= + * org.onap.aai + * ================================================================================ + * Copyright © 2017-2018 AT&T Intellectual Property. All rights reserved. + * Copyright © 2017-2018 Amdocs + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ +package org.onap.aai.datarouter.service; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import javax.servlet.http.HttpServletRequest; +import javax.ws.rs.Consumes; +import javax.ws.rs.Encoded; +import javax.ws.rs.GET; +import javax.ws.rs.Path; +import javax.ws.rs.PathParam; +import javax.ws.rs.Produces; +import javax.ws.rs.core.Context; +import javax.ws.rs.core.HttpHeaders; +import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.Response; +import javax.ws.rs.core.Response.Status; +import javax.ws.rs.core.UriInfo; + +import org.onap.aai.cl.api.Logger; +import org.onap.aai.cl.eelf.LoggerFactory; +import org.onap.aai.datarouter.exception.DataRouterException; +import org.onap.aai.datarouter.logging.DataRouterMsgs; +import org.onap.aai.datarouter.logging.LoggingUtil; +import org.onap.aai.datarouter.query.QueryRouter; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.stereotype.Component; + +@Component +@Path("/services/champ-service/v1") +public class HistoricalQueryService { + + private Logger logger = LoggerFactory.getInstance().getLogger(HistoricalQueryService.class); + Logger auditLogger = LoggerFactory.getInstance().getAuditLogger(HistoricalQueryService.class.getName()); + private static Logger metricsLogger = LoggerFactory.getInstance() + .getMetricsLogger(HistoricalQueryService.class.getName()); + + @Autowired + @Qualifier("champ") + private QueryRouter champRouter; + + @Autowired + @Qualifier("chameleon") + private QueryRouter chameleonRouter; + + @GET + @Path("{uri: .+}") + @Produces({ MediaType.APPLICATION_JSON }) + public Response process(String content, @PathParam("version") String versionParam, + @PathParam("uri") @Encoded String uri, @Context HttpHeaders httpHeaders, @Context UriInfo uriInfo, + @Context HttpServletRequest req) { + LoggingUtil.initMdcContext(req, httpHeaders); + long startTimeInMs = System.currentTimeMillis(); + Response response = null; + String urlContext = "/"+ uri; + String queryParams = uriInfo.getRequestUri().getQuery(); + + try { + + Map> parameters = new HashMap>(); + for (Map.Entry> e : httpHeaders.getRequestHeaders().entrySet()) { + parameters.put(e.getKey(), e.getValue()); + } + if (uriInfo.getQueryParameters().containsKey("t-k")) { + response = Response.status(Status.OK).entity(chameleonRouter.process(urlContext, queryParams, parameters)) + .build(); + } else { + response = Response.status(Status.OK).entity(champRouter.process(urlContext, queryParams, parameters)).build(); + } + } catch (DataRouterException ex) { + response = Response.status(ex.getHttpStatus()).entity(ex.getMessage()).build(); + + } catch (Exception e) { + response = Response.status(Status.INTERNAL_SERVER_ERROR).entity(e.getMessage()).build(); + + } finally { + LoggingUtil.logRestRequest(logger, auditLogger, req, response); + metricsLogger.info(DataRouterMsgs.PROCESSED_REQUEST, "GET", + Long.toString(System.currentTimeMillis() - startTimeInMs)); + } + return response; + + } + +} diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties index 74a378f..6233e5c 100644 --- a/src/main/resources/application.properties +++ b/src/main/resources/application.properties @@ -1 +1,14 @@ -camel.springboot.xmlRoutes = file:${DYNAMIC_ROUTES}/*.route \ No newline at end of file +camel.springboot.xmlRoutes = file:${DYNAMIC_ROUTES}/*.route +server.ssl.key-store=file:${CONFIG_HOME}/auth/tomcat_keystore + +server.ssl.enabled=true +server.port=9502 +server.ssl.client-auth=want + +server.ssl.enabled-protocols=TLSv1.1,TLSv1.2 +#server.ssl.key-store=client-cert-onap.p12 +#server.ssl.key-store-password=onapSecret +#server.ssl.trust-store=C:\\ONAP\\spring\\data-router\\dynamic\\tomcat_keystore +#server.ssl.trust-store-password=onapSecret +#server.ssl.client-auth=want +server.ssl.key-store-type=JKS \ No newline at end of file diff --git a/src/main/resources/logging/DataRouterMsgs.properties b/src/main/resources/logging/DataRouterMsgs.properties index fff262c..6267321 100644 --- a/src/main/resources/logging/DataRouterMsgs.properties +++ b/src/main/resources/logging/DataRouterMsgs.properties @@ -170,4 +170,7 @@ FAIL_TO_CREATE_UPDATE_DOC=\ Failed to create or update document in index {0}. Cause: {1} LOAD_OXM_ERROR=\ DR5000E|\ - Unable to load Oxm model: {0}\ + Unable to load Oxm model: {0}\ +PROCESSED_REQUEST=\ + DR00015I|\ + Processed DataRouter {0} request in {1} ms diff --git a/src/test/java/org/onap/aai/datarouter/query/ChameleonRouterTest.java b/src/test/java/org/onap/aai/datarouter/query/ChameleonRouterTest.java new file mode 100644 index 0000000..27c2606 --- /dev/null +++ b/src/test/java/org/onap/aai/datarouter/query/ChameleonRouterTest.java @@ -0,0 +1,104 @@ +/** + * ============LICENSE_START======================================================= + * org.onap.aai + * ================================================================================ + * Copyright © 2017-2018 AT&T Intellectual Property. All rights reserved. + * Copyright © 2017-2018 Amdocs + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ +package org.onap.aai.datarouter.query; + +import static org.mockito.Matchers.any; +import static org.mockito.Mockito.mock; + +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.util.HashMap; + +import javax.ws.rs.core.MediaType; + +import org.apache.commons.io.IOUtils; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.onap.aai.restclient.client.OperationResult; +import org.onap.aai.restclient.client.RestClient; +import org.powermock.api.mockito.PowerMockito; +import org.powermock.core.classloader.annotations.PrepareForTest; +import org.powermock.modules.junit4.PowerMockRunner; + +import com.google.gson.JsonParser; + +@RunWith(PowerMockRunner.class) +@PrepareForTest({ ChameleonRouter.class, RestClient.class }) +public class ChameleonRouterTest { + + ChameleonRouter chameleonRouter; + RestClient mockRestClient = mock(RestClient.class); + + JsonParser parser = new JsonParser(); + + @SuppressWarnings("unchecked") + @Before + public void init() throws Exception { + RestClientConfig config = PowerMockito.mock(RestClientConfig.class); + PowerMockito.when(config.getCertPassword()).thenReturn("password"); + + PowerMockito.whenNew(RestClient.class).withAnyArguments().thenReturn(mockRestClient); + PowerMockito.when(mockRestClient.validateServerHostname(any(Boolean.class))).thenReturn(mockRestClient); + PowerMockito.when(mockRestClient.validateServerCertChain(any(Boolean.class))).thenReturn(mockRestClient); + PowerMockito.when(mockRestClient.clientCertFile(any(String.class))).thenReturn(mockRestClient); + PowerMockito.when(mockRestClient.clientCertPassword(any(String.class))).thenReturn(mockRestClient); + PowerMockito.when(mockRestClient.trustStore(any(String.class))).thenReturn(mockRestClient); + PowerMockito.when(mockRestClient.connectTimeoutMs(any(Integer.class))).thenReturn(mockRestClient); + PowerMockito.when(mockRestClient.readTimeoutMs(any(Integer.class))).thenReturn(mockRestClient); + + chameleonRouter = new ChameleonRouter("http:///test", config); + } + + @Test + public void testProcess() throws Exception { + OperationResult chameleonResponse = buildChameleonResponse(); + PowerMockito.when(mockRestClient.get(any(String.class), any(HashMap.class), any(MediaType.class))) + .thenReturn(chameleonResponse); + + String chameleonRouterResponse = chameleonRouter.process("/objects/364d646e-c947-4010-a66a-adf06aa306fb", "", null); + Assert.assertEquals(parser.parse(chameleonRouterResponse), parser.parse(readSampleChampResponse())); + + } + + private OperationResult buildChameleonResponse() throws IOException { + OperationResult response = new OperationResult(); + response.setResultCode(200); + + response.setResult(readSampleChameleonResponse()); + return response; + } + + private String readSampleChampResponse() throws IOException { + FileInputStream event = new FileInputStream(new File("src/test/resources/champ-response.json")); + String json = IOUtils.toString(event, "UTF-8"); + return json; + } + + private String readSampleChameleonResponse() throws IOException { + FileInputStream event = new FileInputStream(new File("src/test/resources/chameleon-response.json")); + String json = IOUtils.toString(event, "UTF-8"); + return json; + } + +} diff --git a/src/test/java/org/onap/aai/datarouter/query/ChampRouterTest.java b/src/test/java/org/onap/aai/datarouter/query/ChampRouterTest.java new file mode 100644 index 0000000..1bf7c88 --- /dev/null +++ b/src/test/java/org/onap/aai/datarouter/query/ChampRouterTest.java @@ -0,0 +1,94 @@ +/** + * ============LICENSE_START======================================================= + * org.onap.aai + * ================================================================================ + * Copyright © 2017-2018 AT&T Intellectual Property. All rights reserved. + * Copyright © 2017-2018 Amdocs + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ +package org.onap.aai.datarouter.query; + +import static org.mockito.Matchers.any; +import static org.mockito.Mockito.mock; + +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.util.HashMap; + +import javax.ws.rs.core.MediaType; + +import org.apache.commons.io.IOUtils; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.onap.aai.restclient.client.OperationResult; +import org.onap.aai.restclient.client.RestClient; +import org.powermock.api.mockito.PowerMockito; +import org.powermock.core.classloader.annotations.PrepareForTest; +import org.powermock.modules.junit4.PowerMockRunner; + +@RunWith(PowerMockRunner.class) +@PrepareForTest({ ChampRouter.class, RestClient.class }) +public class ChampRouterTest { + + ChampRouter champRouter; + RestClient mockRestClient = mock(RestClient.class); + + @SuppressWarnings("unchecked") + @Before + public void init() throws Exception { + RestClientConfig config = PowerMockito.mock(RestClientConfig.class); + PowerMockito.when(config.getCertPassword()).thenReturn("password"); + + PowerMockito.whenNew(RestClient.class).withAnyArguments().thenReturn(mockRestClient); + PowerMockito.when(mockRestClient.validateServerHostname(any(Boolean.class))).thenReturn(mockRestClient); + PowerMockito.when(mockRestClient.validateServerCertChain(any(Boolean.class))).thenReturn(mockRestClient); + PowerMockito.when(mockRestClient.clientCertFile(any(String.class))).thenReturn(mockRestClient); + PowerMockito.when(mockRestClient.clientCertPassword(any(String.class))).thenReturn(mockRestClient); + PowerMockito.when(mockRestClient.trustStore(any(String.class))).thenReturn(mockRestClient); + PowerMockito.when(mockRestClient.connectTimeoutMs(any(Integer.class))).thenReturn(mockRestClient); + PowerMockito.when(mockRestClient.readTimeoutMs(any(Integer.class))).thenReturn(mockRestClient); + + champRouter = new ChampRouter("http:///test", config); + } + + @Test + public void testProcess() throws Exception { + OperationResult champResponse = buildChampResponse(); + PowerMockito.when(mockRestClient.get(any(String.class), any(HashMap.class), any(MediaType.class))) + .thenReturn(champResponse); + + String champRouterResponse = champRouter.process("/object/1234", "", null); + Assert.assertEquals(champRouterResponse, readSampleChampResponse()); + + } + + private OperationResult buildChampResponse() throws IOException { + OperationResult response = new OperationResult(); + response.setResultCode(200); + + response.setResult(readSampleChampResponse()); + return response; + } + + private String readSampleChampResponse() throws IOException { + FileInputStream event = new FileInputStream(new File("src/test/resources/champ-response.json")); + String json = IOUtils.toString(event, "UTF-8"); + return json; + } + +} diff --git a/src/test/resources/chameleon-response.json b/src/test/resources/chameleon-response.json new file mode 100644 index 0000000..056bd46 --- /dev/null +++ b/src/test/resources/chameleon-response.json @@ -0,0 +1,13 @@ +{ + "ptnii-equip-name": "mtanj119snd-updated-now", + "equip-type": "phone", + "equip-vendor": "Samsung", + "fqdn": "mtanjrsv119.mtanj.sbcglobal.net", + "purpose": "", + "ipv4-oam-address": "135.182.138.60", + "hostname": "phonehost", + "equip-model": "DL380p-nd", + "aai-uuid": "364d646e-c947-4010-a66a-adf06aa306fb", + "resource-version": "1477013499", + "type": "pserver" +} \ No newline at end of file diff --git a/src/test/resources/champ-response.json b/src/test/resources/champ-response.json new file mode 100644 index 0000000..105f408 --- /dev/null +++ b/src/test/resources/champ-response.json @@ -0,0 +1,16 @@ +{ + "key": "364d646e-c947-4010-a66a-adf06aa306fb", + "type": "pserver", + "properties": { + "ptnii-equip-name": "mtanj119snd-updated-now", + "equip-type": "phone", + "equip-vendor": "Samsung", + "fqdn": "mtanjrsv119.mtanj.sbcglobal.net", + "purpose": "", + "ipv4-oam-address": "135.182.138.60", + "hostname": "phonehost", + "equip-model": "DL380p-nd", + "aai-uuid": "364d646e-c947-4010-a66a-adf06aa306fb", + "resource-version": "1477013499" + } +} \ No newline at end of file -- 2.16.6