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