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