2 * Copyright (c) 2016 Cisco Systems, Inc. and others. All rights reserved.
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
8 package org.opendaylight.netconf.sal.streams.listeners;
10 import static java.util.Objects.requireNonNull;
12 import com.google.common.annotations.VisibleForTesting;
13 import java.io.StringReader;
14 import java.time.Instant;
15 import java.util.Optional;
16 import javax.xml.XMLConstants;
17 import javax.xml.parsers.DocumentBuilderFactory;
18 import javax.xml.parsers.ParserConfigurationException;
19 import javax.xml.xpath.XPath;
20 import javax.xml.xpath.XPathConstants;
21 import javax.xml.xpath.XPathFactory;
22 import org.opendaylight.restconf.common.errors.RestconfDocumentedException;
23 import org.w3c.dom.Document;
24 import org.xml.sax.InputSource;
27 * Features of query parameters part of both notifications.
30 abstract class AbstractQueryParams extends AbstractNotificationsData {
31 // FIXME: BUG-7956: switch to using UntrustedXML
32 private static final DocumentBuilderFactory DBF;
35 final DocumentBuilderFactory f = DocumentBuilderFactory.newInstance();
36 f.setCoalescing(true);
37 f.setExpandEntityReferences(false);
38 f.setIgnoringElementContentWhitespace(true);
39 f.setIgnoringComments(true);
40 f.setXIncludeAware(false);
42 f.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true);
43 f.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true);
44 f.setFeature("http://xml.org/sax/features/external-general-entities", false);
45 f.setFeature("http://xml.org/sax/features/external-parameter-entities", false);
46 } catch (final ParserConfigurationException e) {
47 throw new ExceptionInInitializerError(e);
52 // FIXME: these should be final
53 private Instant start = null;
54 private Instant stop = null;
55 private String filter = null;
56 private boolean leafNodesOnly = false;
57 private boolean skipNotificationData = false;
60 public final Instant getStart() {
65 * Set query parameters for listener.
68 * start-time of getting notification
70 * stop-time of getting notification
72 * indicate which subset of all possible events are of interest
73 * @param leafNodesOnly
74 * if true, notifications will contain changes to leaf nodes only
75 * @param skipNotificationData
76 * if true, notification will not contain changed data
78 @SuppressWarnings("checkstyle:hiddenField")
79 public void setQueryParams(final Instant start, final Optional<Instant> stop, final Optional<String> filter,
80 final boolean leafNodesOnly, final boolean skipNotificationData) {
81 this.start = requireNonNull(start);
82 this.stop = stop.orElse(null);
83 this.filter = filter.orElse(null);
84 this.leafNodesOnly = leafNodesOnly;
85 this.skipNotificationData = skipNotificationData;
89 * Check whether this query should only notify about leaf node changes.
91 * @return true if this query should only notify about leaf node changes
93 public boolean getLeafNodesOnly() {
98 * Check whether this query should notify changes without data.
100 * @return true if this query should notify about changes with data
102 public boolean isSkipNotificationData() {
103 return skipNotificationData;
106 @SuppressWarnings("checkstyle:IllegalCatch")
107 <T extends BaseListenerInterface> boolean checkStartStop(final Instant now, final T listener) {
108 if (this.stop != null) {
109 if (this.start.compareTo(now) < 0 && this.stop.compareTo(now) > 0) {
112 if (this.stop.compareTo(now) < 0) {
115 } catch (final Exception e) {
116 throw new RestconfDocumentedException("Problem with unregister listener." + e);
119 } else if (this.start != null) {
120 if (this.start.compareTo(now) < 0) {
131 * Check if is filter used and then prepare and post data do client.
133 * @param xml data of notification
135 @SuppressWarnings("checkstyle:IllegalCatch")
136 boolean checkFilter(final String xml) {
137 if (this.filter == null) {
142 return parseFilterParam(xml);
143 } catch (final Exception e) {
144 throw new RestconfDocumentedException("Problem while parsing filter.", e);
149 * Parse and evaluate filter value by xml.
151 * @return true or false - depends on filter expression and data of
153 * @throws Exception if operation fails
155 private boolean parseFilterParam(final String xml) throws Exception {
156 final Document docOfXml = DBF.newDocumentBuilder().parse(new InputSource(new StringReader(xml)));
157 final XPath xPath = XPathFactory.newInstance().newXPath();
158 // FIXME: BUG-7956: xPath.setNamespaceContext(nsContext);
159 return (boolean) xPath.compile(this.filter).evaluate(docOfXml, XPathConstants.BOOLEAN);