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