2df25241de8db9ac20b8d6213ba96771ed73aabe
[aai/data-router.git] / src / main / java / org / onap / aai / datarouter / query / ChameleonRouter.java
1 /**
2  * ============LICENSE_START=======================================================
3  * org.onap.aai
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
11  *
12  *       http://www.apache.org/licenses/LICENSE-2.0
13  *
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=========================================================
20  */
21 package  org.onap.aai.datarouter.query;
22
23 import java.security.InvalidParameterException;
24 import java.util.regex.Matcher;
25 import java.util.regex.Pattern;
26
27 import javax.ws.rs.BadRequestException;
28
29 import org.apache.camel.Exchange;
30 import org.apache.camel.RuntimeCamelException;
31 import org.onap.aai.rest.RestClientEndpoint;
32 import org.onap.aai.cl.api.Logger;
33 import org.onap.aai.cl.eelf.LoggerFactory;
34
35 public class ChameleonRouter extends QueryRouter {
36
37   Logger logger = LoggerFactory.getInstance().getLogger(ChameleonRouter.class.getName());
38
39   private String chameleonBaseURL;
40
41   private enum ChameleonAction {
42     GET_OBJECT_BY_ID, GET_REL_BY_ID, GET_OBJECT_RELS, GET_OBJECTS_BY_FILTER, GET_RELS_BY_FILTER
43   };
44
45   private static final Pattern QUERY_OBJECT_FILTER_URL_MATCH = Pattern.compile("/objects/filter(.*)");
46   private static final Pattern QUERY_REL_FILTER_URL_MATCH = Pattern.compile("/relationships/filter(.*)");
47   private static final Pattern QUERY_OBJECT_REL_URL_MATCH = Pattern.compile("/objects/relationships/(.*)");
48   private static final Pattern QUERY_OBJECT_ID_URL_MATCH = Pattern.compile("/objects/(.*)");
49   private static final Pattern QUERY_REL_ID_URL_MATCH = Pattern.compile("/relationships/(.*)");
50
51   private static final String ECOMP_QUERY_ID = "ECOMP_QUERY_ID";
52   private static final String ECOMP_QUERY_TYPE = "ECOMP_QUERY_TYPE";
53
54   public ChameleonRouter(String chameleonBaseURL) {
55     String baseURL = chameleonBaseURL.endsWith("/") ? chameleonBaseURL.substring(0, chameleonBaseURL.length() - 1)
56         : chameleonBaseURL;
57     if (checkRecursion(baseURL)) {
58       logger.error(QueryMsgs.QUERY_ERROR,
59           "Invalid chameleonBaseURL : Can't re-route back to DataRouter " + chameleonBaseURL);
60       throw new InvalidParameterException(
61           "Invalid chameleonBaseURL : Can't re-route back to DataRouter " + chameleonBaseURL);
62     }
63     this.chameleonBaseURL = baseURL;
64   }
65
66   public void setQueryRequest(Exchange exchange) {
67     setMDC(exchange);
68     ChameleonAction action = resolveChameleonAction(exchange);
69     String ecompUrl = buildUrl(exchange, action);
70     logger.info(QueryMsgs.QUERY_INFO, "Routing request to Chameleon service URL: " + ecompUrl);
71     exchange.getIn().setHeader(RestClientEndpoint.IN_HEADER_URL, ecompUrl);
72     exchange.getIn().setHeader("X-FromAppId", SERVICE_NAME);
73     exchange.getIn().setHeader("X-TransactionId", getTxId(exchange));
74
75   }
76
77   private boolean urlMatcher(Pattern p, String url) {
78     Matcher m = p.matcher(url);
79     if (m.matches() && !m.group(1).contains("/")) {
80       return true;
81     } else {
82       return false;
83     }
84   }
85
86   private ChameleonAction resolveChameleonAction(Exchange exchange) {
87     String path = exchange.getIn().getHeader(Exchange.HTTP_PATH, String.class);
88     path = path.endsWith("/") ? path.substring(0, path.length() - 1) : path;
89     ChameleonAction action;
90
91     if (urlMatcher(QUERY_OBJECT_FILTER_URL_MATCH, path)) {
92       action = ChameleonAction.GET_OBJECTS_BY_FILTER;
93     } else if (urlMatcher(QUERY_REL_FILTER_URL_MATCH, path)) {
94       action = ChameleonAction.GET_RELS_BY_FILTER;
95     } else if (urlMatcher(QUERY_OBJECT_REL_URL_MATCH, path)) {
96       action = ChameleonAction.GET_OBJECT_RELS;
97     } else if (urlMatcher(QUERY_OBJECT_ID_URL_MATCH, path)) {
98       action = ChameleonAction.GET_OBJECT_BY_ID;
99     } else if (urlMatcher(QUERY_REL_ID_URL_MATCH, path)) {
100       action = ChameleonAction.GET_REL_BY_ID;
101     } else {
102       exchange.getIn().setHeader(ChameleonErrorProcessor.ECOMP_QUERY_ERROR_CODE, 404);
103       throw new RuntimeCamelException();
104     }
105     return action;
106   }
107
108   private String buildUrl(Exchange exchange, ChameleonAction action) {
109     String path = exchange.getIn().getHeader(Exchange.HTTP_PATH, String.class);
110     path = path.endsWith("/") ? path.substring(0, path.length() - 1) : path;
111     String queryParams = exchange.getIn().getHeader(Exchange.HTTP_QUERY, String.class);
112     String ecompUrl = "";
113     String ID = "";
114
115     switch (action) {
116     case GET_OBJECT_BY_ID:
117       ID = path.substring(path.lastIndexOf("/") + 1, path.length());
118       if (ID == null || ID.isEmpty()) {
119         throw new IllegalArgumentException("Invalid URI path with no Object ID: " + path);
120       } else {
121         if (queryParams != null && !queryParams.isEmpty()) {
122           ecompUrl = chameleonBaseURL + "/" + ID + "?" + queryParams;
123
124         } else {
125           ecompUrl = chameleonBaseURL + "/" + ID;
126         }
127       }
128       exchange.getIn().setHeader(ECOMP_QUERY_ID, ID);
129       exchange.getIn().setHeader(ECOMP_QUERY_TYPE, ChameleonAction.GET_OBJECT_BY_ID);
130       break;
131
132     case GET_REL_BY_ID:
133       ID = path.substring(path.lastIndexOf("/") + 1, path.length());
134       if (ID == null || ID.isEmpty()) {
135         throw new IllegalArgumentException("Invalid URI path with no Relationship ID: " + path);
136       } else {
137         if (queryParams != null && !queryParams.isEmpty()) {
138           ecompUrl = chameleonBaseURL + "/" + ID + "?" + queryParams;
139
140         } else {
141           ecompUrl = chameleonBaseURL + "/" + ID;
142         }
143       }
144       exchange.getIn().setHeader(ECOMP_QUERY_ID, ID);
145       exchange.getIn().setHeader(ECOMP_QUERY_TYPE, ChameleonAction.GET_REL_BY_ID);
146       break;
147
148     case GET_OBJECT_RELS:
149       ID = path.substring(path.lastIndexOf("/") + 1, path.length());
150       if (ID == null || ID.isEmpty()) {
151         throw new IllegalArgumentException("Invalid URI path with no Object ID: " + path);
152       } else {
153         if (queryParams != null && !queryParams.isEmpty()) {
154           // TODO: Fix the URL for getting object relations when Chameloen
155           // supports this API
156           ecompUrl = chameleonBaseURL + "/relations" + ID + "?" + queryParams;
157
158         } else {
159           ecompUrl = chameleonBaseURL + "/relations" + ID;
160         }
161       }
162       exchange.getIn().setHeader(ECOMP_QUERY_ID, ID);
163       exchange.getIn().setHeader(ECOMP_QUERY_TYPE, ChameleonAction.GET_OBJECT_RELS);
164       break;
165
166     case GET_OBJECTS_BY_FILTER:
167       if (queryParams != null && !queryParams.isEmpty()) {
168         // TODO: Fix the URL for getting object filter when Chameloen
169         // supports this API
170         ecompUrl = chameleonBaseURL + "/filter?" + queryParams;
171       } else {
172         ecompUrl = chameleonBaseURL + "/filter";
173       }
174       exchange.getIn().setHeader(ECOMP_QUERY_TYPE, ChameleonAction.GET_OBJECTS_BY_FILTER);
175       break;
176
177     case GET_RELS_BY_FILTER:
178       if (queryParams != null && !queryParams.isEmpty()) {
179         // TODO: Fix the URL for getting rel filter when Chameloen
180         // supports this API
181         ecompUrl = chameleonBaseURL + "/filter?" + queryParams;
182       } else {
183         ecompUrl = chameleonBaseURL + "/filter";
184       }
185       exchange.getIn().setHeader(ECOMP_QUERY_TYPE, ChameleonAction.GET_RELS_BY_FILTER);
186       break;
187
188     }
189
190     return ecompUrl;
191   }
192
193   public void setQueryResponse(Exchange exchange) {
194     parseResponse(exchange);
195     adjustHeaders(exchange);
196   }
197
198   private void adjustHeaders(Exchange exchange) {
199     // Remove the internal heders
200     exchange.getIn().removeHeader(ECOMP_QUERY_ID);
201     exchange.getIn().removeHeader(ECOMP_QUERY_TYPE);
202   }
203
204   private void parseResponse(Exchange exchange) throws BadRequestException {
205
206     ChameleonAction action = exchange.getIn().getHeader(ECOMP_QUERY_TYPE, ChameleonAction.class);
207     Integer httpResponseCode = exchange.getIn().getHeader(RestClientEndpoint.OUT_HEADER_RESPONSE_CODE, Integer.class);
208     String ID = "";
209
210     switch (action) {
211     case GET_OBJECT_BY_ID:
212       if (httpResponseCode >= 200 && httpResponseCode <= 299) {
213         ID = exchange.getIn().getHeader(ECOMP_QUERY_ID, String.class);
214         if (ID == null || ID.isEmpty()) {
215           exchange.getIn().setHeader(Exchange.HTTP_RESPONSE_CODE, 400);
216         } else {
217           ChameleonResponseBuiler.buildEntity(exchange, ID);
218         }
219       } else {
220         exchange.getIn().setHeader(Exchange.HTTP_RESPONSE_CODE, httpResponseCode);
221       }
222       break;
223     case GET_REL_BY_ID:
224       if (httpResponseCode >= 200 && httpResponseCode <= 299) {
225         ID = exchange.getIn().getHeader(ECOMP_QUERY_ID, String.class);
226         if (ID == null || ID.isEmpty()) {
227           exchange.getIn().setHeader(Exchange.HTTP_RESPONSE_CODE, 400);
228         } else {
229           ChameleonResponseBuiler.buildEntity(exchange, ID);
230         }
231       } else {
232         exchange.getIn().setHeader(Exchange.HTTP_RESPONSE_CODE, httpResponseCode);
233       }
234       break;
235     case GET_OBJECT_RELS:
236       if (httpResponseCode >= 200 && httpResponseCode <= 299) {
237         ID = exchange.getIn().getHeader(ECOMP_QUERY_ID, String.class);
238         if (ID == null || ID.isEmpty()) {
239           exchange.getIn().setHeader(Exchange.HTTP_RESPONSE_CODE, 400);
240         } else {
241           ChameleonResponseBuiler.buildObjectRelationship(exchange, ID);
242         }
243       } else {
244         // TODO:Return 200 with empty body for now until chameleon supports this
245         // query
246         exchange.getIn().setHeader(Exchange.HTTP_RESPONSE_CODE, 200);
247         exchange.getIn().setBody("[]");
248       }
249       break;
250     case GET_OBJECTS_BY_FILTER:
251       if (httpResponseCode >= 200 && httpResponseCode <= 299) {
252         ChameleonResponseBuiler.buildCollection(exchange);
253       } else {
254         // TODO:Return 200 with empty body for now until chameleon supports this
255         // query
256         exchange.getIn().setHeader(Exchange.HTTP_RESPONSE_CODE, 200);
257         exchange.getIn().setBody("[]");
258       }
259       break;
260     case GET_RELS_BY_FILTER:
261       if (httpResponseCode >= 200 && httpResponseCode <= 299) {
262         ChameleonResponseBuiler.buildCollection(exchange);
263       } else {
264         // TODO:Return 200 with empty body for now until chameleon supports this
265         // query
266         exchange.getIn().setHeader(Exchange.HTTP_RESPONSE_CODE, 200);
267         exchange.getIn().setBody("[]");
268       }
269       break;
270
271     }
272
273   }
274
275 }