2 * ============LICENSE_START=======================================================
4 * ================================================================================
5 * Copyright © 2017-2018 AT&T Intellectual Property. All rights reserved.
6 * ================================================================================
7 * Licensed under the Apache License, Version 2.0 (the "License");
8 * you may not use this file except in compliance with the License.
9 * You may obtain a copy of the License at
11 * http://www.apache.org/licenses/LICENSE-2.0
13 * Unless required by applicable law or agreed to in writing, software
14 * distributed under the License is distributed on an "AS IS" BASIS,
15 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 * See the License for the specific language governing permissions and
17 * limitations under the License.
18 * ============LICENSE_END=========================================================
20 package org.onap.aai.rest;
22 import io.swagger.jaxrs.PATCH;
23 import org.javatuples.Pair;
24 import org.onap.aai.concurrent.AaiCallable;
25 import org.onap.aai.config.SpringContextAware;
26 import org.onap.aai.exceptions.AAIException;
27 import org.onap.aai.introspection.Introspector;
28 import org.onap.aai.introspection.Loader;
29 import org.onap.aai.parsers.query.QueryParser;
30 import org.onap.aai.rest.db.DBRequest;
31 import org.onap.aai.rest.db.HttpEntry;
32 import org.onap.aai.rest.exceptions.AAIInvalidXMLNamespace;
33 import org.onap.aai.rest.util.ValidateEncoding;
34 import org.onap.aai.restcore.HttpMethod;
35 import org.onap.aai.restcore.RESTAPI;
36 import org.onap.aai.serialization.engines.TransactionalGraphEngine;
37 import org.onap.aai.setup.SchemaVersion;
38 import org.onap.aai.util.AAIConstants;
39 import org.slf4j.Logger;
40 import org.slf4j.LoggerFactory;
41 import org.springframework.stereotype.Controller;
43 import javax.servlet.http.HttpServletRequest;
45 import javax.ws.rs.core.*;
46 import java.io.UnsupportedEncodingException;
49 import java.util.stream.Collectors;
52 * The Class LegacyMoxyConsumer.
55 @Path("{version: v[1-9][0-9]*|latest}")
56 public class LegacyMoxyConsumer extends RESTAPI {
58 private static final Logger logger = LoggerFactory.getLogger(LegacyMoxyConsumer.class.getName());
72 @Consumes({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
73 @Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
74 public Response update (String content, @PathParam("version")String versionParam, @PathParam("uri") @Encoded String uri, @Context HttpHeaders headers, @Context UriInfo info, @Context HttpServletRequest req) {
75 MediaType mediaType = headers.getMediaType();
76 return this.handleWrites(mediaType, HttpMethod.PUT, content, versionParam, uri, headers, info);
80 * Update relationship.
82 * @param content the content
83 * @param versionParam the version param
85 * @param headers the headers
86 * @param info the info
88 * @return the response
91 @Path("/{uri: .+}/relationship-list/relationship")
92 @Consumes({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
93 @Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
94 public Response updateRelationship (String content, @PathParam("version")String versionParam, @PathParam("uri") @Encoded String uri, @Context HttpHeaders headers, @Context UriInfo info, @Context HttpServletRequest req) {
96 String sourceOfTruth = headers.getRequestHeaders().getFirst("X-FromAppId");
97 String transId = headers.getRequestHeaders().getFirst("X-TransactionId");
98 MediaType inputMediaType = headers.getMediaType();
101 TransactionalGraphEngine dbEngine = null;
102 boolean success = true;
105 validateRequest(info);
106 SchemaVersion version = new SchemaVersion(versionParam);
108 HttpEntry traversalUriHttpEntry = SpringContextAware.getBean("traversalUriHttpEntry", HttpEntry.class);
109 traversalUriHttpEntry.setHttpEntryProperties(version);
110 loader = traversalUriHttpEntry.getLoader();
111 dbEngine = traversalUriHttpEntry.getDbEngine();
113 URI uriObject = UriBuilder.fromPath(uri).build();
114 this.validateURI(uriObject);
116 QueryParser uriQuery = dbEngine.getQueryBuilder().createQueryFromURI(uriObject);
118 Introspector wrappedEntity = loader.unmarshal("relationship", content, org.onap.aai.restcore.MediaType.getEnum(this.getInputMediaType(inputMediaType)));
120 DBRequest request = new DBRequest.Builder(HttpMethod.PUT_EDGE, uriObject, uriQuery, wrappedEntity, headers, info, transId).build();
121 List<DBRequest> requests = new ArrayList<>();
122 requests.add(request);
123 Pair<Boolean, List<Pair<URI, Response>>> responsesTuple = traversalUriHttpEntry.process(requests, sourceOfTruth);
125 response = responsesTuple.getValue1().get(0).getValue1();
126 success = responsesTuple.getValue0();
128 } catch (AAIException e) {
129 response = consumerExceptionResponseGenerator(headers, info, HttpMethod.PUT, e);
131 } catch (Exception e) {
132 AAIException aaiException = new AAIException("AAI_4000", e);
133 response = consumerExceptionResponseGenerator(headers, info, HttpMethod.PUT, aaiException);
136 if (dbEngine != null) {
152 * @param content the content
153 * @param versionParam the version param
155 * @param headers the headers
156 * @param info the info
158 * @return the response
162 @Consumes({ "application/merge-patch+json" })
163 @Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
164 public Response patch (String content, @PathParam("version")String versionParam, @PathParam("uri") @Encoded String uri, @Context HttpHeaders headers, @Context UriInfo info, @Context HttpServletRequest req) {
166 MediaType mediaType = MediaType.APPLICATION_JSON_TYPE;
167 return this.handleWrites(mediaType, HttpMethod.MERGE_PATCH, content, versionParam, uri, headers, info);
174 * @param content the content
175 * @param versionParam the version param
177 * @param depthParam the depth param
178 * @param cleanUp the clean up
179 * @param headers the headers
180 * @param info the info
186 @Consumes({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
187 @Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
188 public Response getLegacy (String content, @DefaultValue("-1") @QueryParam("resultIndex") String resultIndex, @DefaultValue("-1") @QueryParam("resultSize") String resultSize, @PathParam("version")String versionParam, @PathParam("uri") @Encoded String uri, @DefaultValue("all") @QueryParam("depth") String depthParam, @DefaultValue("false") @QueryParam("cleanup") String cleanUp, @Context HttpHeaders headers, @Context UriInfo info, @Context HttpServletRequest req) {
189 return runner(AAIConstants.AAI_CRUD_TIMEOUT_ENABLED,
190 AAIConstants.AAI_CRUD_TIMEOUT_APP,
191 AAIConstants.AAI_CRUD_TIMEOUT_LIMIT,
195 new AaiCallable<Response>() {
197 public Response process() {
198 return getLegacy(content, versionParam, uri, depthParam, cleanUp, headers, info, req, new HashSet<String>(), resultIndex, resultSize);
205 * This method exists as a workaround for filtering out undesired query params while routing between REST consumers
208 * @param versionParam
215 * @param removeQueryParams
218 public Response getLegacy(String content, String versionParam, String uri, String depthParam, String cleanUp, HttpHeaders headers, UriInfo info, HttpServletRequest req, Set<String> removeQueryParams, String resultIndex, String resultSize) {
219 String sourceOfTruth = headers.getRequestHeaders().getFirst("X-FromAppId");
220 String transId = headers.getRequestHeaders().getFirst("X-TransactionId");
222 TransactionalGraphEngine dbEngine = null;
226 validateRequest(info);
227 SchemaVersion version = new SchemaVersion(versionParam);
229 final HttpEntry traversalUriHttpEntry = SpringContextAware.getBean("traversalUriHttpEntry", HttpEntry.class);
230 String serverBase = req.getRequestURL().toString().replaceAll("/(v[0-9]+|latest)/.*", "/");
231 traversalUriHttpEntry.setHttpEntryProperties(version, serverBase);
232 dbEngine = traversalUriHttpEntry.getDbEngine();
233 loader = traversalUriHttpEntry.getLoader();
234 MultivaluedMap<String, String> params = info.getQueryParameters();
236 params = removeNonFilterableParams(params);
238 uri = uri.split("\\?")[0];
240 URI uriObject = UriBuilder.fromPath(uri).build();
242 QueryParser uriQuery = dbEngine.getQueryBuilder().createQueryFromURI(uriObject, params);
245 if (!uriQuery.getContainerType().equals("")) {
246 objType = uriQuery.getContainerType();
248 objType = uriQuery.getResultType();
250 Introspector obj = loader.introspectorFromName(objType);
252 new DBRequest.Builder(HttpMethod.GET, uriObject, uriQuery, obj, headers, info, transId).build();
253 List<DBRequest> requests = new ArrayList<>();
254 requests.add(request);
255 if (resultIndex != null && !"-1".equals(resultIndex) && resultSize != null && !"-1".equals(resultSize)) {
256 traversalUriHttpEntry.setPaginationIndex(Integer.parseInt(resultIndex));
257 traversalUriHttpEntry.setPaginationBucket(Integer.parseInt(resultSize));
259 Pair<Boolean, List<Pair<URI, Response>>> responsesTuple = traversalUriHttpEntry.process(requests, sourceOfTruth);
261 response = responsesTuple.getValue1().get(0).getValue1();
263 } catch (AAIException e) {
264 response = consumerExceptionResponseGenerator(headers, info, HttpMethod.GET, e);
265 } catch (Exception e ) {
266 AAIException ex = new AAIException("AAI_4000", e);
268 response = consumerExceptionResponseGenerator(headers, info, HttpMethod.GET, ex);
270 if (dbEngine != null) {
271 if (cleanUp.equals("true")) {
282 private MultivaluedMap<String, String> removeNonFilterableParams(MultivaluedMap<String, String> params) {
284 String[] toRemove = { "depth", "cleanup", "nodes-only", "format", "resultIndex", "resultSize", "skip-related-to"};
285 Set<String> toRemoveSet = Arrays.stream(toRemove).collect(Collectors.toSet());
287 MultivaluedMap<String, String> cleanedParams = new MultivaluedHashMap<>();
288 params.keySet().forEach(k -> {
289 if (!toRemoveSet.contains(k)) {
290 cleanedParams.addAll(k, params.get(k));
294 return cleanedParams;
299 * @param versionParam the version param
301 * @param headers the headers
302 * @param info the info
303 * @param resourceVersion the resource version
305 * @return the response
309 @Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
310 public Response delete (@PathParam("version")String versionParam, @PathParam("uri") @Encoded String uri, @Context HttpHeaders headers, @Context UriInfo info, @QueryParam("resource-version")String resourceVersion, @Context HttpServletRequest req) {
313 String outputMediaType = getMediaType(headers.getAcceptableMediaTypes());
314 String sourceOfTruth = headers.getRequestHeaders().getFirst("X-FromAppId");
315 String transId = headers.getRequestHeaders().getFirst("X-TransactionId");
317 TransactionalGraphEngine dbEngine = null;
320 boolean success = true;
324 validateRequest(info);
325 SchemaVersion version = new SchemaVersion(versionParam);
327 HttpEntry traversalUriHttpEntry = SpringContextAware.getBean("traversalUriHttpEntry", HttpEntry.class);
328 traversalUriHttpEntry.setHttpEntryProperties(version);
329 dbEngine = traversalUriHttpEntry.getDbEngine();
330 Loader loader = traversalUriHttpEntry.getLoader();
332 URI uriObject = UriBuilder.fromPath(uri).build();
334 QueryParser uriQuery = dbEngine.getQueryBuilder().createQueryFromURI(uriObject);
335 String objType = uriQuery.getResultType();
336 Introspector obj = loader.introspectorFromName(objType);
338 DBRequest request = new DBRequest.Builder(HttpMethod.DELETE, uriObject, uriQuery, obj, headers, info, transId).build();
339 List<DBRequest> requests = new ArrayList<>();
340 requests.add(request);
341 Pair<Boolean, List<Pair<URI, Response>>> responsesTuple = traversalUriHttpEntry.process(requests, sourceOfTruth);
343 response = responsesTuple.getValue1().get(0).getValue1();
344 success = responsesTuple.getValue0();
346 } catch (AAIException e) {
347 response = consumerExceptionResponseGenerator(headers, info, HttpMethod.DELETE, e);
349 } catch (Exception e) {
350 AAIException ex = new AAIException("AAI_4000", e);
351 response = consumerExceptionResponseGenerator(headers, info, HttpMethod.DELETE, ex);
354 if (dbEngine != null) {
367 * This whole method does nothing because the body is being dropped while fielding the request.
369 * @param content the content
370 * @param versionParam the version param
372 * @param headers the headers
373 * @param info the info
375 * @return the response
378 @Path("/{uri: .+}/relationship-list/relationship")
379 @Consumes({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
380 @Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
381 public Response deleteRelationship (String content, @PathParam("version")String versionParam, @PathParam("uri") @Encoded String uri, @Context HttpHeaders headers, @Context UriInfo info, @Context HttpServletRequest req) {
383 MediaType inputMediaType = headers.getMediaType();
384 String sourceOfTruth = headers.getRequestHeaders().getFirst("X-FromAppId");
385 String transId = headers.getRequestHeaders().getFirst("X-TransactionId");
387 TransactionalGraphEngine dbEngine = null;
390 boolean success = true;
393 this.validateRequest(info);
394 SchemaVersion version = new SchemaVersion(versionParam);
396 HttpEntry traversalUriHttpEntry = SpringContextAware.getBean("traversalUriHttpEntry", HttpEntry.class);
397 traversalUriHttpEntry.setHttpEntryProperties(version);
398 loader = traversalUriHttpEntry.getLoader();
399 dbEngine = traversalUriHttpEntry.getDbEngine();
401 if (content.equals("")) {
402 throw new AAIException("AAI_3102", "You must supply a relationship");
404 URI uriObject = UriBuilder.fromPath(uri).build();
405 this.validateURI(uriObject);
407 QueryParser uriQuery = dbEngine.getQueryBuilder().createQueryFromURI(uriObject);
409 Introspector wrappedEntity = loader.unmarshal("relationship", content, org.onap.aai.restcore.MediaType.getEnum(this.getInputMediaType(inputMediaType)));
411 DBRequest request = new DBRequest.Builder(HttpMethod.DELETE_EDGE, uriObject, uriQuery, wrappedEntity, headers, info, transId).build();
412 List<DBRequest> requests = new ArrayList<>();
413 requests.add(request);
414 Pair<Boolean, List<Pair<URI, Response>>> responsesTuple = traversalUriHttpEntry.process(requests, sourceOfTruth);
416 response = responsesTuple.getValue1().get(0).getValue1();
417 success = responsesTuple.getValue0();
418 } catch (AAIException e) {
419 response = consumerExceptionResponseGenerator(headers, info, HttpMethod.DELETE, e);
421 } catch (Exception e) {
422 AAIException ex = new AAIException("AAI_4000", e);
423 response = consumerExceptionResponseGenerator(headers, info, HttpMethod.DELETE, ex);
426 if (dbEngine != null) {
439 @Path("/{uri: .+}/relationship-list")
440 @Consumes({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
441 @Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
442 public Response getRelationshipList (@DefaultValue("-1") @QueryParam("resultIndex") String resultIndex, @DefaultValue("-1") @QueryParam("resultSize") String resultSize, @PathParam("version")String versionParam, @PathParam("uri") @Encoded String uri, @DefaultValue("false") @QueryParam("cleanup") String cleanUp, @Context HttpHeaders headers, @Context HttpServletRequest req,@Context UriInfo info) {
443 return runner(AAIConstants.AAI_CRUD_TIMEOUT_ENABLED,
444 AAIConstants.AAI_CRUD_TIMEOUT_APP,
445 AAIConstants.AAI_CRUD_TIMEOUT_LIMIT,
449 new AaiCallable<Response>() {
451 public Response process() {
452 return getRelationshipList(versionParam, req, uri, cleanUp, headers, info, resultIndex, resultSize);
460 * @param versionParam
467 public Response getRelationshipList(String versionParam, HttpServletRequest req, String uri, String cleanUp, HttpHeaders headers, UriInfo info, String resultIndex, String resultSize) {
468 String sourceOfTruth = headers.getRequestHeaders().getFirst("X-FromAppId");
469 String transId = headers.getRequestHeaders().getFirst("X-TransactionId");
470 Response response = null;
471 TransactionalGraphEngine dbEngine = null;
472 Loader loader = null;
475 validateRequest(info);
476 SchemaVersion version = new SchemaVersion(versionParam);
478 final HttpEntry traversalUriHttpEntry = SpringContextAware.getBean("traversalUriHttpEntry", HttpEntry.class);
479 String serverBase = req.getRequestURL().toString().replaceAll("/(v[0-9]+|latest)/.*", "/");
480 traversalUriHttpEntry.setHttpEntryProperties(version, serverBase);
481 dbEngine = traversalUriHttpEntry.getDbEngine();
482 loader = traversalUriHttpEntry.getLoader();
483 MultivaluedMap<String, String> params = info.getQueryParameters();
485 params = removeNonFilterableParams(params);
487 uri = uri.split("\\?")[0];
489 URI uriObject = UriBuilder.fromPath(uri).build();
491 QueryParser uriQuery = dbEngine.getQueryBuilder().createQueryFromURI(uriObject, params);
494 if (!uriQuery.getContainerType().equals("")) {
495 objType = uriQuery.getContainerType();
497 objType = uriQuery.getResultType();
499 Introspector obj = loader.introspectorFromName(objType);
501 new DBRequest.Builder(HttpMethod.GET_RELATIONSHIP, uriObject, uriQuery, obj, headers, info, transId).build();
502 List<DBRequest> requests = new ArrayList<>();
503 requests.add(request);
504 if (resultIndex != null && !"-1".equals(resultIndex) && resultSize != null && !"-1".equals(resultSize)) {
505 traversalUriHttpEntry.setPaginationIndex(Integer.parseInt(resultIndex));
506 traversalUriHttpEntry.setPaginationBucket(Integer.parseInt(resultSize));
508 Pair<Boolean, List<Pair<URI, Response>>> responsesTuple = traversalUriHttpEntry.process(requests, sourceOfTruth);
510 response = responsesTuple.getValue1().get(0).getValue1();
511 } catch (AAIException e) {
512 response = consumerExceptionResponseGenerator(headers, info, HttpMethod.GET_RELATIONSHIP, e);
513 } catch (Exception e ) {
514 AAIException ex = new AAIException("AAI_4000", e);
516 response = consumerExceptionResponseGenerator(headers, info, HttpMethod.GET_RELATIONSHIP, ex);
518 if (dbEngine != null) {
519 if (cleanUp.equals("true")) {
532 * @param info the info
533 * @throws AAIException the AAI exception
534 * @throws UnsupportedEncodingException the unsupported encoding exception
536 private void validateRequest(UriInfo info) throws AAIException, UnsupportedEncodingException {
538 if (!ValidateEncoding.getInstance().validate(info)) {
539 throw new AAIException("AAI_3008", "uri=" + getPath(info));
546 * @param info the info
549 private String getPath(UriInfo info) {
550 String path = info.getPath(false);
551 MultivaluedMap<String, String> map = info.getQueryParameters(false);
553 List<String> parmList = new ArrayList<>();
554 for (String key : map.keySet()) {
555 for (String value : map.get(key)) {
556 parmList.add(key + "=" + value);
559 String queryParams = String.join("&", parmList);
560 if (!map.isEmpty()) {
561 path += params + queryParams;
571 * @param mediaType the media type
572 * @param method the method
573 * @param content the content
574 * @param versionParam the version param
576 * @param headers the headers
577 * @param info the info
578 * @return the response
580 private Response handleWrites(MediaType mediaType, HttpMethod method, String content, String versionParam, String uri, HttpHeaders headers, UriInfo info) {
583 TransactionalGraphEngine dbEngine = null;
585 SchemaVersion version;
586 String sourceOfTruth = headers.getRequestHeaders().getFirst("X-FromAppId");
587 String transId = headers.getRequestHeaders().getFirst("X-TransactionId");
588 boolean success = true;
591 validateRequest(info);
593 version = new SchemaVersion(versionParam);
595 HttpEntry traversalUriHttpEntry = SpringContextAware.getBean("traversalUriHttpEntry", HttpEntry.class);
596 traversalUriHttpEntry.setHttpEntryProperties(version);
597 loader = traversalUriHttpEntry.getLoader();
598 dbEngine = traversalUriHttpEntry.getDbEngine();
599 URI uriObject = UriBuilder.fromPath(uri).build();
600 this.validateURI(uriObject);
601 QueryParser uriQuery = dbEngine.getQueryBuilder().createQueryFromURI(uriObject);
602 String objName = uriQuery.getResultType();
603 if (content.length() == 0) {
604 if (mediaType.toString().contains(MediaType.APPLICATION_JSON)) {
607 content = "<empty/>";
610 Introspector obj = loader.unmarshal(objName, content, org.onap.aai.restcore.MediaType.getEnum(this.getInputMediaType(mediaType)));
612 throw new AAIException("AAI_3000", "object could not be unmarshalled:" + content);
615 if (mediaType.toString().contains(MediaType.APPLICATION_XML) && !content.equals("<empty/>") && isEmptyObject(obj)) {
616 throw new AAIInvalidXMLNamespace(content);
619 this.validateIntrospector(obj, loader, uriObject, method);
622 new DBRequest.Builder(method, uriObject, uriQuery, obj, headers, info, transId)
623 .rawRequestContent(content).build();
624 List<DBRequest> requests = new ArrayList<>();
625 requests.add(request);
626 Pair<Boolean, List<Pair<URI, Response>>> responsesTuple = traversalUriHttpEntry.process(requests, sourceOfTruth);
628 response = responsesTuple.getValue1().get(0).getValue1();
629 success = responsesTuple.getValue0();
630 } catch (AAIException e) {
631 response = consumerExceptionResponseGenerator(headers, info, method, e);
633 } catch (Exception e ) {
634 AAIException ex = new AAIException("AAI_4000", e);
635 response = consumerExceptionResponseGenerator(headers, info, method, ex);
638 if (dbEngine != null) {
650 private void validateURI(URI uri) throws AAIException {
651 if (hasRelatedTo(uri)) {
652 throw new AAIException("AAI_3010");
655 private boolean hasRelatedTo(URI uri) {
657 return uri.toString().contains("/" + RestTokens.COUSIN + "/");
660 protected boolean isEmptyObject(Introspector obj) {
661 return "{}".equals(obj.marshal(false));