Convert to using requireNonNull()
[netconf.git] / restconf / restconf-nb-rfc8040 / src / main / java / org / opendaylight / restconf / nb / rfc8040 / streams / listeners / ListenerAdapter.java
index 0296e469d52e8a46fddf8fc74488449a7a253f0e..c241a63281b861bdcefbf2ebac993fe60f6212db 100644 (file)
@@ -7,16 +7,20 @@
  */
 package org.opendaylight.restconf.nb.rfc8040.streams.listeners;
 
-import com.google.common.base.Preconditions;
+import static com.google.common.base.Preconditions.checkArgument;
+import static com.google.common.base.Preconditions.checkState;
+import static java.util.Objects.requireNonNull;
+
+import com.google.common.base.MoreObjects;
 import java.io.IOException;
+import java.time.Instant;
 import java.util.Collection;
-import java.util.Map;
 import java.util.Map.Entry;
 import java.util.Optional;
 import javax.xml.stream.XMLStreamException;
 import javax.xml.transform.dom.DOMResult;
 import org.json.XML;
-import org.opendaylight.controller.md.sal.dom.api.ClusteredDOMDataTreeChangeListener;
+import org.opendaylight.mdsal.dom.api.ClusteredDOMDataTreeChangeListener;
 import org.opendaylight.yang.gen.v1.urn.sal.restconf.event.subscription.rev140708.NotificationOutputTypeGrouping.NotificationOutputType;
 import org.opendaylight.yangtools.yang.common.QName;
 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
@@ -29,6 +33,7 @@ import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
 import org.opendaylight.yangtools.yang.data.api.schema.UnkeyedListEntryNode;
 import org.opendaylight.yangtools.yang.data.api.schema.tree.DataTreeCandidate;
 import org.opendaylight.yangtools.yang.data.api.schema.tree.DataTreeCandidateNode;
+import org.opendaylight.yangtools.yang.data.util.DataSchemaContextNode;
 import org.opendaylight.yangtools.yang.data.util.DataSchemaContextTree;
 import org.opendaylight.yangtools.yang.model.api.Module;
 import org.opendaylight.yangtools.yang.model.api.SchemaContext;
