BUG 1330 - list key counts|values diff in payload and URI
[controller.git] / opendaylight / md-sal / sal-rest-connector / src / main / java / org / opendaylight / controller / sal / restconf / impl / RestconfImpl.java
index c8440c0a1692066660b0a6b2025abee6476c28a6..ae48ca7196904a135429bd9aae88626f947924d1 100644 (file)
@@ -52,6 +52,8 @@ import org.opendaylight.yangtools.yang.common.RpcResult;
 import org.opendaylight.yangtools.yang.data.api.CompositeNode;
 import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier;
 import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.InstanceIdentifierBuilder;
+import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.NodeIdentifierWithPredicates;
+import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.PathArgument;
 import org.opendaylight.yangtools.yang.data.api.MutableCompositeNode;
 import org.opendaylight.yangtools.yang.data.api.Node;
 import org.opendaylight.yangtools.yang.data.api.SimpleNode;
@@ -674,6 +676,7 @@ public class RestconfImpl implements RestconfService {
 
         MountInstance mountPoint = iiWithData.getMountPoint();
         final CompositeNode value = this.normalizeNode(payload, iiWithData.getSchemaNode(), mountPoint);
+        validateListKeysEqualityInPayloadAndUri(iiWithData, payload);
         RpcResult<TransactionStatus> status = null;
 
         try {
@@ -695,6 +698,52 @@ public class RestconfImpl implements RestconfService {
         return Response.status(Status.INTERNAL_SERVER_ERROR).build();
     }
 
+    /**
+     * Validates whether keys in {@code payload} are equal to values of keys in
+     * {@code iiWithData} for list schema node
+     *
+     * @throws RestconfDocumentedException
+     *             if key values or key count in payload and URI isn't equal
+     *
+     */
+    private void validateListKeysEqualityInPayloadAndUri(final InstanceIdWithSchemaNode iiWithData,
+            final CompositeNode payload) {
+        if (iiWithData.getSchemaNode() instanceof ListSchemaNode) {
+            final List<QName> keyDefinitions = ((ListSchemaNode) iiWithData.getSchemaNode()).getKeyDefinition();
+            final PathArgument lastPathArgument = iiWithData.getInstanceIdentifier().getLastPathArgument();
+            if (lastPathArgument instanceof NodeIdentifierWithPredicates) {
+                final Map<QName, Object> uriKeyValues = ((NodeIdentifierWithPredicates) lastPathArgument)
+                        .getKeyValues();
+                isEqualUriAndPayloadKeyValues(uriKeyValues, payload, keyDefinitions);
+            }
+        }
+    }
+
+    private void isEqualUriAndPayloadKeyValues(final Map<QName, Object> uriKeyValues, final CompositeNode payload,
+            final List<QName> keyDefinitions) {
+        for (QName keyDefinition : keyDefinitions) {
+            final Object uriKeyValue = uriKeyValues.get(keyDefinition);
+            // should be caught during parsing URI to InstanceIdentifier
+            if (uriKeyValue == null) {
+                throw new RestconfDocumentedException("Missing key " + keyDefinition + " in URI.",
+                        ErrorType.PROTOCOL, ErrorTag.DATA_MISSING);
+            }
+            final List<SimpleNode<?>> payloadKeyValues = payload.getSimpleNodesByName(keyDefinition.getLocalName());
+            if (payloadKeyValues.isEmpty()) {
+                throw new RestconfDocumentedException("Missing key " + keyDefinition.getLocalName()
+                        + " in the message body.", ErrorType.PROTOCOL,
+                        ErrorTag.DATA_MISSING);
+            }
+
+            Object payloadKeyValue = payloadKeyValues.iterator().next().getValue();
+            if (!uriKeyValue.equals(payloadKeyValue)) {
+                throw new RestconfDocumentedException("The value '"+uriKeyValue+ "' for key '" + keyDefinition.getLocalName() +
+                        "' specified in the URI doesn't match the value '" + payloadKeyValue + "' specified in the message body. ",
+                        ErrorType.PROTOCOL, ErrorTag.INVALID_VALUE);
+            }
+        }
+    }
+
     @Override
     public Response createConfigurationData(final String identifier, final CompositeNode payload) {
         if( payload == null ) {
@@ -1190,9 +1239,9 @@ public class RestconfImpl implements RestconfService {
 
                 if (!foundKey) {
                     throw new RestconfDocumentedException(
-                            "Missing key in URI \"" + listKey.getLocalName() +
-                            "\" of list \"" + listSchemaNode.getQName().getLocalName() + "\"",
-                            ErrorType.PROTOCOL, ErrorTag.INVALID_VALUE );
+                            "Missing key '" + listKey.getLocalName() +
+                            "' for list '" + listSchemaNode.getQName().getLocalName() + "' in the message body",
+                            ErrorType.PROTOCOL, ErrorTag.DATA_MISSING );
                 }
             }
         }