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