Merge "BUG-997: Fix URLSchemaContextResolver"
authorTony Tkacik <ttkacik@cisco.com>
Mon, 25 Aug 2014 10:17:37 +0000 (10:17 +0000)
committerGerrit Code Review <gerrit@opendaylight.org>
Mon, 25 Aug 2014 10:17:37 +0000 (10:17 +0000)
46 files changed:
code-generator/binding-data-codec/src/main/java/org/opendaylight/yangtools/binding/data/codec/impl/BindingNormalizedNodeCodecRegistry.java
code-generator/binding-data-codec/src/main/java/org/opendaylight/yangtools/binding/data/codec/impl/BindingToNormalizedStreamWriter.java
code-generator/binding-data-codec/src/main/java/org/opendaylight/yangtools/binding/data/codec/util/AugmentableDispatchSerializer.java
code-generator/binding-data-codec/src/main/java/org/opendaylight/yangtools/binding/data/codec/util/ChoiceDispatchSerializer.java
yang/pom.xml
yang/yang-binding/src/main/java/org/opendaylight/yangtools/yang/binding/BindingStreamEventWriter.java
yang/yang-binding/src/main/java/org/opendaylight/yangtools/yang/binding/DataObjectSerializer.java
yang/yang-binding/src/main/java/org/opendaylight/yangtools/yang/binding/DataObjectSerializerImplementation.java
yang/yang-data-api/src/main/java/org/opendaylight/yangtools/yang/data/api/schema/stream/LoggingNormalizedNodeStreamWriter.java [new file with mode: 0644]
yang/yang-data-api/src/main/java/org/opendaylight/yangtools/yang/data/api/schema/stream/NormalizedNodeStreamWriter.java
yang/yang-data-api/src/main/java/org/opendaylight/yangtools/yang/data/api/schema/stream/NormalizedNodeWriter.java [new file with mode: 0644]
yang/yang-data-codec-gson/pom.xml [new file with mode: 0644]
yang/yang-data-codec-gson/src/main/java/org/opendaylight/yangtools/yang/data/codec/gson/AbstractNodeDataWithSchema.java [new file with mode: 0644]
yang/yang-data-codec-gson/src/main/java/org/opendaylight/yangtools/yang/data/codec/gson/AnyXmlNodeDataWithSchema.java [new file with mode: 0644]
yang/yang-data-codec-gson/src/main/java/org/opendaylight/yangtools/yang/data/codec/gson/CaseNodeDataWithSchema.java [new file with mode: 0644]
yang/yang-data-codec-gson/src/main/java/org/opendaylight/yangtools/yang/data/codec/gson/ChoiceNodeDataWithSchema.java [new file with mode: 0644]
yang/yang-data-codec-gson/src/main/java/org/opendaylight/yangtools/yang/data/codec/gson/CompositeNodeDataWithSchema.java [new file with mode: 0644]
yang/yang-data-codec-gson/src/main/java/org/opendaylight/yangtools/yang/data/codec/gson/ContainerNodeDataWithSchema.java [new file with mode: 0644]
yang/yang-data-codec-gson/src/main/java/org/opendaylight/yangtools/yang/data/codec/gson/JSONNormalizedNodeStreamWriter.java [new file with mode: 0644]
yang/yang-data-codec-gson/src/main/java/org/opendaylight/yangtools/yang/data/codec/gson/JsonParserStream.java [new file with mode: 0644]
yang/yang-data-codec-gson/src/main/java/org/opendaylight/yangtools/yang/data/codec/gson/LeafListEntryNodeDataWithSchema.java [new file with mode: 0644]
yang/yang-data-codec-gson/src/main/java/org/opendaylight/yangtools/yang/data/codec/gson/LeafListNodeDataWithSchema.java [new file with mode: 0644]
yang/yang-data-codec-gson/src/main/java/org/opendaylight/yangtools/yang/data/codec/gson/LeafNodeDataWithSchema.java [new file with mode: 0644]
yang/yang-data-codec-gson/src/main/java/org/opendaylight/yangtools/yang/data/codec/gson/ListEntryNodeDataWithSchema.java [new file with mode: 0644]
yang/yang-data-codec-gson/src/main/java/org/opendaylight/yangtools/yang/data/codec/gson/ListNodeDataWithSchema.java [new file with mode: 0644]
yang/yang-data-codec-gson/src/main/java/org/opendaylight/yangtools/yang/data/codec/gson/SimpleNodeDataWithSchema.java [new file with mode: 0644]
yang/yang-data-codec-gson/src/main/java/org/opendaylight/yangtools/yang/data/codec/gson/helpers/AbstractCodecImpl.java [new file with mode: 0644]
yang/yang-data-codec-gson/src/main/java/org/opendaylight/yangtools/yang/data/codec/gson/helpers/IdentityValuesDTO.java [new file with mode: 0644]
yang/yang-data-codec-gson/src/main/java/org/opendaylight/yangtools/yang/data/codec/gson/helpers/IdentityrefCodecImpl.java [new file with mode: 0644]
yang/yang-data-codec-gson/src/main/java/org/opendaylight/yangtools/yang/data/codec/gson/helpers/InstanceIdentifierCodecImpl.java [new file with mode: 0644]
yang/yang-data-codec-gson/src/main/java/org/opendaylight/yangtools/yang/data/codec/gson/helpers/LeafrefCodecImpl.java [new file with mode: 0644]
yang/yang-data-codec-gson/src/main/java/org/opendaylight/yangtools/yang/data/codec/gson/helpers/ObjectCodec.java [new file with mode: 0644]
yang/yang-data-codec-gson/src/main/java/org/opendaylight/yangtools/yang/data/codec/gson/helpers/RestCodecFactory.java [new file with mode: 0644]
yang/yang-data-codec-gson/src/main/java/org/opendaylight/yangtools/yang/data/codec/gson/helpers/RestUtil.java [new file with mode: 0644]
yang/yang-data-codec-gson/src/main/java/org/opendaylight/yangtools/yang/data/codec/gson/helpers/SchemaContextUtils.java [new file with mode: 0644]
yang/yang-data-codec-gson/src/test/java/org/opendaylight/yangtools/yang/data/codec/gson/StreamToNormalizedNodeTest.java [new file with mode: 0644]
yang/yang-data-codec-gson/src/test/resources/complexjson/complex-json.json [new file with mode: 0644]
yang/yang-data-codec-gson/src/test/resources/complexjson/yang/complexjson-augmentation.yang [new file with mode: 0644]
yang/yang-data-codec-gson/src/test/resources/complexjson/yang/complexjson.yang [new file with mode: 0644]
yang/yang-data-impl/src/main/java/org/opendaylight/yangtools/yang/data/impl/schema/ImmutableNormalizedNodeStreamWriter.java
yang/yang-data-impl/src/main/java/org/opendaylight/yangtools/yang/data/impl/schema/tree/InMemoryDataTree.java
yang/yang-data-impl/src/main/java/org/opendaylight/yangtools/yang/data/impl/schema/tree/InMemoryDataTreeModification.java
yang/yang-model-util/src/main/java/org/opendaylight/yangtools/yang/model/repo/util/AbstractSchemaSourceCache.java
yang/yang-model-util/src/main/java/org/opendaylight/yangtools/yang/model/util/BaseConstraints.java
yang/yang-model-util/src/main/java/org/opendaylight/yangtools/yang/model/util/repo/package-info.java
yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/util/ModuleDependencySort.java

index 3a29713d0e390b6858e495e4501500c64709e7b3..9b772bd9dc0f344503d2e3a53c3d98bffef117a6 100644 (file)
@@ -13,11 +13,14 @@ import com.google.common.base.Preconditions;
 import com.google.common.cache.CacheBuilder;
 import com.google.common.cache.CacheLoader;
 import com.google.common.cache.LoadingCache;
+
+import java.io.IOException;
 import java.util.AbstractMap.SimpleEntry;
 import java.util.LinkedList;
 import java.util.List;
 import java.util.Map;
 import java.util.Map.Entry;
+
 import org.opendaylight.yangtools.binding.data.codec.api.BindingNormalizedNodeSerializer;
 import org.opendaylight.yangtools.binding.data.codec.api.BindingNormalizedNodeWriterFactory;
 import org.opendaylight.yangtools.binding.data.codec.gen.impl.DataObjectSerializerGenerator;
@@ -39,8 +42,11 @@ import org.opendaylight.yangtools.yang.data.api.schema.UnkeyedListNode;
 import org.opendaylight.yangtools.yang.data.api.schema.stream.NormalizedNodeStreamWriter;
 import org.opendaylight.yangtools.yang.data.impl.schema.ImmutableNormalizedNodeStreamWriter;
 import org.opendaylight.yangtools.yang.data.impl.schema.NormalizedNodeResult;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 
 public class BindingNormalizedNodeCodecRegistry implements DataObjectSerializerRegistry, BindingNormalizedNodeWriterFactory, BindingNormalizedNodeSerializer {
+    private static final Logger LOG = LoggerFactory.getLogger(BindingNormalizedNodeCodecRegistry.class);
 
     private final DataObjectSerializerGenerator generator;
     private final LoadingCache<Class<? extends DataObject>, DataObjectSerializer> serializers;
@@ -87,8 +93,13 @@ public class BindingNormalizedNodeCodecRegistry implements DataObjectSerializerR
         // We create Binding Stream Writer wchich translates from Binding to Normalized Nodes
         Entry<YangInstanceIdentifier, BindingStreamEventWriter> writeCtx = codecContext.newWriter(path, domWriter);
 
-        // We get serializer which reads binding data and uses Binding To NOrmalized Node writer to write result
-        getSerializer(path.getTargetType()).serialize(data, writeCtx.getValue());
+        // We get serializer which reads binding data and uses Binding To Normalized Node writer to write result
+        try {
+            getSerializer(path.getTargetType()).serialize(data, writeCtx.getValue());
+        } catch (IOException e) {
+            LOG.error("Unexpected failure while serializing path {} data {}", path, data, e);
+            throw new IllegalStateException("Failed to create normalized node", e);
+        }
         return new SimpleEntry<YangInstanceIdentifier,NormalizedNode<?,?>>(writeCtx.getKey(),result.getResult());
     }
 
@@ -176,7 +187,7 @@ public class BindingNormalizedNodeCodecRegistry implements DataObjectSerializerR
         }
 
         @Override
-        public void serialize(final DataObject obj, final BindingStreamEventWriter stream) {
+        public void serialize(final DataObject obj, final BindingStreamEventWriter stream) throws IOException {
             delegate.serialize(BindingNormalizedNodeCodecRegistry.this, obj, stream);
         }
     }
index 3aa60c94e5dd5fd86faddf0f82e5120436a5783a..9c12bbd42a2a022ee321c97b4c7848c20001e1b5 100644 (file)
@@ -9,6 +9,7 @@ package org.opendaylight.yangtools.binding.data.codec.impl;
 
 import com.google.common.base.Preconditions;
 
+import java.io.IOException;
 import java.util.AbstractMap;
 import java.util.ArrayDeque;
 import java.util.Deque;
@@ -82,7 +83,7 @@ class BindingToNormalizedStreamWriter implements BindingStreamEventWriter, Deleg
     }
 
     @Override
