a9e451a39f25c52c4ebc47cfe8bd1df6a492d11f
[ccsdk/features.git] /
1 /*******************************************************************************
2  * ============LICENSE_START========================================================================
3  * ONAP : ccsdk feature sdnr wt
4  * =================================================================================================
5  * Copyright (C) 2019 highstreet technologies GmbH Intellectual Property. All rights reserved.
6  * =================================================================================================
7  * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
8  * in compliance with the License. You may obtain a copy of the License at
9  *
10  * http://www.apache.org/licenses/LICENSE-2.0
11  *
12  * Unless required by applicable law or agreed to in writing, software distributed under the License
13  * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
14  * or implied. See the License for the specific language governing permissions and limitations under
15  * the License.
16  * ============LICENSE_END==========================================================================
17  ******************************************************************************/
18 package org.onap.ccsdk.features.sdnr.wt.devicemanager.base.netconf.util;
19
20 import java.text.ParseException;
21 import java.text.SimpleDateFormat;
22 import java.util.Date;
23 import java.util.TimeZone;
24 import java.util.regex.Matcher;
25 import java.util.regex.Pattern;
26 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.DateAndTime;
27 import org.slf4j.Logger;
28 import org.slf4j.LoggerFactory;
29
30 /**
31  * Function is handling the NETCONF and the format used by database and restconf communication.
32  *
33  * Input supported for the formats used in NETCONF messages:
34  *
35  * Format1 ISO 8601 2017-01-18T11:44:49.482-05:00
36  *
37  * Format2 NETCONF - pattern from ietf-yang-types "2013-07-15" Pattern:
38  * "\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(\.\d+)?(Z|[\+\-](\d{2}):(\d{2}))"
39  *
40  * Format3 NETCONF DateAndTime CoreModel-CoreFoundationModule-TypeDefinitions vom
41  * 2016-07-01 Example1: 20170118114449.1Z Example2: 20170118114449.1-0500 Pattern:
42  * "\d{4}\d{2}\d{2}\d{2}\d{2}\d{2}.\d+?(Z|[\+\-](\d{2})(\d{2}))" typedef DateAndTime { description
43  * "This primitive type defines the date and time according to the following structure:
44  * 'yyyyMMddhhmmss.s[Z|{+|-}HHMm]' where: yyyy '0000'..'9999' year MM '01'..'12' month dd '01'..'31'
45  * day hh '00'..'23' hour mm '00'..'59' minute ss '00'..'59' second s '.0'..'.9' tenth of second
46  * (set to '.0' if EMS or NE cannot support this granularity) Z 'Z' indicates UTC (rather than local
47  * time) {+|-} '+' or '-' delta from UTC HH '00'..'23' time zone difference in hours Mm '00'..'59'
48  * time zone difference in minutes."; type string; } Format4 E/// specific Example1:
49  * 2017-01-23T13:32:38-05:00 Example2: 2017-01-23T13:32-05:00
50  *
51  * Input formats netconfTime as String according the formats given above
52  *
53  * Return format is String in ISO8601 Format for database and presentation.
54  *
55  * Example formats:
56  *    1) ISO8601. Example 2017-01-18T11:44:49.482-05:00
57  *    2) Microwave ONF. Examples 20170118114449.1Z, 20170118114449.1-0500
58  *    3.1) Ericson. Example: 2017-01-23T13:32:38-05:00
59  *    3.2) Ericson. Example: 2017-01-23T13:32-05:00
60  *          Always 10 Groups,
61  *          1:Year 2:Month 3:day 4:Hour 5:minute 6:optional sec 7:optional ms 8:optional Z or 9:offset
62  *           signedhour 10:min
63  *
64  * Template:
65  *     private static final NetconfTimeStamp NETCONFTIME_CONVERTER = NetconfTimeStamp.getConverter();
66  */
67
68 public class NetconfTimeStamp {
69     private static final Logger LOG = LoggerFactory.getLogger(NetconfTimeStamp.class);
70
71     private static final NetconfTimeStamp CONVERTER = new NetconfTimeStamp();
72
73     private final SimpleDateFormat dateFormatResult = init("yyyy-MM-dd'T'HH:mm:ss.S'Z'", TimeZone.getTimeZone("GMT"));
74     private final SimpleDateFormat dateFormatConvert = init("yyyy-MM-dd HH:mm:ss.S", TimeZone.getTimeZone("GMT"));
75     private static int MILLISECONDSDIGITS = 3; // Digits of milliseconds in dateFormatResult
76     private static String MILLISECONDZEROS = "000"; // String with zeros for milliseconds in dateFormatResult
77     private static final Pattern dateNetconfPatter = Pattern.compile(
78         "(\\d{4})-?(\\d{2})-?(\\d{2})T?(\\d{2}):?(\\d{2})(?:(?::?)(\\d{2}))?(?:.(\\d+))?(?:(Z)|([+-]\\d{2}):?(\\d{2}))");
79
80     /*
81      * ------------------------------------ Public function
82      */
83
84     /**
85      * Use static access
86      */
87     private NetconfTimeStamp() {
88     }
89
90     /**
91      * Use this function to get the converter
92      * @return global converter
93      */
94     public static NetconfTimeStamp getConverter() {
95         return CONVERTER;
96     }
97
98     /**
99      * Get actual timestamp as NETCONF specific type NETCONF/YANG 1.0 Format
100      *
101      * @return String with Date in NETCONF/YANG Format Version 1.0.
102      */
103     public String getTimeStampAsNetconfString() {
104         return getRightFormattedDate(new Date().getTime());
105     }
106
107     /**
108      * Get actual timestamp as NETCONF specific type NETCONF/YANG 1.0 Format in GMT
109      *
110      * @return DateAndTime Type 1.0. Date in NETCONF/YANG Format Version 1.0.
111      */
112     public DateAndTime getTimeStamp() {
113         return DateAndTime.getDefaultInstance(getTimeStampAsNetconfString());
114     }
115
116
117     /**
118      * Return the String with a NETCONF time converted to long
119      *
120      * @param netconfTime as String according the formats given above
121      * @return Epoch milliseconds
122      * @throws IllegalArgumentException In case of no compliant time format definition for the string
123      * @throws ParseException Time parsing failed
124      */
125     public long getTimeStampFromNetconfAsMilliseconds(String netconfTime)
126             throws IllegalArgumentException, ParseException {
127         Matcher m = dateNetconfPatter.matcher(netconfTime);
128         // According to spezified matches there have to be 10 parameter
129         if (m.matches() && m.groupCount() == 10) {
130             // Convert now
131             long utcMillis = dateFormatConvert.parse(getTimeAsNormalizedString(m, m.group(6), m.group(7))).getTime()
132                     - getTimezoneOffsetMilliseconds(m.group(9), m.group(10));
133             return utcMillis;
134         } else {
135             throw new IllegalArgumentException("No pattern for NETCONF data string: " + netconfTime);
136         }
137     }
138
139     /**
140      * Deliver String result.
141      *
142      * @param netconfTime as String according the formats given above
143      * @return If successful: String in ISO8601 Format for database and presentation. If "wrong formed
144      *         input" the Input string with the prefix "Mailformed date" is delivered back.
145      */
146     public String getTimeStampFromNetconf(String netconfTime) {
147         Matcher m = dateNetconfPatter.matcher(netconfTime);
148         // According to spezified matches there have to be 10 parameter
149         if (m.matches() && m.groupCount() == 10) {
150             // Convert now
151             try {
152                 long utcMillis = dateFormatConvert.parse(getTimeAsNormalizedString(m, m.group(6), m.group(7))).getTime()
153                         - getTimezoneOffsetMilliseconds(m.group(9), m.group(10));
154                 return getRightFormattedDate(utcMillis);
155             } catch (ParseException e) {
156                 LOG.info(e.getMessage());
157             } catch (IllegalArgumentException e) {
158                 LOG.info(e.getMessage());
159             }
160         }
161         LOG.debug("No pattern for NETCONF data string: {}", netconfTime);
162         return "Malformed date: " + netconfTime; // Error handling
163     }
164
165     /*-------------------------------------------
166      * Private and static functions
167      */
168     /**
169      * Convert timeZone parameter in format [+-]/d/d:/d/d into milliseconds
170      *
171      * @param m Index 9 with "+/-" and hour string or null for UTZ, Index 10 with minutes
172      * @return long milliseconds of TimeZoneOffset
173      * @throws IllegalArgumentException If parameters are wrong
174      */
175     private static long getTimezoneOffsetMilliseconds(String timeZoneHour, String timeZoneMinute)
176             throws IllegalArgumentException {
177         // -- Calculate timezone specific offset
178         long timeZoneOffsetMilliseconds = 0;
179         if (timeZoneHour != null) {
180             // Time zone offset in hours and minutes
181             int tzHour = 0;
182             int tzMinutes = 0;
183             tzHour = Integer.valueOf(timeZoneHour);
184             if (timeZoneMinute != null) {
185                 tzMinutes = Integer.valueOf(timeZoneMinute);
186             } else {
187                 throw new IllegalArgumentException("Problem in Netconf Time format timeZone minutes parameter.");
188             }
189             timeZoneOffsetMilliseconds = (tzHour * 60 + (tzHour > 0 ? tzMinutes : -tzMinutes)) * 60000L;
190         }
191         return timeZoneOffsetMilliseconds;
192     }
193
194     /**
195      * Convert parameters to String with year .. minutes and optional Seconds and .. milliseconds
196      *
197      * @param m Matcher with parsed date
198      * @param secString Seconds as String or null
199      * @param msString Milliseconds as String or null
200      * @return Normalized time string
201      */
202     private static String getTimeAsNormalizedString(Matcher m, String secString, String msString) {
203         // -- Create time as normalized string
204         StringBuffer sb = new StringBuffer();
205         sb.append(m.group(1)); // year
206         sb.append('-');
207         sb.append(m.group(2)); // Month
208         sb.append('-');
209         sb.append(m.group(3)); // Day
210         sb.append(' ');
211         sb.append(m.group(4)); // Hour 0-23
212         sb.append(':');
213         sb.append(m.group(5)); // Minute
214         sb.append(':');
215         sb.append(secString != null ? secString : "00"); // Seconds (optional)
216         sb.append('.');
217         if (msString == null) { // Milliseconds optional
218             sb.append(MILLISECONDZEROS);
219         } else if (msString.length() <= MILLISECONDSDIGITS) {
220             sb.append(msString); // Millisecond
221             sb.append(MILLISECONDZEROS.substring(0, MILLISECONDSDIGITS - msString.length()));
222         } else {
223             sb.append(msString.substring(0, MILLISECONDSDIGITS)); // Only first Three
224         }
225         return sb.toString();
226     }
227
228     /**
229      * Deliver format in a way that milliseconds are correct.
230      *
231      * @param dateMillis Date as milliseconds in Java definition
232      * @return String
233      */
234     private String getRightFormattedDate(long dateMillis) {
235         long tenthOfSeconds = dateMillis % 1000 / 100L; // Extract 100 milliseconds
236         long base = dateMillis / 1000L * 1000L; // Cut milliseconds to 000
237         Date newDate = new Date(base + tenthOfSeconds);
238         return dateFormatResult.format(newDate);
239     }
240
241     /**
242      * Static initialization
243      */
244     private static SimpleDateFormat init(String format, TimeZone zone) {
245         if (zone == null) {
246             throw new ExceptionInInitializerError();
247         } else {
248             SimpleDateFormat dateFormat;
249             dateFormat = new SimpleDateFormat(format);
250             dateFormat.setTimeZone(zone);
251             return dateFormat;
252         }
253     }
254
255 }