Merge "Bug 1817 - Add in ietf-restonf to the yangtools-models feature."
[yangtools.git] / yang / yang-data-codec-gson / src / main / java / org / opendaylight / yangtools / yang / data / codec / gson / JsonParserStream.java
index 18232ff77ec4d0e971cf21df382322d0e6c922e2..cea3fa683c02cee5c120370d5c680a325d1b5479 100644 (file)
@@ -10,13 +10,10 @@ package org.opendaylight.yangtools.yang.data.codec.gson;
 import com.google.common.annotations.Beta;
 import com.google.common.base.Optional;
 import com.google.common.base.Preconditions;
-import com.google.common.base.Splitter;
-import com.google.common.collect.Iterators;
 import com.google.gson.JsonIOException;
 import com.google.gson.JsonParseException;
 import com.google.gson.JsonSyntaxException;
 import com.google.gson.stream.JsonReader;
-import com.google.gson.stream.JsonToken;
 import com.google.gson.stream.MalformedJsonException;
 
 import java.io.Closeable;
@@ -24,24 +21,16 @@ import java.io.EOFException;
 import java.io.Flushable;
 import java.io.IOException;
 import java.net.URI;
-import java.security.InvalidParameterException;
 import java.util.ArrayDeque;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Deque;
 import java.util.HashSet;
-import java.util.Iterator;
 import java.util.List;
 import java.util.Set;
 
-import org.opendaylight.yangtools.concepts.Codec;
 import org.opendaylight.yangtools.yang.common.QName;
 import org.opendaylight.yangtools.yang.data.api.schema.stream.NormalizedNodeStreamWriter;
-import org.opendaylight.yangtools.yang.data.codec.gson.helpers.IdentityValuesDTO;
-import org.opendaylight.yangtools.yang.data.codec.gson.helpers.RestCodecFactory;
-import org.opendaylight.yangtools.yang.data.codec.gson.helpers.RestUtil;
-import org.opendaylight.yangtools.yang.data.codec.gson.helpers.RestUtil.PrefixMapingFromJson;
-import org.opendaylight.yangtools.yang.data.codec.gson.helpers.SchemaContextUtils;
 import org.opendaylight.yangtools.yang.model.api.AnyXmlSchemaNode;
 import org.opendaylight.yangtools.yang.model.api.ChoiceCaseNode;
 import org.opendaylight.yangtools.yang.model.api.ChoiceNode;
@@ -49,10 +38,9 @@ import org.opendaylight.yangtools.yang.model.api.DataNodeContainer;
 import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
 import org.opendaylight.yangtools.yang.model.api.LeafListSchemaNode;
 import org.opendaylight.yangtools.yang.model.api.LeafSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.Module;
 import org.opendaylight.yangtools.yang.model.api.SchemaContext;
 import org.opendaylight.yangtools.yang.model.api.TypeDefinition;
