Bug 6947 / Bug 6948 - implement point and insert query params
[netconf.git] / restconf / sal-rest-connector / src / main / java / org / opendaylight / netconf / sal / restconf / impl / RestconfImpl.java
index a7e2161702ed88ab184c6d1f3bd5b8a087cef264..2f724ec26a95dae3344ef3568990417885a80101 100644 (file)
@@ -437,6 +437,7 @@ public class RestconfImpl implements RestconfService {
         final CheckedFuture<DOMRpcResult, DOMRpcException> response;
         final DOMMountPoint mountPoint = payload.getInstanceIdentifierContext().getMountPoint();
         final SchemaContext schemaContext;
+
         if (mountPoint != null) {
             final Optional<DOMRpcService> mountRpcServices = mountPoint.getService(DOMRpcService.class);
             if ( ! mountRpcServices.isPresent()) {
@@ -710,8 +711,46 @@ public class RestconfImpl implements RestconfService {
     }
 
     @Override
-    public Response updateConfigurationData(final String identifier, final NormalizedNodeContext payload) {
+    public Response updateConfigurationData(final String identifier, final NormalizedNodeContext payload,
+            final UriInfo uriInfo) {
+        boolean insert_used = false;
+        boolean point_used = false;
+        String insert = null;
+        String point = null;
+
+        for (final Entry<String, List<String>> entry : uriInfo.getQueryParameters().entrySet()) {
+            switch (entry.getKey()) {
+                case "insert":
+                    if (!insert_used) {
+                        insert_used = true;
+                        insert = entry.getValue().iterator().next();
+                    } else {
+                        throw new RestconfDocumentedException("Insert parameter can be used only once.");
+                    }
+                    break;
+                case "point":
+                    if (!point_used) {
+                        point_used = true;
+                        point = entry.getValue().iterator().next();
+                    } else {
+                        throw new RestconfDocumentedException("Point parameter can be used only once.");
+                    }
+                    break;
+                default:
+                    throw new RestconfDocumentedException("Bad parameter for post: " + entry.getKey());
+            }
+        }
+
+        if (point_used && !insert_used) {
+            throw new RestconfDocumentedException("Point parameter can't be used without Insert parameter.");
+        }
+        if (point_used && (insert.equals("first") || insert.equals("last"))) {
+            throw new RestconfDocumentedException(
+                    "Point parameter can be used only with 'after' or 'before' values of Insert parameter.");
+        }
+
         Preconditions.checkNotNull(identifier);
+
         final InstanceIdentifierContext<?> iiWithData = payload.getInstanceIdentifierContext();
 
         validateInput(iiWithData.getSchemaNode(), payload);
@@ -739,10 +778,11 @@ public class RestconfImpl implements RestconfService {
         while(true) {
             if (mountPoint != null) {
 
-                result = this.broker.commitMountPointDataPut(mountPoint, normalizedII, payload.getData());
+                result = this.broker.commitMountPointDataPut(mountPoint, normalizedII, payload.getData(), insert,
+                        point);
             } else {
                 result = this.broker.commitConfigurationDataPut(this.controllerContext.getGlobalSchema(), normalizedII,
-                        payload.getData());
+                        payload.getData(), insert, point);
             }
             final CountDownLatch waiter = new CountDownLatch(1);
             Futures.addCallback(result.getFutureOfPutData(), new FutureCallback<Void>() {
@@ -905,25 +945,53 @@ public class RestconfImpl implements RestconfService {
         if (payload == null) {
             throw new RestconfDocumentedException("Input is required.", ErrorType.PROTOCOL, ErrorTag.MALFORMED_MESSAGE);
         }
-
-        // FIXME: move this to parsing stage (we can have augmentation nodes here which do not have namespace)
-//        final URI payloadNS = payload.getData().getNodeType().getNamespace();
-//        if (payloadNS == null) {
-//            throw new RestconfDocumentedException(
-//                    "Data has bad format. Root element node must have namespace (XML format) or module name(JSON format)",
-//                    ErrorType.PROTOCOL, ErrorTag.UNKNOWN_NAMESPACE);
-//        }
-
         final DOMMountPoint mountPoint = payload.getInstanceIdentifierContext().getMountPoint();
         final InstanceIdentifierContext<?> iiWithData = payload.getInstanceIdentifierContext();
         final YangInstanceIdentifier normalizedII = iiWithData.getInstanceIdentifier();
 
+        boolean insert_used = false;
+        boolean point_used = false;
+        String insert = null;
+        String point = null;
+
+        for (final Entry<String, List<String>> entry : uriInfo.getQueryParameters().entrySet()) {
+            switch (entry.getKey()) {
+                case "insert":
+                    if (!insert_used) {
+                        insert_used = true;
+                        insert = entry.getValue().iterator().next();
+                    } else {
+                        throw new RestconfDocumentedException("Insert parameter can be used only once.");
+                    }
+                    break;
+                case "point":
+                    if (!point_used) {
+                        point_used = true;
+                        point = entry.getValue().iterator().next();
+                    } else {
+                        throw new RestconfDocumentedException("Point parameter can be used only once.");
+                    }
+                    break;
+                default:
+                    throw new RestconfDocumentedException("Bad parameter for post: " + entry.getKey());
+            }
+        }
+
+        if (point_used && !insert_used) {
+            throw new RestconfDocumentedException("Point parameter can't be used without Insert parameter.");
+        }
+        if (point_used && (insert.equals("first") || insert.equals("last"))) {
+            throw new RestconfDocumentedException(
+                    "Point parameter can be used only with 'after' or 'before' values of Insert parameter.");
+        }
+
         CheckedFuture<Void, TransactionCommitFailedException> future;
         if (mountPoint != null) {
-            future = this.broker.commitConfigurationDataPost(mountPoint, normalizedII, payload.getData());
+            future = this.broker.commitConfigurationDataPost(mountPoint, normalizedII, payload.getData(), insert,
+                    point);
         } else {
             future = this.broker.commitConfigurationDataPost(this.controllerContext.getGlobalSchema(), normalizedII,
-                    payload.getData());
+                    payload.getData(), insert, point);
         }
 
         final CountDownLatch waiter = new CountDownLatch(1);
@@ -1051,8 +1119,10 @@ public class RestconfImpl implements RestconfService {
     public NormalizedNodeContext subscribeToStream(final String identifier, final UriInfo uriInfo) {
         boolean startTime_used = false;
         boolean stopTime_used = false;
+        boolean filter_used = false;
         Date start = null;
         Date stop = null;
+        String filter = null;
 
         for (final Entry<String, List<String>> entry : uriInfo.getQueryParameters().entrySet()) {
             switch (entry.getKey()) {
@@ -1072,6 +1142,14 @@ public class RestconfImpl implements RestconfService {
                         throw new RestconfDocumentedException("Stop-time parameter can be used only once.");
                     }
                     break;
+                case "filter":
+                    if (!filter_used) {
+                        filter_used = true;
+                        filter = entry.getValue().iterator().next();
+                    } else {
+                        throw new RestconfDocumentedException("Filter parameter can be used only once.");
+                    }
+                    break;
                 default:
                     throw new RestconfDocumentedException("Bad parameter used with notifications: " + entry.getKey());
             }
@@ -1081,9 +1159,9 @@ public class RestconfImpl implements RestconfService {
         }
         URI response = null;
         if (identifier.contains(DATA_SUBSCR)) {
-            response = dataSubs(identifier, uriInfo, start, stop);
+            response = dataSubs(identifier, uriInfo, start, stop, filter);
         } else if (identifier.contains(NOTIFICATION_STREAM)) {
-            response = notifStream(identifier, uriInfo, start, stop);
+            response = notifStream(identifier, uriInfo, start, stop, filter);
         }
 
         if(response != null){
@@ -1161,9 +1239,12 @@ public class RestconfImpl implements RestconfService {
      *            - stop-time of getting notification
      * @param start
      *            - start-time of getting notification
-     * @return {@link Response}
+     * @param filter
+     *            - indicate wh ich subset of allpossible events are of interest
+     * @return {@link URI} of location
      */
-    private URI notifStream(final String identifier, final UriInfo uriInfo, final Date start, final Date stop) {
+    private URI notifStream(final String identifier, final UriInfo uriInfo, final Date start, final Date stop,
+            final String filter) {
         final String streamName = Notificator.createStreamNameFromUri(identifier);
         if (Strings.isNullOrEmpty(streamName)) {
             throw new RestconfDocumentedException("Stream name is empty.", ErrorType.PROTOCOL, ErrorTag.INVALID_VALUE);
@@ -1176,7 +1257,7 @@ public class RestconfImpl implements RestconfService {
 
         for (final NotificationListenerAdapter listener : listeners) {
             this.broker.registerToListenNotification(listener);
-            listener.setTime(start, stop);
+            listener.setQueryParams(start, stop, filter);
         }
 
         final UriBuilder uriBuilder = uriInfo.getAbsolutePathBuilder();
@@ -1204,9 +1285,12 @@ public class RestconfImpl implements RestconfService {
      *            - start-time of getting notification
      * @param start
      *            - stop-time of getting notification
-     * @return {@link Response}
+     * @param filter
+     *            - indicate which subset of all possible events are of interest
+     * @return {@link URI} of location
      */
-    private URI dataSubs(final String identifier, final UriInfo uriInfo, final Date start, final Date stop) {
+    private URI dataSubs(final String identifier, final UriInfo uriInfo, final Date start, final Date stop,
+            final String filter) {
         final String streamName = Notificator.createStreamNameFromUri(identifier);
         if (Strings.isNullOrEmpty(streamName)) {
             throw new RestconfDocumentedException("Stream name is empty.", ErrorType.PROTOCOL, ErrorTag.INVALID_VALUE);
@@ -1216,7 +1300,7 @@ public class RestconfImpl implements RestconfService {
         if (listener == null) {
             throw new RestconfDocumentedException("Stream was not found.", ErrorType.PROTOCOL, ErrorTag.UNKNOWN_ELEMENT);
         }
-        listener.setTimer(start, stop);
+        listener.setQueryParams(start, stop, filter);
 
         final Map<String, String> paramToValues = resolveValuesFromUri(identifier);
         final LogicalDatastoreType datastore = parserURIEnumParameter(LogicalDatastoreType.class,