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