[AAI] Fix doc config files
[aai/aai-common.git] / aai-core / src / main / java / org / onap / aai / parsers / uri / URIParser.java
1 /**
2  * ============LICENSE_START=======================================================
3  * org.onap.aai
4  * ================================================================================
5  * Copyright © 2017-2018 AT&T Intellectual Property. All rights reserved.
6  * Modification Copyright © 2019 IBM
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
22 package org.onap.aai.parsers.uri;
23
24 import java.io.UnsupportedEncodingException;
25 import java.net.URI;
26 import java.util.Set;
27
28 import javax.ws.rs.core.MultivaluedHashMap;
29 import javax.ws.rs.core.MultivaluedMap;
30 import javax.ws.rs.core.UriBuilder;
31
32 import org.onap.aai.edges.enums.EdgeType;
33 import org.onap.aai.exceptions.AAIException;
34 import org.onap.aai.introspection.Introspector;
35 import org.onap.aai.introspection.Loader;
36 import org.onap.aai.parsers.exceptions.DoesNotStartWithValidNamespaceException;
37 import org.onap.aai.rest.RestTokens;
38 import org.onap.aai.schema.enums.ObjectMetadata;
39 import org.springframework.web.util.UriUtils;
40
41 /**
42  * The Class URIParser.
43  */
44 public class URIParser {
45
46     private URI uri = null;
47
48     protected Loader loader = null;
49
50     protected Loader originalLoader = null;
51
52     private URI originalURI = null;
53
54     private MultivaluedMap<String, String> queryParams = null;
55   
56     private static String aaiExceptionCode = "AAI_3001";
57
58     /**
59      * Instantiates a new URI parser.
60      *
61      * @param loader the loader
62      * @param uri the uri
63      */
64     public URIParser(Loader loader, URI uri) {
65         this.uri = uri;
66
67         this.originalLoader = loader;
68         // Load the latest version because we need it for cloud region
69
70         this.loader = loader;
71     }
72
73     /**
74      * Instantiates a new URI parser.
75      *
76      * @param loader the loader
77      * @param uri the uri
78      * @param queryParams the query params
79      */
80     public URIParser(Loader loader, URI uri, MultivaluedMap<String, String> queryParams) {
81         this(loader, uri);
82         this.queryParams = queryParams;
83     }
84
85     public Loader getLoader() {
86
87         return this.loader;
88
89     }
90
91     /**
92      * Gets the original URI.
93      *
94      * @return the original URI
95      */
96     public URI getOriginalURI() {
97         return this.originalURI;
98     }
99
100     /**
101      * Parses the.
102      *
103      * @param p the p
104      * @throws UnsupportedEncodingException the unsupported encoding exception
105      * @throws AAIException the AAI exception
106      */
107     public void parse(Parsable p) throws UnsupportedEncodingException, AAIException {
108         try {
109             boolean isRelative = false;
110             uri = this.trimURI(uri);
111             uri = handleCloudRegion(p.getCloudRegionTransform(), uri);
112             if (p.useOriginalLoader()) {
113                 this.loader = this.originalLoader;
114             }
115             this.originalURI = UriBuilder.fromPath(uri.getRawPath()).build();
116             if (uri.getRawPath().startsWith("./")) {
117                 uri = new URI(uri.getRawPath().replaceFirst("\\./", ""));
118                 isRelative = true;
119             }
120             String[] parts = uri.getRawPath().split("/");
121             Introspector validNamespaces = loader.introspectorFromName("inventory");
122             Set<String> keys = null;
123             String part = "";
124             Introspector previousObj = null;
125             EdgeType type = EdgeType.TREE;
126             for (int i = 0; i < parts.length;) {
127                 part = parts[i];
128                 Introspector introspector = null;
129                 if (part.equals(RestTokens.COUSIN.toString())) {
130                     if (i == parts.length - 1) {
131                         throw new AAIException("AAI_3000",
132                                 uri + " not a valid path. Cannot end in " + RestTokens.COUSIN);
133                     }
134                     introspector = loader.introspectorFromName(parts[i + 1]);
135                     if (null == previousObj) {
136                         throw new AAIException(aaiExceptionCode);
137                     }
138                     if (previousObj.isContainer() && introspector.isContainer()) {
139                         throw new AAIException("AAI_3000", uri + " not a valid path. Cannot chain plurals together");
140                     }
141                     MultivaluedMap<String, String> uriKeys = new MultivaluedHashMap<>();
142                     if (i == parts.length - 2 && queryParams != null) {
143                         Set<String> queryKeys = queryParams.keySet();
144                         for (String key : queryKeys) {
145                             uriKeys.put(key, queryParams.get(key));
146
147                         }
148                     }
149                     if (introspector.isContainer()) {
150                         boolean isFinalContainer = i == parts.length - 2;
151                         /*
152                          * Related-to could be COUSIN OR TREE and in some cases BOTH. So Let EdgeRuleBuilder use all the
153                          * edgeTypes
154                          */
155                         p.processContainer(introspector, EdgeType.ALL, uriKeys, isFinalContainer);
156                     }
157                     previousObj = introspector;
158                     type = EdgeType.ALL;
159                     i += 2;
160                     continue;
161                 }
162                 introspector = loader.introspectorFromName(part);
163                 if (introspector != null) {
164
165                     // previous has current as property
166                     if (previousObj != null && !previousObj.hasChild(introspector)
167                             && !previousObj.getDbName().equals("nodes")) {
168                         throw new AAIException(aaiExceptionCode, uri + " not a valid path. " + part + " not valid");
169                     } else if (previousObj == null) {
170                         String abstractType = introspector.getMetadata(ObjectMetadata.ABSTRACT);
171                         if (abstractType == null) {
172                             abstractType = "";
173                         }
174                         // first time through, make sure it starts from a namespace
175                         // ignore abstract types
176                         if (!isRelative && !abstractType.equals("true") && !validNamespaces.hasChild(introspector)) {
177                             throw new DoesNotStartWithValidNamespaceException(
178                                     uri + " not a valid path. It does not start from a valid namespace");
179                         }
180                     }
181
182                     keys = introspector.getKeys();
183                     if (keys.size() > 0) {
184                         MultivaluedMap<String, String> uriKeys = new MultivaluedHashMap<>();
185                         i++;
186                         if (i == parts.length && queryParams != null) {
187                             Set<String> queryKeys = queryParams.keySet();
188                             for (String key : queryKeys) {
189                                 uriKeys.put(key, queryParams.get(key));
190                             }
191                         } else {
192                             for (String key : keys) {
193                                 part = UriUtils.decode(parts[i], "UTF-8");
194
195                                 introspector.setValue(key, part);
196
197                                 // skip this for further processing
198                                 i++;
199                             }
200                         }
201
202                         p.processObject(introspector, type, uriKeys);
203                         type = EdgeType.TREE;
204                     } else if (introspector.isContainer()) {
205                         boolean isFinalContainer = i == parts.length - 1;
206                         MultivaluedMap<String, String> uriKeys = new MultivaluedHashMap<>();
207
208                         if (isFinalContainer && queryParams != null) {
209                             Set<String> queryKeys = queryParams.keySet();
210                             for (String key : queryKeys) {
211                                 uriKeys.put(key, queryParams.get(key));
212
213                             }
214                         }
215                         p.processContainer(introspector, type, uriKeys, isFinalContainer);
216                         i++;
217                     } else {
218                         p.processNamespace(introspector);
219                         // namespace case
220                         i++;
221                     }
222                     previousObj = introspector;
223                 } else {
224                     // invalid item found should log
225                     // original said bad path
226                     throw new AAIException(aaiExceptionCode, "invalid item found in path: " + part);
227                 }
228             }
229         } catch (AAIException e) {
230             throw e;
231         } catch (Exception e) {
232             throw new AAIException(aaiExceptionCode, e);
233         }
234     }
235
236     public boolean validate() throws UnsupportedEncodingException, AAIException {
237         this.parse(new URIValidate());
238         return true;
239     }
240
241     /**
242      * Handle cloud region.
243      *
244      * @param action the action
245      * @param uri the uri
246      * @return the uri
247      */
248     protected URI handleCloudRegion(String action, URI uri) {
249
250         return uri;
251
252     }
253
254     /**
255      * Trim URI.
256      *
257      * @param uri the uri
258      * @return the uri
259      */
260     protected URI trimURI(URI uri) {
261
262         String result = uri.getRawPath();
263         if (result.startsWith("/")) {
264             result = result.substring(1, result.length());
265         }
266
267         if (result.endsWith("/")) {
268             result = result.substring(0, result.length() - 1);
269         }
270
271         // TODO - Check if this makes to do for model driven for base uri path
272         result = result.replaceFirst("[a-z][a-z]*/v\\d+/", "");
273
274         return UriBuilder.fromPath(result).build();
275     }
276
277 }