-import org.opendaylight.yangtools.yang.model.api.type.IdentityrefTypeDefinition;
-import org.opendaylight.yangtools.yang.model.api.type.InstanceIdentifierTypeDefinition;
 
 /**
  * This class parses JSON elements from a GSON JsonReader. It disallows multiple elements of the same name unlike the
@@ -60,19 +48,15 @@ import org.opendaylight.yangtools.yang.model.api.type.InstanceIdentifierTypeDefi
  */
 @Beta
 public final class JsonParserStream implements Closeable, Flushable {
-    private static final Splitter COLON_SPLITTER = Splitter.on(':');
-
     private final Deque<URI> namespaces = new ArrayDeque<>();
     private final NormalizedNodeStreamWriter writer;
-    private final SchemaContextUtils utils;
-    private final RestCodecFactory codecs;
+    private final JSONCodecFactory codecs;
     private final SchemaContext schema;
 
     private JsonParserStream(final NormalizedNodeStreamWriter writer, final SchemaContext schemaContext) {
         this.schema = Preconditions.checkNotNull(schemaContext);
-        this.utils = SchemaContextUtils.create(schemaContext);
         this.writer = Preconditions.checkNotNull(writer);
-        this.codecs = RestCodecFactory.create(utils);
+        this.codecs = JSONCodecFactory.create(schemaContext);
     }
 
     public static JsonParserStream create(final NormalizedNodeStreamWriter writer, final SchemaContext schemaContext) {
@@ -90,7 +74,7 @@ public final class JsonParserStream implements Closeable, Flushable {
             isEmpty = false;
             CompositeNodeDataWithSchema compositeNodeDataWithSchema = new CompositeNodeDataWithSchema(schema);
             read(reader, compositeNodeDataWithSchema);
-            compositeNodeDataWithSchema.writeToStream(writer);
+            compositeNodeDataWithSchema.write(writer);
 
             return this;
             // return read(reader);
@@ -114,31 +98,26 @@ public final class JsonParserStream implements Closeable, Flushable {
         }
     }
 
-    public void read(final JsonReader in, final AbstractNodeDataWithSchema parent) throws IOException {
+    private final void setValue(final AbstractNodeDataWithSchema parent, final String value) {
+        Preconditions.checkArgument(parent instanceof SimpleNodeDataWithSchema, "Node %s is not a simple type", parent);
+
+        final Object translatedValue = translateValueByType(value, parent.getSchema());
+        ((SimpleNodeDataWithSchema) parent).setValue(translatedValue);
+    }
 
-        final JsonToken peek = in.peek();
-        Optional<String> value = Optional.absent();
-        switch (peek) {
+    public void read(final JsonReader in, final AbstractNodeDataWithSchema parent) throws IOException {
+        switch (in.peek()) {
         case STRING:
         case NUMBER:
-            value = Optional.of(in.nextString());
+            setValue(parent, in.nextString());
             break;
         case BOOLEAN:
-            value = Optional.of(Boolean.toString(in.nextBoolean()));
+            setValue(parent, Boolean.toString(in.nextBoolean()));
             break;
         case NULL:
             in.nextNull();
-            value = Optional.of((String) null);
-            break;
-        default:
+            setValue(parent, null);
             break;
-        }
-        if (value.isPresent()) {
-            final Object translatedValue = translateValueByType(value.get(), parent.getSchema());
-            ((SimpleNodeDataWithSchema) parent).setValue(translatedValue);
-        }
-
-        switch (peek) {
         case BEGIN_ARRAY:
             in.beginArray();
             while (in.hasNext()) {
@@ -189,6 +168,7 @@ public final class JsonParserStream implements Closeable, Flushable {
         case NAME:
         case END_OBJECT:
         case END_ARRAY:
+            break;
         }
     }
 
@@ -198,21 +178,7 @@ public final class JsonParserStream implements Closeable, Flushable {
             return value;
         }
 
-        final Object inputValue;
-        if (typeDefinition instanceof IdentityrefTypeDefinition) {
-            inputValue = valueAsIdentityRef(value);
-        } else if (typeDefinition instanceof InstanceIdentifierTypeDefinition) {
-            inputValue = valueAsInstanceIdentifier(value);
-        } else {
-            inputValue = value;
-        }
-
-        // FIXME: extract this as a cacheable context?
-        final Codec<Object, Object> codec = codecs.codecFor(typeDefinition);
-        if (codec == null) {
-            return null;
-        }
-        return codec.deserialize(inputValue);
+        return codecs.codecFor(typeDefinition).deserialize(value);
     }
 
     private static TypeDefinition<? extends Object> typeDefinition(final DataSchemaNode node) {
@@ -235,48 +201,6 @@ public final class JsonParserStream implements Closeable, Flushable {
         return baseType;
     }
 
-    private static Object valueAsInstanceIdentifier(final String value) {
-        // it could be instance-identifier Built-In Type
-        if (!value.isEmpty() && value.charAt(0) == '/') {
-            IdentityValuesDTO resolvedValue = RestUtil.asInstanceIdentifier(value, new PrefixMapingFromJson());
-            if (resolvedValue != null) {
-                return resolvedValue;
-            }
-        }
-        throw new InvalidParameterException("Value for instance-identifier doesn't have correct format");
-    }
-
-    private static IdentityValuesDTO valueAsIdentityRef(final String value) {
-        // it could be identityref Built-In Type
-        URI namespace = getNamespaceFor(value);
-        if (namespace != null) {
-            return new IdentityValuesDTO(namespace.toString(), getLocalNameFor(value), null, value);
-        }
-        throw new InvalidParameterException("Value for identityref has to be in format moduleName:localName.");
-    }
-
-    private static URI getNamespaceFor(final String jsonElementName) {
-        final Iterator<String> it = COLON_SPLITTER.split(jsonElementName).iterator();
-
-        // The string needs to me in form "moduleName:localName"
-        if (it.hasNext()) {
-            final String maybeURI = it.next();
-            if (Iterators.size(it) == 1) {
-                return URI.create(maybeURI);
-            }
-        }
-
-        return null;
-    }
-
-    private static String getLocalNameFor(final String jsonElementName) {
-        final Iterator<String> it = COLON_SPLITTER.split(jsonElementName).iterator();
-
-        // The string needs to me in form "moduleName:localName"
-        final String ret = Iterators.get(it, 1, null);
-        return ret != null && !it.hasNext() ? ret : jsonElementName;
-    }
-
     private void removeNamespace() {
         namespaces.pop();
     }
@@ -294,14 +218,16 @@ public final class JsonParserStream implements Closeable, Flushable {
     }
 
     private NamespaceAndName resolveNamespace(final String childName) {
-        int lastIndexOfColon = childName.lastIndexOf(":");
+        int lastIndexOfColon = childName.lastIndexOf(':');
         String moduleNamePart = null;
         String nodeNamePart = null;
         URI namespace = null;
         if (lastIndexOfColon != -1) {
             moduleNamePart = childName.substring(0, lastIndexOfColon);
             nodeNamePart = childName.substring(lastIndexOfColon + 1);
-            namespace = utils.findNamespaceByModuleName(moduleNamePart);
+
+            final Module m = schema.findModuleByName(moduleNamePart, null);
+            namespace = m == null ? null : m.getNamespace();
         } else {
             nodeNamePart = childName;
         }
@@ -315,14 +241,14 @@ public final class JsonParserStream implements Closeable, Flushable {
     }
 
     /**
-     * Returns stack of schema nodes via which it was necessary to prass to get schema node with specified
+     * Returns stack of schema nodes via which it was necessary to pass to get schema node with specified
      * {@code childName} and {@code namespace}
      *
      * @param dataSchemaNode
      * @param childName
      * @param namespace
-     * @return stack of schema nodes via which it was passed through. If found schema node is dirrect child then stack
-     *         contains only one node. If it is found under choice and case then stack should conains 2*n+1 element
+     * @return stack of schema nodes via which it was passed through. If found schema node is direct child then stack
+     *         contains only one node. If it is found under choice and case then stack should contains 2*n+1 element
      *         (where n is number of choices through it was passed)
      */
     private Deque<DataSchemaNode> findSchemaNodeByNameAndNamespace(final DataSchemaNode dataSchemaNode,