Use parameters in StreamSubscriptionServiceImpl
[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 static java.util.Objects.requireNonNull;
11
12 import com.google.common.annotations.VisibleForTesting;
13 import java.io.StringReader;
14 import java.time.Instant;
15 import javax.xml.XMLConstants;
16 import javax.xml.parsers.DocumentBuilderFactory;
17 import javax.xml.parsers.ParserConfigurationException;
18 import javax.xml.xpath.XPath;
19 import javax.xml.xpath.XPathConstants;
20 import javax.xml.xpath.XPathFactory;
21 import org.opendaylight.restconf.common.errors.RestconfDocumentedException;
22 import org.w3c.dom.Document;
23 import org.xml.sax.InputSource;
24
25 /**
26  * Features of query parameters part of both notifications.
27  */
28 abstract class AbstractQueryParams extends AbstractNotificationsData {
29     // FIXME: BUG-7956: switch to using UntrustedXML
30     private static final DocumentBuilderFactory DBF;
31
32     static {
33         final DocumentBuilderFactory f = DocumentBuilderFactory.newInstance();
34         f.setCoalescing(true);
35         f.setExpandEntityReferences(false);
36         f.setIgnoringElementContentWhitespace(true);
37         f.setIgnoringComments(true);
38         f.setXIncludeAware(false);
39         try {
40             f.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true);
41             f.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true);
42             f.setFeature("http://xml.org/sax/features/external-general-entities", false);
43             f.setFeature("http://xml.org/sax/features/external-parameter-entities", false);
44         } catch (final ParserConfigurationException e) {
45             throw new ExceptionInInitializerError(e);
46         }
47         DBF = f;
48     }
49
50     // FIXME: these should be final
51     private Instant startTime = null;
52     private Instant stopTime = null;
53     private String filter = null;
54     private boolean leafNodesOnly = false;
55     private boolean skipNotificationData = false;
56
57     @VisibleForTesting
58     public final Instant getStart() {
59         return startTime;
60     }
61
62     /**
63      * Set query parameters for listener.
64      *
65      * @param startTime     Start-time of getting notification.
66      * @param stopTime      Stop-time of getting notification.
67      * @param filter        Indicates which subset of all possible events are of interest.
68      * @param leafNodesOnly If TRUE, notifications will contain changes of leaf nodes only.
69      */
70     @SuppressWarnings("checkstyle:hiddenField")
71     public void setQueryParams(final Instant startTime, final Instant stopTime, final String filter,
72             final boolean leafNodesOnly, final boolean skipNotificationData) {
73         this.startTime = requireNonNull(startTime);
74         this.stopTime = stopTime;
75         this.filter = filter;
76         this.leafNodesOnly = leafNodesOnly;
77         this.skipNotificationData = skipNotificationData;
78     }
79
80     /**
81      * Check whether this query should only notify about leaf node changes.
82      *
83      * @return true if this query should only notify about leaf node changes
84      */
85     boolean getLeafNodesOnly() {
86         return leafNodesOnly;
87     }
88
89     /**
90      * Check whether this query should notify changes without data.
91      *
92      * @return true if this query should notify about changes with  data
93      */
94     public boolean isSkipNotificationData() {
95         return skipNotificationData;
96     }
97
98     @SuppressWarnings("checkstyle:IllegalCatch")
99     <T extends BaseListenerInterface> boolean checkStartStop(final Instant now, final T listener) {
100         if (stopTime != null) {
101             if (startTime.compareTo(now) < 0 && stopTime.compareTo(now) > 0) {
102                 return true;
103             }
104             if (stopTime.compareTo(now) < 0) {
105                 try {
106                     listener.close();
107                 } catch (final Exception e) {
108                     throw new RestconfDocumentedException("Problem with unregister listener." + e);
109                 }
110             }
111         } else if (startTime != null) {
112             if (startTime.compareTo(now) < 0) {
113                 startTime = null;
114                 return true;
115             }
116         } else {
117             return true;
118         }
119         return false;
120     }
121
122     /**
123      * Check if is filter used and then prepare and post data do client.
124      *
125      * @param xml XML data of notification.
126      */
127     @SuppressWarnings("checkstyle:IllegalCatch")
128     // FIXME: this method is never called, have we lost functionality compared to bierman02?
129     boolean checkFilter(final String xml) {
130         if (filter == null) {
131             return true;
132         }
133         try {
134             return parseFilterParam(xml);
135         } catch (final Exception e) {
136             throw new RestconfDocumentedException("Problem while parsing filter.", e);
137         }
138     }
139
140     /**
141      * Parse and evaluate filter statement by XML format.
142      *
143      * @return {@code true} or {@code false} depending on filter expression and data of notification.
144      * @throws Exception If operation fails.
145      */
146     private boolean parseFilterParam(final String xml) throws Exception {
147         final Document docOfXml = DBF.newDocumentBuilder().parse(new InputSource(new StringReader(xml)));
148         final XPath xPath = XPathFactory.newInstance().newXPath();
149         // FIXME: BUG-7956: xPath.setNamespaceContext(nsContext);
150         return (boolean) xPath.compile(filter).evaluate(docOfXml, XPathConstants.BOOLEAN);
151     }
152 }