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