Adding back-end support for UI filters
[aai/sparky-be.git] / src / main / java / org / onap / aai / sparky / util / NodeUtils.java
1 /**
2  * ============LICENSE_START=======================================================
3  * org.onap.aai
4  * ================================================================================
5  * Copyright © 2017 AT&T Intellectual Property. All rights reserved.
6  * Copyright © 2017 Amdocs
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  * ECOMP is a trademark and service mark of AT&T Intellectual Property.
22  */
23 package org.onap.aai.sparky.util;
24
25 import java.io.BufferedReader;
26 import java.io.IOException;
27 import java.io.InputStream;
28 import java.io.InputStreamReader;
29 import java.lang.Thread.UncaughtExceptionHandler;
30 import java.nio.ByteBuffer;
31 import java.security.SecureRandom;
32 import java.text.ParseException;
33 import java.text.SimpleDateFormat;
34 import java.util.ArrayList;
35 import java.util.Arrays;
36 import java.util.Collection;
37 import java.util.Collections;
38 import java.util.Date;
39 import java.util.Iterator;
40 import java.util.List;
41 import java.util.Map;
42 import java.util.TimeZone;
43 import java.util.concurrent.ExecutorService;
44 import java.util.concurrent.Executors;
45 import java.util.concurrent.ThreadFactory;
46 import java.util.concurrent.TimeUnit;
47 import java.util.regex.Matcher;
48 import java.util.regex.Pattern;
49
50 import javax.servlet.http.HttpServletRequest;
51 import javax.xml.stream.XMLStreamConstants;
52
53 import org.onap.aai.sparky.logging.AaiUiMsgs;
54 import org.onap.aai.sparky.viewandinspect.config.TierSupportUiConstants;
55 import org.onap.aai.cl.api.Logger;
56
57 import com.fasterxml.jackson.core.JsonProcessingException;
58 import com.fasterxml.jackson.databind.JsonNode;
59 import com.fasterxml.jackson.databind.ObjectMapper;
60 import com.fasterxml.jackson.databind.ObjectWriter;
61 import com.fasterxml.jackson.databind.SerializationFeature;
62 import com.google.common.util.concurrent.ThreadFactoryBuilder;
63
64
65 /**
66  * The Class NodeUtils.
67  */
68 public class NodeUtils {
69   private static SecureRandom sRandom = new SecureRandom();
70
71   /**
72    * @return the sRandom
73    */
74   public static SecureRandom getsRandom() {
75     return sRandom;
76   }
77
78   /**
79    * @param sRandom the sRandom to set
80    */
81   public static void setsRandom(SecureRandom sRandom) {
82     NodeUtils.sRandom = sRandom;
83   }
84
85   /**
86    * @return the entityResourceKeyFormat
87    */
88   public static String getEntityResourceKeyFormat() {
89     return ENTITY_RESOURCE_KEY_FORMAT;
90   }
91
92   /**
93    * @return the timeBreakDownFormat
94    */
95   public static String getTimeBreakDownFormat() {
96     return TIME_BREAK_DOWN_FORMAT;
97   }
98
99   public static synchronized String getRandomTxnId() {
100     byte bytes[] = new byte[6];
101     sRandom.nextBytes(bytes);
102     return Integer.toUnsignedString(ByteBuffer.wrap(bytes).getInt());
103   }
104
105   /**
106    * Builds the depth padding.
107    *
108    * @param depth the depth
109    * @return the string
110    */
111   public static String buildDepthPadding(int depth) {
112     StringBuilder sb = new StringBuilder(32);
113
114     for (int x = 0; x < depth; x++) {
115       sb.append("   ");
116     }
117
118     return sb.toString();
119   }
120
121   /**
122    * Checks if is numeric.
123    *
124    * @param numberStr the number str
125    * @return true, if is numeric
126    */
127   public static boolean isNumeric(String numberStr) {
128
129     try {
130       Double.parseDouble(numberStr);
131     } catch (Exception exc) {
132       return false;
133     }
134
135     return true;
136
137   }
138
139   /**
140    * Creates the named executor.
141    *
142    * @param name the name
143    * @param numWorkers the num workers
144    * @param logger the logger
145    * @return the executor service
146    */
147   public static ExecutorService createNamedExecutor(String name, int numWorkers,
148       final Logger logger) {
149     UncaughtExceptionHandler uncaughtExceptionHandler = new Thread.UncaughtExceptionHandler() {
150
151       @Override
152       public void uncaughtException(Thread thread, Throwable exc) {
153
154         logger.error(AaiUiMsgs.ERROR_GENERIC, thread.getName() + ": " + exc);
155
156       }
157     };
158
159     ThreadFactory namedThreadFactory = new ThreadFactoryBuilder().setNameFormat(name + "-%d")
160         .setUncaughtExceptionHandler(uncaughtExceptionHandler).build();
161
162     return Executors.newScheduledThreadPool(numWorkers + 1, namedThreadFactory);
163   }
164
165   /**
166    * Calculate edit attribute uri.
167    *
168    * @param link the link
169    * @return the string
170    */
171   public static String calculateEditAttributeUri(String link) {
172     String uri = null;
173
174     if (link != null) {
175
176       Pattern pattern = Pattern.compile(TierSupportUiConstants.URI_VERSION_REGEX_PATTERN);
177       Matcher matcher = pattern.matcher(link);
178       if (matcher.find()) {
179         uri = link.substring(matcher.end());
180       }
181     }
182     return uri;
183   }
184
185   /**
186    * Generate unique sha digest.
187    *
188    * @param keys the keys
189    * @return the string
190    */
191   public static String generateUniqueShaDigest(String... keys) {
192
193     if ((keys == null) || keys.length == 0) {
194       return null;
195     }
196
197     final String keysStr = Arrays.asList(keys).toString();
198     final String hashedId = org.apache.commons.codec.digest.DigestUtils.sha256Hex(keysStr);
199
200     return hashedId;
201   }
202
203   /**
204    * Gets the node field as text.
205    *
206    * @param node the node
207    * @param fieldName the field name
208    * @return the node field as text
209    */
210   public static String getNodeFieldAsText(JsonNode node, String fieldName) {
211
212     String fieldValue = null;
213
214     JsonNode valueNode = node.get(fieldName);
215
216     if (valueNode != null) {
217       fieldValue = valueNode.asText();
218     }
219
220     return fieldValue;
221   }
222
223   private static final String ENTITY_RESOURCE_KEY_FORMAT = "%s.%s";
224
225   /**
226    * Convert a millisecond duration to a string format
227    * 
228    * @param millis A duration to convert to a string form
229    * @return A string of the form "X Days Y Hours Z Minutes A Seconds".
230    */
231
232   private static final String TIME_BREAK_DOWN_FORMAT =
233       "[ %d days, %d hours, %d minutes, %d seconds ]";
234
235   /**
236    * Gets the duration breakdown.
237    *
238    * @param millis the millis
239    * @return the duration breakdown
240    */
241   public static String getDurationBreakdown(long millis) {
242
243     if (millis < 0) {
244       return String.format(TIME_BREAK_DOWN_FORMAT, 0, 0, 0, 0);
245     }
246
247     long days = TimeUnit.MILLISECONDS.toDays(millis);
248     millis -= TimeUnit.DAYS.toMillis(days);
249     long hours = TimeUnit.MILLISECONDS.toHours(millis);
250     millis -= TimeUnit.HOURS.toMillis(hours);
251     long minutes = TimeUnit.MILLISECONDS.toMinutes(millis);
252     millis -= TimeUnit.MINUTES.toMillis(minutes);
253     long seconds = TimeUnit.MILLISECONDS.toSeconds(millis);
254
255     return String.format(TIME_BREAK_DOWN_FORMAT, days, hours, minutes, seconds);
256
257   }
258
259   /**
260    * Checks if is equal.
261    *
262    * @param n1 the n 1
263    * @param n2 the n 2
264    * @return true, if is equal
265    */
266   public static boolean isEqual(JsonNode n1, JsonNode n2) {
267
268     /*
269      * due to the inherent nature of json being unordered, comparing object representations of the
270      * same keys and values but different order makes comparison challenging. Let's try an
271      * experiment where we compare the structure of the json, and then simply compare the sorted
272      * order of that structure which should be good enough for what we are trying to accomplish.
273      */
274
275     TreeWalker walker = new TreeWalker();
276     List<String> n1Paths = new ArrayList<String>();
277     List<String> n2Paths = new ArrayList<String>();
278
279     walker.walkTree(n1Paths, n1);
280     walker.walkTree(n2Paths, n2);
281
282     Collections.sort(n1Paths);
283     Collections.sort(n2Paths);
284
285     return n1Paths.equals(n2Paths);
286
287   }
288
289   /**
290    * Concat array.
291    *
292    * @param list the list
293    * @return the string
294    */
295   public static String concatArray(List<String> list) {
296     return concatArray(list, " ");
297   }
298
299   /**
300    * Concat array.
301    *
302    * @param list the list
303    * @param delimiter the delimiter
304    * @return the string
305    */
306   public static String concatArray(List<String> list, String delimiter) {
307
308     if (list == null || list.size() == 0) {
309       return "";
310     }
311
312     StringBuilder result = new StringBuilder(64);
313
314     boolean firstValue = true;
315
316     for (String item : list) {
317
318       if (firstValue) {
319         result.append(item);
320         firstValue = false;
321       } else {
322         result.append(delimiter).append(item);
323       }
324
325     }
326
327     return result.toString();
328
329   }
330
331   /**
332    * Concat array.
333    *
334    * @param values the values
335    * @return the string
336    */
337   public static String concatArray(String[] values) {
338
339     if (values == null || values.length == 0) {
340       return "";
341     }
342
343     StringBuilder result = new StringBuilder(64);
344
345     boolean firstValue = true;
346
347     for (String item : values) {
348
349       if (firstValue) {
350         result.append(item);
351         firstValue = false;
352       } else {
353         result.append(".").append(item);
354       }
355
356     }
357
358     return result.toString();
359
360   }
361
362   /**
363    * Builds the entity resource key.
364    *
365    * @param entityType the entity type
366    * @param resourceId the resource id
367    * @return the string
368    */
369   public static String buildEntityResourceKey(String entityType, String resourceId) {
370     return String.format(ENTITY_RESOURCE_KEY_FORMAT, entityType, resourceId);
371   }
372
373   /**
374    * Extract resource id from link.
375    *
376    * @param link the link
377    * @return the string
378    */
379   public static String extractResourceIdFromLink(String link) {
380
381     if (link == null) {
382       return null;
383     }
384
385     int linkLength = link.length();
386     if (linkLength == 0) {
387       return null;
388     }
389
390     /*
391      * if the last character != / then we need to change the lastIndex position
392      */
393
394     int startIndex = 0;
395     String resourceId = null;
396     if ("/".equals(link.substring(linkLength - 1))) {
397       // Use-case:
398       // https://<AAI-hostname>:9292/aai/v7/business/customers/customer/1607_20160524Func_Ak1_01/service-subscriptions/service-subscription/uCPE-VMS/
399       startIndex = link.lastIndexOf("/", linkLength - 2);
400       resourceId = link.substring(startIndex + 1, linkLength - 1);
401     } else {
402       // Use-case:
403       // https://<AAI-Hostname>:9292/aai/v7/business/customers/customer/1607_20160524Func_Ak1_01/service-subscriptions/service-subscription/uCPE-VMS
404       startIndex = link.lastIndexOf("/");
405       resourceId = link.substring(startIndex + 1, linkLength);
406     }
407
408     String result = null;
409
410     if (resourceId != null) {
411       try {
412         result = java.net.URLDecoder.decode(resourceId, "UTF-8");
413       } catch (Exception exc) {
414         /*
415          * if there is a failure decoding the parameter we will just return the original value.
416          */
417         result = resourceId;
418       }
419     }
420
421     return result;
422
423   }
424
425   /**
426    * Gets the xml stream constant as str.
427    *
428    * @param value the value
429    * @return the xml stream constant as str
430    */
431   public static String getXmlStreamConstantAsStr(int value) {
432     switch (value) {
433       case XMLStreamConstants.ATTRIBUTE:
434         return "ATTRIBUTE";
435       case XMLStreamConstants.CDATA:
436         return "CDATA";
437       case XMLStreamConstants.CHARACTERS:
438         return "CHARACTERS";
439       case XMLStreamConstants.COMMENT:
440         return "COMMENT";
441       case XMLStreamConstants.DTD:
442         return "DTD";
443       case XMLStreamConstants.END_DOCUMENT:
444         return "END_DOCUMENT";
445       case XMLStreamConstants.END_ELEMENT:
446         return "END_ELEMENT";
447       case XMLStreamConstants.ENTITY_DECLARATION:
448         return "ENTITY_DECLARATION";
449       case XMLStreamConstants.ENTITY_REFERENCE:
450         return "ENTITY_REFERENCE";
451       case XMLStreamConstants.NAMESPACE:
452         return "NAMESPACE";
453       case XMLStreamConstants.NOTATION_DECLARATION:
454         return "NOTATION_DECLARATION";
455       case XMLStreamConstants.PROCESSING_INSTRUCTION:
456         return "PROCESSING_INSTRUCTION";
457       case XMLStreamConstants.SPACE:
458         return "SPACE";
459       case XMLStreamConstants.START_DOCUMENT:
460         return "START_DOCUMENT";
461       case XMLStreamConstants.START_ELEMENT:
462         return "START_ELEMENT";
463
464       default:
465         return "Unknown(" + value + ")";
466     }
467   }
468
469   /**
470    * Convert object to json.
471    *
472    * @param object the object
473    * @param pretty the pretty
474    * @return the string
475    * @throws JsonProcessingException the json processing exception
476    */
477   public static String convertObjectToJson(Object object, boolean pretty)
478       throws JsonProcessingException {
479     ObjectWriter ow = null;
480
481     ObjectMapper mapper = new ObjectMapper();
482     mapper.configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, false);
483
484     if (pretty) {
485       ow = mapper.writer().withDefaultPrettyPrinter();
486
487     } else {
488       ow = mapper.writer();
489     }
490
491     return ow.writeValueAsString(object);
492   }
493
494   /**
495    * Convert json str to json node.
496    *
497    * @param jsonStr the json str
498    * @return the json node
499    * @throws IOException Signals that an I/O exception has occurred.
500    */
501   public static JsonNode convertJsonStrToJsonNode(String jsonStr) throws IOException {
502     ObjectMapper mapper = new ObjectMapper();
503     if (jsonStr == null || jsonStr.length() == 0) {
504       return null;
505     }
506
507     return mapper.readTree(jsonStr);
508   }
509
510   /**
511    * Convert object to xml.
512    *
513    * @param object the object
514    * @return the string
515    * @throws JsonProcessingException the json processing exception
516    */
517   public static String convertObjectToXml(Object object) throws JsonProcessingException {
518     ObjectWriter ow = new ObjectMapper().writer().withDefaultPrettyPrinter();
519     String jsonOutput = ow.writeValueAsString(object);
520
521     if (jsonOutput == null) {
522       return null;
523     }
524
525     return JsonXmlConverter.convertJsontoXml(jsonOutput);
526
527   }
528
529   /**
530    * Extract objects by key.
531    *
532    * @param node the node
533    * @param searchKey the search key
534    * @param foundObjects the found objects
535    */
536   public static void extractObjectsByKey(JsonNode node, String searchKey,
537       Collection<JsonNode> foundObjects) {
538
539     if (node == null) {
540       return;
541     }
542
543     if (node.isObject()) {
544       Iterator<Map.Entry<String, JsonNode>> nodeIterator = node.fields();
545
546       while (nodeIterator.hasNext()) {
547         Map.Entry<String, JsonNode> entry = nodeIterator.next();
548         if (!entry.getValue().isValueNode()) {
549           extractObjectsByKey(entry.getValue(), searchKey, foundObjects);
550         }
551
552         String name = entry.getKey();
553         if (name.equalsIgnoreCase(searchKey)) {
554
555           JsonNode entryNode = entry.getValue();
556
557           if (entryNode.isArray()) {
558
559             Iterator<JsonNode> arrayItemsIterator = entryNode.elements();
560             while (arrayItemsIterator.hasNext()) {
561               foundObjects.add(arrayItemsIterator.next());
562             }
563
564           } else {
565             foundObjects.add(entry.getValue());
566           }
567
568
569         }
570       }
571     } else if (node.isArray()) {
572       Iterator<JsonNode> arrayItemsIterator = node.elements();
573       while (arrayItemsIterator.hasNext()) {
574         extractObjectsByKey(arrayItemsIterator.next(), searchKey, foundObjects);
575       }
576
577     }
578
579   }
580
581   /**
582    * Convert array into list.
583    *
584    * @param node the node
585    * @param instances the instances
586    */
587   public static void convertArrayIntoList(JsonNode node, Collection<JsonNode> instances) {
588
589     if (node.isArray()) {
590       Iterator<JsonNode> arrayItemsIterator = node.elements();
591       while (arrayItemsIterator.hasNext()) {
592         instances.add(arrayItemsIterator.next());
593       }
594
595     } else {
596       instances.add(node);
597     }
598
599   }
600
601   /**
602    * Extract field values from object.
603    *
604    * @param node the node
605    * @param attributesToExtract the attributes to extract
606    * @param fieldValues the field values
607    */
608   public static void extractFieldValuesFromObject(JsonNode node,
609       Collection<String> attributesToExtract, Collection<String> fieldValues) {
610
611     if (node == null) {
612       return;
613     }
614
615     if (node.isObject()) {
616
617       JsonNode valueNode = null;
618
619       for (String attrToExtract : attributesToExtract) {
620
621         valueNode = node.get(attrToExtract);
622
623         if (valueNode != null) {
624
625           if (valueNode.isValueNode()) {
626             fieldValues.add(valueNode.asText());
627           }
628         }
629       }
630     }
631   }
632
633   /**
634    * Extract field value from object.
635    *
636    * @param node the node
637    * @param fieldName the field name
638    * @return the string
639    */
640   public static String extractFieldValueFromObject(JsonNode node, String fieldName) {
641
642     if (node == null) {
643       return null;
644     }
645
646     if (node.isObject()) {
647
648       JsonNode valueNode = node.get(fieldName);
649
650       if (valueNode != null) {
651
652         if (valueNode.isValueNode()) {
653           return valueNode.asText();
654         }
655       }
656
657     }
658     return null;
659
660   }
661
662   /**
663    * Format timestamp.
664    *
665    * @param timestamp the timestamp
666    * @return the string
667    */
668   public static String formatTimestamp(String timestamp) {
669     try {
670       SimpleDateFormat originalFormat = new SimpleDateFormat("yyyyMMdd'T'HHmmss'Z'");
671       originalFormat.setTimeZone(TimeZone.getTimeZone("UTC"));
672       Date toDate = originalFormat.parse(timestamp);
673       SimpleDateFormat newFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'");
674       newFormat.setTimeZone(TimeZone.getTimeZone("UTC"));
675       return newFormat.format(toDate);
676
677     } catch (ParseException pe) {
678       return timestamp;
679     }
680   }
681
682   /**
683    * Gets the HttpRequest payload.
684    *
685    * @param request the request
686    * @return the body
687    * @throws IOException Signals that an I/O exception has occurred.
688    */
689   public static String getBody(HttpServletRequest request) throws IOException {
690
691     String body = null;
692     StringBuilder stringBuilder = new StringBuilder();
693     BufferedReader bufferedReader = null;
694
695     try {
696       InputStream inputStream = request.getInputStream();
697       if (inputStream != null) {
698         bufferedReader = new BufferedReader(new InputStreamReader(inputStream));
699         char[] charBuffer = new char[128];
700         int bytesRead = -1;
701         while ((bytesRead = bufferedReader.read(charBuffer)) > 0) {
702           stringBuilder.append(charBuffer, 0, bytesRead);
703         }
704       } else {
705         stringBuilder.append("");
706       }
707     } catch (IOException ex) {
708       throw ex;
709     } finally {
710       if (bufferedReader != null) {
711         try {
712           bufferedReader.close();
713         } catch (IOException ex) {
714           throw ex;
715         }
716       }
717     }
718
719     body = stringBuilder.toString();
720     return body;
721   }
722 }