-    public void endNode() {
+    public void endNode() throws IOException {
         NodeCodecContext left = schema.pop();
         // NormalizedNode writer does not have entry into case, but into choice
         // so for leaving case, we do not emit endNode.
@@ -108,26 +109,26 @@ class BindingToNormalizedStreamWriter implements BindingStreamEventWriter, Deleg
     }
 
     @Override
-    public void leafNode(final String localName, final Object value) throws IllegalArgumentException {
+    public void leafNode(final String localName, final Object value) throws IOException, IllegalArgumentException {
         Entry<NodeIdentifier, Object> dom = serializeLeaf(localName, value);
         getDelegate().leafNode(dom.getKey(), dom.getValue());
     };
 
     @Override
-    public void anyxmlNode(final String name, final Object value) throws IllegalArgumentException {
+    public void anyxmlNode(final String name, final Object value) throws IOException, IllegalArgumentException {
         Entry<NodeIdentifier, Object> dom = serializeLeaf(name, value);
         getDelegate().anyxmlNode(dom.getKey(), dom.getValue());
     }
 
     @Override
-    public void leafSetEntryNode(final Object value) throws IllegalArgumentException {
+    public void leafSetEntryNode(final Object value) throws IOException, IllegalArgumentException {
         LeafNodeCodecContext ctx = (LeafNodeCodecContext) current();
         getDelegate().leafSetEntryNode(ctx.getValueCodec().serialize(value));
     }
 
     @Override
     public void startAugmentationNode(final Class<? extends Augmentation<?>> augmentationType)
-            throws IllegalArgumentException {
+            throws IOException, IllegalArgumentException {
         getDelegate().startAugmentationNode(enter(augmentationType, AugmentationIdentifier.class));
     }
 
@@ -139,23 +140,23 @@ class BindingToNormalizedStreamWriter implements BindingStreamEventWriter, Deleg
 
     @Override
     public void startChoiceNode(final Class<? extends DataContainer> type, final int childSizeHint)
-            throws IllegalArgumentException {
+            throws IOException, IllegalArgumentException {
         getDelegate().startChoiceNode(enter(type, NodeIdentifier.class), childSizeHint);
     }
 
     @Override
     public void startContainerNode(final Class<? extends DataObject> object, final int childSizeHint)
-            throws IllegalArgumentException {
+            throws IOException, IllegalArgumentException {
         getDelegate().startContainerNode(enter(object, NodeIdentifier.class), childSizeHint);
     }
 
     @Override
-    public void startLeafSet(final String localName, final int childSizeHint) throws IllegalArgumentException {
+    public void startLeafSet(final String localName, final int childSizeHint) throws IOException, IllegalArgumentException {
         getDelegate().startLeafSet(enter(localName, NodeIdentifier.class), childSizeHint);
     };
 
     @Override
-    public void startMapEntryNode(final Identifier<?> key, final int childSizeHint) throws IllegalArgumentException {
+    public void startMapEntryNode(final Identifier<?> key, final int childSizeHint) throws IOException, IllegalArgumentException {
         duplicateSchemaEnter();
         NodeIdentifierWithPredicates identifier = ((ListNodeCodecContext) current()).serialize(key);
         getDelegate().startMapEntryNode(identifier, childSizeHint);
@@ -163,25 +164,34 @@ class BindingToNormalizedStreamWriter implements BindingStreamEventWriter, Deleg
 
     @Override
     public <T extends DataObject & Identifiable<?>> void startMapNode(final Class<T> mapEntryType,
-            final int childSizeHint) throws IllegalArgumentException {
+            final int childSizeHint) throws IOException, IllegalArgumentException {
         getDelegate().startMapNode(enter(mapEntryType, NodeIdentifier.class), childSizeHint);
     };
 
     @Override
     public <T extends DataObject & Identifiable<?>> void startOrderedMapNode(final Class<T> mapEntryType,
-            final int childSizeHint) throws IllegalArgumentException {
+            final int childSizeHint) throws IOException, IllegalArgumentException {
         getDelegate().startOrderedMapNode(enter(mapEntryType, NodeIdentifier.class), childSizeHint);
     };
 
     @Override
     public void startUnkeyedList(final Class<? extends DataObject> obj, final int childSizeHint)
-            throws IllegalArgumentException {
+            throws IOException, IllegalArgumentException {
         getDelegate().startUnkeyedList(enter(obj, NodeIdentifier.class), childSizeHint);
     };
 
     @Override
-    public void startUnkeyedListItem(final int childSizeHint) throws IllegalStateException {
+    public void startUnkeyedListItem(final int childSizeHint) throws IllegalStateException, IOException {
         getDelegate().startUnkeyedListItem(duplicateSchemaEnter(), childSizeHint);
     }
 
+    @Override
+    public void flush() throws IOException {
+        getDelegate().flush();
+    }
+
+    @Override
+    public void close() throws IOException {
+        getDelegate().close();
+    }
 }
index 548a998dfffec626a1001d10c0d2d8efbfdff962..38b4e8b211e00cb181e246623928dff4b2de32b6 100644 (file)
@@ -9,6 +9,7 @@ package org.opendaylight.yangtools.binding.data.codec.util;
 
 import com.google.common.base.Preconditions;
 
+import java.io.IOException;
 import java.lang.reflect.InvocationHandler;
 import java.lang.reflect.Proxy;
 import java.util.Collections;
@@ -38,7 +39,7 @@ public class AugmentableDispatchSerializer implements DataObjectSerializerImplem
 
     @Override
     public void serialize(final DataObjectSerializerRegistry reg, final DataObject obj,
-            final BindingStreamEventWriter stream) {
+            final BindingStreamEventWriter stream) throws IOException {
         if (obj instanceof Augmentable<?>) {
             final Map<Class<? extends Augmentation<?>>, Augmentation<?>> augmentations;
             if (reg instanceof AugmentationReader) {
@@ -64,7 +65,7 @@ public class AugmentableDispatchSerializer implements DataObjectSerializerImplem
 
     @SuppressWarnings("rawtypes")
     private void emitAugmentation(final Class type, final Augmentation<?> value, final BindingStreamEventWriter stream,
-            final DataObjectSerializerRegistry registry) {
+            final DataObjectSerializerRegistry registry) throws IOException {
         Preconditions.checkArgument(value instanceof DataObject);
         @SuppressWarnings("unchecked")
         DataObjectSerializer serializer = registry.getSerializer(type);
index 84ebc68e6dcaf1567e454f4038e66164bba9463b..5671ed52d73c307b1a366078ff339fd097238f05 100644 (file)
@@ -9,6 +9,8 @@ package org.opendaylight.yangtools.binding.data.codec.util;
 
 import com.google.common.base.Preconditions;
 
+import java.io.IOException;
+
 import org.opendaylight.yangtools.yang.binding.BindingStreamEventWriter;
 import org.opendaylight.yangtools.yang.binding.DataContainer;
 import org.opendaylight.yangtools.yang.binding.DataObject;
@@ -36,7 +38,7 @@ public class ChoiceDispatchSerializer implements DataObjectSerializerImplementat
 
     @SuppressWarnings("unchecked")
     @Override
-    public void serialize(final DataObjectSerializerRegistry reg, final DataObject obj, final BindingStreamEventWriter stream) {
+    public void serialize(final DataObjectSerializerRegistry reg, final DataObject obj, final BindingStreamEventWriter stream) throws IOException {
         @SuppressWarnings("rawtypes")
         Class cazeClass = obj.getImplementedInterface();
         stream.startChoiceNode(choiceClass, BindingStreamEventWriter.UNKNOWN_SIZE);
index a7e7cc77ada2232130cc69f2ce53e7cf9858615c..2e12378abbe72c837203188ccc92c6859202a9d2 100644 (file)
@@ -22,6 +22,7 @@
         <module>yang-data-util</module>
         <module>yang-data-impl</module>
         <module>yang-data-operations</module>
+        <module>yang-data-codec-gson</module>
         <module>yang-model-api</module>
         <module>yang-maven-plugin</module>
         <module>yang-maven-plugin-it</module>
index 0428ee2c2e73123cdb247a03a6279bca3deaed6f..97b42f37ce53d8256600d5ef2602fe03013278ba 100644 (file)
@@ -7,6 +7,10 @@
  */
 package org.opendaylight.yangtools.yang.binding;
 
+import java.io.Closeable;
+import java.io.Flushable;
+import java.io.IOException;
+
 
 /**
  * Event Stream Writer for Binding Representation
@@ -31,33 +35,33 @@ package org.opendaylight.yangtools.yang.binding;
  * and finished using {@link #endNode()}.</li>
  *
  * <li><code>UnkeyedList</code> - Unkeyed list represent list without keys,
- * unkeyed list start is emmited using {@link #startUnkeyedList(Class, int)} list
- * end is emmited using {@link #endNode()}. Each list item is emmited using
+ * unkeyed list start is emitted using {@link #startUnkeyedList(Class, int)} list
+ * end is emitted using {@link #endNode()}. Each list item is emitted using
  * {@link #startUnkeyedListItem()} and ended using {@link #endNode()}.</li>
  * </ul>
  *
  * <li><code>leaf</code> - Leaf node event is emitted using
- * {@link #leafNode(String, Object)}. {@link #endNode()} MUST be not emmited for
+ * {@link #leafNode(String, Object)}. {@link #endNode()} MUST be not emitted for
  * leaf node.</li>
  *
  * <li><code>leaf-list</code> - Leaf list start is emitted using
  * {@link #startLeafSet(String, int)}. Leaf list end is emitted using
- * {@link #endNode()}. Leaf list entries are emmited using
+ * {@link #endNode()}. Leaf list entries are emitted using
  * {@link #leafSetEntryNode(Object).
  *
  * <li><code>anyxml - Anyxml node event is emitted using
- * {@link #leafNode(String, Object)}. {@link #endNode()} MUST be not emmited
+ * {@link #leafNode(String, Object)}. {@link #endNode()} MUST be not emitted
  * for anyxml node.</code></li>
  *
  *
- * <li><code>choice</code> Choice node event is emmited by
+ * <li><code>choice</code> Choice node event is emitted by
  * {@link #startChoiceNode(Class, int)} event and must be immediately followed by
- * {@link #startCase(Class, int)} event. Choice node is finished by emitting
+ * {@link #startCase(Class, int)} event. Choice node is finished by emitting an
  * {@link #endNode()} event.</li>
  *
  * <li>
  * <code>case</code> - Case node may be emitted only inside choice node by
- * invoking {@link #startCase(Class, int)}. Case node is finished be emitting
+ * invoking {@link #startCase(Class, int)}. Case node is finished be emitting an
  * {@link #endNode()} event.</li>
  *
  * <li>
@@ -82,11 +86,11 @@ package org.opendaylight.yangtools.yang.binding;
  *
  *
  */
-public interface BindingStreamEventWriter {
+public interface BindingStreamEventWriter extends Closeable, Flushable {
 
     /**
      * Methods in this interface allow users to hint the underlying
-     * implementation about the sizing of container-like constructurs
+     * implementation about the sizing of container-like constructors
      * (leafLists, containers, etc.). These hints may be taken into account by a
      * particular implementation to improve performance, but clients are not
      * required to provide hints. This constant should be used by clients who
@@ -117,8 +121,9 @@ public interface BindingStreamEventWriter {
      * @throws IllegalStateException
      *             If node was emitted inside <code>map</code>,
      *             <code>choice</code> <code>unkeyed list</code> node.
+     * @throws IOException if an underlying IO error occurs
      */
-    void leafNode(String localName, Object value) throws IllegalArgumentException;
+    void leafNode(String localName, Object value) throws IOException, IllegalArgumentException;
 
     /**
      *
@@ -142,8 +147,9 @@ public interface BindingStreamEventWriter {
      * @throws IllegalStateException
      *             If node was emitted inside <code>map</code>,
      *             <code>choice</code> <code>unkeyed list</code> node.
+     * @throws IOException if an underlying IO error occurs
      */
-    void startLeafSet(String localName, int childSizeHint) throws IllegalArgumentException;
+    void startLeafSet(String localName, int childSizeHint) throws IOException, IllegalArgumentException;
 
     /**
      * Emits a leaf set entry node
@@ -154,8 +160,9 @@ public interface BindingStreamEventWriter {
      *             If emitted leaf node has invalid value.
      * @throws IllegalStateException
      *             If node was emitted outside <code>leaf set</code> node.
+     * @throws IOException if an underlying IO error occurs
      */
-    void leafSetEntryNode(Object value) throws IllegalArgumentException;
+    void leafSetEntryNode(Object value) throws IOException, IllegalArgumentException;
 
     /**
      *
@@ -190,8 +197,9 @@ public interface BindingStreamEventWriter {
      * @throws IllegalStateException
      *             If node was emitted inside <code>map</code>,
      *             <code>choice</code> <code>unkeyed list</code> node.
+     * @throws IOException if an underlying IO error occurs
      */
-    void startContainerNode(Class<? extends DataObject> container, int childSizeHint) throws IllegalArgumentException;
+    void startContainerNode(Class<? extends DataObject> container, int childSizeHint) throws IOException, IllegalArgumentException;
 
     /**
      *
@@ -216,8 +224,9 @@ public interface BindingStreamEventWriter {
      * @throws IllegalStateException
      *             If node was emitted inside <code>map</code>,
      *             <code>choice</code> <code>unkeyed list</code> node.
+     * @throws IOException if an underlying IO error occurs
      */
-    void startUnkeyedList(Class<? extends DataObject> localName, int childSizeHint) throws IllegalArgumentException;
+    void startUnkeyedList(Class<? extends DataObject> localName, int childSizeHint) throws IOException, IllegalArgumentException;
 
     /**
      * Emits start of new unkeyed list item.
@@ -246,8 +255,9 @@ public interface BindingStreamEventWriter {
      *            events than count.
      * @throws IllegalStateException
      *             If node was emitted outside <code>unkeyed list</code> node.
+     * @throws IOException if an underlying IO error occurs
      */
-    void startUnkeyedListItem(int childSizeHint) throws IllegalStateException;
+    void startUnkeyedListItem(int childSizeHint) throws IOException, IllegalStateException;
 
     /**
      *
@@ -269,34 +279,35 @@ public interface BindingStreamEventWriter {
      * @throws IllegalStateException
      *             If node was emitted inside <code>map</code>,
      *             <code>choice</code> <code>unkeyed list</code> node.
+     * @throws IOException if an underlying IO error occurs
      */
     <T extends DataObject & Identifiable<?>> void startMapNode(Class<T> mapEntryType, int childSizeHint)
-            throws IllegalArgumentException;
-
+            throws IOException, IllegalArgumentException;
 
     /**
-    *
-    * Emits start of ordered map node event.
-    *
-    * <p>
-    * End of map node event is emitted by invoking {@link #endNode()}. Valid
-    * subevents is only {@link #startMapEntryNode(Identifier, int)}. All other methods will
-    * throw {@link IllegalArgumentException}.
-    *
-    * @param mapEntryType
-    *            Class of list item, which has defined key.
-    * @param childSizeHint
-    *            Non-negative count of expected direct child nodes or
-    *            {@link #UNKNOWN_SIZE} if count is unknown. This is only hint
-    *            and should not fail writing of child events, if there are more
-    *            events than count.
-    * @throws IllegalArgumentException
-    * @throws IllegalStateException
-    *             If node was emitted inside <code>map</code>,
-    *             <code>choice</code> <code>unkeyed list</code> node.
-    */
-   <T extends DataObject & Identifiable<?>> void startOrderedMapNode(Class<T> mapEntryType, int childSizeHint)
-           throws IllegalArgumentException;
+     *
+     * Emits start of ordered map node event.
+     *
+     * <p>
+     * End of map node event is emitted by invoking {@link #endNode()}. Valid
+     * subevents is only {@link #startMapEntryNode(Identifier, int)}. All other methods will
+     * throw {@link IllegalArgumentException}.
+     *
+     * @param mapEntryType
+     *            Class of list item, which has defined key.
+     * @param childSizeHint
+     *            Non-negative count of expected direct child nodes or
+     *            {@link #UNKNOWN_SIZE} if count is unknown. This is only hint
+     *            and should not fail writing of child events, if there are more
+     *            events than count.
+     * @throws IllegalArgumentException
+     * @throws IllegalStateException
+     *             If node was emitted inside <code>map</code>,
+     *             <code>choice</code> <code>unkeyed list</code> node.
+     * @throws IOException if an underlying IO error occurs
+     */
+    <T extends DataObject & Identifiable<?>> void startOrderedMapNode(Class<T> mapEntryType, int childSizeHint)
+           throws IOException, IllegalArgumentException;
 
     /**
      *
@@ -330,8 +341,9 @@ public interface BindingStreamEventWriter {
      *             If key contains incorrect value.
      * @throws IllegalStateException
      *             If node was emitted outside <code>map entry</code> node.
+     * @throws IOException if an underlying IO error occurs
      */
-    void startMapEntryNode(Identifier<?> keyValues, int childSizeHint) throws IllegalArgumentException;
+    void startMapEntryNode(Identifier<?> keyValues, int childSizeHint) throws IOException, IllegalArgumentException;
 
     /**
      * Emits start of choice node.
@@ -353,8 +365,9 @@ public interface BindingStreamEventWriter {
      * @throws IllegalStateException
      *             If node was emitted inside <code>map</code>, <code>choice
      *             </code> <code>unkeyed list</code> node.
+     * @throws IOException if an underlying IO error occurs
      */
-    void startChoiceNode(Class<? extends DataContainer> choice, int childSizeHint) throws IllegalArgumentException;
+    void startChoiceNode(Class<? extends DataContainer> choice, int childSizeHint) throws IOException, IllegalArgumentException;
 
     /**
      *
@@ -374,8 +387,9 @@ public interface BindingStreamEventWriter {
      *
      * @param name
      * @throws IllegalArgumentException
+     * @throws IOException if an underlying IO error occurs
      */
-    void startCase(Class<? extends DataObject> caze, int childSizeHint) throws IllegalArgumentException;
+    void startCase(Class<? extends DataObject> caze, int childSizeHint) throws IOException, IllegalArgumentException;
 
     /**
      * Emits start of augmentation node.
@@ -407,8 +421,9 @@ public interface BindingStreamEventWriter {
      *            Local names of all valid children defined by augmentation.
      * @throws IllegalArgumentException
      *             If augmentation is invalid in current context.
+     * @throws IOException if an underlying IO error occurs
      */
-    void startAugmentationNode(Class<? extends Augmentation<?>> augmentationType) throws IllegalArgumentException;
+    void startAugmentationNode(Class<? extends Augmentation<?>> augmentationType) throws IOException, IllegalArgumentException;
 
     /**
      * Emits anyxml node event.
@@ -419,13 +434,21 @@ public interface BindingStreamEventWriter {
      * @throws IllegalStateException
      *             If node was emitted inside <code>map</code>,
      *             <code>choice</code> <code>unkeyed list</code> node.
+     * @throws IOException if an underlying IO error occurs
      */
-    void anyxmlNode(String name, Object value) throws IllegalArgumentException;
+    void anyxmlNode(String name, Object value) throws IOException, IllegalArgumentException;
 
     /**
      * Emits end event for node.
      *
      * @throws IllegalStateException If there is no open node.
+     * @throws IOException if an underlying IO error occurs
      */
-    void endNode() throws IllegalStateException;
+    void endNode() throws IOException, IllegalStateException;
+
+    @Override
+    void flush() throws IOException;
+
+    @Override
+    void close() throws IOException;
 }
index 90d9cc2cae857986c3d01f06e3dd2966761aa631..faa7056e0f6e7858412234c5b299374061bd1b29 100644 (file)
@@ -7,24 +7,19 @@
  */
 package org.opendaylight.yangtools.yang.binding;
 
+import java.io.IOException;
+
 /**
- *
- * Serializer which writes DataObject to supplied stream event writer.
- *
- *
+ * A serializer which writes DataObject to supplied stream event writer.
  */
 public interface DataObjectSerializer {
-
     /**
-     *
      * Writes stream events representing object to supplied stream
-
      *
      * @param obj
      *            Source of stream events
      * @param stream
      *            Stream to which events should be written.
      */
-    void serialize(DataObject obj, BindingStreamEventWriter stream);
-
+    void serialize(DataObject obj, BindingStreamEventWriter stream) throws IOException;
 }
index 7aedc47d6f00a59e6652e4373ea86f3a1409ef7d..4c9b3c816ab15e2019138e6feb466af0c6475d66 100644 (file)
@@ -7,6 +7,8 @@
  */
 package org.opendaylight.yangtools.yang.binding;
 
+import java.io.IOException;
+
 /**
  * SPI-level contract for implementations of {@link DataObjectSerializer}.
  * The contract is kept between implementation of {@link DataObjectSerializerRegistry},
@@ -14,7 +16,7 @@ package org.opendaylight.yangtools.yang.binding;
  *
  * FIXME: this interface needs to be moved into .spi, but due to classpath funkyness
  *        of OSGi, that change has to be carefully orchestrated to ensure proper imports
- *        exist in all generated pacakges. One avenue how to achieve that is to move
+ *        exist in all generated packages. One avenue how to achieve that is to move
  *        {@link YangModuleInfo} and modify code generator to add a static field
  *        to all generated classes which will point to the per-model YangModuleInfo
  *        (currently all users of it have to walk the package hierarchy, so that
@@ -22,7 +24,6 @@ package org.opendaylight.yangtools.yang.binding;
  *
  */
 public interface DataObjectSerializerImplementation {
-
     /**
      *
      * Writes stream events for supplied data object to provided stream.
@@ -32,6 +33,5 @@ public interface DataObjectSerializerImplementation {
      * their events.
      *
      */
-    void serialize(DataObjectSerializerRegistry reg,DataObject obj, BindingStreamEventWriter stream);
-
+    void serialize(DataObjectSerializerRegistry reg,DataObject obj, BindingStreamEventWriter stream) throws IOException;
 }
diff --git a/yang/yang-data-api/src/main/java/org/opendaylight/yangtools/yang/data/api/schema/stream/LoggingNormalizedNodeStreamWriter.java b/yang/yang-data-api/src/main/java/org/opendaylight/yangtools/yang/data/api/schema/stream/LoggingNormalizedNodeStreamWriter.java
new file mode 100644 (file)
index 0000000..83a8c33
--- /dev/null
@@ -0,0 +1,119 @@
+package org.opendaylight.yangtools.yang.data.api.schema.stream;
+
+import com.google.common.annotations.Beta;
+import com.google.common.base.Preconditions;
+import com.google.common.base.Strings;
+
+import java.io.IOException;
+
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.AugmentationIdentifier;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifier;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifierWithPredicates;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+@Beta
+public class LoggingNormalizedNodeStreamWriter implements NormalizedNodeStreamWriter {
+    private static final Logger LOG = LoggerFactory.getLogger(LoggingNormalizedNodeStreamWriter.class);
+    private static final int DEFAULT_INDENT_SIZE = 2;
+    private final int indentSize = DEFAULT_INDENT_SIZE;
+    private int currentIndent = 0;
+
+    private String ind() {
+        return Strings.repeat(" ", currentIndent);
+    }
+
+    private void decIndent() {
+        Preconditions.checkState(currentIndent >= 0, "Unexpected indentation %s", currentIndent);
+        currentIndent -= indentSize;
+    }
+
+    private void incIndent() {
+        currentIndent += indentSize;
+    }
+
+    @Override
+    public void startUnkeyedListItem(final NodeIdentifier name, final int childSizeHint) throws IllegalStateException {
+        LOG.debug("{}{}[](no key)", ind(), name);
+        incIndent();
+    }
+
+    @Override
+    public void startUnkeyedList(final NodeIdentifier name, final int childSizeHint) throws IllegalArgumentException {
+        LOG.debug("{}{}(no key)", ind(), name);
+        incIndent();
+    }
+
+    @Override
+    public void startOrderedMapNode(final NodeIdentifier name, final int childSizeHint) throws IllegalArgumentException {
+
+    }
+
+    @Override
+    public void startMapNode(final NodeIdentifier name, final int childSizeHint) throws IllegalArgumentException {
+        LOG.debug("{}{}(key)", ind(), name);
+        incIndent();
+    }
+
+    @Override
+    public void startMapEntryNode(final NodeIdentifierWithPredicates identifier, final int childSizeHint)
+            throws IllegalArgumentException {
+        LOG.debug("{}{}[](key)", ind(), identifier);
+        incIndent();
+    }
+
+    @Override
+    public void startLeafSet(final NodeIdentifier name, final int childSizeHint) throws IllegalArgumentException {
+        LOG.debug("{}{}(leaf-list)", ind(), name);
+        incIndent();
+    }
+
+    @Override
+    public void startContainerNode(final NodeIdentifier name, final int childSizeHint) throws IllegalArgumentException {
+        LOG.debug("{}{}(container)", ind(), name);
+        incIndent();
+    }
+
+    @Override
+    public void startChoiceNode(final NodeIdentifier name, final int childSizeHint) throws IllegalArgumentException {
+        LOG.debug("{}{}(choice)", ind(), name);
+        incIndent();
+    }
+
+    @Override
+    public void startAugmentationNode(final AugmentationIdentifier identifier) throws IllegalArgumentException {
+        LOG.debug("{}{}(augmentation)", ind(), identifier);
+        incIndent();
+    }
+
+    @Override
+    public void leafSetEntryNode(final Object value) throws IllegalArgumentException {
+        LOG.debug("{}{}({}) ", ind(), value, value.getClass().getSimpleName());
+    }
+
+    @Override
+    public void leafNode(final NodeIdentifier name, final Object value) throws IllegalArgumentException {
+        LOG.debug("{}{}(leaf({}))=", ind(), name, value.getClass().getSimpleName(), value);
+    }
+
+    @Override
+    public void endNode() throws IllegalStateException {
+        decIndent();
+        LOG.debug("{}(end)", ind());
+    }
+
+    @Override
+    public void anyxmlNode(final NodeIdentifier name, final Object value) throws IllegalArgumentException {
+        LOG.debug("{}{}(anyxml)=", ind(), name, value);
+    }
+
+    @Override
+    public void flush() throws IOException {
+        LOG.trace("<<FLUSH>>");
+    }
+
+    @Override
+    public void close() throws IOException {
+        LOG.debug("<<END-OF-STREAM>>");
+    }
+}
\ No newline at end of file
index 96b5c15e91e933f0075c0eb9f1e6f446c332b4f9..13d314282a6d35f2b34e7cbb5b2b2c868774f0d8 100644 (file)
@@ -7,6 +7,10 @@
  */
 package org.opendaylight.yangtools.yang.data.api.schema.stream;
 
+import java.io.Closeable;
+import java.io.Flushable;
+import java.io.IOException;
+
 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.AugmentationIdentifier;
 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifier;
 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifierWithPredicates;
@@ -34,13 +38,13 @@ import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdent
  * and finished using {@link #endNode()}.</li>
  *
  * <li><code>UnkeyedList</code> - Unkeyed list represent list without keys,
- * unkeyed list start is emmited using {@link #startUnkeyedList(NodeIdentifier, int)} list
- * end is emmited using {@link #endNode()}. Each list item is emmited using
+ * unkeyed list start is emitted using {@link #startUnkeyedList(NodeIdentifier, int)} list
+ * end is emitted using {@link #endNode()}. Each list item is emitted using
  * {@link #startUnkeyedListItem(NodeIdentifier, int)} and ended using {@link #endNode()}.</li>
  * </ul>
  *
  * <li><code>leaf</code> - Leaf node event is emitted using
- * {@link #leafNode(NodeIdentifier, Object)}. {@link #endNode()} MUST NOT BE emmited for
+ * {@link #leafNode(NodeIdentifier, Object)}. {@link #endNode()} MUST NOT BE emitted for
  * leaf node.</li>
  *
  * <li><code>leaf-list</code> - Leaf list start is emitted using
@@ -49,7 +53,7 @@ import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdent
  * {@link #leafSetEntryNode(Object).
  *
  * <li><code>anyxml - Anyxml node event is emitted using
- * {@link #leafNode(NodeIdentifier, Object)}. {@link #endNode()} MUST NOT BE emmited
+ * {@link #leafNode(NodeIdentifier, Object)}. {@link #endNode()} MUST NOT BE emitted
  * for anyxml node.</code></li>
  *
  *
@@ -70,11 +74,11 @@ import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdent
  * and resources needlessly.
  *
  */
-public interface NormalizedNodeStreamWriter {
+public interface NormalizedNodeStreamWriter extends Closeable, Flushable {
 
     /**
      * Methods in this interface allow users to hint the underlying
-     * implementation about the sizing of container-like constructurs
+     * implementation about the sizing of container-like constructors
      * (leafLists, containers, etc.). These hints may be taken into account by a
      * particular implementation to improve performance, but clients are not
      * required to provide hints. This constant should be used by clients who
@@ -105,8 +109,9 @@ public interface NormalizedNodeStreamWriter {
      * @throws IllegalStateException
      *             If node was emitted inside <code>map</code>,
      *             <code>choice</code> <code>unkeyed list</code> node.
+     * @throws IOException if an underlying IO error occurs
      */
-    void leafNode(NodeIdentifier name, Object value) throws IllegalArgumentException;
+    void leafNode(NodeIdentifier name, Object value) throws IOException, IllegalArgumentException;
 
     /**
      *
@@ -130,8 +135,9 @@ public interface NormalizedNodeStreamWriter {
      * @throws IllegalStateException
      *             If node was emitted inside <code>map</code>,
      *             <code>choice</code> <code>unkeyed list</code> node.
+     * @throws IOException if an underlying IO error occurs
      */
-    void startLeafSet(NodeIdentifier name, int childSizeHint) throws IllegalArgumentException;
+    void startLeafSet(NodeIdentifier name, int childSizeHint) throws IOException, IllegalArgumentException;
 
     /**
      * Emits a leaf set entry node
@@ -142,8 +148,9 @@ public interface NormalizedNodeStreamWriter {
      *             If emitted leaf node has invalid value.
      * @throws IllegalStateException
      *             If node was emitted outside <code>leaf set</code> node.
+     * @throws IOException if an underlying IO error occurs
      */
-    void leafSetEntryNode(Object value) throws IllegalArgumentException;
+    void leafSetEntryNode(Object value) throws IOException, IllegalArgumentException;
 
     /**
      *
@@ -161,8 +168,8 @@ public interface NormalizedNodeStreamWriter {
      * <li>{@link #startLeafSet(NodeIdentifier, int)}</li>
      * <li>{@link #startMapNode(NodeIdentifier, int)}</li>
      * <li>{@link #startUnkeyedList(NodeIdentifier, int)}</li>
-    * <li>{@link #startAugmentationNode(AugmentationIdentifier)}</li>
-    * </ul>
+     * <li>{@link #startAugmentationNode(AugmentationIdentifier)}</li>
+     * </ul>
      *
      * @param name
      *            name of node as defined in schema, namespace and revision are
@@ -178,8 +185,9 @@ public interface NormalizedNodeStreamWriter {
      * @throws IllegalStateException
      *             If node was emitted inside <code>map</code>,
      *             <code>choice</code> <code>unkeyed list</code> node.
+     * @throws IOException if an underlying IO error occurs
      */
-    void startContainerNode(NodeIdentifier name, int childSizeHint) throws IllegalArgumentException;
+    void startContainerNode(NodeIdentifier name, int childSizeHint) throws IOException, IllegalArgumentException;
 
     /**
      *
@@ -204,8 +212,9 @@ public interface NormalizedNodeStreamWriter {
      * @throws IllegalStateException
      *             If node was emitted inside <code>map</code>,
      *             <code>choice</code> <code>unkeyed list</code> node.
+     * @throws IOException if an underlying IO error occurs
      */
-    void startUnkeyedList(NodeIdentifier name, int childSizeHint) throws IllegalArgumentException;
+    void startUnkeyedList(NodeIdentifier name, int childSizeHint) throws IOException, IllegalArgumentException;
 
     /**
      * Emits start of new unkeyed list item.
@@ -231,8 +240,9 @@ public interface NormalizedNodeStreamWriter {
      *            events than count.
      * @throws IllegalStateException
      *             If node was emitted outside <code>unkeyed list</code> node.
+     * @throws IOException if an underlying IO error occurs
      */
-    void startUnkeyedListItem(NodeIdentifier name, int childSizeHint) throws IllegalStateException;
+    void startUnkeyedListItem(NodeIdentifier name, int childSizeHint) throws IOException, IllegalStateException;
 
     /**
      *
@@ -252,8 +262,9 @@ public interface NormalizedNodeStreamWriter {
      * @throws IllegalStateException
      *             If node was emitted inside <code>map</code>,
      *             <code>choice</code> <code>unkeyed list</code> node.
+     * @throws IOException if an underlying IO error occurs
      */
-    void startMapNode(NodeIdentifier name, int childSizeHint) throws IllegalArgumentException;
+    void startMapNode(NodeIdentifier name, int childSizeHint) throws IOException, IllegalArgumentException;
 
     /**
      *
@@ -281,8 +292,9 @@ public interface NormalizedNodeStreamWriter {
      *             If key contains incorrect value.
      * @throws IllegalStateException
      *             If node was emitted outside <code>map entry</code> node.
+     * @throws IOException if an underlying IO error occurs
      */
-    void startMapEntryNode(NodeIdentifierWithPredicates identifier, int childSizeHint) throws IllegalArgumentException;
+    void startMapEntryNode(NodeIdentifierWithPredicates identifier, int childSizeHint) throws IOException, IllegalArgumentException;
 
     /**
      *
@@ -301,8 +313,9 @@ public interface NormalizedNodeStreamWriter {
      * @throws IllegalStateException
      *             If node was emitted inside <code>map</code>,
      *             <code>choice</code> <code>unkeyed list</code> node.
+     * @throws IOException if an underlying IO error occurs
      */
-    void startOrderedMapNode(NodeIdentifier name, int childSizeHint) throws IllegalArgumentException;
+    void startOrderedMapNode(NodeIdentifier name, int childSizeHint) throws IOException, IllegalArgumentException;
 
     /**
      *
@@ -316,8 +329,9 @@ public interface NormalizedNodeStreamWriter {
      * @throws IllegalStateException
      *             If node was emitted inside <code>map</code>,
      *             <code>choice</code> <code>unkeyed list</code> node.
+     * @throws IOException if an underlying IO error occurs
      */
-    void startChoiceNode(NodeIdentifier name, int childSizeHint) throws IllegalArgumentException;
+    void startChoiceNode(NodeIdentifier name, int childSizeHint) throws IOException, IllegalArgumentException;
 
     /**
      * Emits start of augmentation node.
@@ -341,28 +355,34 @@ public interface NormalizedNodeStreamWriter {
      *            Augmentation identifier
      * @throws IllegalArgumentException
      *             If augmentation is invalid in current context.
+     * @throws IOException if an underlying IO error occurs
      */
-    void startAugmentationNode(AugmentationIdentifier identifier) throws IllegalArgumentException;
+    void startAugmentationNode(AugmentationIdentifier identifier) throws IOException, IllegalArgumentException;
 
     /**
      * Emits anyxml node event.
      *
-     *
      * @param name
      * @param value
      * @throws IllegalArgumentException
      * @throws IllegalStateException
      *             If node was emitted inside <code>map</code>,
      *             <code>choice</code> <code>unkeyed list</code> node.
+     * @throws IOException if an underlying IO error occurs
      */
-    void anyxmlNode(NodeIdentifier name, Object value) throws IllegalArgumentException;
+    void anyxmlNode(NodeIdentifier name, Object value) throws IOException, IllegalArgumentException;
 
     /**
      * Emits end event for node.
      *
-     * @throws IllegalStateException If there is no start* event to be closed.B
-     *
+     * @throws IllegalStateException If there is no start* event to be closed.
+     * @throws IOException if an underlying IO error occurs
      */
-    void endNode() throws IllegalStateException;
+    void endNode() throws IOException, IllegalStateException;
+
+    @Override
+    void close() throws IOException;
 
+    @Override
+    void flush() throws IOException;
 }
diff --git a/yang/yang-data-api/src/main/java/org/opendaylight/yangtools/yang/data/api/schema/stream/NormalizedNodeWriter.java b/yang/yang-data-api/src/main/java/org/opendaylight/yangtools/yang/data/api/schema/stream/NormalizedNodeWriter.java
new file mode 100644 (file)
index 0000000..a0068c3
--- /dev/null
@@ -0,0 +1,131 @@
+/*
+ * Copyright (c) 2014 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.yangtools.yang.data.api.schema.stream;
+
+import static org.opendaylight.yangtools.yang.data.api.schema.stream.NormalizedNodeStreamWriter.UNKNOWN_SIZE;
+
+import com.google.common.annotations.Beta;
+import com.google.common.base.Preconditions;
+
+import java.io.Closeable;
+import java.io.Flushable;
+import java.io.IOException;
+
+import org.opendaylight.yangtools.yang.data.api.schema.AnyXmlNode;
+import org.opendaylight.yangtools.yang.data.api.schema.AugmentationNode;
+import org.opendaylight.yangtools.yang.data.api.schema.ChoiceNode;
+import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode;
+import org.opendaylight.yangtools.yang.data.api.schema.LeafNode;
+import org.opendaylight.yangtools.yang.data.api.schema.LeafSetEntryNode;
+import org.opendaylight.yangtools.yang.data.api.schema.LeafSetNode;
+import org.opendaylight.yangtools.yang.data.api.schema.MapEntryNode;
+import org.opendaylight.yangtools.yang.data.api.schema.MapNode;
+import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
+import org.opendaylight.yangtools.yang.data.api.schema.OrderedMapNode;
+import org.opendaylight.yangtools.yang.data.api.schema.UnkeyedListEntryNode;
+import org.opendaylight.yangtools.yang.data.api.schema.UnkeyedListNode;
+
+/**
+ * This is an experimental
+ */
+@Beta
+public final class NormalizedNodeWriter implements Closeable, Flushable {
+    private final NormalizedNodeStreamWriter writer;
+
+    private NormalizedNodeWriter(final NormalizedNodeStreamWriter writer) {
+        this.writer = Preconditions.checkNotNull(writer);
+    }
+
+    public static NormalizedNodeWriter forStreamWriter(final NormalizedNodeStreamWriter writer) {
+        return new NormalizedNodeWriter(writer);
+    }
+
+    public NormalizedNodeWriter write(final NormalizedNode<?, ?> node) throws IOException {
+        if (wasProcessedAsCompositeNode(node)) {
+            return this;
+        }
+
+        if (wasProcessAsSimpleNode(node)) {
+            return this;
+        }
+
+        throw new IllegalStateException("It wasn't possible to serialize node " + node);
+    }
+
+    private boolean wasProcessAsSimpleNode(final NormalizedNode<?, ?> node) throws IOException {
+        if (node instanceof LeafSetEntryNode) {
+            final LeafSetEntryNode<?> nodeAsLeafList = (LeafSetEntryNode<?>)node;
+            writer.leafSetEntryNode(nodeAsLeafList.getValue());
+            return true;
+        } else if (node instanceof LeafNode) {
+            final LeafNode<?> nodeAsLeaf = (LeafNode<?>)node;
+            writer.leafNode(nodeAsLeaf.getIdentifier(), nodeAsLeaf.getValue());
+            return true;
+        } else if (node instanceof AnyXmlNode) {
+            final AnyXmlNode anyXmlNode = (AnyXmlNode)node;
+            writer.anyxmlNode(anyXmlNode.getIdentifier(), anyXmlNode.getValue());
+            return true;
+        }
+
+        return false;
+    }
+
+    private boolean wasProcessedAsCompositeNode(final NormalizedNode<?, ?> node) throws IOException {
+        boolean hasDataContainerChild = false;
+        if (node instanceof ContainerNode) {
+            writer.startContainerNode(((ContainerNode) node).getIdentifier(), UNKNOWN_SIZE);
+            hasDataContainerChild = true;
+        } else if (node instanceof MapEntryNode) {
+            writer.startMapEntryNode(((MapEntryNode) node).getIdentifier(), UNKNOWN_SIZE);
+            hasDataContainerChild = true;
+        } else if (node instanceof UnkeyedListEntryNode) {
+            writer.startUnkeyedListItem(((UnkeyedListEntryNode) node).getIdentifier(), UNKNOWN_SIZE);
+            hasDataContainerChild = true;
+        } else if (node instanceof ChoiceNode) {
+            writer.startChoiceNode(((ChoiceNode) node).getIdentifier(), UNKNOWN_SIZE);
+            hasDataContainerChild = true;
+        } else if (node instanceof AugmentationNode) {
+            writer.startAugmentationNode(((AugmentationNode) node).getIdentifier());
+            hasDataContainerChild = true;
+        } else if (node instanceof UnkeyedListNode) {
+            writer.startUnkeyedList(((UnkeyedListNode) node).getIdentifier(), UNKNOWN_SIZE);
+            hasDataContainerChild = true;
+        } else if (node instanceof OrderedMapNode) {
+            writer.startOrderedMapNode(((OrderedMapNode) node).getIdentifier(), UNKNOWN_SIZE);
+            hasDataContainerChild = true;
+        } else if (node instanceof MapNode) {
+            writer.startMapNode(((MapNode) node).getIdentifier(), UNKNOWN_SIZE);
+            hasDataContainerChild = true;
+          //covers also OrderedLeafSetNode for which doesn't exist start* method
+        } else if (node instanceof LeafSetNode) {
+            writer.startLeafSet(((LeafSetNode<?>) node).getIdentifier(), UNKNOWN_SIZE);
+            hasDataContainerChild = true;
+        }
+
+        if (hasDataContainerChild) {
+            for (NormalizedNode<?, ?> childNode : ((NormalizedNode<?, Iterable<NormalizedNode<?, ?>>>) node).getValue()) {
+                write(childNode);
+            }
+
+            writer.endNode();
+            return true;
+        }
+        return false;
+
+    }
+
+    @Override
+    public void flush() throws IOException {
+        writer.flush();
+    }
+
+    @Override
+    public void close() throws IOException {
+        writer.close();
+    }
+}
diff --git a/yang/yang-data-codec-gson/pom.xml b/yang/yang-data-codec-gson/pom.xml
new file mode 100644 (file)
index 0000000..c8e1719
--- /dev/null
@@ -0,0 +1,47 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- vi: set et smarttab sw=4 tabstop=4: -->
+<!--
+ Copyright (c) 2013 Cisco Systems, Inc. and others.  All rights reserved.
+
+ This program and the accompanying materials are made available under the
+ terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ and is available at http://www.eclipse.org/legal/epl-v10.html
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <parent>
+        <groupId>org.opendaylight.yangtools</groupId>
+        <artifactId>yangtools-parent</artifactId>
+        <version>0.6.2-SNAPSHOT</version>
+        <relativePath>/../../common/parent/pom.xml</relativePath>
+    </parent>
+
+    <modelVersion>4.0.0</modelVersion>
+    <artifactId>yang-data-codec-gson</artifactId>
+    <name>${project.artifactId}</name>
+    <description>${project.artifactId}</description>
+
+    <dependencies>
+        <dependency>
+            <groupId>org.opendaylight.yangtools</groupId>
+            <artifactId>yang-data-api</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>com.google.code.gson</groupId>
+            <artifactId>gson</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.opendaylight.yangtools</groupId>
+            <artifactId>yang-data-impl</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.opendaylight.yangtools</groupId>
+            <artifactId>yang-parser-impl</artifactId>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>junit</groupId>
+            <artifactId>junit</artifactId>
+            <scope>test</scope>
+        </dependency>
+    </dependencies>
+</project>
diff --git a/yang/yang-data-codec-gson/src/main/java/org/opendaylight/yangtools/yang/data/codec/gson/AbstractNodeDataWithSchema.java b/yang/yang-data-codec-gson/src/main/java/org/opendaylight/yangtools/yang/data/codec/gson/AbstractNodeDataWithSchema.java
new file mode 100644 (file)
index 0000000..3284df2
--- /dev/null
@@ -0,0 +1,65 @@
+/*
+ * Copyright (c) 2014 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.yangtools.yang.data.codec.gson;
+
+import java.io.IOException;
+
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifier;
+import org.opendaylight.yangtools.yang.data.api.schema.stream.NormalizedNodeStreamWriter;
+import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
+
+abstract class AbstractNodeDataWithSchema {
+
+    private final DataSchemaNode schema;
+
+    public AbstractNodeDataWithSchema(final DataSchemaNode schema) {
+        this.schema = schema;
+    }
+
+    public final DataSchemaNode getSchema() {
+        return schema;
+    }
+
+    protected abstract void writeToStream(final NormalizedNodeStreamWriter nnStreamWriter) throws IOException;
+
+    protected NodeIdentifier provideNodeIdentifier() {
+        return new NodeIdentifier(schema.getQName());
+    }
+
+    @Override
+    public int hashCode() {
+        final int prime = 31;
+        int result = 1;
+        result = prime * result + ((schema == null) ? 0 : schema.hashCode());
+        return result;
+    }
+
+    @Override
+    public boolean equals(final Object obj) {
+        if (this == obj) {
+            return true;
+        }
+        if (obj == null) {
+            return false;
+        }
+        if (getClass() != obj.getClass()) {
+            return false;
+        }
+        AbstractNodeDataWithSchema other = (AbstractNodeDataWithSchema) obj;
+        if (schema == null) {
+            if (other.schema != null) {
+                return false;
+            }
+        } else if (!schema.equals(other.schema)) {
+            return false;
+        }
+
+        return true;
+    }
+
+}
diff --git a/yang/yang-data-codec-gson/src/main/java/org/opendaylight/yangtools/yang/data/codec/gson/AnyXmlNodeDataWithSchema.java b/yang/yang-data-codec-gson/src/main/java/org/opendaylight/yangtools/yang/data/codec/gson/AnyXmlNodeDataWithSchema.java
new file mode 100644 (file)
index 0000000..aaef749
--- /dev/null
@@ -0,0 +1,26 @@
+/*
+ * Copyright (c) 2014 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.yangtools.yang.data.codec.gson;
+
+import java.io.IOException;
+
+import org.opendaylight.yangtools.yang.data.api.schema.stream.NormalizedNodeStreamWriter;
+import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
+
+class AnyXmlNodeDataWithSchema extends SimpleNodeDataWithSchema {
+
+    public AnyXmlNodeDataWithSchema(final DataSchemaNode dataSchemaNode) {
+        super(dataSchemaNode);
+    }
+
+    @Override
+    protected void writeToStream(final NormalizedNodeStreamWriter nnStreamWriter) throws IOException {
+//      FIXME: should be changed according to format of value
+        nnStreamWriter.anyxmlNode(provideNodeIdentifier(), getValue());
+    }
+}
diff --git a/yang/yang-data-codec-gson/src/main/java/org/opendaylight/yangtools/yang/data/codec/gson/CaseNodeDataWithSchema.java b/yang/yang-data-codec-gson/src/main/java/org/opendaylight/yangtools/yang/data/codec/gson/CaseNodeDataWithSchema.java
new file mode 100644 (file)
index 0000000..e3fdaed
--- /dev/null
@@ -0,0 +1,25 @@
+/*
+ * Copyright (c) 2014 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.yangtools.yang.data.codec.gson;
+
+import java.io.IOException;
+
+import org.opendaylight.yangtools.yang.data.api.schema.stream.NormalizedNodeStreamWriter;
+import org.opendaylight.yangtools.yang.model.api.ChoiceCaseNode;
+
+class CaseNodeDataWithSchema extends CompositeNodeDataWithSchema {
+
+    public CaseNodeDataWithSchema(final ChoiceCaseNode schema) {
+        super(schema);
+    }
+
+    @Override
+    protected void writeToStream(final NormalizedNodeStreamWriter nnStreamWriter) throws IOException {
+        super.writeToStream(nnStreamWriter);
+    }
+}
diff --git a/yang/yang-data-codec-gson/src/main/java/org/opendaylight/yangtools/yang/data/codec/gson/ChoiceNodeDataWithSchema.java b/yang/yang-data-codec-gson/src/main/java/org/opendaylight/yangtools/yang/data/codec/gson/ChoiceNodeDataWithSchema.java
new file mode 100644 (file)
index 0000000..39c1589
--- /dev/null
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 2014 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.yangtools.yang.data.codec.gson;
+
+import static org.opendaylight.yangtools.yang.data.api.schema.stream.NormalizedNodeStreamWriter.UNKNOWN_SIZE;
+
+import java.io.IOException;
+
+import org.opendaylight.yangtools.yang.data.api.schema.stream.NormalizedNodeStreamWriter;
+import org.opendaylight.yangtools.yang.model.api.ChoiceCaseNode;
+import org.opendaylight.yangtools.yang.model.api.ChoiceNode;
+import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
+
+/**
+ *
+ * childs - empty augment - only one element can be
+ *
+ */
+class ChoiceNodeDataWithSchema extends CompositeNodeDataWithSchema {
+
+    private CaseNodeDataWithSchema caseNodeDataWithSchema;
+
+    public ChoiceNodeDataWithSchema(final ChoiceNode schema) {
+        super(schema);
+    }
+
+    @Override
+    public CompositeNodeDataWithSchema addCompositeChild(final DataSchemaNode schema) {
+        CaseNodeDataWithSchema newChild = new CaseNodeDataWithSchema((ChoiceCaseNode) schema);
+        caseNodeDataWithSchema = newChild;
+        addCompositeChild(newChild);
+        return newChild;
+    }
+
+    public CaseNodeDataWithSchema getCase() {
+        return caseNodeDataWithSchema;
+    }
+
+    @Override
+    protected void writeToStream(final NormalizedNodeStreamWriter nnStreamWriter) throws IOException {
+        nnStreamWriter.startChoiceNode(provideNodeIdentifier(), UNKNOWN_SIZE);
+        super.writeToStream(nnStreamWriter);
+        nnStreamWriter.endNode();
+    }
+
+}
diff --git a/yang/yang-data-codec-gson/src/main/java/org/opendaylight/yangtools/yang/data/codec/gson/CompositeNodeDataWithSchema.java b/yang/yang-data-codec-gson/src/main/java/org/opendaylight/yangtools/yang/data/codec/gson/CompositeNodeDataWithSchema.java
new file mode 100644 (file)
index 0000000..83d715c
--- /dev/null
@@ -0,0 +1,234 @@
+/*
+ * Copyright (c) 2014 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.yangtools.yang.data.codec.gson;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Deque;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Set;
+
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.AugmentationIdentifier;
+import org.opendaylight.yangtools.yang.data.api.schema.stream.NormalizedNodeStreamWriter;
+import org.opendaylight.yangtools.yang.model.api.AnyXmlSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.AugmentationSchema;
+import org.opendaylight.yangtools.yang.model.api.AugmentationTarget;
+import org.opendaylight.yangtools.yang.model.api.ChoiceCaseNode;
+import org.opendaylight.yangtools.yang.model.api.ChoiceNode;
+import org.opendaylight.yangtools.yang.model.api.ContainerSchemaNode;
+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.ListSchemaNode;
+
+class CompositeNodeDataWithSchema extends AbstractNodeDataWithSchema {
+
+    /**
+     * nodes which were added to schema via augmentation and are present in data input
+     */
+    protected Map<AugmentationSchema, List<AbstractNodeDataWithSchema>> augmentationsToChild = new HashMap<>();
+
+    /**
+     * remaining data nodes (which aren't added via augment). Every of them should have the same QName
+     */
+    protected List<AbstractNodeDataWithSchema> childs = new ArrayList<>();
+
+    public CompositeNodeDataWithSchema(final DataSchemaNode schema) {
+        super(schema);
+    }
+
+    public AbstractNodeDataWithSchema addSimpleChild(final DataSchemaNode schema) {
+        SimpleNodeDataWithSchema newChild = null;
+        if (schema instanceof LeafSchemaNode) {
+            newChild = new LeafNodeDataWithSchema(schema);
+        } else if (schema instanceof AnyXmlSchemaNode) {
+            newChild = new AnyXmlNodeDataWithSchema(schema);
+        }
+
+        if (newChild != null) {
+
+            AugmentationSchema augSchema = null;
+            if (schema.isAugmenting()) {
+                augSchema = findCorrespondingAugment(getSchema(), schema);
+            }
+            if (augSchema != null) {
+                addChildToAugmentation(augSchema, newChild);
+            } else {
+                addChild(newChild);
+            }
+            return newChild;
+        }
+        return null;
+    }
+
+    private void addChildToAugmentation(final AugmentationSchema augSchema, final AbstractNodeDataWithSchema newChild) {
+        List<AbstractNodeDataWithSchema> childsInAugment = augmentationsToChild.get(augSchema);
+        if (childsInAugment == null) {
+            childsInAugment = new ArrayList<>();
+            augmentationsToChild.put(augSchema, childsInAugment);
+        }
+        childsInAugment.add(newChild);
+    }
+
+    public AbstractNodeDataWithSchema addChild(final Deque<DataSchemaNode> schemas) {
+        if (schemas.size() == 1) {
+            final DataSchemaNode childDataSchemaNode = schemas.pop();
+            return addChild(childDataSchemaNode);
+        } else {
+            DataSchemaNode choiceCandidate = schemas.pop();
+            DataSchemaNode caseCandidate = schemas.pop();
+            ChoiceNode choiceNode = null;
+            ChoiceCaseNode caseNode = null;
+            if (choiceCandidate instanceof ChoiceNode) {
+                choiceNode = (ChoiceNode) choiceCandidate;
+            } else {
+                throw new IllegalArgumentException("Awaited node of type ChoiceNode but was "
+                        + choiceCandidate.getClass().getSimpleName());
+            }
+
+            if (caseCandidate instanceof ChoiceCaseNode) {
+                caseNode = (ChoiceCaseNode) caseCandidate;
+            } else {
+                throw new IllegalArgumentException("Awaited node of type ChoiceCaseNode but was "
+                        + caseCandidate.getClass().getSimpleName());
+            }
+
+            AugmentationSchema augSchema = null;
+            if (choiceCandidate.isAugmenting()) {
+                augSchema = findCorrespondingAugment(getSchema(), choiceCandidate);
+            }
+
+            // looking for existing choice
+            List<AbstractNodeDataWithSchema> childNodes = Collections.emptyList();
+            if (augSchema != null) {
+                childNodes = augmentationsToChild.get(augSchema);
+            } else {
+                childNodes = childs;
+            }
+
+            CompositeNodeDataWithSchema caseNodeDataWithSchema = findChoice(childNodes, choiceCandidate, caseCandidate);
+            if (caseNodeDataWithSchema == null) {
+                ChoiceNodeDataWithSchema choiceNodeDataWithSchema = new ChoiceNodeDataWithSchema(choiceNode);
+                addChild(choiceNodeDataWithSchema);
+                caseNodeDataWithSchema = choiceNodeDataWithSchema.addCompositeChild(caseNode);
+            }
+
+            return caseNodeDataWithSchema.addChild(schemas);
+        }
+
+    }
+
+    private CaseNodeDataWithSchema findChoice(final List<AbstractNodeDataWithSchema> childNodes, final DataSchemaNode choiceCandidate,
+            final DataSchemaNode caseCandidate) {
+        if (childNodes == null) {
+            return null;
+        }
+        for (AbstractNodeDataWithSchema nodeDataWithSchema : childNodes) {
+            if (nodeDataWithSchema instanceof ChoiceNodeDataWithSchema
+                    && nodeDataWithSchema.getSchema().getQName().equals(choiceCandidate.getQName())) {
+                CaseNodeDataWithSchema casePrevious = ((ChoiceNodeDataWithSchema) nodeDataWithSchema).getCase();
+                if (casePrevious.getSchema().getQName() != caseCandidate.getQName()) {
+                    throw new IllegalArgumentException("Data from case " + caseCandidate.getQName()
+                            + " are specified but other data from case " + casePrevious.getSchema().getQName()
+                            + " were specified erlier. Data aren't from the same case.");
+                }
+                return casePrevious;
+            }
+        }
+        return null;
+    }
+
+    public AbstractNodeDataWithSchema addCompositeChild(final DataSchemaNode schema) {
+        CompositeNodeDataWithSchema newChild;
+        if (schema instanceof ListSchemaNode) {
+            newChild = new ListNodeDataWithSchema(schema);
+        } else if (schema instanceof LeafListSchemaNode) {
+            newChild = new LeafListNodeDataWithSchema(schema);
+        } else if (schema instanceof ContainerSchemaNode) {
+            newChild = new ContainerNodeDataWithSchema(schema);
+        } else {
+            newChild = new CompositeNodeDataWithSchema(schema);
+        }
+        addCompositeChild(newChild);
+        return newChild;
+    }
+
+    public void addCompositeChild(final CompositeNodeDataWithSchema newChild) {
+        AugmentationSchema augSchema = findCorrespondingAugment(getSchema(), newChild.getSchema());
+        if (augSchema != null) {
+            addChildToAugmentation(augSchema, newChild);
+        } else {
+            addChild(newChild);
+        }
+    }
+
+    private AbstractNodeDataWithSchema addChild(final DataSchemaNode schema) {
+        AbstractNodeDataWithSchema newChild = addSimpleChild(schema);
+        return newChild == null ? addCompositeChild(schema) : newChild;
+    }
+
+    public void addChild(final AbstractNodeDataWithSchema newChild) {
+        childs.add(newChild);
+    }
+
+    /**
+     * Tries to find in {@code parent} which is dealed as augmentation target node with QName as {@code child}. If such
+     * node is found then it is returned, else null.
+     */
+    protected AugmentationSchema findCorrespondingAugment(final DataSchemaNode parent, final DataSchemaNode child) {
+        if (parent instanceof AugmentationTarget) {
+            for (AugmentationSchema augmentation : ((AugmentationTarget) parent).getAvailableAugmentations()) {
+                DataSchemaNode childInAugmentation = augmentation.getDataChildByName(child.getQName());
+                if (childInAugmentation != null) {
+                    return augmentation;
+                }
+            }
+        }
+        return null;
+    }
+
+    @Override
+    protected void writeToStream(final NormalizedNodeStreamWriter nnStreamWriter) throws IOException {
+        for (AbstractNodeDataWithSchema child : childs) {
+            child.writeToStream(nnStreamWriter);
+        }
+        for (Entry<AugmentationSchema, List<AbstractNodeDataWithSchema>> augmentationToChild : augmentationsToChild.entrySet()) {
+
+            final List<AbstractNodeDataWithSchema> childsFromAgumentation = augmentationToChild.getValue();
+
+            if (!childsFromAgumentation.isEmpty()) {
+                nnStreamWriter.startAugmentationNode(toAugmentationIdentifier(augmentationToChild));
+
+                for (AbstractNodeDataWithSchema nodeDataWithSchema : childsFromAgumentation) {
+                    nodeDataWithSchema.writeToStream(nnStreamWriter);
+                }
+
+                nnStreamWriter.endNode();
+            }
+        }
+    }
+
+    private static AugmentationIdentifier toAugmentationIdentifier(
+            final Entry<AugmentationSchema, List<AbstractNodeDataWithSchema>> augmentationToChild) {
+        Collection<DataSchemaNode> nodes = augmentationToChild.getKey().getChildNodes();
+        Set<QName> nodesQNames = new HashSet<>();
+        for (DataSchemaNode node : nodes) {
+            nodesQNames.add(node.getQName());
+        }
+
+        return new AugmentationIdentifier(nodesQNames);
+    }
+
+}
diff --git a/yang/yang-data-codec-gson/src/main/java/org/opendaylight/yangtools/yang/data/codec/gson/ContainerNodeDataWithSchema.java b/yang/yang-data-codec-gson/src/main/java/org/opendaylight/yangtools/yang/data/codec/gson/ContainerNodeDataWithSchema.java
new file mode 100644 (file)
index 0000000..c49d71b
--- /dev/null
@@ -0,0 +1,30 @@
+/*
+ * Copyright (c) 2014 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.yangtools.yang.data.codec.gson;
+
+import static org.opendaylight.yangtools.yang.data.api.schema.stream.NormalizedNodeStreamWriter.UNKNOWN_SIZE;
+
+import java.io.IOException;
+
+import org.opendaylight.yangtools.yang.data.api.schema.stream.NormalizedNodeStreamWriter;
+import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
+
+class ContainerNodeDataWithSchema extends CompositeNodeDataWithSchema {
+
+    public ContainerNodeDataWithSchema(final DataSchemaNode schema) {
+        super(schema);
+    }
+
+    @Override
+    protected void writeToStream(final NormalizedNodeStreamWriter nnStreamWriter) throws IOException {
+        nnStreamWriter.startContainerNode(provideNodeIdentifier(), UNKNOWN_SIZE);
+        super.writeToStream(nnStreamWriter);
+        nnStreamWriter.endNode();
+    }
+
+}
diff --git a/yang/yang-data-codec-gson/src/main/java/org/opendaylight/yangtools/yang/data/codec/gson/JSONNormalizedNodeStreamWriter.java b/yang/yang-data-codec-gson/src/main/java/org/opendaylight/yangtools/yang/data/codec/gson/JSONNormalizedNodeStreamWriter.java
new file mode 100644 (file)
index 0000000..16428cd
--- /dev/null
@@ -0,0 +1,314 @@
+/*
+ * Copyright (c) 2014 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.yangtools.yang.data.codec.gson;
+
+import com.google.common.base.Preconditions;
+import com.google.common.base.Strings;
+import com.google.gson.stream.JsonWriter;
+
+import java.io.IOException;
+import java.io.Writer;
+import java.net.URI;
+import java.util.ArrayDeque;
+import java.util.Deque;
+
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.AugmentationIdentifier;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifier;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifierWithPredicates;
+import org.opendaylight.yangtools.yang.data.api.schema.stream.NormalizedNodeStreamWriter;
+import org.opendaylight.yangtools.yang.model.api.Module;
+import org.opendaylight.yangtools.yang.model.api.SchemaContext;
+
+/**
+ * This implementation will create JSON output as output stream.
+ *
+ * Values of leaf and leaf-list are NOT translated according to codecs.
+ *
+ * FIXME: rewrite this in terms of {@link JsonWriter}.
+ */
+public class JSONNormalizedNodeStreamWriter implements NormalizedNodeStreamWriter {
+
+    private static enum NodeType {
+        OBJECT,
+        LIST,
+        OTHER,
+    }
+
+    private static class TypeInfo {
+        private boolean hasAtLeastOneChild = false;
+        private final NodeType type;
+        private final URI uri;
+
+        public TypeInfo(final NodeType type, final URI uri) {
+            this.type = type;
+            this.uri = uri;
+        }
+
+        public void setHasAtLeastOneChild(final boolean hasChildren) {
+            this.hasAtLeastOneChild = hasChildren;
+        }
+
+        public NodeType getType() {
+            return type;
+        }
+
+        public URI getNamespace() {
+            return uri;
+        }
+
+        public boolean hasAtLeastOneChild() {
+            return hasAtLeastOneChild;
+        }
+    }
+
+    private final Deque<TypeInfo> stack = new ArrayDeque<>();
+    private final SchemaContext schemaContext;
+    private final Writer writer;
+    private final String indent;
+
+    private URI currentNamespace = null;
+    private int currentDepth = 0;
+
+    private JSONNormalizedNodeStreamWriter(final SchemaContext schemaContext,
+            final Writer writer, final int indentSize) {
+        this.schemaContext = Preconditions.checkNotNull(schemaContext);
+        this.writer = Preconditions.checkNotNull(writer);
+
+        Preconditions.checkArgument(indentSize >= 0, "Indent size must be non-negative");
+
+        if (indentSize != 0) {
+            indent = Strings.repeat(" ", indentSize);
+        } else {
+            indent = null;
+        }
+    }
+
+    /**
+     * Create a new stream writer, which writes to the specified {@link Writer}.
+     *
+     * @param schemaContext Schema context
+     * @param writer Output writer
+     * @return A stream writer instance
+     */
+    public static NormalizedNodeStreamWriter create(final SchemaContext schemaContext, final Writer writer) {
+        return new JSONNormalizedNodeStreamWriter(schemaContext, writer, 0);
+    }
+
+    /**
+     * Create a new stream writer, which writes to the specified output stream.
+     *
+     * @param schemaContext Schema context
+     * @param writer Output writer
+     * @param indentSize indentation size
+     * @return A stream writer instance
+     */
+    public static NormalizedNodeStreamWriter create(final SchemaContext schemaContext, final Writer writer, final int indentSize) {
+        return new JSONNormalizedNodeStreamWriter(schemaContext, writer, indentSize);
+    }
+
+    @Override
+    public void leafNode(final NodeIdentifier name, final Object value) throws IOException {
+        separateElementFromPreviousElement();
+        writeJsonIdentifier(name);
+        currentNamespace = stack.peek().getNamespace();
+        writeValue(value.toString());
+        separateNextSiblingsWithComma();
+    }
+
+    @Override
+    public void startLeafSet(final NodeIdentifier name, final int childSizeHint) throws IOException {
+        separateElementFromPreviousElement();
+        stack.push(new TypeInfo(NodeType.LIST, name.getNodeType().getNamespace()));
+        writeJsonIdentifier(name);
+        writeStartList();
+        indentRight();
+    }
+
+    @Override
+    public void leafSetEntryNode(final Object value) throws IOException {
+        separateElementFromPreviousElement();
+        writeValue(value.toString());
+        separateNextSiblingsWithComma();
+    }
+
+    @Override
+    public void startContainerNode(final NodeIdentifier name, final int childSizeHint) throws IOException {
+        separateElementFromPreviousElement();
+        stack.push(new TypeInfo(NodeType.OBJECT, name.getNodeType().getNamespace()));
+        writeJsonIdentifier(name);
+        writeStartObject();
+        indentRight();
+    }
+
+    @Override
+    public void startUnkeyedList(final NodeIdentifier name, final int childSizeHint) throws IOException {
+        separateElementFromPreviousElement();
+        stack.push(new TypeInfo(NodeType.LIST, name.getNodeType().getNamespace()));
+        writeJsonIdentifier(name);
+        writeStartList();
+        indentRight();
+    }
+
+    @Override
+    public void startUnkeyedListItem(final NodeIdentifier name, final int childSizeHint) throws IOException {
+        stack.push(new TypeInfo(NodeType.OBJECT, name.getNodeType().getNamespace()));
+        separateElementFromPreviousElement();
+        writeStartObject();
+        indentRight();
+    }
+
+    @Override
+    public void startMapNode(final NodeIdentifier name, final int childSizeHint) throws IOException {
+        separateElementFromPreviousElement();
+        stack.push(new TypeInfo(NodeType.LIST, name.getNodeType().getNamespace()));
+        writeJsonIdentifier(name);
+        writeStartList();
+        indentRight();
+    }
+
+    @Override
+    public void startMapEntryNode(final NodeIdentifierWithPredicates identifier, final int childSizeHint)
+            throws IOException {
+        stack.push(new TypeInfo(NodeType.OBJECT, identifier.getNodeType().getNamespace()));
+        separateElementFromPreviousElement();
+        writeStartObject();
+        indentRight();
+    }
+
+    @Override
+    public void startOrderedMapNode(final NodeIdentifier name, final int childSizeHint) throws IOException {
+        stack.push(new TypeInfo(NodeType.LIST, name.getNodeType().getNamespace()));
+        separateElementFromPreviousElement();
+        writeJsonIdentifier(name);
+        writeStartList();
+        indentRight();
+    }
+
+    @Override
+    public void startChoiceNode(final NodeIdentifier name, final int childSizeHint) throws IllegalArgumentException {
+        handleInvisibleNode(name.getNodeType().getNamespace());
+    }
+
+    @Override
+    public void startAugmentationNode(final AugmentationIdentifier identifier) throws IllegalArgumentException {
+        handleInvisibleNode(currentNamespace);
+    }
+
+    @Override
+    public void anyxmlNode(final NodeIdentifier name, final Object value) throws IOException {
+        separateElementFromPreviousElement();
+        writeJsonIdentifier(name);
+        currentNamespace = stack.peek().getNamespace();
+        writeValue(value.toString());
+        separateNextSiblingsWithComma();
+    }
+
+    @Override
+    public void endNode() throws IOException {
+        switch (stack.peek().getType()) {
+        case LIST:
+            indentLeft();
+            newLine();
+            writer.append(']');
+            break;
+        case OBJECT:
+            indentLeft();
+            newLine();
+            writer.append('}');
+            break;
+        default:
+            break;
+        }
+        stack.pop();
+        currentNamespace = stack.isEmpty() ? null : stack.peek().getNamespace();
+        separateNextSiblingsWithComma();
+    }
+
+    private void separateElementFromPreviousElement() throws IOException {
+        if (!stack.isEmpty() && stack.peek().hasAtLeastOneChild()) {
+            writer.append(',');
+        }
+        newLine();
+    }
+
+    private void newLine() throws IOException {
+        if (indent != null) {
+            writer.append('\n');
+
+            for (int i = 0; i < currentDepth; i++) {
+                writer.append(indent);
+            }
+        }
+    }
+
+    private void separateNextSiblingsWithComma() {
+        if (!stack.isEmpty()) {
+            stack.peek().setHasAtLeastOneChild(true);
+        }
+    }
+
+    /**
+     * Invisible nodes have to be also pushed to stack because of pairing of start*() and endNode() methods. Information
+     * about child existing (due to printing comma) has to be transfered to invisible node.
+     */
+    private void handleInvisibleNode(final URI uri) {
+        TypeInfo typeInfo = new TypeInfo(NodeType.OTHER, uri);
+        typeInfo.setHasAtLeastOneChild(stack.peek().hasAtLeastOneChild());
+        stack.push(typeInfo);
+    }
+
+    private void writeStartObject() throws IOException {
+        writer.append('{');
+    }
+
+    private void writeStartList() throws IOException {
+        writer.append('[');
+    }
+
+    private void writeModulName(final URI namespace) throws IOException {
+        if (this.currentNamespace == null || namespace != this.currentNamespace) {
+            Module module = schemaContext.findModuleByNamespaceAndRevision(namespace, null);
+            writer.append(module.getName());
+            writer.append(':');
+            currentNamespace = namespace;
+        }
+    }
+
+    private void writeValue(final String value) throws IOException {
+        writer.append('"');
+        writer.append(value);
+        writer.append('"');
+    }
+
+    private void writeJsonIdentifier(final NodeIdentifier name) throws IOException {
+        writer.append('"');
+        writeModulName(name.getNodeType().getNamespace());
+        writer.append(name.getNodeType().getLocalName());
+        writer.append("\":");
+    }
+
+    private void indentRight() {
+        currentDepth++;
+    }
+
+    private void indentLeft() {
+        currentDepth--;
+    }
+
+    @Override
+    public void flush() throws IOException {
+        writer.flush();
+    }
+
+    @Override
+    public void close() throws IOException {
+        writer.flush();
+        writer.close();
+    }
+
+}
diff --git a/yang/yang-data-codec-gson/src/main/java/org/opendaylight/yangtools/yang/data/codec/gson/JsonParserStream.java b/yang/yang-data-codec-gson/src/main/java/org/opendaylight/yangtools/yang/data/codec/gson/JsonParserStream.java
new file mode 100644 (file)
index 0000000..18232ff
--- /dev/null
@@ -0,0 +1,388 @@
+/*
+ * Copyright (c) 2014 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+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;
+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;
+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.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
+ * default GSON JsonParser.
+ */
+@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 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);
+    }
+
+    public static JsonParserStream create(final NormalizedNodeStreamWriter writer, final SchemaContext schemaContext) {
+        return new JsonParserStream(writer, schemaContext);
+    }
+
+    public JsonParserStream parse(final JsonReader reader) throws JsonIOException, JsonSyntaxException {
+        // code copied from gson's JsonParser and Stream classes
+
+        boolean lenient = reader.isLenient();
+        reader.setLenient(true);
+        boolean isEmpty = true;
+        try {
+            reader.peek();
+            isEmpty = false;
+            CompositeNodeDataWithSchema compositeNodeDataWithSchema = new CompositeNodeDataWithSchema(schema);
+            read(reader, compositeNodeDataWithSchema);
+            compositeNodeDataWithSchema.writeToStream(writer);
+
+            return this;
+            // return read(reader);
+        } catch (EOFException e) {
+            if (isEmpty) {
+                return this;
+                // return JsonNull.INSTANCE;
+            }
+            // The stream ended prematurely so it is likely a syntax error.
+            throw new JsonSyntaxException(e);
+        } catch (MalformedJsonException e) {
+            throw new JsonSyntaxException(e);
+        } catch (IOException e) {
+            throw new JsonIOException(e);
+        } catch (NumberFormatException e) {
+            throw new JsonSyntaxException(e);
+        } catch (StackOverflowError | OutOfMemoryError e) {
+            throw new JsonParseException("Failed parsing JSON source: " + reader + " to Json", e);
+        } finally {
+            reader.setLenient(lenient);
+        }
+    }
+
+    public void read(final JsonReader in, final AbstractNodeDataWithSchema parent) throws IOException {
+
+        final JsonToken peek = in.peek();
+        Optional<String> value = Optional.absent();
+        switch (peek) {
+        case STRING:
+        case NUMBER:
+            value = Optional.of(in.nextString());
+            break;
+        case BOOLEAN:
+            value = Optional.of(Boolean.toString(in.nextBoolean()));
+            break;
+        case NULL:
+            in.nextNull();
+            value = Optional.of((String) null);
+            break;
+        default:
+            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()) {
+                AbstractNodeDataWithSchema newChild = null;
+                if (parent instanceof ListNodeDataWithSchema) {
+                    newChild = new ListEntryNodeDataWithSchema(parent.getSchema());
+                    ((CompositeNodeDataWithSchema) parent).addChild(newChild);
+                } else if (parent instanceof LeafListNodeDataWithSchema) {
+                    newChild = new LeafListEntryNodeDataWithSchema(parent.getSchema());
+                    ((CompositeNodeDataWithSchema) parent).addChild(newChild);
+                }
+                read(in, newChild);
+            }
+            in.endArray();
+            return;
+        case BEGIN_OBJECT:
+            Set<String> namesakes = new HashSet<>();
+            in.beginObject();
+            while (in.hasNext()) {
+                final String jsonElementName = in.nextName();
+                final NamespaceAndName namespaceAndName = resolveNamespace(jsonElementName);
+                final String localName = namespaceAndName.getName();
+                addNamespace(namespaceAndName.getUri());
+                if (namesakes.contains(jsonElementName)) {
+                    throw new JsonSyntaxException("Duplicate name " + jsonElementName + " in JSON input.");
+                }
+                namesakes.add(jsonElementName);
+                final Deque<DataSchemaNode> childDataSchemaNodes = findSchemaNodeByNameAndNamespace(parent.getSchema(),
+                        localName, getCurrentNamespace());
+                if (childDataSchemaNodes.isEmpty()) {
+                    throw new IllegalStateException("Schema for node with name " + localName + " and namespace "
+                            + getCurrentNamespace() + " doesn't exist.");
+                }
+
+                AbstractNodeDataWithSchema newChild;
+                newChild = ((CompositeNodeDataWithSchema) parent).addChild(childDataSchemaNodes);
+//                FIXME:anyxml data shouldn't be skipped but should be loaded somehow. will be specified after 17AUG2014
+                if (newChild instanceof AnyXmlNodeDataWithSchema) {
+                    in.skipValue();
+                } else {
+                    read(in, newChild);
+                }
+                removeNamespace();
+            }
+            in.endObject();
+            return;
+        case END_DOCUMENT:
+        case NAME:
+        case END_OBJECT:
+        case END_ARRAY:
+        }
+    }
+
+    private Object translateValueByType(final String value, final DataSchemaNode node) {
+        final TypeDefinition<? extends Object> typeDefinition = typeDefinition(node);
+        if (typeDefinition == null) {
+            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);
+    }
+
+    private static TypeDefinition<? extends Object> typeDefinition(final DataSchemaNode node) {
+        TypeDefinition<?> baseType = null;
+        if (node instanceof LeafListSchemaNode) {
+            baseType = ((LeafListSchemaNode) node).getType();
+        } else if (node instanceof LeafSchemaNode) {
+            baseType = ((LeafSchemaNode) node).getType();
+        } else if (node instanceof AnyXmlSchemaNode) {
+            return null;
+        } else {
+            throw new IllegalArgumentException("Unhandled parameter types: " + Arrays.<Object> asList(node).toString());
+        }
+
+        if (baseType != null) {
+            while (baseType.getBaseType() != null) {
+                baseType = baseType.getBaseType();
+            }
+        }
+        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();
+    }
+
+    private void addNamespace(final Optional<URI> namespace) {
+        if (!namespace.isPresent()) {
+            if (namespaces.isEmpty()) {
+                throw new IllegalStateException("Namespace has to be specified at top level.");
+            } else {
+                namespaces.push(namespaces.peek());
+            }
+        } else {
+            namespaces.push(namespace.get());
+        }
+    }
+
+    private NamespaceAndName resolveNamespace(final String childName) {
+        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);
+        } else {
+            nodeNamePart = childName;
+        }
+
+        Optional<URI> namespaceOpt = namespace == null ? Optional.<URI> absent() : Optional.of(namespace);
+        return new NamespaceAndName(nodeNamePart, namespaceOpt);
+    }
+
+    private URI getCurrentNamespace() {
+        return namespaces.peek();
+    }
+
+    /**
+     * Returns stack of schema nodes via which it was necessary to prass 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
+     *         (where n is number of choices through it was passed)
+     */
+    private Deque<DataSchemaNode> findSchemaNodeByNameAndNamespace(final DataSchemaNode dataSchemaNode,
+            final String childName, final URI namespace) {
+        final Deque<DataSchemaNode> result = new ArrayDeque<>();
+        List<ChoiceNode> childChoices = new ArrayList<>();
+        if (dataSchemaNode instanceof DataNodeContainer) {
+            for (DataSchemaNode childNode : ((DataNodeContainer) dataSchemaNode).getChildNodes()) {
+                if (childNode instanceof ChoiceNode) {
+                    childChoices.add((ChoiceNode) childNode);
+                } else {
+                    final QName childQName = childNode.getQName();
+                    if (childQName.getLocalName().equals(childName) && childQName.getNamespace().equals(namespace)) {
+                        result.push(childNode);
+                        return result;
+                    }
+                }
+            }
+        }
+        // try to find data schema node in choice (looking for first match)
+        for (ChoiceNode choiceNode : childChoices) {
+            for (ChoiceCaseNode concreteCase : choiceNode.getCases()) {
+                Deque<DataSchemaNode> resultFromRecursion = findSchemaNodeByNameAndNamespace(concreteCase, childName,
+                        namespace);
+                if (!resultFromRecursion.isEmpty()) {
+                    resultFromRecursion.push(concreteCase);
+                    resultFromRecursion.push(choiceNode);
+                    return resultFromRecursion;
+                }
+            }
+        }
+        return result;
+    }
+
+    private static class NamespaceAndName {
+        private final Optional<URI> uri;
+        private final String name;
+
+        public NamespaceAndName(final String name, final Optional<URI> uri) {
+            this.name = name;
+            this.uri = uri;
+        }
+
+        public String getName() {
+            return name;
+        }
+
+        public Optional<URI> getUri() {
+            return uri;
+        }
+    }
+
+    @Override
+    public void flush() throws IOException {
+        writer.flush();
+    }
+
+    @Override
+    public void close() throws IOException {
+        writer.flush();
+        writer.close();
+    }
+}
diff --git a/yang/yang-data-codec-gson/src/main/java/org/opendaylight/yangtools/yang/data/codec/gson/LeafListEntryNodeDataWithSchema.java b/yang/yang-data-codec-gson/src/main/java/org/opendaylight/yangtools/yang/data/codec/gson/LeafListEntryNodeDataWithSchema.java
new file mode 100644 (file)
index 0000000..e53367c
--- /dev/null
@@ -0,0 +1,24 @@
+/*
+ * Copyright (c) 2014 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.yangtools.yang.data.codec.gson;
+
+import java.io.IOException;
+
+import org.opendaylight.yangtools.yang.data.api.schema.stream.NormalizedNodeStreamWriter;
+import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
+
+class LeafListEntryNodeDataWithSchema extends SimpleNodeDataWithSchema {
+    public LeafListEntryNodeDataWithSchema(final DataSchemaNode dataSchemaNode) {
+        super(dataSchemaNode);
+    }
+
+    @Override
+    protected void writeToStream(final NormalizedNodeStreamWriter nnStreamWriter) throws IOException {
+        nnStreamWriter.leafSetEntryNode(getValue());
+    }
+}
diff --git a/yang/yang-data-codec-gson/src/main/java/org/opendaylight/yangtools/yang/data/codec/gson/LeafListNodeDataWithSchema.java b/yang/yang-data-codec-gson/src/main/java/org/opendaylight/yangtools/yang/data/codec/gson/LeafListNodeDataWithSchema.java
new file mode 100644 (file)
index 0000000..8b23acd
--- /dev/null
@@ -0,0 +1,28 @@
+/*
+ * Copyright (c) 2014 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.yangtools.yang.data.codec.gson;
+
+import static org.opendaylight.yangtools.yang.data.api.schema.stream.NormalizedNodeStreamWriter.UNKNOWN_SIZE;
+
+import java.io.IOException;
+
+import org.opendaylight.yangtools.yang.data.api.schema.stream.NormalizedNodeStreamWriter;
+import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
+
+class LeafListNodeDataWithSchema extends CompositeNodeDataWithSchema {
+    public LeafListNodeDataWithSchema(final DataSchemaNode schema) {
+        super(schema);
+    }
+
+    @Override
+    protected void writeToStream(final NormalizedNodeStreamWriter nnStreamWriter) throws IOException {
+        nnStreamWriter.startLeafSet(provideNodeIdentifier(), UNKNOWN_SIZE);
+        super.writeToStream(nnStreamWriter);
+        nnStreamWriter.endNode();
+    }
+}
diff --git a/yang/yang-data-codec-gson/src/main/java/org/opendaylight/yangtools/yang/data/codec/gson/LeafNodeDataWithSchema.java b/yang/yang-data-codec-gson/src/main/java/org/opendaylight/yangtools/yang/data/codec/gson/LeafNodeDataWithSchema.java
new file mode 100644 (file)
index 0000000..c63422a
--- /dev/null
@@ -0,0 +1,26 @@
+/*
+ * Copyright (c) 2014 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.yangtools.yang.data.codec.gson;
+
+import java.io.IOException;
+
+import org.opendaylight.yangtools.yang.data.api.schema.stream.NormalizedNodeStreamWriter;
+import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
+
+class LeafNodeDataWithSchema extends SimpleNodeDataWithSchema {
+
+    public LeafNodeDataWithSchema(final DataSchemaNode schema) {
+        super(schema);
+    }
+
+    @Override
+    protected void writeToStream(final NormalizedNodeStreamWriter nnStreamWriter) throws IOException {
+        nnStreamWriter.leafNode(provideNodeIdentifier(), getValue());
+    }
+
+}
diff --git a/yang/yang-data-codec-gson/src/main/java/org/opendaylight/yangtools/yang/data/codec/gson/ListEntryNodeDataWithSchema.java b/yang/yang-data-codec-gson/src/main/java/org/opendaylight/yangtools/yang/data/codec/gson/ListEntryNodeDataWithSchema.java
new file mode 100644 (file)
index 0000000..b08add8
--- /dev/null
@@ -0,0 +1,77 @@
+/*
+ * Copyright (c) 2014 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.yangtools.yang.data.codec.gson;
+
+import static org.opendaylight.yangtools.yang.data.api.schema.stream.NormalizedNodeStreamWriter.UNKNOWN_SIZE;
+
+import java.io.IOException;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifierWithPredicates;
+import org.opendaylight.yangtools.yang.data.api.schema.stream.NormalizedNodeStreamWriter;
+import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.LeafSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.ListSchemaNode;
+
+class ListEntryNodeDataWithSchema extends CompositeNodeDataWithSchema {
+
+    private final Map<QName, SimpleNodeDataWithSchema> qNameToKeys = new HashMap<>();
+
+    public ListEntryNodeDataWithSchema(final DataSchemaNode schema) {
+        super(schema);
+    }
+
+    @Override
+    public void addChild(final AbstractNodeDataWithSchema newChild) {
+        DataSchemaNode childSchema = newChild.getSchema();
+        if (childSchema instanceof LeafSchemaNode && isPartOfKey((LeafSchemaNode) childSchema)) {
+            qNameToKeys.put(childSchema.getQName(), (SimpleNodeDataWithSchema)newChild);
+        }
+        super.addChild(newChild);
+    }
+
+    private boolean isPartOfKey(final LeafSchemaNode potentialKey) {
+        List<QName> keys = ((ListSchemaNode) getSchema()).getKeyDefinition();
+        for (QName qName : keys) {
+            if (qName.equals(potentialKey.getQName())) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    @Override
+    protected void writeToStream(final NormalizedNodeStreamWriter nnStreamWriter) throws IOException {
+        int keyCount = ((ListSchemaNode) getSchema()).getKeyDefinition().size();
+        if (keyCount == 0) {
+            nnStreamWriter.startUnkeyedListItem(provideNodeIdentifier(), UNKNOWN_SIZE);
+            super.writeToStream(nnStreamWriter);
+            nnStreamWriter.endNode();
+        } else if (keyCount == qNameToKeys.size()) {
+            nnStreamWriter.startMapEntryNode(provideNodeIdentifierWithPredicates(), UNKNOWN_SIZE);
+            super.writeToStream(nnStreamWriter);
+            nnStreamWriter.endNode();
+        } else {
+            throw new IllegalStateException("Some of keys of " + getSchema().getQName() + " are missing in input.");
+        }
+    }
+
+    private NodeIdentifierWithPredicates provideNodeIdentifierWithPredicates() {
+        Map<QName, Object> qNameToPredicateValues = new HashMap<>();
+
+        for (SimpleNodeDataWithSchema simpleNodeDataWithSchema : qNameToKeys.values()) {
+            qNameToPredicateValues.put(simpleNodeDataWithSchema.getSchema().getQName(), simpleNodeDataWithSchema.getValue());
+        }
+
+        return new NodeIdentifierWithPredicates(getSchema().getQName(), qNameToPredicateValues);
+    }
+
+}
diff --git a/yang/yang-data-codec-gson/src/main/java/org/opendaylight/yangtools/yang/data/codec/gson/ListNodeDataWithSchema.java b/yang/yang-data-codec-gson/src/main/java/org/opendaylight/yangtools/yang/data/codec/gson/ListNodeDataWithSchema.java
new file mode 100644 (file)
index 0000000..612c386
--- /dev/null
@@ -0,0 +1,35 @@
+/*
+ * Copyright (c) 2014 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.yangtools.yang.data.codec.gson;
+
+import static org.opendaylight.yangtools.yang.data.api.schema.stream.NormalizedNodeStreamWriter.UNKNOWN_SIZE;
+
+import java.io.IOException;
+
+import org.opendaylight.yangtools.yang.data.api.schema.stream.NormalizedNodeStreamWriter;
+import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.ListSchemaNode;
+
+class ListNodeDataWithSchema extends CompositeNodeDataWithSchema {
+
+    public ListNodeDataWithSchema(final DataSchemaNode schema) {
+        super(schema);
+    }
+
+    @Override
+    protected void writeToStream(final NormalizedNodeStreamWriter nnStreamWriter) throws IOException {
+        if (!((ListSchemaNode) getSchema()).getKeyDefinition().isEmpty()) {
+            nnStreamWriter.startMapNode(provideNodeIdentifier(), UNKNOWN_SIZE);
+        } else {
+            nnStreamWriter.startUnkeyedList(provideNodeIdentifier(), UNKNOWN_SIZE);
+        }
+        super.writeToStream(nnStreamWriter);
+        nnStreamWriter.endNode();
+    }
+
+}
diff --git a/yang/yang-data-codec-gson/src/main/java/org/opendaylight/yangtools/yang/data/codec/gson/SimpleNodeDataWithSchema.java b/yang/yang-data-codec-gson/src/main/java/org/opendaylight/yangtools/yang/data/codec/gson/SimpleNodeDataWithSchema.java
new file mode 100644 (file)
index 0000000..26d774c
--- /dev/null
@@ -0,0 +1,28 @@
+/*
+ * Copyright (c) 2014 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.yangtools.yang.data.codec.gson;
+
+import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
+
+abstract class SimpleNodeDataWithSchema extends AbstractNodeDataWithSchema {
+
+    private Object value;
+
+    public SimpleNodeDataWithSchema(final DataSchemaNode dataSchemaNode) {
+        super(dataSchemaNode);
+    }
+
+    void setValue(final Object value) {
+        this.value = value;
+    }
+
+    public Object getValue() {
+        return value;
+    }
+
+}
diff --git a/yang/yang-data-codec-gson/src/main/java/org/opendaylight/yangtools/yang/data/codec/gson/helpers/AbstractCodecImpl.java b/yang/yang-data-codec-gson/src/main/java/org/opendaylight/yangtools/yang/data/codec/gson/helpers/AbstractCodecImpl.java
new file mode 100644 (file)
index 0000000..407d866
--- /dev/null
@@ -0,0 +1,49 @@
+/*
+ * Copyright (c) 2014 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.yangtools.yang.data.codec.gson.helpers;
+
+import com.google.common.base.Preconditions;
+
+import java.net.URI;
+
+import org.opendaylight.yangtools.yang.model.api.Module;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+abstract class AbstractCodecImpl {
+    private static final Logger LOG = LoggerFactory.getLogger(AbstractCodecImpl.class);
+    private final SchemaContextUtils schema;
+
+    protected AbstractCodecImpl(final SchemaContextUtils schema) {
+        this.schema = Preconditions.checkNotNull(schema);
+    }
+
+    protected final SchemaContextUtils getSchema() {
+        return schema;
+    }
+
+    protected final Module getModuleByNamespace(final String namespace) {
+        URI validNamespace = resolveValidNamespace(namespace);
+
+        Module module = schema.findModuleByNamespace(validNamespace);
+        if (module == null) {
+            LOG.info("Module for namespace " + validNamespace + " wasn't found.");
+            return null;
+        }
+        return module;
+    }
+
+    protected final URI resolveValidNamespace(final String namespace) {
+        URI validNamespace = schema.findNamespaceByModuleName(namespace);
+        if (validNamespace == null) {
+            validNamespace = URI.create(namespace);
+        }
+
+        return validNamespace;
+    }
+}
diff --git a/yang/yang-data-codec-gson/src/main/java/org/opendaylight/yangtools/yang/data/codec/gson/helpers/IdentityValuesDTO.java b/yang/yang-data-codec-gson/src/main/java/org/opendaylight/yangtools/yang/data/codec/gson/helpers/IdentityValuesDTO.java
new file mode 100644 (file)
index 0000000..30ba2a0
--- /dev/null
@@ -0,0 +1,155 @@
+/*
+ * Copyright (c) 2014 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.yangtools.yang.data.codec.gson.helpers;
+
+import com.google.common.annotations.Beta;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+/**
+ * This class is implementation-internal and subject to change. Please do not use it.
+ */
+@Beta
+public final class IdentityValuesDTO {
+
+    private final List<IdentityValue> elementData = new ArrayList<>();
+    private final String originValue;
+
+    public IdentityValuesDTO(final String namespace, final String value, final String prefix, final String originValue) {
+        elementData.add(new IdentityValue(namespace, value, prefix));
+        this.originValue = originValue;
+    }
+
+    public IdentityValuesDTO(final String originValue) {
+        this.originValue = originValue;
+    }
+
+    public IdentityValuesDTO() {
+        originValue = null;
+    }
+
+    public void add(final String namespace, final String value, final String prefix) {
+        elementData.add(new IdentityValue(namespace, value, prefix));
+    }
+
+    public void add(final IdentityValue identityValue) {
+        elementData.add(identityValue);
+    }
+
+    public List<IdentityValue> getValuesWithNamespaces() {
+        return Collections.unmodifiableList(elementData);
+    }
+
+    @Override
+    public String toString() {
+        return elementData.toString();
+    }
+
+    public String getOriginValue() {
+        return originValue;
+    }
+
+    public static final class IdentityValue {
+
+        private final String namespace;
+        private final String value;
+        private final String prefix;
+        private List<Predicate> predicates;
+
+        public IdentityValue(final String namespace, final String value, final String prefix) {
+            this.namespace = namespace;
+            this.value = value;
+            this.prefix = prefix;
+        }
+
+        public String getNamespace() {
+            return namespace;
+        }
+
+        public String getValue() {
+            return value;
+        }
+
+        public String getPrefix() {
+            return prefix;
+        }
+
+        public List<Predicate> getPredicates() {
+            if (predicates == null) {
+                return Collections.emptyList();
+            }
+            return Collections.unmodifiableList(predicates);
+        }
+
+        public void setPredicates(final List<Predicate> predicates) {
+            this.predicates = predicates;
+        }
+
+        @Override
+        public String toString() {
+            StringBuilder sb = new StringBuilder();
+            if (namespace != null) {
+                sb.append(namespace);
+            }
+            if (prefix != null) {
+                sb.append("(").append(prefix).append(")");
+            }
+            if (value != null) {
+                sb.append(" - ").append(value);
+            }
+            if (predicates != null && !predicates.isEmpty()) {
+                for (Predicate predicate : predicates) {
+                    sb.append("[");
+                    predicate.toString();
+                    sb.append("]");
+                }
+            }
+            return sb.toString();
+        }
+
+    }
+
+    public static final class Predicate {
+
+        private final IdentityValue name;
+        private final String value;
+
+        public Predicate(final IdentityValue name, final String value) {
+            super();
+            this.name = name;
+            this.value = value;
+        }
+
+        public IdentityValue getName() {
+            return name;
+        }
+
+        public String getValue() {
+            return value;
+        }
+
+        @Override
+        public String toString() {
+            StringBuilder sb = new StringBuilder();
+            if (name != null) {
+                sb.append(name.toString());
+            }
+            if (value != null) {
+                sb.append("=").append(value);
+            }
+            return sb.toString();
+        }
+
+        public boolean isLeafList() {
+            return name == null ? true : false;
+        }
+
+    }
+}
diff --git a/yang/yang-data-codec-gson/src/main/java/org/opendaylight/yangtools/yang/data/codec/gson/helpers/IdentityrefCodecImpl.java b/yang/yang-data-codec-gson/src/main/java/org/opendaylight/yangtools/yang/data/codec/gson/helpers/IdentityrefCodecImpl.java
new file mode 100644 (file)
index 0000000..a8c8b8d
--- /dev/null
@@ -0,0 +1,42 @@
+/*
+ * Copyright (c) 2014 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.yangtools.yang.data.codec.gson.helpers;
+
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.data.api.codec.IdentityrefCodec;
+import org.opendaylight.yangtools.yang.data.codec.gson.helpers.IdentityValuesDTO.IdentityValue;
+import org.opendaylight.yangtools.yang.model.api.Module;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+class IdentityrefCodecImpl extends AbstractCodecImpl implements IdentityrefCodec<IdentityValuesDTO> {
+    private static final Logger LOG = LoggerFactory.getLogger(IdentityrefCodecImpl.class);
+
+    IdentityrefCodecImpl(final SchemaContextUtils schema) {
+        super(schema);
+    }
+
+    @Override
+    public IdentityValuesDTO serialize(final QName data) {
+        return new IdentityValuesDTO(data.getNamespace().toString(), data.getLocalName(), data.getPrefix(), null);
+    }
+
+    @Override
+    public QName deserialize(final IdentityValuesDTO data) {
+        IdentityValue valueWithNamespace = data.getValuesWithNamespaces().get(0);
+        Module module = getModuleByNamespace(valueWithNamespace.getNamespace());
+        if (module == null) {
+            LOG.info("Module was not found for namespace {}", valueWithNamespace.getNamespace());
+            LOG.info("Idenetityref will be translated as NULL for data - {}", String.valueOf(valueWithNamespace));
+            return null;
+        }
+
+        return QName.create(module.getNamespace(), module.getRevision(), valueWithNamespace.getValue());
+    }
+
+}
\ No newline at end of file
diff --git a/yang/yang-data-codec-gson/src/main/java/org/opendaylight/yangtools/yang/data/codec/gson/helpers/InstanceIdentifierCodecImpl.java b/yang/yang-data-codec-gson/src/main/java/org/opendaylight/yangtools/yang/data/codec/gson/helpers/InstanceIdentifierCodecImpl.java
new file mode 100644 (file)
index 0000000..5904859
--- /dev/null
@@ -0,0 +1,151 @@
+/*
+ * Copyright (c) 2014 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.yangtools.yang.data.codec.gson.helpers;
+
+import java.net.URI;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifier;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifierWithPredicates;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeWithValue;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.PathArgument;
+import org.opendaylight.yangtools.yang.data.api.codec.InstanceIdentifierCodec;
+import org.opendaylight.yangtools.yang.data.codec.gson.helpers.IdentityValuesDTO.IdentityValue;
+import org.opendaylight.yangtools.yang.data.codec.gson.helpers.IdentityValuesDTO.Predicate;
+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.ListSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.Module;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+class InstanceIdentifierCodecImpl extends AbstractCodecImpl implements InstanceIdentifierCodec<IdentityValuesDTO> {
+    private static final Logger LOG = LoggerFactory.getLogger(InstanceIdentifierCodecImpl.class);
+
+    InstanceIdentifierCodecImpl(final SchemaContextUtils schema) {
+        super(schema);
+    }
+
+    @Override
+    public IdentityValuesDTO serialize(final YangInstanceIdentifier data) {
+        IdentityValuesDTO identityValuesDTO = new IdentityValuesDTO();
+        for (PathArgument pathArgument : data.getPathArguments()) {
+            IdentityValue identityValue = qNameToIdentityValue(pathArgument.getNodeType());
+            if (pathArgument instanceof NodeIdentifierWithPredicates && identityValue != null) {
+                List<Predicate> predicates = keyValuesToPredicateList(((NodeIdentifierWithPredicates) pathArgument)
+                        .getKeyValues());
+                identityValue.setPredicates(predicates);
+            } else if (pathArgument instanceof NodeWithValue && identityValue != null) {
+                List<Predicate> predicates = new ArrayList<>();
+                String value = String.valueOf(((NodeWithValue) pathArgument).getValue());
+                predicates.add(new Predicate(null, value));
+                identityValue.setPredicates(predicates);
+            }
+            identityValuesDTO.add(identityValue);
+        }
+        return identityValuesDTO;
+    }
+
+    @Override
+    public YangInstanceIdentifier deserialize(final IdentityValuesDTO data) {
+        List<PathArgument> result = new ArrayList<PathArgument>();
+        IdentityValue valueWithNamespace = data.getValuesWithNamespaces().get(0);
+        Module module = getModuleByNamespace(valueWithNamespace.getNamespace());
+        if (module == null) {
+            LOG.info("Module by namespace '{}' of first node in instance-identiefier was not found.",
+                    valueWithNamespace.getNamespace());
+            LOG.info("Instance-identifier will be translated as NULL for data - {}",
+                    String.valueOf(valueWithNamespace.getValue()));
+            return null;
+        }
+
+        DataNodeContainer parentContainer = module;
+        List<IdentityValue> identities = data.getValuesWithNamespaces();
+        for (int i = 0; i < identities.size(); i++) {
+            IdentityValue identityValue = identities.get(i);
+            URI validNamespace = resolveValidNamespace(identityValue.getNamespace());
+            DataSchemaNode node = getSchema().findInstanceDataChildByNameAndNamespace(
+                    parentContainer, identityValue.getValue(), validNamespace);
+            if (node == null) {
+                LOG.info("'{}' node was not found in {}", identityValue, parentContainer.getChildNodes());
+                LOG.info("Instance-identifier will be translated as NULL for data - {}",
+                        String.valueOf(identityValue.getValue()));
+                return null;
+            }
+            QName qName = node.getQName();
+            PathArgument pathArgument = null;
+            if (identityValue.getPredicates().isEmpty()) {
+                pathArgument = new NodeIdentifier(qName);
+            } else {
+                if (node instanceof LeafListSchemaNode) { // predicate is value of leaf-list entry
+                    Predicate leafListPredicate = identityValue.getPredicates().get(0);
+                    if (!leafListPredicate.isLeafList()) {
+                        LOG.info("Predicate's data is not type of leaf-list. It should be in format \".='value'\"");
+                        LOG.info("Instance-identifier will be translated as NULL for data - {}",
+                                String.valueOf(identityValue.getValue()));
+                        return null;
+                    }
+                    pathArgument = new NodeWithValue(qName, leafListPredicate.getValue());
+                } else if (node instanceof ListSchemaNode) { // predicates are keys of list
+                    DataNodeContainer listNode = (DataNodeContainer) node;
+                    Map<QName, Object> predicatesMap = new HashMap<>();
+                    for (Predicate predicate : identityValue.getPredicates()) {
+                        validNamespace = resolveValidNamespace(predicate.getName().getNamespace());
+                        DataSchemaNode listKey = getSchema()
+                                .findInstanceDataChildByNameAndNamespace(listNode, predicate.getName().getValue(),
+                                        validNamespace);
+                        predicatesMap.put(listKey.getQName(), predicate.getValue());
+                    }
+                    pathArgument = new NodeIdentifierWithPredicates(qName, predicatesMap);
+                } else {
+                    LOG.info("Node {} is not List or Leaf-list.", node);
+                    LOG.info("Instance-identifier will be translated as NULL for data - {}",
+                            String.valueOf(identityValue.getValue()));
+                    return null;
+                }
+            }
+            result.add(pathArgument);
+            if (i < identities.size() - 1) { // last element in instance-identifier can be other than
+                // DataNodeContainer
+                if (node instanceof DataNodeContainer) {
+                    parentContainer = (DataNodeContainer) node;
+                } else {
+                    LOG.info("Node {} isn't instance of DataNodeContainer", node);
+                    LOG.info("Instance-identifier will be translated as NULL for data - {}",
+                            String.valueOf(identityValue.getValue()));
+                    return null;
+                }
+            }
+        }
+
+        return result.isEmpty() ? null : YangInstanceIdentifier.create(result);
+    }
+
+    private static List<Predicate> keyValuesToPredicateList(final Map<QName, Object> keyValues) {
+        List<Predicate> result = new ArrayList<>();
+        for (QName qName : keyValues.keySet()) {
+            Object value = keyValues.get(qName);
+            result.add(new Predicate(qNameToIdentityValue(qName), String.valueOf(value)));
+        }
+        return result;
+    }
+
+    private static IdentityValue qNameToIdentityValue(final QName qName) {
+        if (qName != null) {
+            // FIXME: the prefix here is completely arbitrary
+            return new IdentityValue(qName.getNamespace().toString(), qName.getLocalName(), qName.getPrefix());
+        }
+        return null;
+    }
+}
\ No newline at end of file
diff --git a/yang/yang-data-codec-gson/src/main/java/org/opendaylight/yangtools/yang/data/codec/gson/helpers/LeafrefCodecImpl.java b/yang/yang-data-codec-gson/src/main/java/org/opendaylight/yangtools/yang/data/codec/gson/helpers/LeafrefCodecImpl.java
new file mode 100644 (file)
index 0000000..c6d8baf
--- /dev/null
@@ -0,0 +1,24 @@
+/*
+ * Copyright (c) 2014 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.yangtools.yang.data.codec.gson.helpers;
+
+import org.opendaylight.yangtools.yang.data.api.codec.LeafrefCodec;
+
+class LeafrefCodecImpl implements LeafrefCodec<String> {
+
+    @Override
+    public String serialize(final Object data) {
+        return String.valueOf(data);
+    }
+
+    @Override
+    public Object deserialize(final String data) {
+        return data;
+    }
+
+}
\ No newline at end of file
diff --git a/yang/yang-data-codec-gson/src/main/java/org/opendaylight/yangtools/yang/data/codec/gson/helpers/ObjectCodec.java b/yang/yang-data-codec-gson/src/main/java/org/opendaylight/yangtools/yang/data/codec/gson/helpers/ObjectCodec.java
new file mode 100644 (file)
index 0000000..abe7cd2
--- /dev/null
@@ -0,0 +1,117 @@
+/*
+ * Copyright (c) 2014 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.yangtools.yang.data.codec.gson.helpers;
+
+import org.opendaylight.yangtools.concepts.Codec;
+import org.opendaylight.yangtools.yang.data.impl.codec.TypeDefinitionAwareCodec;
+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;
+import org.opendaylight.yangtools.yang.model.api.type.LeafrefTypeDefinition;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+@SuppressWarnings("rawtypes")
+final class ObjectCodec extends AbstractCodecImpl implements Codec<Object, Object> {
+    public static final Codec LEAFREF_DEFAULT_CODEC = new LeafrefCodecImpl();
+    private static final Logger LOG = LoggerFactory.getLogger(RestCodecFactory.class);
+    private final Codec instanceIdentifier;
+    private final Codec identityrefCodec;
+    private final TypeDefinition<?> type;
+
+    ObjectCodec(final SchemaContextUtils schema, final TypeDefinition<?> typeDefinition) {
+        super(schema);
+        type = RestUtil.resolveBaseTypeFrom(typeDefinition);
+        if (type instanceof IdentityrefTypeDefinition) {
+            identityrefCodec = new IdentityrefCodecImpl(schema);
+        } else {
+            identityrefCodec = null;
+        }
+        if (type instanceof InstanceIdentifierTypeDefinition) {
+            instanceIdentifier = new InstanceIdentifierCodecImpl(schema);
+        } else {
+            instanceIdentifier = null;
+        }
+    }
+
+    @SuppressWarnings("unchecked")
+    @Override
+    public Object deserialize(final Object input) {
+        try {
+            if (type instanceof IdentityrefTypeDefinition) {
+                if (input instanceof IdentityValuesDTO) {
+                    return identityrefCodec.deserialize(input);
+                }
+                LOG.debug("Value is not instance of IdentityrefTypeDefinition but is {}. Therefore NULL is used as translation of  - {}",
+                        input == null ? "null" : input.getClass(), String.valueOf(input));
+                return null;
+            } else if (type instanceof LeafrefTypeDefinition) {
+                if (input instanceof IdentityValuesDTO) {
+                    return LEAFREF_DEFAULT_CODEC.deserialize(((IdentityValuesDTO) input).getOriginValue());
+                }
+                return LEAFREF_DEFAULT_CODEC.deserialize(input);
+            } else if (type instanceof InstanceIdentifierTypeDefinition) {
+                if (input instanceof IdentityValuesDTO) {
+                    return instanceIdentifier.deserialize(input);
+                }
+                LOG.info(
+                        "Value is not instance of InstanceIdentifierTypeDefinition but is {}. Therefore NULL is used as translation of  - {}",
+                        input == null ? "null" : input.getClass(), String.valueOf(input));
+                return null;
+            } else {
+                TypeDefinitionAwareCodec<Object, ? extends TypeDefinition<?>> typeAwarecodec = TypeDefinitionAwareCodec
+                        .from(type);
+                if (typeAwarecodec != null) {
+                    if (input instanceof IdentityValuesDTO) {
+                        return typeAwarecodec.deserialize(((IdentityValuesDTO) input).getOriginValue());
+                    }
+                    return typeAwarecodec.deserialize(String.valueOf(input));
+                } else {
+                    LOG.debug("Codec for type \"" + type.getQName().getLocalName()
+                            + "\" is not implemented yet.");
+                    return null;
+                }
+            }
+        } catch (ClassCastException e) {
+            // TODO remove this catch when everyone use codecs
+            LOG.error("ClassCastException was thrown when codec is invoked with parameter " + String.valueOf(input),
+                    e);
+            return null;
+        }
+    }
+
+    @SuppressWarnings("unchecked")
+    @Override
+    public Object serialize(final Object input) {
+        try {
+            if (type instanceof IdentityrefTypeDefinition) {
+                return identityrefCodec.serialize(input);
+            } else if (type instanceof LeafrefTypeDefinition) {
+                return LEAFREF_DEFAULT_CODEC.serialize(input);
+            } else if (type instanceof InstanceIdentifierTypeDefinition) {
+                return instanceIdentifier.serialize(input);
+            } else {
+                TypeDefinitionAwareCodec<Object, ? extends TypeDefinition<?>> typeAwarecodec = TypeDefinitionAwareCodec
+                        .from(type);
+                if (typeAwarecodec != null) {
+                    return typeAwarecodec.serialize(input);
+                } else {
+                    LOG.debug("Codec for type \"" + type.getQName().getLocalName()
+                            + "\" is not implemented yet.");
+                    return null;
+                }
+            }
+        } catch (ClassCastException e) { // TODO remove this catch when everyone use codecs
+            LOG.error(
+                    "ClassCastException was thrown when codec is invoked with parameter " + String.valueOf(input),
+                    e);
+            return input;
+        }
+    }
+
+}
\ No newline at end of file
diff --git a/yang/yang-data-codec-gson/src/main/java/org/opendaylight/yangtools/yang/data/codec/gson/helpers/RestCodecFactory.java b/yang/yang-data-codec-gson/src/main/java/org/opendaylight/yangtools/yang/data/codec/gson/helpers/RestCodecFactory.java
new file mode 100644 (file)
index 0000000..94bba92
--- /dev/null
@@ -0,0 +1,35 @@
+/*
+ * Copyright (c) 2014 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.yangtools.yang.data.codec.gson.helpers;
+
+import com.google.common.annotations.Beta;
+import com.google.common.base.Preconditions;
+
+import org.opendaylight.yangtools.concepts.Codec;
+import org.opendaylight.yangtools.yang.model.api.TypeDefinition;
+
+/**
+ * This class is implementation-internal and subject to change. Please do not use it.
+ */
+@Beta
+public final class RestCodecFactory {
+    private final SchemaContextUtils utils;
+
+    private RestCodecFactory(final SchemaContextUtils utils) {
+        this.utils = Preconditions.checkNotNull(utils);
+    }
+
+    public static RestCodecFactory create(final SchemaContextUtils utils) {
+        return new RestCodecFactory(utils);
+    }
+
+    public final Codec<Object, Object> codecFor(final TypeDefinition<?> typeDefinition) {
+        // FIXME: implement loadingcache
+        return new ObjectCodec(utils, typeDefinition);
+    }
+}
diff --git a/yang/yang-data-codec-gson/src/main/java/org/opendaylight/yangtools/yang/data/codec/gson/helpers/RestUtil.java b/yang/yang-data-codec-gson/src/main/java/org/opendaylight/yangtools/yang/data/codec/gson/helpers/RestUtil.java
new file mode 100644 (file)
index 0000000..c3d002c
--- /dev/null
@@ -0,0 +1,160 @@
+/*
+ * Copyright (c) 2014 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.yangtools.yang.data.codec.gson.helpers;
+
+
+import com.google.common.annotations.Beta;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import javax.xml.stream.events.StartElement;
+
+import org.opendaylight.yangtools.yang.data.codec.gson.helpers.IdentityValuesDTO.IdentityValue;
+import org.opendaylight.yangtools.yang.data.codec.gson.helpers.IdentityValuesDTO.Predicate;
+import org.opendaylight.yangtools.yang.model.api.TypeDefinition;
+
+/**
+ * This class is implementation-internal and subject to change. Please do not use it.
+ */
+@Beta
+public final class RestUtil {
+
+    // FIXME: BUG-1275: this is code duplicates data.impl.codec
+
+    public static final String SQUOTE = "'";
+    public static final String DQUOTE = "\"";
+    private static final Pattern PREDICATE_PATTERN = Pattern.compile("\\[(.*?)\\]");
+
+    public final static TypeDefinition<?> resolveBaseTypeFrom(final TypeDefinition<?> type) {
+        TypeDefinition<?> superType = type;
+        while (superType.getBaseType() != null) {
+            superType = superType.getBaseType();
+        }
+        return superType;
+    }
+
+    public static IdentityValuesDTO asInstanceIdentifier(final String value, final PrefixesMaping prefixMap) {
+        String valueTrimmed = value.trim();
+        if (!valueTrimmed.startsWith("/")) {
+            return null;
+        }
+        String[] xPathParts = valueTrimmed.split("/");
+        if (xPathParts.length < 2) { // must be at least "/pr:node"
+            return null;
+        }
+        IdentityValuesDTO identityValuesDTO = new IdentityValuesDTO(value);
+        for (int i = 1; i < xPathParts.length; i++) {
+            String xPathPartTrimmed = xPathParts[i].trim();
+
+            String xPathPartStr = getIdAndPrefixAsStr(xPathPartTrimmed);
+            IdentityValue identityValue = toIdentity(xPathPartStr, prefixMap);
+            if (identityValue == null) {
+                return null;
+            }
+
+            List<Predicate> predicates = toPredicates(xPathPartTrimmed, prefixMap);
+            if (predicates == null) {
+                return null;
+            }
+            identityValue.setPredicates(predicates);
+
+            identityValuesDTO.add(identityValue);
+        }
+        return identityValuesDTO.getValuesWithNamespaces().isEmpty() ? null : identityValuesDTO;
+    }
+
+    private static String getIdAndPrefixAsStr(final String pathPart) {
+        int predicateStartIndex = pathPart.indexOf("[");
+        return predicateStartIndex == -1 ? pathPart : pathPart.substring(0, predicateStartIndex);
+    }
+
+    private static IdentityValue toIdentity(final String xPathPart, final PrefixesMaping prefixMap) {
+        String xPathPartTrimmed = xPathPart.trim();
+        if (xPathPartTrimmed.isEmpty()) {
+            return null;
+        }
+        String[] prefixAndIdentifier = xPathPartTrimmed.split(":");
+        // it is not "prefix:value"
+        if (prefixAndIdentifier.length != 2) {
+            return null;
+        }
+        String prefix = prefixAndIdentifier[0].trim();
+        String identifier = prefixAndIdentifier[1].trim();
+        if (prefix.isEmpty() || identifier.isEmpty()) {
+            return null;
+        }
+        String namespace = prefixMap.getNamespace(prefix);
+        return new IdentityValue(namespace, identifier, namespace.equals(prefix) ? null : prefix);
+    }
+
+    private static List<Predicate> toPredicates(final String predicatesStr, final PrefixesMaping prefixMap) {
+        List<Predicate> result = new ArrayList<>();
+        List<String> predicates = new ArrayList<>();
+        Matcher matcher = PREDICATE_PATTERN.matcher(predicatesStr);
+        while (matcher.find()) {
+            predicates.add(matcher.group(1).trim());
+        }
+        for (String predicate : predicates) {
+            int indexOfEqualityMark = predicate.indexOf("=");
+            if (indexOfEqualityMark != -1) {
+                String predicateValue = toPredicateValue(predicate.substring(indexOfEqualityMark + 1));
+                if (predicate.startsWith(".")) { // it is leaf-list
+                    if (predicateValue == null) {
+                        return null;
+                    }
+                    result.add(new Predicate(null, predicateValue));
+                } else {
+                    IdentityValue identityValue = toIdentity(predicate.substring(0, indexOfEqualityMark), prefixMap);
+                    if (identityValue == null || predicateValue == null) {
+                        return null;
+                    }
+                    result.add(new Predicate(identityValue, predicateValue));
+                }
+            }
+        }
+        return result;
+    }
+
+    private static String toPredicateValue(final String predicatedValue) {
+        String predicatedValueTrimmed = predicatedValue.trim();
+        if ((predicatedValueTrimmed.startsWith(DQUOTE) || predicatedValueTrimmed.startsWith(SQUOTE))
+                && (predicatedValueTrimmed.endsWith(DQUOTE) || predicatedValueTrimmed.endsWith(SQUOTE))) {
+            return predicatedValueTrimmed.substring(1, predicatedValueTrimmed.length() - 1);
+        }
+        return null;
+    }
+
+    public interface PrefixesMaping {
+        public String getNamespace(String prefix);
+    }
+
+    public static class PrefixMapingFromXml implements PrefixesMaping {
+        StartElement startElement = null;
+
+        public PrefixMapingFromXml(final StartElement startElement) {
+            this.startElement = startElement;
+        }
+
+        @Override
+        public String getNamespace(final String prefix) {
+            return startElement.getNamespaceContext().getNamespaceURI(prefix);
+        }
+    }
+
+    public static class PrefixMapingFromJson implements PrefixesMaping {
+
+        @Override
+        public String getNamespace(final String prefix) {
+            return prefix;
+        }
+    }
+
+}
diff --git a/yang/yang-data-codec-gson/src/main/java/org/opendaylight/yangtools/yang/data/codec/gson/helpers/SchemaContextUtils.java b/yang/yang-data-codec-gson/src/main/java/org/opendaylight/yangtools/yang/data/codec/gson/helpers/SchemaContextUtils.java
new file mode 100644 (file)
index 0000000..5e8f6f1
--- /dev/null
@@ -0,0 +1,141 @@
+/*
+ * Copyright (c) 2014 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.yangtools.yang.data.codec.gson.helpers;
+
+import com.google.common.annotations.Beta;
+import com.google.common.base.Function;
+import com.google.common.base.Objects;
+import com.google.common.base.Preconditions;
+import com.google.common.base.Predicate;
+import com.google.common.collect.Iterables;
+
+import java.net.URI;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Set;
+
+import org.opendaylight.yangtools.yang.model.api.AnyXmlSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.ChoiceCaseNode;
+import org.opendaylight.yangtools.yang.model.api.ChoiceNode;
+import org.opendaylight.yangtools.yang.model.api.ContainerSchemaNode;
+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.ListSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.Module;
+import org.opendaylight.yangtools.yang.model.api.SchemaContext;
+
+/**
+ * This class is implementation-internal and subject to change. Please do not use it.
+ */
+@Beta
+public final class SchemaContextUtils {
+    private final SchemaContext schemaContext;
+
+    private SchemaContextUtils(final SchemaContext schemaContext) {
+        this.schemaContext = Preconditions.checkNotNull(schemaContext);
+    }
+
+    public static SchemaContextUtils create(final SchemaContext schemaContext) {
+        return new SchemaContextUtils(schemaContext);
+    }
+
+    public URI findNamespaceByModuleName(final String moduleName) {
+        final Module module = this.findModuleByName(moduleName);
+        return module == null ? null : module.getNamespace();
+    }
+
+
+    public Module findModuleByName(final String moduleName) {
+        checkPreconditions();
+        Preconditions.checkArgument(moduleName != null && !moduleName.isEmpty());
+        return schemaContext.findModuleByName(moduleName, null);
+    }
+
+    public Module findModuleByNamespace(final URI namespace) {
+        this.checkPreconditions();
+        Preconditions.checkArgument(namespace != null);
+        return schemaContext.findModuleByNamespaceAndRevision(namespace, null);
+    }
+
+    private void checkPreconditions() {
+        if (schemaContext == null) {
+            throw new IllegalStateException("Schema context isn't set.");
+        }
+    }
+
+    public DataSchemaNode findInstanceDataChildByNameAndNamespace(final DataNodeContainer container, final String name,
+            final URI namespace) {
+        Preconditions.<URI> checkNotNull(namespace);
+
+        final List<DataSchemaNode> potentialSchemaNodes = findInstanceDataChildrenByName(container, name);
+
+        Predicate<DataSchemaNode> filter = new Predicate<DataSchemaNode>() {
+            @Override
+            public boolean apply(final DataSchemaNode node) {
+                return Objects.equal(node.getQName().getNamespace(), namespace);
+            }
+        };
+
+        Iterable<DataSchemaNode> result = Iterables.filter(potentialSchemaNodes, filter);
+        return Iterables.getFirst(result, null);
+    }
+
+    public List<DataSchemaNode> findInstanceDataChildrenByName(final DataNodeContainer container, final String name) {
+        Preconditions.<DataNodeContainer> checkNotNull(container);
+        Preconditions.<String> checkNotNull(name);
+
+        List<DataSchemaNode> instantiatedDataNodeContainers = new ArrayList<DataSchemaNode>();
+        collectInstanceDataNodeContainers(instantiatedDataNodeContainers, container, name);
+        return instantiatedDataNodeContainers;
+    }
+
+    private void collectInstanceDataNodeContainers(final List<DataSchemaNode> potentialSchemaNodes,
+            final DataNodeContainer container, final String name) {
+
+        Predicate<DataSchemaNode> filter = new Predicate<DataSchemaNode>() {
+            @Override
+            public boolean apply(final DataSchemaNode node) {
+                return Objects.equal(node.getQName().getLocalName(), name);
+            }
+        };
+
+        Iterable<DataSchemaNode> nodes = Iterables.filter(container.getChildNodes(), filter);
+
+        // Can't combine this loop with the filter above because the filter is
+        // lazily-applied by Iterables.filter.
+        for (final DataSchemaNode potentialNode : nodes) {
+            if (isInstantiatedDataSchema(potentialNode)) {
+                potentialSchemaNodes.add(potentialNode);
+            }
+        }
+
+        Iterable<ChoiceNode> choiceNodes = Iterables.filter(container.getChildNodes(), ChoiceNode.class);
+        Iterable<Set<ChoiceCaseNode>> map = Iterables.transform(choiceNodes, CHOICE_FUNCTION);
+
+        final Iterable<ChoiceCaseNode> allCases = Iterables.<ChoiceCaseNode> concat(map);
+        for (final ChoiceCaseNode caze : allCases) {
+            collectInstanceDataNodeContainers(potentialSchemaNodes, caze, name);
+        }
+    }
+
+    public boolean isInstantiatedDataSchema(final DataSchemaNode node) {
+        return node instanceof LeafSchemaNode || node instanceof LeafListSchemaNode
+                || node instanceof ContainerSchemaNode || node instanceof ListSchemaNode
+                || node instanceof AnyXmlSchemaNode;
+    }
+
+    private final Function<ChoiceNode, Set<ChoiceCaseNode>> CHOICE_FUNCTION = new Function<ChoiceNode, Set<ChoiceCaseNode>>() {
+        @Override
+        public Set<ChoiceCaseNode> apply(final ChoiceNode node) {
+            return node.getCases();
+        }
+    };
+
+}
diff --git a/yang/yang-data-codec-gson/src/test/java/org/opendaylight/yangtools/yang/data/codec/gson/StreamToNormalizedNodeTest.java b/yang/yang-data-codec-gson/src/test/java/org/opendaylight/yangtools/yang/data/codec/gson/StreamToNormalizedNodeTest.java
new file mode 100644 (file)
index 0000000..1010989
--- /dev/null
@@ -0,0 +1,153 @@
+/*
+ * Copyright (c) 2014 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.yangtools.yang.data.codec.gson;
+
+import com.google.gson.stream.JsonReader;
+
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.FileReader;
+import java.io.IOException;
+import java.io.StringReader;
+import java.io.StringWriter;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifier;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.PathArgument;
+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.NormalizedNode;
+import org.opendaylight.yangtools.yang.data.api.schema.stream.LoggingNormalizedNodeStreamWriter;
+import org.opendaylight.yangtools.yang.data.api.schema.stream.NormalizedNodeStreamWriter;
+import org.opendaylight.yangtools.yang.data.api.schema.stream.NormalizedNodeWriter;
+import org.opendaylight.yangtools.yang.data.impl.schema.Builders;
+import org.opendaylight.yangtools.yang.data.impl.schema.ImmutableNormalizedNodeStreamWriter;
+import org.opendaylight.yangtools.yang.data.impl.schema.builder.api.NormalizedNodeContainerBuilder;
+import org.opendaylight.yangtools.yang.model.api.SchemaContext;
+import org.opendaylight.yangtools.yang.model.parser.api.YangContextParser;
+import org.opendaylight.yangtools.yang.parser.impl.YangParserImpl;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class StreamToNormalizedNodeTest {
+    private static final Logger LOG = LoggerFactory.getLogger(StreamToNormalizedNodeTest.class);
+    private static SchemaContext schemaContext;
+    private static String streamAsString;
+
+    @BeforeClass
+    public static void initialization() throws IOException {
+        schemaContext = loadModules("/complexjson/yang");
+        streamAsString = loadTextFile(StreamToNormalizedNodeTest.class.getResource("/complexjson/complex-json.json")
+                .getPath());
+    }
+
+    /**
+     * Demonstrates how to log events produced by a {@link JsonReader}.
+     *
+     * @throws IOException
+     */
+    @Test
+    public void ownStreamWriterImplementationDemonstration() throws IOException {
+        // GSON's JsonReader reading from the loaded string (our event source)
+        final JsonReader reader = new JsonReader(new StringReader(streamAsString));
+
+        // StreamWriter which outputs SLF4J events
+        final LoggingNormalizedNodeStreamWriter logWriter = new LoggingNormalizedNodeStreamWriter();
+
+        // JSON -> StreamWriter parser
+        try (final JsonParserStream jsonHandler = JsonParserStream.create(logWriter, schemaContext)) {
+            // Process multiple readers, flush()/close() as needed
+            jsonHandler.parse(reader);
+        }
+    }
+
+    /**
+     * Demonstrates how to create an immutable NormalizedNode tree from a {@link JsonReader} and
+     * then writes the data back into string representation.
+     *
+     * @throws IOException
+     */
+    @Test
+    public void immutableNormalizedNodeStreamWriterDemonstration() throws IOException {
+        /*
+         * This is the parsing part
+         */
+        // This is where we will output the nodes
+        final NormalizedNodeContainerBuilder<NodeIdentifier, ?, ?, ? extends NormalizedNode<?, ?>> parent =
+                Builders.containerBuilder().withNodeIdentifier(new NodeIdentifier(QName.create("dummy", "2014-12-31", "dummy")));
+
+        // StreamWriter which attaches NormalizedNode under parent
+        final NormalizedNodeStreamWriter streamWriter = ImmutableNormalizedNodeStreamWriter.from(parent);
+
+        // JSON -> StreamWriter parser
+        try (JsonParserStream handler = JsonParserStream.create(streamWriter, schemaContext)) {
+            handler.parse(new JsonReader(new StringReader(streamAsString)));
+        }
+
+        // Finally build the node
+        final NormalizedNode<?, ?> parsedData = parent.build();
+        LOG.debug("Parsed NormalizedNodes: {}", parsedData);
+
+        /*
+         * This is the serialization part.
+         */
+        // We want to write the first child out
+        final DataContainerChild<? extends PathArgument, ?> firstChild = ((ContainerNode) parsedData).getValue().iterator().next();
+        LOG.debug("Serializing first child: {}", firstChild);
+
+        // String holder
+        final StringWriter writer = new StringWriter();
+
+        // StreamWriter which outputs JSON strings
+        final NormalizedNodeStreamWriter jsonStream = JSONNormalizedNodeStreamWriter.create(schemaContext, writer, 2);
+
+        // NormalizedNode -> StreamWriter
+        final NormalizedNodeWriter nodeWriter = NormalizedNodeWriter.forStreamWriter(jsonStream);
+
+        // Write multiple NormalizedNodes fluently, flush()/close() as needed
+        nodeWriter.write(firstChild).close();
+
+        // Just to put it somewhere
+        LOG.debug("Serialized JSON: {}", writer.toString());
+    }
+
+    private static SchemaContext loadModules(final String resourceDirectory) throws IOException {
+        YangContextParser parser = new YangParserImpl();
+        String path = StreamToNormalizedNodeTest.class.getResource(resourceDirectory).getPath();
+        final File testDir = new File(path);
+        final String[] fileList = testDir.list();
+        final List<File> testFiles = new ArrayList<File>();
+        if (fileList == null) {
+            throw new FileNotFoundException(resourceDirectory);
+        }
+        for (String fileName : fileList) {
+            if (new File(testDir, fileName).isDirectory() == false) {
+                testFiles.add(new File(testDir, fileName));
+            }
+        }
+        return parser.parseFiles(testFiles);
+    }
+
+    private static String loadTextFile(final String filePath) throws IOException {
+        FileReader fileReader = new FileReader(filePath);
+        BufferedReader bufReader = new BufferedReader(fileReader);
+
+        String line = null;
+        StringBuilder result = new StringBuilder();
+        while ((line = bufReader.readLine()) != null) {
+            result.append(line);
+        }
+        bufReader.close();
+        return result.toString();
+    }
+}
diff --git a/yang/yang-data-codec-gson/src/test/resources/complexjson/complex-json.json b/yang/yang-data-codec-gson/src/test/resources/complexjson/complex-json.json
new file mode 100644 (file)
index 0000000..8ecaa37
--- /dev/null
@@ -0,0 +1,41 @@
+{
+    "complexjson:cont1": {
+        "lf12-any":[
+            {
+                "anyxml-in-data":"foo"
+            }
+        ],
+        
+        "lf13-any":{
+            "anyxml-in-data":"foo"
+        },
+        
+        "lf14-any":"anyxml data",
+       
+        "lflst11":["lflst11 value1","lflst11 value2"],
+        
+        "lst11":[
+            {            
+                "key111":"key111 value",
+                "lf112":"/complexjson:cont1/complexjson:lflst11",
+                "lf113":"lf113 value",
+                "lf111":"lf111 value"
+            }
+        ],        
+        "lf11" : "453",
+        "lf12_1" : "lf12 value",
+        "lf13" : "lf13 value",        
+        "complexjson-augmentation:lf15_11" : "lf15_11 value from augmentation",
+        "complexjson-augmentation:lf15_12" : "lf15_12 value from augmentation",
+        "lf15_11" : "one two",
+        "lf15_12" : "complexjson:lf11",
+        "lf15_21" : "lf15_21 value",
+        "lf17" : "lf17 value",        
+        
+        "lst12":[
+            {
+                "lf121":"lf121 value"
+            }
+        ]
+    }
+}
\ No newline at end of file
diff --git a/yang/yang-data-codec-gson/src/test/resources/complexjson/yang/complexjson-augmentation.yang b/yang/yang-data-codec-gson/src/test/resources/complexjson/yang/complexjson-augmentation.yang
new file mode 100644 (file)
index 0000000..d4ea623
--- /dev/null
@@ -0,0 +1,37 @@
+module complexjson-augmentation {
+    namespace "ns:complex:json:augmentation";
+    prefix cjaug;
+    
+  import complexjson {
+    prefix cj;
+  }    
+
+    revision "2014-08-14" {        
+    }
+    
+    augment "/cj:cont1/cj:choc11/cj:c11A" {
+        leaf lf15_11  {
+                    type string;
+                }
+        leaf lf15_12  {
+                    type string;
+                }
+                
+    }    
+    
+    augment "/cj:cont1" {
+        leaf lf12_1aug {
+                    type string;
+                }
+        leaf lf12_2aug {
+            type string;
+        }
+    }    
+    
+    augment "/cj:cont1/cj:choc11/cj:c11A" {
+        leaf lf15_21aug {
+                    type string;
+                }
+    }    
+
+}
diff --git a/yang/yang-data-codec-gson/src/test/resources/complexjson/yang/complexjson.yang b/yang/yang-data-codec-gson/src/test/resources/complexjson/yang/complexjson.yang
new file mode 100644 (file)
index 0000000..6c07d65
--- /dev/null
@@ -0,0 +1,140 @@
+module complexjson {
+    namespace "ns:complex:json";
+    prefix cj;
+
+    revision "2014-08-11" {        
+    }
+    
+    
+    identity ident;
+    
+    container cont1 {
+    
+        anyxml lf12-any;
+        anyxml lf13-any;
+        anyxml lf14-any;
+        
+        leaf lf11 {
+            type int32;
+        }
+        
+        leaf-list lflst11 {
+            type string;
+        }
+        
+        list lst11 {
+            key "key111 lf111";
+            leaf key111 {
+                type string;
+            }
+            leaf lf111 {
+                type string;
+            }
+            leaf lf112 {
+                type instance-identifier;
+            }
+            leaf lf113 {
+                type string;
+            }
+        }
+        
+        list lst12 {
+            leaf lf121 {
+                type string;
+            }
+            leaf lf122 {
+                type string;
+            }
+        }
+        
+    
+        choice choc11 {
+            case c11A {
+                leaf lf13 {
+                    type string;
+                }
+            }
+            leaf lf16 {
+                type string;
+            }
+        }
+
+        choice choc12 {
+            case c12A {
+            }
+        }
+    }
+    
+    
+    augment "/cont1/choc12" {
+        case c12B {
+            leaf lf17 {
+                type string;
+            }
+        }
+    }    
+    
+    
+    augment "/cont1" {
+        container cont11 {
+            leaf lf111 {
+                type string;
+            }
+        }        
+    }
+    
+    augment "/cont1" {
+        leaf lf12_1 {
+                    type string;
+                }
+        leaf lf12_2 {
+            type string;
+        }
+    }
+    
+    augment "/cont1" {
+        leaf lf12_3 {
+                    type string;
+                }
+    }
+    
+    
+    augment "/cont1/choc11" {
+        case c11B {
+            leaf lf14_1  {
+                    type string;
+                }
+        }
+    }
+    
+    augment "/cont1/choc11" {
+        case c11C {
+            leaf lf14_2  {
+                    type string;
+                }
+        }
+    }
+    
+    augment "/cont1/choc11/c11A" {
+        leaf lf15_11  {
+                    type bits {
+                        bit one;
+                        bit two;
+                        bit three;                        
+                    }
+                }
+        leaf lf15_12  {
+                    type identityref {
+                        base ident;
+                    }
+                }
+                
+    }
+    
+    augment "/cont1/choc11/c11A" {
+        leaf lf15_21 {
+                    type string;
+                }
+    }
+
+}
index a0b54900be9f419d0c69f43c5299be4e7f77a7e4..fe3d1841a2bd8b67041aa66b7cddaa40120cb4e9 100644 (file)
@@ -8,9 +8,12 @@
 package org.opendaylight.yangtools.yang.data.impl.schema;
 
 import com.google.common.base.Preconditions;
+
+import java.io.IOException;
 import java.util.ArrayDeque;
 import java.util.Deque;
 import java.util.List;
+
 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.AugmentationIdentifier;
 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifier;
 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifierWithPredicates;
@@ -43,15 +46,11 @@ import org.opendaylight.yangtools.yang.data.impl.schema.builder.impl.ImmutableUn
  */
 public class ImmutableNormalizedNodeStreamWriter implements NormalizedNodeStreamWriter {
 
-
-
     @SuppressWarnings("rawtypes")
-    private final Deque<NormalizedNodeContainerBuilder> builders;
-
+    private final Deque<NormalizedNodeContainerBuilder> builders = new ArrayDeque<>();
 
     @SuppressWarnings("rawtypes")
     private ImmutableNormalizedNodeStreamWriter( final NormalizedNodeContainerBuilder topLevelBuilder) {
-        builders = new ArrayDeque<>();
         builders.push(topLevelBuilder);
     }
 
@@ -177,17 +176,15 @@ public class ImmutableNormalizedNodeStreamWriter implements NormalizedNodeStream
     @Override
     public void startMapEntryNode(final NodeIdentifierWithPredicates identifier,final int childSizeHint) throws IllegalArgumentException {
         if(!(getCurrent() instanceof NormalizedNodeResultBuilder)) {
-            Preconditions.checkArgument(getCurrent() instanceof ImmutableMapNodeBuilder);
+            Preconditions.checkArgument(getCurrent() instanceof ImmutableMapNodeBuilder || getCurrent() instanceof ImmutableOrderedMapNodeBuilder);
         }
         enter(Builders.mapEntryBuilder().withNodeIdentifier(identifier));
     }
 
     @Override
     public void startOrderedMapNode(final NodeIdentifier name,final int childSizeHint) throws IllegalArgumentException {
-        if(!(getCurrent() instanceof NormalizedNodeResultBuilder)) {
-            Preconditions.checkArgument(getCurrent() instanceof ImmutableOrderedMapNodeBuilder);
-        }
-        enter(Builders.mapBuilder().withNodeIdentifier(name));
+        checkDataNodeContainer();
+        enter(Builders.orderedMapBuilder().withNodeIdentifier(name));
     }
 
     @Override
@@ -252,4 +249,15 @@ public class ImmutableNormalizedNodeStreamWriter implements NormalizedNodeStream
 
     }
 
+    @Override
+    public void flush() {
+        // no-op
+    }
+
+    @Override
+    public void close() throws IOException {
+        // TODO Auto-generated method stub
+
+    }
+
 }
index 02e85a46a0bca643c3f2315d71730417ea3ac875..0f0b4a12da7e96f594a5d7a8f78c1a0dc79bf8c4 100644 (file)
@@ -103,7 +103,7 @@ final class InMemoryDataTree implements DataTree {
         rwLock.writeLock().lock();
         try {
             final Optional<TreeNode> newRoot = m.getStrategy().apply(m.getRootModification(),
-                    Optional.<TreeNode>of(rootNode), rootNode.getSubtreeVersion().next());
+                    Optional.<TreeNode>of(rootNode), m.getVersion());
             Preconditions.checkState(newRoot.isPresent(), "Apply strategy failed to produce root node");
             return new InMemoryDataTreeCandidate(PUBLIC_ROOT_PATH, root, rootNode, newRoot.get());
         } finally {
index 73d3ac36c03980d86d3235764755ea924ad38a10..e26c32ee5b03bfc01edd2ec64698a66911797bd0 100644 (file)
@@ -18,6 +18,7 @@ import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNodeContainer;
 import org.opendaylight.yangtools.yang.data.api.schema.tree.DataTreeModification;
 import org.opendaylight.yangtools.yang.data.api.schema.tree.ModificationType;
 import org.opendaylight.yangtools.yang.data.api.schema.tree.spi.TreeNode;
+import org.opendaylight.yangtools.yang.data.api.schema.tree.spi.Version;
 import org.opendaylight.yangtools.yang.data.impl.schema.NormalizedNodeUtils;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -30,6 +31,7 @@ final class InMemoryDataTreeModification implements DataTreeModification {
     private final RootModificationApplyOperation strategyTree;
     private final InMemoryDataTreeSnapshot snapshot;
     private final ModifiedNode rootNode;
+    private final Version version;
 
     @GuardedBy("this")
     private boolean sealed = false;
@@ -38,6 +40,17 @@ final class InMemoryDataTreeModification implements DataTreeModification {
         this.snapshot = Preconditions.checkNotNull(snapshot);
         this.strategyTree = Preconditions.checkNotNull(resolver).snapshot();
         this.rootNode = ModifiedNode.createUnmodified(snapshot.getRootNode());
+        /*
+         * We could allocate version beforehand, since Version contract
+         * states two allocated version must be allways different.
+         * 
+         * Preallocating version simplifies scenarios such as
+         * chaining of modifications, since version for particular
+         * node in modification and in data tree (if successfully
+         * commited) will be same and will not change.
+         * 
+         */
+        this.version = snapshot.getRootNode().getSubtreeVersion().next();
     }
 
     ModifiedNode getRootModification() {
@@ -108,7 +121,7 @@ final class InMemoryDataTreeModification implements DataTreeModification {
 
         try {
             return resolveModificationStrategy(path).apply(modification, modification.getOriginal(),
-                    snapshot.getRootNode().getSubtreeVersion().next());
+                    version);
         } catch (Exception e) {
             LOG.error("Could not create snapshot for {}:{}", path,modification,e);
             throw e;
@@ -160,22 +173,17 @@ final class InMemoryDataTreeModification implements DataTreeModification {
         }
 
         /*
-         *  FIXME: Add advanced transaction chaining for modification of not rebased
-         *  modification.
-         *
-         *  Current computation of tempRoot may yeld incorrect subtree versions
-         *  if there are multiple concurrent transactions, which may break
-         *  versioning preconditions for modification of previously occured write,
-         *  directly nested under parent node, since node version is derived from
-         *  subtree version.
-         *
-         *  For deeper nodes subtree version is derived from their respective metadata
-         *  nodes, so this incorrect root subtree version is not affecting us.
+         *  We will use preallocated version, this means returned snapshot will 
+         *  have same version each time this method is called.
          */
         TreeNode originalSnapshotRoot = snapshot.getRootNode();
-        Optional<TreeNode> tempRoot = strategyTree.apply(rootNode, Optional.of(originalSnapshotRoot), originalSnapshotRoot.getSubtreeVersion().next());
+        Optional<TreeNode> tempRoot = strategyTree.apply(rootNode, Optional.of(originalSnapshotRoot), version);
 
         InMemoryDataTreeSnapshot tempTree = new InMemoryDataTreeSnapshot(snapshot.getSchemaContext(), tempRoot.get(), strategyTree);
         return tempTree.newModification();
     }
+
+    Version getVersion() {
+        return version;
+    }
 }
index 498f403f5dcbc86418dfff034335e880b0cb15f9..2d7347cc4699259035504a7d0cc6c43720511c3b 100644 (file)
@@ -53,7 +53,7 @@ public abstract class AbstractSchemaSourceCache<T extends SchemaSourceRepresenta
      *
      * @param sourceIdentifier Source identifier
      * @return schema source registration, which the subclass needs to
-     *         {@link SchemaSourceRegistration#close() once it expunges the source
+     *         {@link SchemaSourceRegistration#close()} once it expunges the source
      *         from the cache.
      */
     protected final SchemaSourceRegistration<T> register(final SourceIdentifier sourceIdentifier) {
index 7dd5fb402934afbb3caad6913c409e587caf1a59..9fe6805c815a3abfd42dca8e452c8f00d8d00bfb 100644 (file)
@@ -37,7 +37,7 @@ public final class BaseConstraints {
      *
      * <ul>
      * <li>{@link LengthConstraint#getErrorAppTag()} returns <code>length-out-of-specified-bounds</code>
-     * <li>{@link LengthConstraint#getErrorMessage() returns <code>The argument is out of bounds &lt;<i>min</i>, <i>max</i> &gt;</code>
+     * <li>{@link LengthConstraint#getErrorMessage()} returns <code>The argument is out of bounds &lt;<i>min</i>, <i>max</i> &gt;</code>
      * </ul>
      *
      * @see LengthConstraint
@@ -61,7 +61,7 @@ public final class BaseConstraints {
      *
      * <ul>
      * <li>{@link RangeConstraint#getErrorAppTag()} returns <code>range-out-of-specified-bounds</code>
-     * <li>{@link RangeConstraint#getErrorMessage() returns <code>The argument is out of bounds &lt;<i>min</i>, <i>max</i> &gt;</code>
+     * <li>{@link RangeConstraint#getErrorMessage()} returns <code>The argument is out of bounds &lt;<i>min</i>, <i>max</i> &gt;</code>
      * </ul>
      *
      *
@@ -94,7 +94,7 @@ public final class BaseConstraints {
      * @param pattern Regular expression, MUST NOT BE null.
      * @param description Description associated with constraint.
      * @param reference Reference associated with constraint.
-     * @returnInstance of {@link PatternConstraint}
+     * @return Instance of {@link PatternConstraint}
      */
     public static PatternConstraint newPatternConstraint(final String pattern, final Optional<String> description,
             final Optional<String> reference) {
@@ -110,7 +110,7 @@ public final class BaseConstraints {
      *
      * <ul>
      * <li>{@link LengthConstraint#getErrorAppTag()} returns <code>length-out-of-specified-bounds</code>
-     * <li>{@link LengthConstraint#getErrorMessage() returns <code>The argument is out of bounds &lt;<i>min</i>, <i>max</i> &gt;</code>
+     * <li>{@link LengthConstraint#getErrorMessage()} returns <code>The argument is out of bounds &lt;<i>min</i>, <i>max</i> &gt;</code>
      * </ul>
      *
      * @see LengthConstraint
@@ -136,7 +136,7 @@ public final class BaseConstraints {
      *
      * <ul>
      * <li>{@link RangeConstraint#getErrorAppTag()} returns <code>range-out-of-specified-bounds</code>
-     * <li>{@link RangeConstraint#getErrorMessage() returns <code>The argument is out of bounds &lt;<i>min</i>, <i>max</i> &gt;</code>
+     * <li>{@link RangeConstraint#getErrorMessage()} returns <code>The argument is out of bounds &lt;<i>min</i>, <i>max</i> &gt;</code>
      * </ul>
      *
      *
index 6e31ba1ee7c3ec1b0ed7bb01bbb24b58c8b14e50..297e0a8f96180ca3fc4f9dcb2cef5a7b97d4ffe5 100644 (file)
@@ -24,7 +24,7 @@
  * still result of processing only single unit of schema source (e.g. file, input stream). E.g.:
  * <ul>
  * <li>{@link java.lang.String} - textual representation of source code
- * <li>{@link InputStream} - input stream containing source code
+ * <li>{@link java.io.InputStream} - input stream containing source code
  * <li>{@link com.google.common.io.ByteSource} - source for input streams containing source code
  * <li>Parsed AST - abstract syntax tree, which is result of a parser, but still it is not linked
  * against other schemas.
@@ -44,4 +44,4 @@
  *
  *
  */
-package org.opendaylight.yangtools.yang.model.util.repo;
\ No newline at end of file
+package org.opendaylight.yangtools.yang.model.util.repo;
index 7b543b730702718226447a1ba3efde9ee4cc9a17..051dd4f72729a94bb9d76f3e3c117d5797f4c282 100644 (file)
@@ -178,12 +178,25 @@ public final class ModuleDependencySort {
                 Object mod = allNS.get(ns);
                 String name = null;
                 Date revision = null;
+
+                if(mod instanceof ModuleOrModuleBuilder) {
+                    ModuleOrModuleBuilder modOrmodBuilder = ((ModuleOrModuleBuilder) mod);
+                    if(modOrmodBuilder.isModule()) {
+                        mod = ((ModuleOrModuleBuilder) mod).getModule();
+                    } else if (modOrmodBuilder.isModuleBuilder()) {
+                        mod = ((ModuleOrModuleBuilder) mod).getModuleBuilder();
+                    } else {
+                        LOGGER.warn("ModuleOrModuleBuilder is neither Module or ModuleBuilder");
+                    }
+                }
                 if (mod instanceof Module) {
                     name = ((Module) mod).getName();
                     revision = ((Module) mod).getRevision();
                 } else if (mod instanceof ModuleBuilder) {
                     name = ((ModuleBuilder) mod).getName();
                     revision = ((ModuleBuilder) mod).getRevision();
+                } else {
+                    LOGGER.warn("Module has no name: {}", mod);
                 }
                 if (!(fromName.equals(name))) {
                     LOGGER.warn(