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