25265cf80c69e3f3dcd49d62818f91bbea8e17d4
[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.FilterParam;
21 import org.opendaylight.restconf.nb.rfc8040.LeafNodesOnlyParam;
22 import org.opendaylight.restconf.nb.rfc8040.SkipNotificationDataParam;
23 import org.opendaylight.restconf.nb.rfc8040.StartTimeParam;
24 import org.opendaylight.restconf.nb.rfc8040.StopTimeParam;
25 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.DateAndTime;
26
27 /**
28  * Features of query parameters part of both notifications.
29  */
30 abstract class AbstractQueryParams extends AbstractNotificationsData {
31     private static final DateTimeFormatter FORMATTER = new DateTimeFormatterBuilder()
32         .appendValue(ChronoField.YEAR, 4).appendLiteral('-')
33         .appendValue(ChronoField.MONTH_OF_YEAR, 2).appendLiteral('-')
34         .appendValue(ChronoField.DAY_OF_MONTH, 2).appendLiteral('T')
35         .appendValue(ChronoField.HOUR_OF_DAY, 2).appendLiteral(':')
36         .appendValue(ChronoField.MINUTE_OF_HOUR, 2).appendLiteral(':')
37         .appendValue(ChronoField.SECOND_OF_MINUTE, 2)
38         .appendFraction(ChronoField.NANO_OF_SECOND, 0, 9, true)
39         .appendOffset("+HH:MM", "Z").toFormatter();
40
41     // FIXME: these should be final
42     private Instant start = null;
43     private Instant stop = null;
44     private boolean leafNodesOnly = false;
45     private boolean skipNotificationData = false;
46
47     public final Instant getStart() {
48         return start;
49     }
50
51     /**
52      * Set query parameters for listener.
53      *
54      * @param startTime     Start-time of getting notification.
55      * @param stopTime      Stop-time of getting notification.
56      * @param filter        Indicates which subset of all possible events are of interest.
57      * @param leafNodesOnly If TRUE, notifications will contain changes of leaf nodes only.
58      */
59     @SuppressWarnings("checkstyle:hiddenField")
60     public final void setQueryParams(final StartTimeParam startTime, final StopTimeParam stopTime,
61             final FilterParam filter, final LeafNodesOnlyParam leafNodesOnly,
62             final SkipNotificationDataParam skipNotificationData) {
63         start = startTime == null ? Instant.now() : parseDateAndTime(startTime.value());
64         stop = stopTime == null ? null : parseDateAndTime(stopTime.value());
65         this.leafNodesOnly = leafNodesOnly == null ? false : leafNodesOnly.value();
66         this.skipNotificationData = skipNotificationData == null ? false : skipNotificationData.value();
67
68         if (filter != null) {
69             try {
70                 setFilter(filter.paramValue());
71             } catch (XPathExpressionException e) {
72                 throw new IllegalArgumentException("Failed to get filter", e);
73             }
74         }
75     }
76
77     abstract void setFilter(@Nullable String xpathString) throws XPathExpressionException;
78
79     /**
80      * Parse input of query parameters - start-time or stop-time - from {@link DateAndTime} format
81      * to {@link Instant} format.
82      *
83      * @param uriValue Start-time or stop-time as string in {@link DateAndTime} format.
84      * @return Parsed {@link Instant} by entry.
85      */
86     private static @NonNull Instant parseDateAndTime(final DateAndTime dateAndTime) {
87         final TemporalAccessor accessor;
88         try {
89             accessor = FORMATTER.parse(dateAndTime.getValue());
90         } catch (final DateTimeParseException e) {
91             throw new RestconfDocumentedException("Cannot parse of value in date: " + dateAndTime, e);
92         }
93         return Instant.from(accessor);
94     }
95
96     /**
97      * Check whether this query should only notify about leaf node changes.
98      *
99      * @return true if this query should only notify about leaf node changes
100      */
101     boolean getLeafNodesOnly() {
102         return leafNodesOnly;
103     }
104
105     /**
106      * Check whether this query should notify changes without data.
107      *
108      * @return true if this query should notify about changes with  data
109      */
110     public boolean isSkipNotificationData() {
111         return skipNotificationData;
112     }
113
114     @SuppressWarnings("checkstyle:IllegalCatch")
115     <T extends BaseListenerInterface> boolean checkStartStop(final Instant now, final T listener) {
116         if (stop != null) {
117             if (start.compareTo(now) < 0 && stop.compareTo(now) > 0) {
118                 return true;
119             }
120             if (stop.compareTo(now) < 0) {
121                 try {
122                     listener.close();
123                 } catch (final Exception e) {
124                     throw new RestconfDocumentedException("Problem with unregister listener." + e);
125                 }
126             }
127         } else if (start != null) {
128             if (start.compareTo(now) < 0) {
129                 start = null;
130                 return true;
131             }
132         } else {
133             return true;
134         }
135         return false;
136     }
137 }