2 * ============LICENSE_START=======================================================
4 * ================================================================================
5 * Copyright © 2017-2018 AT&T Intellectual Property. All rights reserved.
6 * Copyright © 2017-2018 Amdocs
7 * ================================================================================
8 * Licensed under the Apache License, Version 2.0 (the "License");
9 * you may not use this file except in compliance with the License.
10 * You may obtain a copy of the License at
12 * http://www.apache.org/licenses/LICENSE-2.0
14 * Unless required by applicable law or agreed to in writing, software
15 * distributed under the License is distributed on an "AS IS" BASIS,
16 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17 * See the License for the specific language governing permissions and
18 * limitations under the License.
19 * ============LICENSE_END=========================================================
21 package org.onap.aai.datarouter.query;
23 import java.security.InvalidParameterException;
24 import java.util.Arrays;
25 import java.util.HashMap;
26 import java.util.List;
28 import java.util.regex.Matcher;
29 import java.util.regex.Pattern;
31 import javax.annotation.PostConstruct;
32 import javax.ws.rs.core.MediaType;
33 import javax.ws.rs.core.Response.Status;
35 import org.eclipse.jetty.util.security.Password;
36 import org.onap.aai.cl.api.Logger;
37 import org.onap.aai.cl.eelf.LoggerFactory;
38 import org.onap.aai.datarouter.exception.DataRouterException;
39 import org.onap.aai.datarouter.util.DataRouterConstants;
40 import org.onap.aai.restclient.client.OperationResult;
41 import org.onap.aai.restclient.client.RestClient;
42 import org.springframework.beans.factory.annotation.Qualifier;
43 import org.springframework.stereotype.Component;
46 @Qualifier("chameleon")
47 public class ChameleonRouter implements QueryRouter {
49 Logger logger = LoggerFactory.getInstance().getLogger(ChameleonRouter.class.getName());
51 private String chameleonBaseURL;
53 private RestClient restClient ;
55 private enum ChameleonAction {
56 GET_OBJECT_BY_ID, GET_REL_BY_ID, GET_OBJECT_RELS, GET_OBJECTS_BY_FILTER, GET_RELS_BY_FILTER
59 private static final Pattern QUERY_OBJECT_FILTER_URL_MATCH = Pattern.compile("/objects/filter(.*)");
60 private static final Pattern QUERY_REL_FILTER_URL_MATCH = Pattern.compile("/relationships/filter(.*)");
61 private static final Pattern QUERY_OBJECT_REL_URL_MATCH = Pattern.compile("/objects/relationships/(.*)");
62 private static final Pattern QUERY_OBJECT_ID_URL_MATCH = Pattern.compile("/objects/(.*)");
63 private static final Pattern QUERY_REL_ID_URL_MATCH = Pattern.compile("/relationships/(.*)");
66 public ChameleonRouter(){}
69 public ChameleonRouter(String chameleonBaseURL, RestClientConfig config) {
70 this.chameleonBaseURL = chameleonBaseURL;
71 this.restClient = new RestClient().validateServerHostname(false).validateServerCertChain(true)
72 .clientCertFile(config.getCertPath())
73 .clientCertPassword(Password.deobfuscate(config.getCertPassword()))
74 .trustStore(config.getTrustStorePath())
75 .connectTimeoutMs(config.getConnectionTimeout())
76 .readTimeoutMs(config.getReadTimeout());
81 public void validate() {
82 String baseURL = chameleonBaseURL.endsWith("/") ? chameleonBaseURL.substring(0, chameleonBaseURL.length() - 1)
84 if (baseURL.contains(DATA_ROUTER_PORT)) {
85 logger.error(QueryMsgs.QUERY_ERROR,
86 "Invalid chameleonBaseURL : Can't re-route back to DataRouter " + chameleonBaseURL);
87 throw new InvalidParameterException(
88 "Invalid chameleonBaseURL : Can't re-route back to DataRouter " + chameleonBaseURL);
90 this.chameleonBaseURL = baseURL;
93 private boolean urlMatcher(Pattern p, String url) {
94 Matcher m = p.matcher(url);
95 if (m.matches() && !m.group(1).contains("/")) {
102 private ChameleonAction resolveChameleonAction(String urlContext) throws DataRouterException {
104 urlContext = urlContext.endsWith("/") ? urlContext.substring(0, urlContext.length() - 1) : urlContext;
105 ChameleonAction action;
107 if (urlMatcher(QUERY_OBJECT_FILTER_URL_MATCH, urlContext)) {
108 action = ChameleonAction.GET_OBJECTS_BY_FILTER;
109 } else if (urlMatcher(QUERY_REL_FILTER_URL_MATCH, urlContext)) {
110 action = ChameleonAction.GET_RELS_BY_FILTER;
111 } else if (urlMatcher(QUERY_OBJECT_REL_URL_MATCH, urlContext)) {
112 action = ChameleonAction.GET_OBJECT_RELS;
113 } else if (urlMatcher(QUERY_OBJECT_ID_URL_MATCH, urlContext)) {
114 action = ChameleonAction.GET_OBJECT_BY_ID;
115 } else if (urlMatcher(QUERY_REL_ID_URL_MATCH, urlContext)) {
116 action = ChameleonAction.GET_REL_BY_ID;
119 throw new DataRouterException("", Status.NOT_FOUND);
124 private String buildUrl(String urlContext, String queryParams, ChameleonAction action) {
126 urlContext = urlContext.endsWith("/") ? urlContext.substring(0, urlContext.length() - 1) : urlContext;
127 String ecompUrl = "";
131 case GET_OBJECT_BY_ID:
132 ID = urlContext.substring(urlContext.lastIndexOf("/") + 1, urlContext.length());
133 if (ID == null || ID.isEmpty()) {
134 throw new IllegalArgumentException("Invalid URI path with no Object ID: " + urlContext);
136 if (queryParams != null && !queryParams.isEmpty()) {
137 ecompUrl = chameleonBaseURL + "/" + ID + "?" + queryParams;
140 ecompUrl = chameleonBaseURL + "/" + ID;
147 ID = urlContext.substring(urlContext.lastIndexOf("/") + 1, urlContext.length());
148 if (ID == null || ID.isEmpty()) {
149 throw new IllegalArgumentException("Invalid URI path with no Relationship ID: " + urlContext);
151 if (queryParams != null && !queryParams.isEmpty()) {
152 ecompUrl = chameleonBaseURL + "/" + ID + "?" + queryParams;
155 ecompUrl = chameleonBaseURL + "/" + ID;
161 case GET_OBJECT_RELS:
162 ID = urlContext.substring(urlContext.lastIndexOf("/") + 1, urlContext.length());
163 if (ID == null || ID.isEmpty()) {
164 throw new IllegalArgumentException("Invalid URI path with no Object ID: " + urlContext);
166 if (queryParams != null && !queryParams.isEmpty()) {
167 // TODO: Fix the URL for getting object relations when Chameloen
169 ecompUrl = chameleonBaseURL + "/relations" + ID + "?" + queryParams;
172 ecompUrl = chameleonBaseURL + "/relations" + ID;
178 case GET_OBJECTS_BY_FILTER:
179 if (queryParams != null && !queryParams.isEmpty()) {
180 // TODO: Fix the URL for getting object filter when Chameloen
182 ecompUrl = chameleonBaseURL + "/filter?" + queryParams;
184 ecompUrl = chameleonBaseURL + "/filter";
189 case GET_RELS_BY_FILTER:
190 if (queryParams != null && !queryParams.isEmpty()) {
191 // TODO: Fix the URL for getting rel filter when Chameloen
193 ecompUrl = chameleonBaseURL + "/filter?" + queryParams;
195 ecompUrl = chameleonBaseURL + "/filter";
205 private String parseResponse(String urlContext, OperationResult result, ChameleonAction action)
206 throws DataRouterException {
208 Integer httpResponseCode = result.getResultCode();
209 String ID = urlContext.substring(urlContext.lastIndexOf("/") + 1, urlContext.length());
212 case GET_OBJECT_BY_ID:
213 if (httpResponseCode >= 200 && httpResponseCode <= 299) {
214 if (ID == null || ID.isEmpty()) {
215 throw new DataRouterException("", Status.BAD_REQUEST);
217 return ChameleonResponseBuiler.buildEntity(result.getResult(), ID);
220 throw new DataRouterException("", Status.fromStatusCode(httpResponseCode));
224 if (httpResponseCode >= 200 && httpResponseCode <= 299) {
226 if (ID == null || ID.isEmpty()) {
227 throw new DataRouterException("", Status.BAD_REQUEST);
229 return ChameleonResponseBuiler.buildEntity(result.getResult(), ID);
232 throw new DataRouterException("", Status.fromStatusCode(httpResponseCode));
235 case GET_OBJECT_RELS:
237 // TODO:Return 200 with empty body for now until chameleon supports this
239 if (ID == null || ID.isEmpty()) {
240 throw new DataRouterException("", Status.BAD_REQUEST);
242 return ChameleonResponseBuiler.buildObjectRelationship(result.getResult(), ID);
245 case GET_OBJECTS_BY_FILTER:
246 // TODO:Return 200 with empty body for now until chameleon supports this
248 return ChameleonResponseBuiler.buildCollection(result.getResult());
250 case GET_RELS_BY_FILTER:
251 // TODO:Return 200 with empty body for now until chameleon supports this
253 return ChameleonResponseBuiler.buildCollection(result.getResult());
255 throw new DataRouterException("", Status.NOT_FOUND);
262 public String process(String urlContext, String queryParams, Map<String, List<String>> headers)
263 throws DataRouterException {
265 ChameleonAction action = resolveChameleonAction(urlContext);
266 String chameleonURL = buildUrl(urlContext, queryParams, action);
267 logger.info(QueryMsgs.QUERY_INFO, "Routing request to Chameleon service URL: " + chameleonURL);
269 headers = headers == null ? new HashMap<String, List<String>>() : headers;
270 headers.put("X-FromAppId", Arrays.asList(DataRouterConstants.DATA_ROUTER_SERVICE_NAME));
271 OperationResult result = restClient.get(chameleonURL, headers, MediaType.APPLICATION_JSON_TYPE);
274 response = parseResponse(urlContext, result, action);
275 } catch (DataRouterException ex) {
276 logger.info(QueryMsgs.QUERY_ERROR,
277 "Error while calling Chameleon service URL: " + chameleonURL + " failure cause: " + result.getFailureCause());