Bug 6848 - Renaming to draft17
[netconf.git] / restconf / sal-rest-connector / src / main / java / org / opendaylight / netconf / sal / rest / impl / JsonToPATCHBodyReader.java
index dd5ced4a37cb6f8f09e29baeee5e7e3b27fd9b73..75240378cb99c6e174ac99523a6d670310c23ba1 100644 (file)
@@ -8,6 +8,8 @@
 
 package org.opendaylight.netconf.sal.rest.impl;
 
+import static org.opendaylight.netconf.sal.restconf.impl.PATCHEditOperation.isPatchOperationWithValue;
+
 import com.google.common.collect.ImmutableList;
 import com.google.gson.stream.JsonReader;
 import com.google.gson.stream.JsonToken;
@@ -31,12 +33,12 @@ import org.opendaylight.netconf.sal.rest.api.RestconfService;
 import org.opendaylight.netconf.sal.restconf.impl.ControllerContext;
 import org.opendaylight.netconf.sal.restconf.impl.InstanceIdentifierContext;
 import org.opendaylight.netconf.sal.restconf.impl.PATCHContext;
-import org.opendaylight.netconf.sal.restconf.impl.PATCHEditOperation;
 import org.opendaylight.netconf.sal.restconf.impl.PATCHEntity;
 import org.opendaylight.netconf.sal.restconf.impl.RestconfDocumentedException;
 import org.opendaylight.netconf.sal.restconf.impl.RestconfError.ErrorTag;
 import org.opendaylight.netconf.sal.restconf.impl.RestconfError.ErrorType;
 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifierWithPredicates;
 import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
 import org.opendaylight.yangtools.yang.data.api.schema.stream.NormalizedNodeStreamWriter;
 import org.opendaylight.yangtools.yang.data.codec.gson.JsonParserStream;
@@ -48,20 +50,30 @@ import org.opendaylight.yangtools.yang.model.util.SchemaContextUtil;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
+/**
+ * @deprecated This class will be replaced by
+ *             {@link org.opendaylight.restconf.utils.patch.JsonToPATCHBodyReader}
+ */
+@Deprecated
 @Provider
 @Consumes({Draft02.MediaTypes.PATCH + RestconfService.JSON})