@@ -40,8 +45,7 @@ import org.w3c.dom.Element;
 import org.w3c.dom.Node;
 
 /**
- * {@link ListenerAdapter} is responsible to track events, which occurred by
- * changing data in data source.
+ * {@link ListenerAdapter} is responsible to track events, which occurred by changing data in data source.
  */
 public class ListenerAdapter extends AbstractCommonSubscriber implements ClusteredDOMDataTreeChangeListener {
 
@@ -52,31 +56,31 @@ public class ListenerAdapter extends AbstractCommonSubscriber implements Cluster
     private final NotificationOutputType outputType;
 
     /**
-     * Creates new {@link ListenerAdapter} listener specified by path and stream
-     * name and register for subscribing.
+     * Creates new {@link ListenerAdapter} listener specified by path and stream name and register for subscribing.
      *
-     * @param path
-     *            Path to data in data store.
-     * @param streamName
-     *            The name of the stream.
-     * @param outputType
-     *            Type of output on notification (JSON, XML)
+     * @param path       Path to data in data store.
+     * @param streamName The name of the stream.
+     * @param outputType Type of output on notification (JSON, XML).
      */
     ListenerAdapter(final YangInstanceIdentifier path, final String streamName,
             final NotificationOutputType outputType) {
-        register(this);
         setLocalNameOfPath(path.getLastPathArgument().getNodeType().getLocalName());
 
-        this.outputType = Preconditions.checkNotNull(outputType);
-        this.path = Preconditions.checkNotNull(path);
-        Preconditions.checkArgument(streamName != null && !streamName.isEmpty());
-        this.streamName = streamName;
+        this.outputType = requireNonNull(outputType);
+        this.path = requireNonNull(path);
+        this.streamName = requireNonNull(streamName);
+        checkArgument(!streamName.isEmpty());
     }
 
     @Override
     public void onDataTreeChanged(final Collection<DataTreeCandidate> dataTreeCandidates) {
+        final Instant now = Instant.now();
+        if (!checkStartStop(now, this)) {
+            return;
+        }
+
         final String xml = prepareXml(dataTreeCandidates);
-        if (checkQueryParams(xml, this)) {
+        if (checkFilter(xml)) {
             prepareAndPostData(xml);
         }
     }
@@ -108,27 +112,20 @@ public class ListenerAdapter extends AbstractCommonSubscriber implements Cluster
     /**
      * Prepare data of notification and data to client.
      *
-     * @param xml   data
+     * @param xml XML-formatted data.
      */
     private void prepareAndPostData(final String xml) {
-        final Event event = new Event(EventType.NOTIFY);
         if (this.outputType.equals(NotificationOutputType.JSON)) {
-            event.setData(XML.toJSONObject(xml).toString());
+            post(XML.toJSONObject(xml).toString());
         } else {
-            event.setData(xml);
+            post(xml);
         }
-        post(event);
     }
 
-    /**
-     * Tracks events of data change by customer.
-     */
-
     /**
      * Prepare data in printable form and transform it to String.
      *
-     * @param dataTreeCandidates the DataTreeCandidates to transform
-     *
+     * @param dataTreeCandidates Data-tree candidates to be transformed.
      * @return Data in printable form.
      */
     private String prepareXml(final Collection<DataTreeCandidate> dataTreeCandidates) {
@@ -151,8 +148,7 @@ public class ListenerAdapter extends AbstractCommonSubscriber implements Cluster
      */
     @SuppressWarnings("checkstyle:hiddenField")
     private void addValuesToDataChangedNotificationEventElement(final Document doc,
-            final Element dataChangedNotificationEventElement,
-            final Collection<DataTreeCandidate> dataTreeCandidates,
+            final Element dataChangedNotificationEventElement, final Collection<DataTreeCandidate> dataTreeCandidates,
             final SchemaContext schemaContext, final DataSchemaContextTree dataSchemaContextTree) {
 
         for (DataTreeCandidate dataTreeCandidate : dataTreeCandidates) {
@@ -171,7 +167,7 @@ public class ListenerAdapter extends AbstractCommonSubscriber implements Cluster
             final YangInstanceIdentifier parentYiid, final SchemaContext schemaContext,
             final DataSchemaContextTree dataSchemaContextTree) {
 
-        Optional<NormalizedNode<?,?>> optionalNormalizedNode = Optional.empty();
+        Optional<NormalizedNode<?, ?>> optionalNormalizedNode = Optional.empty();
         switch (candidateNode.getModificationType()) {
             case APPEARED:
             case SUBTREE_MODIFIED:
@@ -192,11 +188,13 @@ public class ListenerAdapter extends AbstractCommonSubscriber implements Cluster
             return;
         }
 
-        NormalizedNode<?,?> normalizedNode = optionalNormalizedNode.get();
+        NormalizedNode<?, ?> normalizedNode = optionalNormalizedNode.get();
         YangInstanceIdentifier yiid = YangInstanceIdentifier.builder(parentYiid)
-                                                            .append(normalizedNode.getIdentifier()).build();
+                .append(normalizedNode.getIdentifier()).build();
 
-        boolean isNodeMixin = dataSchemaContextTree.getChild(yiid).isMixin();
+        final Optional<DataSchemaContextNode<?>> childrenSchemaNode = dataSchemaContextTree.findChild(yiid);
+        checkState(childrenSchemaNode.isPresent());
+        boolean isNodeMixin = childrenSchemaNode.get().isMixin();
         boolean isSkippedNonLeaf = getLeafNodesOnly() && !(normalizedNode instanceof LeafNode);
         if (!isNodeMixin && !isSkippedNonLeaf) {
             Node node = null;
@@ -210,7 +208,7 @@ public class ListenerAdapter extends AbstractCommonSubscriber implements Cluster
                     break;
                 case DELETE:
                 case DISAPPEARED:
-                    node = createDataChangeEventElement(doc, yiid, Operation.DELETED, schemaContext);
+                    node = createDataChangeEventElement(doc, yiid, schemaContext);
                     break;
                 case UNMODIFIED:
                 default:
@@ -222,41 +220,35 @@ public class ListenerAdapter extends AbstractCommonSubscriber implements Cluster
         }
 
         for (DataTreeCandidateNode childNode : candidateNode.getChildNodes()) {
-            addNodeToDataChangeNotificationEventElement(doc, dataChangedNotificationEventElement, childNode,
-                                                                        yiid, schemaContext, dataSchemaContextTree);
+            addNodeToDataChangeNotificationEventElement(
+                    doc, dataChangedNotificationEventElement, childNode, yiid, schemaContext, dataSchemaContextTree);
         }
     }
 
     /**
-     * Creates changed event element from data.
+     * Creates data-changed event element from data.
      *
-     * @param doc
-     *            {@link Document}
-     * @param path
-     *            Path to data in data store.
-     * @param operation
-     *            {@link Operation}
-     * @param schemaContext
-     *            schema context
-     * @return {@link Node} node represented by changed event element.
+     * @param doc           {@link Document}
+     * @param schemaContext Schema context.
+     * @return {@link Node} represented by changed event element.
      */
     private Node createDataChangeEventElement(final Document doc, final YangInstanceIdentifier eventPath,
-            final Operation operation, final SchemaContext schemaContext) {
+            final SchemaContext schemaContext) {
         final Element dataChangeEventElement = doc.createElement("data-change-event");
         final Element pathElement = doc.createElement("path");
         addPathAsValueToElement(eventPath, pathElement, schemaContext);
         dataChangeEventElement.appendChild(pathElement);
 
         final Element operationElement = doc.createElement("operation");
-        operationElement.setTextContent(operation.value);
+        operationElement.setTextContent(Operation.DELETED.value);
         dataChangeEventElement.appendChild(operationElement);
 
         return dataChangeEventElement;
     }
 
-    private Node createCreatedChangedDataChangeEventElement(final Document doc,
-            final YangInstanceIdentifier eventPath, NormalizedNode<?, ?> normalized, final Operation operation,
-            final SchemaContext schemaContext, final DataSchemaContextTree dataSchemaContextTree) {
+    private Node createCreatedChangedDataChangeEventElement(final Document doc, final YangInstanceIdentifier eventPath,
+            final NormalizedNode<?, ?> normalized, final Operation operation, final SchemaContext schemaContext,
+            final DataSchemaContextTree dataSchemaContextTree) {
         final Element dataChangeEventElement = doc.createElement("data-change-event");
         final Element pathElement = doc.createElement("path");
         addPathAsValueToElement(eventPath, pathElement, schemaContext);
@@ -268,10 +260,12 @@ public class ListenerAdapter extends AbstractCommonSubscriber implements Cluster
 
         try {
             SchemaPath nodePath;
+            final Optional<DataSchemaContextNode<?>> childrenSchemaNode = dataSchemaContextTree.findChild(eventPath);
+            checkState(childrenSchemaNode.isPresent());
             if (normalized instanceof MapEntryNode || normalized instanceof UnkeyedListEntryNode) {
-                nodePath = dataSchemaContextTree.getChild(eventPath).getDataSchemaNode().getPath();
+                nodePath = childrenSchemaNode.get().getDataSchemaNode().getPath();
             } else {
-                nodePath = dataSchemaContextTree.getChild(eventPath).getDataSchemaNode().getPath().getParent();
+                nodePath = childrenSchemaNode.get().getDataSchemaNode().getPath().getParent();
             }
             final DOMResult domResult = writeNormalizedNode(normalized, schemaContext, nodePath);
             final Node result = doc.importNode(domResult.getNode().getFirstChild(), true);
@@ -290,12 +284,9 @@ public class ListenerAdapter extends AbstractCommonSubscriber implements Cluster
     /**
      * Adds path as value to element.
      *
-     * @param eventPath
-     *            Path to data in data store.
-     * @param element
-     *            {@link Element}
-     * @param schemaContext
-     *            schema context
+     * @param eventPath     Path to data in data store.
+     * @param element       {@link Element}
+     * @param schemaContext Schema context.
      */
     @SuppressWarnings("rawtypes")
     private void addPathAsValueToElement(final YangInstanceIdentifier eventPath, final Element element,
@@ -307,14 +298,13 @@ public class ListenerAdapter extends AbstractCommonSubscriber implements Cluster
                 continue;
             }
             textContent.append("/");
-            writeIdentifierWithNamespacePrefix(element, textContent, pathArgument.getNodeType(), schemaContext);
+            writeIdentifierWithNamespacePrefix(textContent, pathArgument.getNodeType(), schemaContext);
             if (pathArgument instanceof NodeIdentifierWithPredicates) {
-                final Map<QName, Object> predicates = ((NodeIdentifierWithPredicates) pathArgument).getKeyValues();
-                for (final Entry<QName, Object> entry : predicates.entrySet()) {
+                for (final Entry<QName, Object> entry : ((NodeIdentifierWithPredicates) pathArgument).entrySet()) {
                     final QName keyValue = entry.getKey();
                     final String predicateValue = String.valueOf(entry.getValue());
                     textContent.append("[");
-                    writeIdentifierWithNamespacePrefix(element, textContent, keyValue, schemaContext);
+                    writeIdentifierWithNamespacePrefix(textContent, keyValue, schemaContext);
                     textContent.append("='");
                     textContent.append(predicateValue);
                     textContent.append("'");
@@ -333,30 +323,32 @@ public class ListenerAdapter extends AbstractCommonSubscriber implements Cluster
     /**
      * Writes identifier that consists of prefix and QName.
      *
-     * @param element
-     *            {@link Element}
-     * @param textContent
-     *            StringBuilder
-     * @param qualifiedName
-     *            QName
-     * @param schemaContext
-     *            schema context
+     * @param textContent   Text builder that should be supplemented by QName and its modules name.
+     * @param qualifiedName QName of the element.
+     * @param schemaContext Schema context that holds modules which should contain module specified in QName.
      */
-    private static void writeIdentifierWithNamespacePrefix(final Element element, final StringBuilder textContent,
-            final QName qualifiedName, final SchemaContext schemaContext) {
-        final Module module = schemaContext.findModule(qualifiedName.getModule()).get();
-
-        textContent.append(module.getName());
-        textContent.append(":");
-        textContent.append(qualifiedName.getLocalName());
+    private static void writeIdentifierWithNamespacePrefix(final StringBuilder textContent, final QName qualifiedName,
+            final SchemaContext schemaContext) {
+        final Optional<Module> module = schemaContext.findModule(qualifiedName.getModule());
+        if (module.isPresent()) {
+            textContent.append(module.get().getName());
+            textContent.append(":");
+            textContent.append(qualifiedName.getLocalName());
+        } else {
+            LOG.error("Cannot write identifier with namespace prefix in data-change listener adapter: "
+                    + "Cannot find module in schema context for input QName {}.", qualifiedName);
+            throw new IllegalStateException(String.format("Cannot find module in schema context for input QName %s.",
+                    qualifiedName));
+        }
     }
 
     /**
-     * Consists of three types {@link Operation#CREATED},
-     * {@link Operation#UPDATED} and {@link Operation#DELETED}.
+     * Consists of three types {@link Operation#CREATED}, {@link Operation#UPDATED} and {@link Operation#DELETED}.
      */
     private enum Operation {
-        CREATED("created"), UPDATED("updated"), DELETED("deleted");
+        CREATED("created"),
+        UPDATED("updated"),
+        DELETED("deleted");
 
         private final String value;
 
@@ -364,4 +356,13 @@ public class ListenerAdapter extends AbstractCommonSubscriber implements Cluster
             this.value = value;
         }
     }
-}
+
+    @Override
+    public String toString() {
+        return MoreObjects.toStringHelper(this)
+                .add("path", path)
+                .add("stream-name", streamName)
+                .add("output-type", outputType)
+                .toString();
+    }
+}
\ No newline at end of file