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