-public class JsonToPATCHBodyReader extends AbstractIdentifierAwareJaxRsProvider implements MessageBodyReader<PATCHContext> {
+public class JsonToPATCHBodyReader extends AbstractIdentifierAwareJaxRsProvider
+        implements MessageBodyReader<PATCHContext> {
 
     private final static Logger LOG = LoggerFactory.getLogger(JsonToPATCHBodyReader.class);
     private String patchId;
 
     @Override
-    public boolean isReadable(Class<?> type, Type genericType, Annotation[] annotations, MediaType mediaType) {
+    public boolean isReadable(final Class<?> type, final Type genericType,
+                              final Annotation[] annotations, final MediaType mediaType) {
         return true;
     }
 
     @Override
-    public PATCHContext readFrom(Class<PATCHContext> type, Type genericType, Annotation[] annotations, MediaType mediaType, MultivaluedMap<String, String> httpHeaders, InputStream entityStream) throws IOException, WebApplicationException {
+    public PATCHContext readFrom(final Class<PATCHContext> type, final Type genericType,
+                                 final Annotation[] annotations, final MediaType mediaType,
+                                 final MultivaluedMap<String, String> httpHeaders, final InputStream entityStream)
+            throws IOException, WebApplicationException {
         try {
             return readFrom(getInstanceIdentifierContext(), entityStream);
         } catch (final Exception e) {
@@ -69,14 +81,13 @@ public class JsonToPATCHBodyReader extends AbstractIdentifierAwareJaxRsProvider
         }
     }
 
-    private static RuntimeException propagateExceptionAs(Exception e) throws RestconfDocumentedException {
-        if(e instanceof RestconfDocumentedException) {
+    private static RuntimeException propagateExceptionAs(final Exception e) throws RestconfDocumentedException {
+        if (e instanceof RestconfDocumentedException) {
             throw (RestconfDocumentedException)e;
         }
 
-        if(e instanceof ResultAlreadySetException) {
+        if (e instanceof ResultAlreadySetException) {
             LOG.debug("Error parsing json input:", e);
-
             throw new RestconfDocumentedException("Error parsing json input: Failed to create new parse result data. ");
         }
 
@@ -94,7 +105,8 @@ public class JsonToPATCHBodyReader extends AbstractIdentifierAwareJaxRsProvider
         }
     }
 
-    private PATCHContext readFrom(final InstanceIdentifierContext<?> path, final InputStream entityStream) throws IOException {
+    private PATCHContext readFrom(final InstanceIdentifierContext<?> path, final InputStream entityStream)
+            throws IOException {
         if (entityStream.available() < 1) {
             return new PATCHContext(path, null, null);
         }
@@ -103,13 +115,14 @@ public class JsonToPATCHBodyReader extends AbstractIdentifierAwareJaxRsProvider
         final List<PATCHEntity> resultList = read(jsonReader, path);
         jsonReader.close();
 
-        return new PATCHContext(path, resultList, patchId);
+        return new PATCHContext(path, resultList, this.patchId);
     }
 
-    private List<PATCHEntity> read(final JsonReader in, InstanceIdentifierContext path) throws IOException {
-        List<PATCHEntity> resultCollection = new ArrayList<>();
-        StringModuleInstanceIdentifierCodec codec = new StringModuleInstanceIdentifierCodec(path.getSchemaContext());
-        JsonToPATCHBodyReader.PatchEdit edit = new JsonToPATCHBodyReader.PatchEdit();
+    private List<PATCHEntity> read(final JsonReader in, final InstanceIdentifierContext path) throws IOException {
+        final List<PATCHEntity> resultCollection = new ArrayList<>();
+        final StringModuleInstanceIdentifierCodec codec = new StringModuleInstanceIdentifierCodec(
+                path.getSchemaContext());
+        final JsonToPATCHBodyReader.PatchEdit edit = new JsonToPATCHBodyReader.PatchEdit();
 
         while (in.hasNext()) {
             switch (in.peek()) {
@@ -201,7 +214,7 @@ public class JsonToPATCHBodyReader extends AbstractIdentifierAwareJaxRsProvider
     private void readEditDefinition(@Nonnull final PatchEdit edit, @Nonnull final JsonReader in,
                                     @Nonnull final InstanceIdentifierContext path,
                                     @Nonnull final StringModuleInstanceIdentifierCodec codec) throws IOException {
-        StringBuffer value = new StringBuffer();
+        final StringBuffer value = new StringBuffer();
         in.beginObject();
 
         while (in.hasNext()) {
@@ -214,10 +227,18 @@ public class JsonToPATCHBodyReader extends AbstractIdentifierAwareJaxRsProvider
                     edit.setOperation(in.nextString());
                     break;
                 case "target" :
-                    edit.setTarget(codec.deserialize(codec.serialize(path.getInstanceIdentifier()) + in.nextString()));
-                    edit.setTargetSchemaNode(SchemaContextUtil.findDataSchemaNode(path.getSchemaContext(),
-                            codec.getDataContextTree().getChild(edit.getTarget()).getDataSchemaNode().getPath()
-                                    .getParent()));
+                    // target can be specified completely in request URI
+                    final String target = in.nextString();
+                    if (target.equals("/")) {
+                        edit.setTarget(path.getInstanceIdentifier());
+                        edit.setTargetSchemaNode(path.getSchemaContext());
+                    } else {
+                        edit.setTarget(codec.deserialize(codec.serialize(path.getInstanceIdentifier()).concat(target)));
+                        edit.setTargetSchemaNode(SchemaContextUtil.findDataSchemaNode(path.getSchemaContext(),
+                                codec.getDataContextTree().getChild(edit.getTarget()).getDataSchemaNode().getPath()
+                                        .getParent()));
+                    }
+
                     break;
                 case "value" :
                     // save data defined in value node for next (later) processing, because target needs to be read
@@ -281,7 +302,28 @@ public class JsonToPATCHBodyReader extends AbstractIdentifierAwareJaxRsProvider
         while (in.hasNext()) {
             value.append("\"" + in.nextName() + "\"");
             value.append(":");
-            value.append("\"" + in.nextString() + "\"");
+
+            if (in.peek() == JsonToken.STRING) {
+                value.append("\"" + in.nextString() + "\"");
+            } else {
+                if (in.peek() == JsonToken.BEGIN_ARRAY) {
+                    in.beginArray();
+                    value.append("[");
+
+                    while (in.hasNext()) {
+                        readValueObject(value, in);
+                        if (in.peek() != JsonToken.END_ARRAY) {
+                            value.append(",");
+                        }
+                    }
+
+                    in.endArray();
+                    value.append("]");
+                } else {
+                    readValueObject(value, in);
+                }
+            }
+
             if (in.peek() != JsonToken.END_OBJECT) {
                 value.append(",");
             }
@@ -296,8 +338,8 @@ public class JsonToPATCHBodyReader extends AbstractIdentifierAwareJaxRsProvider
      * @param in reader JsonReader reader
      * @return NormalizedNode representing data
      */
-    private NormalizedNode readEditData(@Nonnull final JsonReader in, @Nonnull SchemaNode targetSchemaNode,
-                                        @Nonnull InstanceIdentifierContext path) {
+    private NormalizedNode readEditData(@Nonnull final JsonReader in, @Nonnull final SchemaNode targetSchemaNode,
+                                        @Nonnull final InstanceIdentifierContext path) {
         final NormalizedNodeResult resultHolder = new NormalizedNodeResult();
         final NormalizedNodeStreamWriter writer = ImmutableNormalizedNodeStreamWriter.from(resultHolder);
         JsonParserStream.create(writer, path.getSchemaContext(), targetSchemaNode).parse(in);
@@ -311,10 +353,18 @@ public class JsonToPATCHBodyReader extends AbstractIdentifierAwareJaxRsProvider
      * @return PATCHEntity
      */
     private PATCHEntity prepareEditOperation(@Nonnull final PatchEdit edit) {
-        if (edit.getOperation() != null && edit.getTargetSchemaNode() != null
+        if ((edit.getOperation() != null) && (edit.getTargetSchemaNode() != null)
                 && checkDataPresence(edit.getOperation(), (edit.getData() != null))) {
             if (isPatchOperationWithValue(edit.getOperation())) {
-                return new PATCHEntity(edit.getId(), edit.getOperation(), edit.getTarget().getParent(), edit.getData());
+                // for lists allow to manipulate with list items through their parent
+                final YangInstanceIdentifier targetNode;
+                if (edit.getTarget().getLastPathArgument() instanceof NodeIdentifierWithPredicates) {
+                    targetNode = edit.getTarget().getParent();
+                } else {
+                    targetNode = edit.getTarget();
+                }
+
+                return new PATCHEntity(edit.getId(), edit.getOperation(), targetNode, edit.getData());
             } else {
                 return new PATCHEntity(edit.getId(), edit.getOperation(), edit.getTarget());
             }
@@ -346,23 +396,6 @@ public class JsonToPATCHBodyReader extends AbstractIdentifierAwareJaxRsProvider
         }
     }
 
-    /**
-     * Check if operation requires data to be specified
-     * @param operation Name of the operation to be checked
-     * @return true if operation requires data, false otherwise
-     */
-    private boolean isPatchOperationWithValue(@Nonnull final String operation) {
-        switch (PATCHEditOperation.valueOf(operation.toUpperCase())) {
-            case CREATE:
-            case MERGE:
-            case REPLACE:
-            case INSERT:
-                return true;
-            default:
-                return false;
-        }
-    }
-
     /**
      * Helper class representing one patch edit
      */
@@ -374,51 +407,51 @@ public class JsonToPATCHBodyReader extends AbstractIdentifierAwareJaxRsProvider
         private NormalizedNode data;
 
         public String getId() {
-            return id;
+            return this.id;
         }
 
-        public void setId(String id) {
+        public void setId(final String id) {
             this.id = id;
         }
 
         public String getOperation() {
-            return operation;
+            return this.operation;
         }
 
-        public void setOperation(String operation) {
+        public void setOperation(final String operation) {
             this.operation = operation;
         }
 
         public YangInstanceIdentifier getTarget() {
-            return target;
+            return this.target;
         }
 
-        public void setTarget(YangInstanceIdentifier target) {
+        public void setTarget(final YangInstanceIdentifier target) {
             this.target = target;
         }
 
         public SchemaNode getTargetSchemaNode() {
-            return targetSchemaNode;
+            return this.targetSchemaNode;
         }
 
-        public void setTargetSchemaNode(SchemaNode targetSchemaNode) {
+        public void setTargetSchemaNode(final SchemaNode targetSchemaNode) {
             this.targetSchemaNode = targetSchemaNode;
         }
 
         public NormalizedNode getData() {
-            return data;
+            return this.data;
         }
 
-        public void setData(NormalizedNode data) {
+        public void setData(final NormalizedNode data) {
             this.data = data;
         }
 
         public void clear() {
-            id = null;
-            operation = null;
-            target = null;
-            targetSchemaNode = null;
-            data = null;
+            this.id = null;
+            this.operation = null;
+            this.target = null;
+            this.targetSchemaNode = null;
+            this.data = null;
         }
     }
 }