Implement support for inner variables
[ccsdk/sli/adaptors.git] / aai-service / provider / src / main / java / org / onap / ccsdk / sli / adaptors / aai / AAIRequest.java
1 /*-
2  * ============LICENSE_START=======================================================
3  * openECOMP : SDN-C
4  * ================================================================================
5  * Copyright (C) 2017 AT&T Intellectual Property. All rights
6  *             reserved.
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.ccsdk.sli.adaptors.aai;
23
24 import java.io.IOException;
25 import java.io.InputStream;
26 import java.io.InputStreamReader;
27 import java.io.Reader;
28 import java.io.UnsupportedEncodingException;
29 import java.lang.reflect.Method;
30 import java.net.MalformedURLException;
31 import java.net.URISyntaxException;
32 import java.net.URL;
33 import java.net.URLDecoder;
34 import java.net.URLEncoder;
35 import java.nio.charset.StandardCharsets;
36 import java.util.ArrayList;
37 import java.util.Arrays;
38 import java.util.BitSet;
39 import java.util.HashSet;
40 import java.util.HashMap;
41 import java.util.LinkedHashMap;
42 import java.util.List;
43 import java.util.Map;
44 import java.util.Properties;
45 import java.util.Set;
46 import java.util.TreeSet;
47
48 import org.apache.commons.lang.StringUtils;
49 import org.onap.aai.inventory.v14.GenericVnf;
50 import org.onap.ccsdk.sli.adaptors.aai.data.AAIDatum;
51 import org.osgi.framework.Bundle;
52 import org.osgi.framework.BundleContext;
53 import org.osgi.framework.FrameworkUtil;
54 import org.slf4j.Logger;
55 import org.slf4j.LoggerFactory;
56
57 import com.fasterxml.jackson.core.JsonParseException;
58 import com.fasterxml.jackson.core.JsonProcessingException;
59 import com.fasterxml.jackson.databind.JsonMappingException;
60 import com.fasterxml.jackson.databind.ObjectMapper;
61
62 public abstract class AAIRequest {
63     protected static final Logger LOG = LoggerFactory.getLogger(AAIRequest.class);
64
65     protected static final String TARGET_URI = "org.onap.ccsdk.sli.adaptors.aai.uri";
66
67     protected static final String MASTER_REQUEST = "master-request";
68
69     public static final String RESOURCE_VERSION = "resource-version";
70
71     public static final String DEPTH = "depth";
72
73     protected static Properties configProperties;
74     protected final String targetUri;
75     protected static AAIService aaiService;
76
77     protected AAIDatum requestDatum;
78
79     protected final Properties requestProperties = new Properties();
80
81
82     public static AAIRequest createRequest(String resoourceName, Map<String, String> nameValues){
83
84         String resoource = resoourceName;
85         String masterResource = null;
86
87         if(resoource == null)
88             return null;
89
90         if(resoource.contains(":")) {
91             String[] tokens = resoource.split(":");
92             if(tokens != null && tokens.length == 2) {
93                 resoource = tokens[1];
94                 masterResource = tokens[0];
95                 Class<? extends AAIDatum> clazz = getClassFromResource(resoource) ;
96
97                 if(clazz == null) {
98                     return null;
99                 }
100             }
101         }
102
103         if(nameValues.containsKey("selflink")){
104             Class<? extends AAIDatum> clazz = getClassFromResource(resoource) ;
105
106             if(clazz != null)
107                 return new SelfLinkRequest(clazz);
108             else
109                 return null;
110         }
111
112         switch(resoource){
113         case "generic-query":
114             return new GenericQueryRequest();
115         case "named-query":
116             return new NamedQueryRequest();
117         case "nodes-query":
118             return new NodesQueryRequest();
119         case "custom-query":
120         case "formatted-query":
121             return new CustomQueryRequest();
122         case "echo":
123         case "test":
124             return new EchoRequest();
125
126         case "linterface":
127         case "l2-bridge-sbg":
128         case "l2-bridge-bgf":
129             {
130                 resoource = "l-interface";
131                 return getRequestFromResource("l-interface");
132             }
133         case "relationship-list":
134              return new RelationshipListRequest(AAIRequest.createRequest(masterResource, nameValues));
135         case "relationship":
136              return new RelationshipRequest(AAIRequest.createRequest(masterResource, nameValues));
137         default:
138                 return getRequestFromResource(resoource);
139         }
140     }
141
142
143     /**
144      * Map containing resource tag to its bit position in bitset mapping
145      */
146     private static Map<String, String> tagValues = new LinkedHashMap<>();
147     /**
148      * Map containing bitset value of the path to its path mapping
149      */
150     private static Map<BitSet, String> bitsetPaths = new LinkedHashMap<>();
151
152
153     public static Set<String> getResourceNames() {
154         return tagValues.keySet();
155     }
156
157
158     public static void setProperties(Properties props, AAIService aaiService) {
159         AAIRequest.configProperties = props;
160         AAIRequest.aaiService = aaiService;
161
162         try
163         {
164             URL url = null;
165             Bundle bundle = FrameworkUtil.getBundle(AAIService.class);
166             if(bundle != null) {
167                 BundleContext ctx = bundle.getBundleContext();
168                 if(ctx == null)
169                     return;
170
171                 url = ctx.getBundle().getResource(AAIService.PATH_PROPERTIES);
172             } else {
173                 url = aaiService.getClass().getResource("/aai-path.properties");
174             }
175
176             InputStream in = url.openStream();
177             Reader reader = new InputStreamReader(in, StandardCharsets.UTF_8);
178
179             Properties properties = new Properties();
180             properties.load(reader);
181             LOG.info("loaded " + properties.size());
182
183             Set<String> keys = properties.stringPropertyNames();
184
185             int index = 0;
186             Set<String> resourceNames = new TreeSet<>();
187
188             for(String key : keys) {
189                 String[] tags = key.split("\\|");
190                 for(String tag : tags) {
191                     if(!resourceNames.contains(tag)) {
192                         resourceNames.add(tag);
193                         tagValues.put(tag, Integer.toString(++index));
194                     }
195                 }
196                 BitSet bs = new BitSet(256);
197                 for(String tag : tags) {
198                     String value = tagValues.get(tag);
199                     Integer bitIndex = Integer.parseInt(value) ;
200                     bs.set(bitIndex);
201                 }
202                 String path = properties.getProperty(key);
203                 LOG.info(String.format("bitset %s\t\t%s", bs.toString(), path));
204                 bitsetPaths.put(bs, path);
205             }
206             LOG.info("loaded " + resourceNames.toString());
207         }
208         catch (Exception e)
209         {
210             LOG.error("Caught exception", e);
211         }
212     }
213
214     public AAIRequest() {
215         targetUri    = configProperties.getProperty(TARGET_URI);
216     }
217
218     public void addRequestProperty(String key, String value) {
219         requestProperties.put(key, value);
220     }
221
222     public final void setRequestObject(AAIDatum value) {
223         requestDatum = value;
224     }
225
226     public final AAIDatum getRequestObject() {
227         return requestDatum;
228     }
229
230     public final void addMasterRequest(AAIRequest masterRequest) {
231         requestProperties.put(MASTER_REQUEST, masterRequest);
232     }
233
234     protected static String encodeQuery(String param) throws UnsupportedEncodingException {
235         return URLEncoder.encode(param, "UTF-8").replace("+", "%20");
236     }
237
238     protected void handleException(AAIRequest lInterfaceRequest, JsonProcessingException exc) {
239         aaiService.getLogger().warn("Could not deserialize object of type " + lInterfaceRequest.getClass().getSimpleName(), exc) ;
240     }
241
242     public URL getRequestUrl(String method, String resourceVersion) throws UnsupportedEncodingException, MalformedURLException, URISyntaxException {
243
244         String request_url = null;
245
246         request_url = targetUri + updatePathDataValues(resourceVersion);
247
248         URL http_req_url =    new URL(request_url);
249
250         aaiService.LOGwriteFirstTrace(method, http_req_url.toString());
251
252         return http_req_url;
253     }
254
255     public String updatePathDataValues(Object resourceVersion) throws UnsupportedEncodingException, MalformedURLException {
256         String request_url = getRequestPath();
257
258         Set<String> uniqueResources = extractUniqueResourceSetFromKeys(requestProperties.stringPropertyNames());
259
260         for(String resoourceName:uniqueResources) {
261             AAIRequest locRequest = AAIRequest.createRequest(resoourceName, new HashMap<String, String>());
262             if(locRequest != null) {
263                 Class<?> clazz = locRequest.getClass();
264                 Method function = null;
265                 try {
266                     function = clazz.getMethod("processPathData", request_url.getClass(), requestProperties.getClass());
267                     request_url = (String) function.invoke(null, request_url,  requestProperties);
268                 } catch (Exception e) {
269                     e.printStackTrace();
270                 }
271             }
272         }
273
274         if(resourceVersion != null) {
275             request_url = request_url +"?resource-version="+resourceVersion;
276         }
277
278         return request_url;
279     }
280
281     protected String getRequestPath() throws MalformedURLException {
282         return getRequestPath(null);
283     }
284
285     protected String getRequestPath(String resource) throws MalformedURLException {
286         if(requestProperties.containsKey("resource-path")) {
287             return requestProperties.getProperty("resource-path");
288         }
289
290         Set<String> uniqueResources = extractUniqueResourceSetFromKeys(requestProperties.stringPropertyNames());
291         if(resource != null) {
292             // for group search add itself, but remove singular version of itself
293             if(!uniqueResources.contains(resource)) {
294                 boolean replaced =  false;
295                 Set<String> tmpUniqueResources = new HashSet<String>();
296                 tmpUniqueResources.addAll(uniqueResources);
297                 for(String item : tmpUniqueResources){
298                     String plural = item +"s";
299                     if(item.endsWith("y")){
300                         plural = item.substring(0, item.length()-1)+ "ies";
301                     }
302                     if(plural.equals(resource)) {
303                         uniqueResources.remove(item);
304                         uniqueResources.add(resource);
305                         replaced = true;
306                         break;
307                     }
308                 }
309                 if(!replaced){
310                     if(!uniqueResources.contains(resource)) {
311                         uniqueResources.add(resource);
312                     }
313                 }
314             }
315         }
316         BitSet bitset = new BitSet();
317         for(String key : uniqueResources) {
318             if(tagValues.containsKey(key)) {
319                 Object tmpValue = tagValues.get(key);
320                 if(tmpValue != null) {
321                     String value = tmpValue.toString();
322                     int bitIndex = Integer.parseInt(value);
323                     bitset.set(bitIndex);
324                 }
325             }
326         }
327
328         String path = bitsetPaths.get(bitset);
329         if(path == null) {
330             throw new MalformedURLException("PATH not found for key string containing valies :" +requestProperties.toString());
331         }
332         return path;
333     }
334
335     public abstract URL getRequestQueryUrl(String method) throws UnsupportedEncodingException, MalformedURLException, URISyntaxException;
336
337     public abstract String toJSONString();
338
339     public abstract String[] getArgsList();
340
341     public abstract Class<? extends AAIDatum> getModelClass() ;
342
343     public String getPrimaryResourceName(String resource) {
344         return resource;
345     }
346
347     public String formatKey(String argument) {
348         return argument;
349     }
350
351     public AAIDatum jsonStringToObject(String jsonData) throws JsonParseException, JsonMappingException, IOException {
352         if(jsonData == null) {
353             return null;
354         }
355
356         AAIDatum response = null;
357         ObjectMapper mapper = getObjectMapper();
358         response = mapper.readValue(jsonData, getModelClass());
359         return response;
360     }
361
362     protected static Set<String> extractUniqueResourceSetFromKeys(Set<String> keySet) {
363         Set<String> uniqueResources = new TreeSet<>();
364         List<String> keys = new ArrayList<>(keySet);
365         for(String resource : keys) {
366             if(resource.contains(".")) {
367                 String [] split = resource.split("\\.");
368                 uniqueResources.add(split[0].replaceAll("_", "-"));
369             }
370         }
371         return uniqueResources;
372     }
373
374     public void processRequestPathValues(Map<String, String> nameValues) {
375         Set<String> uniqueResources = extractUniqueResourceSetFromKeys(nameValues.keySet());
376
377         Set<String> tokens = new TreeSet<>();
378         tokens.add(DEPTH);
379         tokens.addAll(Arrays.asList(this.getArgsList()));
380
381         for(String resoourceName:uniqueResources) {
382             AAIRequest locRequest = AAIRequest.createRequest(resoourceName, nameValues);
383             if(locRequest != null)
384                 tokens.addAll(Arrays.asList(locRequest.getArgsList()));
385         }
386
387         String[] arguments = tokens.toArray(new String[0]);
388         for(String name : arguments) {
389             String tmpName = name.replaceAll("-", "_");
390             String value = nameValues.get(tmpName);
391             if(value != null && !value.isEmpty()) {
392                 value = value.trim().replace("'", "").replace("$", "").replace("'", "");
393                 this.addRequestProperty(name, value);
394             }
395         }
396     }
397
398     public static String processPathData(String request_url, Properties requestProperties) throws UnsupportedEncodingException {
399         return request_url;
400     }
401
402     public boolean isDeleteDataRequired() {
403         return false;
404     }
405
406     ObjectMapper getObjectMapper() {
407         return AAIService.getObjectMapper();
408     }
409
410     public static Class<? extends AAIDatum> getClassFromResource(String resoourceName) {
411         String className = GenericVnf.class.getName();
412         String[] split = resoourceName.split("-");
413         for(int i = 0; i < split.length; i++) {
414             split[i] = StringUtils.capitalize(split[i]);
415         }
416
417         String caps = StringUtils.join(split);
418         className = className.replace("GenericVnf", caps);
419         try {
420             return (Class<? extends AAIDatum>)Class.forName(className);
421         } catch (ClassNotFoundException e) {
422             LOG.warn("AAIRequest does not support class: " + e.getMessage());
423             return null;
424         }
425     }
426
427     protected static AAIRequest getRequestFromResource(String resoourceName) {
428
429         Class<? extends AAIDatum> clazz = getClassFromResource(resoourceName);
430
431         if(clazz == null) {
432             return null;
433         }
434         GenericRequest request = new GenericRequest(clazz);
435         return request;
436     }
437
438     public static Map<String, String> splitQuery(String query) throws UnsupportedEncodingException {
439         Map<String, String> query_pairs = new LinkedHashMap<>();
440
441         if(query != null && !query.isEmpty()) {
442             String[] pairs = query.split("&");
443             for (String pair : pairs) {
444                 int idx = pair.indexOf('=');
445                 query_pairs.put(URLDecoder.decode(pair.substring(0, idx), "UTF-8"), URLDecoder.decode(pair.substring(idx + 1), "UTF-8"));
446             }
447         }
448         return query_pairs;
449     }
450
451     public static Map<String, String> splitPath(String path) throws UnsupportedEncodingException {
452         Map<String, String> query_pairs = new LinkedHashMap<>();
453
454         if(path != null && !path.isEmpty()) {
455             String[] pairs = path.split("/");
456             for (String pair : pairs) {
457                 int idx = pair.indexOf('=');
458                 query_pairs.put(URLDecoder.decode(pair.substring(0, idx), "UTF-8"), URLDecoder.decode(pair.substring(idx + 1), "UTF-8"));
459             }
460         }
461         return query_pairs;
462     }
463
464     protected boolean expectsDataFromPUTRequest() {
465         return false;
466     }
467
468
469     public String getTargetUri() {
470         return targetUri;
471     }
472  
473     public static final String getSupportedAAIVersion() {
474         return configProperties.getProperty(AAIDeclarations.AAI_VERSION, "/v14/");
475     }
476 }