Bug 5679 - implement ietf-restconf-monitoring - cleanup
[netconf.git] / restconf / sal-rest-connector / src / main / java / org / opendaylight / restconf / restful / utils / CreateStreamUtil.java
index 03b04182471fdf85202d26a81729d6d74af3fc5e..a6e76b56b472d6b4bb2fdd7acb2b0d29295acfad 100644 (file)
@@ -8,7 +8,12 @@
 package org.opendaylight.restconf.restful.utils;
 
 import com.google.common.base.Optional;
+import com.google.common.base.Preconditions;
 import com.google.common.util.concurrent.CheckedFuture;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.List;
 import org.opendaylight.controller.md.sal.common.api.data.AsyncDataBroker.DataChangeScope;
 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
 import org.opendaylight.controller.md.sal.dom.api.DOMRpcResult;
@@ -20,6 +25,7 @@ import org.opendaylight.netconf.sal.restconf.impl.RestconfError.ErrorType;
 import org.opendaylight.netconf.sal.streams.listeners.Notificator;
 import org.opendaylight.restconf.common.references.SchemaContextRef;
 import org.opendaylight.restconf.utils.parser.ParserIdentifier;
+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;
 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifier;
@@ -27,9 +33,14 @@ import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.PathArgum
 import org.opendaylight.yangtools.yang.data.api.schema.AugmentationNode;
 import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode;
 import org.opendaylight.yangtools.yang.data.api.schema.DataContainerChild;
+import org.opendaylight.yangtools.yang.data.api.schema.LeafSetEntryNode;
+import org.opendaylight.yangtools.yang.data.api.schema.LeafSetNode;
 import org.opendaylight.yangtools.yang.data.impl.schema.ImmutableNodes;
 import org.opendaylight.yangtools.yang.data.impl.schema.builder.impl.ImmutableContainerNodeBuilder;
+import org.opendaylight.yangtools.yang.model.api.Module;
+import org.opendaylight.yangtools.yang.model.api.NotificationDefinition;
 import org.opendaylight.yangtools.yang.model.api.SchemaContext;
