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