Update AbstractQueryParams
[netconf.git] / restconf / restconf-nb-rfc8040 / src / main / java / org / opendaylight / restconf / nb / rfc8040 / streams / listeners / AbstractQueryParams.java
1 /*
2  * Copyright (c) 2016 Cisco Systems, Inc. and others.  All rights reserved.
3  *
4  * This program and the accompanying materials are made available under the
5  * terms of the Eclipse Public License v1.0 which accompanies this distribution,
6  * and is available at http://www.eclipse.org/legal/epl-v10.html
7  */
8 package org.opendaylight.restconf.nb.rfc8040.streams.listeners;
9
10 import java.time.Instant;
11 import java.time.format.DateTimeFormatter;
12 import java.time.format.DateTimeFormatterBuilder;
13 import java.time.format.DateTimeParseException;
14 import java.time.temporal.ChronoField;
15 import java.time.temporal.TemporalAccessor;
16 import javax.xml.xpath.XPathExpressionException;
17 import org.eclipse.jdt.annotation.NonNull;
18 import org.eclipse.jdt.annotation.Nullable;
19 import org.opendaylight.restconf.common.errors.RestconfDocumentedException;
20 import org.opendaylight.restconf.nb.rfc8040.NotificationQueryParams;
21 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.DateAndTime;
22
23 /**
24  * Features of query parameters part of both notifications.
25  */
26 abstract class AbstractQueryParams extends AbstractNotificationsData {
27     private static final DateTimeFormatter FORMATTER = new DateTimeFormatterBuilder()
28         .appendValue(ChronoField.YEAR, 4).appendLiteral('-')
29         .appendValue(ChronoField.MONTH_OF_YEAR, 2).appendLiteral('-')
30         .appendValue(ChronoField.DAY_OF_MONTH, 2).appendLiteral('T')
31         .appendValue(ChronoField.HOUR_OF_DAY, 2).appendLiteral(':')
32         .appendValue(ChronoField.MINUTE_OF_HOUR, 2).appendLiteral(':')
33         .appendValue(ChronoField.SECOND_OF_MINUTE, 2)
34         .appendFraction(ChronoField.NANO_OF_SECOND, 0, 9, true)
35         .appendOffset("+HH:MM", "Z").toFormatter();
36
37     // FIXME: these should be final
38     private Instant start = null;
39     private Instant stop = null;
40     private boolean leafNodesOnly = false;
41     private boolean skipNotificationData = false;
42
43     public final Instant getStart() {
44         return start;
45     }
46
47     /**
48      * Set query parameters for listener.
49      *
50      * @param params     NotificationQueryParams to use.
51      */
52     public final void setQueryParams(final NotificationQueryParams params) {
53         final var startTime = params.startTime();
54         start = startTime == null ? Instant.now() : parseDateAndTime(startTime.value());
55
56         final var stopTime = params.stopTime();
57         stop = stopTime == null ? null : parseDateAndTime(stopTime.value());
58
59         final var leafNodes = params.leafNodesOnly();
60         leafNodesOnly = leafNodes == null ? false : leafNodes.value();
61
62         final var skipData = params.skipNotificationData();
63         skipNotificationData = skipData == null ? false : skipData.value();
64
65         final var filter = params.filter();
66         if (filter != null) {
67             try {
68                 setFilter(filter.paramValue());
69             } catch (XPathExpressionException e) {
70                 throw new IllegalArgumentException("Failed to get filter", e);
71             }
72         }
73     }
74
75     abstract void setFilter(@Nullable String xpathString) throws XPathExpressionException;
76
77     /**
78      * Parse input of query parameters - start-time or stop-time - from {@link DateAndTime} format
79      * to {@link Instant} format.
80      *
81      * @param uriValue Start-time or stop-time as string in {@link DateAndTime} format.
82      * @return Parsed {@link Instant} by entry.
83      */
84     private static @NonNull Instant parseDateAndTime(final DateAndTime dateAndTime) {
85         final TemporalAccessor accessor;
86         try {
87             accessor = FORMATTER.parse(dateAndTime.getValue());
88         } catch (final DateTimeParseException e) {
89             throw new RestconfDocumentedException("Cannot parse of value in date: " + dateAndTime, e);
90         }
91         return Instant.from(accessor);
92     }
93
94     /**
95      * Check whether this query should only notify about leaf node changes.
96      *
97      * @return true if this query should only notify about leaf node changes
98      */
99     boolean getLeafNodesOnly() {
100         return leafNodesOnly;
101     }
102
103     /**
104      * Check whether this query should notify changes without data.
105      *
106      * @return true if this query should notify about changes with  data
107      */
108     public boolean isSkipNotificationData() {
109         return skipNotificationData;
110     }
111
112     @SuppressWarnings("checkstyle:IllegalCatch")
113     <T extends BaseListenerInterface> boolean checkStartStop(final Instant now, final T listener) {
114         if (stop != null) {
115             if (start.compareTo(now) < 0 && stop.compareTo(now) > 0) {
116                 return true;
117             }
118             if (stop.compareTo(now) < 0) {
119                 try {
120                     listener.close();
121                 } catch (final Exception e) {
122                     throw new RestconfDocumentedException("Problem with unregister listener." + e);
123                 }
124             }
125         } else if (start != null) {
126             if (start.compareTo(now) < 0) {
127                 start = null;
128                 return true;
129             }
130         } else {
131             return true;
132         }
133         return false;
134     }
135 }