+import org.opendaylight.yangtools.yang.model.api.SchemaPath;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -45,6 +56,7 @@ import org.slf4j.LoggerFactory;
 public final class CreateStreamUtil {
 
     private static final Logger LOG = LoggerFactory.getLogger(CreateStreamUtil.class);
+    private static final String OUTPUT_TYPE_PARAM_NAME = "notification-output-type";
 
     private CreateStreamUtil() {
         throw new UnsupportedOperationException("Util class");
@@ -85,28 +97,42 @@ public final class CreateStreamUtil {
      *         </pre>
      *
      */
-    public static DOMRpcResult createStream(final NormalizedNodeContext payload,
+    public static DOMRpcResult createDataChangeNotifiStream(final NormalizedNodeContext payload,
             final SchemaContextRef refSchemaCtx) {
         final ContainerNode data = (ContainerNode) payload.getData();
         final QName qname = payload.getInstanceIdentifierContext().getSchemaNode().getQName();
-        final YangInstanceIdentifier path = preparePath(payload, data, qname);
-        final String streamName = prepareStream(path, refSchemaCtx.get(), data);
+        final YangInstanceIdentifier path = preparePath(data, qname);
+        String streamName = prepareDataChangeNotifiStreamName(path, refSchemaCtx.get(), data);
 
         final QName outputQname = QName.create(qname, "output");
         final QName streamNameQname = QName.create(qname, "stream-name");
 
-        final ContainerNode output = ImmutableContainerNodeBuilder.create()
-                .withNodeIdentifier(new NodeIdentifier(outputQname))
-                .withChild(ImmutableNodes.leafNode(streamNameQname, streamName)).build();
+        final NotificationOutputType outputType = prepareOutputType(data);
+        if(outputType.equals(NotificationOutputType.JSON)){
+            streamName = streamName + "/JSON";
+        }
 
         if (!Notificator.existListenerFor(streamName)) {
-            Notificator.createListener(path, streamName);
+            Notificator.createListener(path, streamName, outputType);
         }
 
+        final ContainerNode output =
+                ImmutableContainerNodeBuilder.create().withNodeIdentifier(new NodeIdentifier(outputQname))
+                        .withChild(ImmutableNodes.leafNode(streamNameQname, streamName)).build();
         return new DefaultDOMRpcResult(output);
     }
 
-    private static String prepareStream(final YangInstanceIdentifier path, final SchemaContext schemaContext,
+    /**
+     * @param data
+     *            - data of notification
+     * @return output type fo notification
+     */
+    private static NotificationOutputType prepareOutputType(final ContainerNode data) {
+        NotificationOutputType outputType = parseEnum(data, NotificationOutputType.class, OUTPUT_TYPE_PARAM_NAME);
+        return outputType = outputType == null ? NotificationOutputType.XML : outputType;
+    }
+
+    private static String prepareDataChangeNotifiStreamName(final YangInstanceIdentifier path, final SchemaContext schemaContext,
             final ContainerNode data) {
         LogicalDatastoreType ds = parseEnum(data, LogicalDatastoreType.class,
                 RestconfStreamsConstants.DATASTORE_PARAM_NAME);
@@ -115,14 +141,10 @@ public final class CreateStreamUtil {
         DataChangeScope scope = parseEnum(data, DataChangeScope.class, RestconfStreamsConstants.SCOPE_PARAM_NAME);
         scope = scope == null ? RestconfStreamsConstants.DEFAULT_SCOPE : scope;
 
-        final String streamName = Notificator
+        final String streamName = RestconfStreamsConstants.DATA_SUBSCR + "/"
+                + Notificator
                 .createStreamNameFromUri(ParserIdentifier.stringFromYangInstanceIdentifier(path, schemaContext)
                 + RestconfStreamsConstants.DS_URI + ds + RestconfStreamsConstants.SCOPE_URI + scope);
-        if((streamName == null) || streamName.equals("")){
-            final String errMsg = "Path is empty or contains value node which is not Container or List build-in type.";
-            LOG.debug(errMsg + path);
-            throw new RestconfDocumentedException(errMsg, ErrorType.PROTOCOL, ErrorTag.INVALID_VALUE);
-        }
         return streamName;
     }
 
@@ -143,11 +165,10 @@ public final class CreateStreamUtil {
             return null;
         }
 
-        return StreamUtil.resolveEnum(clazz, (String) value);
+        return ResolveEnumUtil.resolveEnum(clazz, (String) value);
     }
 
-    private static YangInstanceIdentifier preparePath(final NormalizedNodeContext payload, final ContainerNode data,
-            final QName qName) {
+    private static YangInstanceIdentifier preparePath(final ContainerNode data, final QName qName) {
         final Optional<DataContainerChild<? extends PathArgument, ?>> path = data
                 .getChild(new YangInstanceIdentifier.NodeIdentifier(QName.create(qName, "path")));
         Object pathValue = null;
@@ -161,4 +182,71 @@ public final class CreateStreamUtil {
         }
         return (YangInstanceIdentifier) pathValue;
     }
+
+    /**
+     * Create stream with POST operation via RPC
+     *
+     * @param payload
+     *            - input of RPC
+     * @param refSchemaCtx
+     *            - schemaContext
+     * @return {@link DOMRpcResult}
+     */
+    public static DOMRpcResult createYangNotifiStream(final NormalizedNodeContext payload,
+            final SchemaContextRef refSchemaCtx) {
+        final ContainerNode data = (ContainerNode) payload.getData();
+        LeafSetNode leafSet = null;
+        String outputType = "XML";
+        for (final DataContainerChild<? extends PathArgument, ?> dataChild : data.getValue()) {
+            if (dataChild instanceof LeafSetNode) {
+                leafSet = (LeafSetNode) dataChild;
+            } else if (dataChild instanceof AugmentationNode) {
+                outputType = (String) (((AugmentationNode) dataChild).getValue()).iterator().next().getValue();
+            }
+        }
+
+        final Collection<LeafSetEntryNode> entryNodes = leafSet.getValue();
+        final List<SchemaPath> paths = new ArrayList<>();
+        String streamName = RestconfStreamsConstants.CREATE_NOTIFICATION_STREAM + "/";
+
+        final Iterator<LeafSetEntryNode> iterator = entryNodes.iterator();
+        while (iterator.hasNext()) {
+            final QName valueQName = QName.create((String) iterator.next().getValue());
+            final Module module = refSchemaCtx.findModuleByNamespaceAndRevision(valueQName.getModule().getNamespace(),
+                    valueQName.getModule().getRevision());
+            Preconditions.checkNotNull(module,
+                    "Module for namespace " + valueQName.getModule().getNamespace() + " does not exist");
+            NotificationDefinition notifiDef = null;
+            for (final NotificationDefinition notification : module.getNotifications()) {
+                if (notification.getQName().equals(valueQName)) {
+                    notifiDef = notification;
+                    break;
+                }
+            }
+            final String moduleName = module.getName();
+            Preconditions.checkNotNull(notifiDef,
+                    "Notification " + valueQName + "doesn't exist in module " + moduleName);
+            paths.add(notifiDef.getPath());
+            streamName = streamName + moduleName + ":" + valueQName.getLocalName();
+            if (iterator.hasNext()) {
+                streamName = streamName + ",";
+            }
+        }
+        if (outputType.equals("JSON")) {
+            streamName = streamName + "/JSON";
+        }
+        final QName rpcQName = payload.getInstanceIdentifierContext().getSchemaNode().getQName();
+        final QName outputQname = QName.create(rpcQName, "output");
+        final QName streamNameQname = QName.create(rpcQName, "notification-stream-identifier");
+
+        final ContainerNode output =
+                ImmutableContainerNodeBuilder.create().withNodeIdentifier(new NodeIdentifier(outputQname))
+                        .withChild(ImmutableNodes.leafNode(streamNameQname, streamName)).build();
+
+        if (!Notificator.existNotificationListenerFor(streamName)) {
+            Notificator.createNotificationListener(paths, streamName, outputType);
+        }
+
+        return new DefaultDOMRpcResult(output);
+    }
 }