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