Merge "BUG-1537: improved YangModuleInfo."
authorTony Tkacik <ttkacik@cisco.com>
Mon, 25 Aug 2014 10:32:33 +0000 (10:32 +0000)
committerGerrit Code Review <gerrit@opendaylight.org>
Mon, 25 Aug 2014 10:32:33 +0000 (10:32 +0000)
63 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
code-generator/binding-generator-impl/src/main/java/org/opendaylight/yangtools/sal/binding/generator/impl/BindingGeneratorImpl.java
code-generator/binding-generator-impl/src/main/java/org/opendaylight/yangtools/sal/binding/generator/impl/RuntimeGeneratedMappingServiceImpl.java
code-generator/binding-generator-impl/src/main/java/org/opendaylight/yangtools/sal/binding/generator/impl/YangTemplate.xtend
code-generator/binding-generator-impl/src/main/java/org/opendaylight/yangtools/sal/binding/generator/util/BindingRuntimeContext.java
code-generator/maven-sal-api-gen-plugin/src/main/java/org/opendaylight/yangtools/maven/sal/api/gen/plugin/CodeGeneratorImpl.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/repo/util/InMemorySchemaSourceCache.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/antlr/YangParser.g4
yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/builder/api/AugmentationSchemaBuilder.java
yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/builder/api/ConstraintsBuilder.java
yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/builder/api/RefineBuilder.java
yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/builder/api/TypeDefinitionBuilder.java
yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/builder/api/UnknownSchemaNodeBuilder.java
yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/builder/impl/BuilderUtils.java
yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/impl/ParserListenerUtils.java
yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/impl/YangParserListenerImpl.java
yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/impl/util/URLSchemaContextResolver.java
yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/repo/URLSchemaContextResolver.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 f42678e7c287d60c30ca69e1dceab8700d9a1305..87f15ab128b1ad26a53993aa7851637e2c3250a9 100644 (file)
@@ -30,6 +30,7 @@ import static org.opendaylight.yangtools.yang.model.util.SchemaContextUtil.findP
 import com.google.common.base.Splitter;
 import com.google.common.collect.Iterables;
 import com.google.common.collect.Sets;
+
 import java.util.ArrayList;
 import java.util.Collection;
 import java.util.Collections;
@@ -38,6 +39,7 @@ import java.util.Iterator;
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
+
 import org.opendaylight.yangtools.binding.generator.util.BindingGeneratorUtil;
 import org.opendaylight.yangtools.binding.generator.util.BindingTypes;
 import org.opendaylight.yangtools.binding.generator.util.ReferencedTypeImpl;
@@ -105,9 +107,28 @@ import org.slf4j.LoggerFactory;
 
 public class BindingGeneratorImpl implements BindingGenerator {
     private static final Logger LOG = LoggerFactory.getLogger(BindingGeneratorImpl.class);
+    private static final Splitter COLON_SPLITTER = Splitter.on(':');
+    private static final Splitter BSDOT_SPLITTER = Splitter.on("\\.");
+    private static final char NEW_LINE = '\n';
+
+    /**
+     * Constant with the concrete name of identifier.
+     */
+    private static final String AUGMENT_IDENTIFIER_NAME = "augment-identifier";
+
+    /**
+     * Constant with the concrete name of namespace.
+     */
+    private static final String YANG_EXT_NAMESPACE = "urn:opendaylight:yang:extension:yang-ext";
 
     private final Map<Module, ModuleContext> genCtx = new HashMap<>();
 
+    /**
+     * When set to true, generated classes will include javadoc comments which
+     * are useful for users.
+     */
+    private final boolean verboseClassComments;
+
     /**
      * Outer key represents the package name. Outer value represents map of all
      * builders in the same package. Inner key represents the schema node name
@@ -128,18 +149,23 @@ public class BindingGeneratorImpl implements BindingGenerator {
     private SchemaContext schemaContext;
 
     /**
-     * Constant with the concrete name of namespace.
+     * Create a new binding generator with verboe comments.
+     *
+     * @deprecated Use {@link #BindingGeneratorImpl(boolean)} instead.
      */
-    private final static String YANG_EXT_NAMESPACE = "urn:opendaylight:yang:extension:yang-ext";
+    @Deprecated
+    public BindingGeneratorImpl() {
+        this(true);
+    }
 
     /**
-     * Constant with the concrete name of identifier.
+     * Create a new binding generator.
+     *
+     * @param verboseClassComments generate verbose comments
      */
-    private final static String AUGMENT_IDENTIFIER_NAME = "augment-identifier";
-
-    private final char NEW_LINE = '\n';
-
-    private final char TAB = '\t';
+    public BindingGeneratorImpl(final boolean verboseClassComments) {
+        this.verboseClassComments = verboseClassComments;
+    }
 
     /**
      * Resolves generated types from <code>context</code> schema nodes of all
@@ -620,7 +646,6 @@ public class BindingGeneratorImpl implements BindingGenerator {
         newType.setDescription(createDescription(identity, newType.getFullyQualifiedName()));
         newType.setReference(identity.getReference());
         newType.setModuleName(module.getName());
-        SchemaPath path = identity.getPath();
         newType.setSchemaPath(identity.getPath().getPathFromRoot());
 
         final QName qname = identity.getQName();
@@ -1373,7 +1398,7 @@ public class BindingGeneratorImpl implements BindingGenerator {
                 final String nodeParam = node.getNodeParameter();
                 IdentitySchemaNode identity = null;
                 String basePackageName = null;
-                final Iterable<String> splittedElement = Splitter.on(':').split(nodeParam);
+                final Iterable<String> splittedElement = COLON_SPLITTER.split(nodeParam);
                 final Iterator<String> iterator = splittedElement.iterator();
                 final int length = Iterables.size(splittedElement);
                 if (length == 1) {
@@ -1966,15 +1991,13 @@ public class BindingGeneratorImpl implements BindingGenerator {
 
     private String createDescription(final Set<? extends SchemaNode> schemaNodes, final String moduleName, final String moduleSourcePath) {
         final StringBuilder sb = new StringBuilder();
-        final String yangSnipet = YangTemplate.generateYangSnipet(schemaNodes);
 
         if (!isNullOrEmpty(schemaNodes)) {
             final SchemaNode node = schemaNodes.iterator().next();
 
             if (node instanceof RpcDefinition) {
                 sb.append("Interface for implementing the following YANG RPCs defined in module <b>" + moduleName + "</b>");
-            }
-            else if (node instanceof NotificationDefinition) {
+            } else if (node instanceof NotificationDefinition) {
                 sb.append("Interface for receiving the following YANG notifications defined in module <b>" + moduleName + "</b>");
             }
         }
@@ -1983,72 +2006,77 @@ public class BindingGeneratorImpl implements BindingGenerator {
         sb.append(moduleSourcePath);
         sb.append("</i>):");
         sb.append(NEW_LINE);
-        sb.append("<pre>");
-        sb.append(NEW_LINE);
-        sb.append(yangSnipet);
-        sb.append("</pre>");
-        sb.append(NEW_LINE);
+
+        if (verboseClassComments) {
+            sb.append("<pre>");
+            sb.append(NEW_LINE);
+            sb.append(YangTemplate.generateYangSnipet(schemaNodes));
+            sb.append("</pre>");
+            sb.append(NEW_LINE);
+        }
 
         return sb.toString();
     }
 
     private String createDescription(final SchemaNode schemaNode, final String fullyQualifiedName) {
         final StringBuilder sb = new StringBuilder();
-        final Module module = findParentModule(schemaContext, schemaNode);
-        final String yangSnipet = YangTemplate.generateYangSnipet(schemaNode);
         final String formattedDescription = YangTemplate.formatToParagraph(schemaNode.getDescription(), 0);
-        final StringBuilder linkToBuilderClass = new StringBuilder();
-        final StringBuilder linkToKeyClass = new StringBuilder();
-        final Splitter splitter = Splitter.on("\\.");
-        final String[] namespace = Iterables.toArray(splitter.split(fullyQualifiedName), String.class);
-        String className = namespace[namespace.length - 1];
-
-        if (hasBuilderClass(schemaNode)) {
-            linkToBuilderClass.append(className);
-            linkToBuilderClass.append("Builder");
-
-            if (schemaNode instanceof ListSchemaNode) {
-                linkToKeyClass.append(className);
-                linkToKeyClass.append("Key");
-            }
-        }
 
         if (!isNullOrEmpty(formattedDescription)) {
             sb.append(formattedDescription);
             sb.append(NEW_LINE);
         }
-        sb.append("<p>");
-        sb.append("This class represents the following YANG schema fragment defined in module <b>");
-        sb.append(module.getName());
-        sb.append("</b>");
-        sb.append(NEW_LINE);
-        sb.append("<br />(Source path: <i>");
-        sb.append(module.getModuleSourcePath());
-        sb.append("</i>):");
-        sb.append(NEW_LINE);
-        sb.append("<pre>");
-        sb.append(NEW_LINE);
-        sb.append(yangSnipet);
-        sb.append("</pre>");
-        sb.append(NEW_LINE);
-        sb.append("The schema path to identify an instance is");
-        sb.append(NEW_LINE);
-        sb.append("<i>");
-        sb.append(YangTemplate.formatSchemaPath(module.getName(), schemaNode.getPath().getPathFromRoot()));
-        sb.append("</i>");
-        sb.append(NEW_LINE);
 
-        if (hasBuilderClass(schemaNode)) {
+        if (verboseClassComments) {
+            final Module module = findParentModule(schemaContext, schemaNode);
+            final StringBuilder linkToBuilderClass = new StringBuilder();
+            final StringBuilder linkToKeyClass = new StringBuilder();
+            final String[] namespace = Iterables.toArray(BSDOT_SPLITTER.split(fullyQualifiedName), String.class);
+            String className = namespace[namespace.length - 1];
+
+            if (hasBuilderClass(schemaNode)) {
+                linkToBuilderClass.append(className);
+                linkToBuilderClass.append("Builder");
+
+                if (schemaNode instanceof ListSchemaNode) {
+                    linkToKeyClass.append(className);
+                    linkToKeyClass.append("Key");
+                }
+            }
+
+            sb.append("<p>");
+            sb.append("This class represents the following YANG schema fragment defined in module <b>");
+            sb.append(module.getName());
+            sb.append("</b>");
+            sb.append(NEW_LINE);
+            sb.append("<br />(Source path: <i>");
+            sb.append(module.getModuleSourcePath());
+            sb.append("</i>):");
             sb.append(NEW_LINE);
-            sb.append("<p>To create instances of this class use " + "{@link " + linkToBuilderClass + "}.");
+            sb.append("<pre>");
             sb.append(NEW_LINE);
-            sb.append("@see ");
-            sb.append(linkToBuilderClass);
-            if (schemaNode instanceof ListSchemaNode) {
+            sb.append(YangTemplate.generateYangSnipet(schemaNode));
+            sb.append("</pre>");
+            sb.append(NEW_LINE);
+            sb.append("The schema path to identify an instance is");
+            sb.append(NEW_LINE);
+            sb.append("<i>");
+            sb.append(YangTemplate.formatSchemaPath(module.getName(), schemaNode.getPath().getPathFromRoot()));
+            sb.append("</i>");
+            sb.append(NEW_LINE);
+
+            if (hasBuilderClass(schemaNode)) {
+                sb.append(NEW_LINE);
+                sb.append("<p>To create instances of this class use " + "{@link " + linkToBuilderClass + "}.");
+                sb.append(NEW_LINE);
                 sb.append("@see ");
-                sb.append(linkToKeyClass);
+                sb.append(linkToBuilderClass);
+                if (schemaNode instanceof ListSchemaNode) {
+                    sb.append("@see ");
+                    sb.append(linkToKeyClass);
+                }
+                sb.append(NEW_LINE);
             }
-            sb.append(NEW_LINE);
         }
 
         return sb.toString();
@@ -2068,26 +2096,28 @@ public class BindingGeneratorImpl implements BindingGenerator {
 
     private String createDescription(final Module module) {
         final StringBuilder sb = new StringBuilder();
-        final String yangSnipet = YangTemplate.generateYangSnipet(module);
         final String formattedDescription = YangTemplate.formatToParagraph(module.getDescription(), 0);
 
         if (!isNullOrEmpty(formattedDescription)) {
             sb.append(formattedDescription);
             sb.append(NEW_LINE);
         }
-        sb.append("<p>");
-        sb.append("This class represents the following YANG schema fragment defined in module <b>");
-        sb.append(module.getName());
-        sb.append("</b>");
-        sb.append(NEW_LINE);
-        sb.append("<br />Source path: <i>");
-        sb.append(module.getModuleSourcePath());
-        sb.append("</i>):");
-        sb.append(NEW_LINE);
-        sb.append("<pre>");
-        sb.append(NEW_LINE);
-        sb.append(yangSnipet);
-        sb.append("</pre>");
+
+        if (verboseClassComments) {
+            sb.append("<p>");
+            sb.append("This class represents the following YANG schema fragment defined in module <b>");
+            sb.append(module.getName());
+            sb.append("</b>");
+            sb.append(NEW_LINE);
+            sb.append("<br />Source path: <i>");
+            sb.append(module.getModuleSourcePath());
+            sb.append("</i>):");
+            sb.append(NEW_LINE);
+            sb.append("<pre>");
+            sb.append(NEW_LINE);
+            sb.append(YangTemplate.generateYangSnipet(module));
+            sb.append("</pre>");
+        }
 
         return sb.toString();
     }
index da757095d6a5d984bbaa2465f772cf86aa5adf33..29a532228dd54bfc6421c34035af5f91f923cafb 100644 (file)
@@ -13,6 +13,7 @@ import com.google.common.collect.HashMultimap;
 import com.google.common.collect.Multimap;
 import com.google.common.util.concurrent.ListenableFuture;
 import com.google.common.util.concurrent.SettableFuture;
+
 import java.net.URI;
 import java.util.AbstractMap.SimpleEntry;
 import java.util.ArrayList;
@@ -27,8 +28,11 @@ import java.util.Set;
 import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.ConcurrentMap;
 import java.util.concurrent.ExecutionException;
+
 import javassist.ClassPool;
+
 import javax.annotation.concurrent.GuardedBy;
+
 import org.opendaylight.yangtools.binding.generator.util.BindingGeneratorUtil;
 import org.opendaylight.yangtools.binding.generator.util.ReferencedTypeImpl;
 import org.opendaylight.yangtools.binding.generator.util.Types;
@@ -134,7 +138,7 @@ SchemaLock, AutoCloseable, SchemaContextHolder, TypeResolver {
 
     @GuardedBy("this")
     private void recreateBindingContext(final SchemaContext schemaContext) {
-        BindingGeneratorImpl newBinding = new BindingGeneratorImpl();
+        BindingGeneratorImpl newBinding = new BindingGeneratorImpl(false);
         newBinding.generateTypes(schemaContext);
 
         for (Map.Entry<Module, ModuleContext> entry : newBinding.getModuleContexts().entrySet()) {
index 98d7ef1d9e120bc4540bf7fa7e8d910ac58cf125..d0ad08c36b950c07a0945204b5bd37cb71f60406 100644 (file)
@@ -7,7 +7,6 @@
  */
 package org.opendaylight.yangtools.sal.binding.generator.impl
 
-import java.text.SimpleDateFormat
 import java.util.Collection
 import java.util.Date
 import java.util.List
@@ -40,11 +39,16 @@ import org.opendaylight.yangtools.yang.model.api.UnknownSchemaNode
 import org.opendaylight.yangtools.yang.model.api.UsesNode
 import org.opendaylight.yangtools.yang.model.api.type.EnumTypeDefinition
 import org.opendaylight.yangtools.yang.model.api.type.EnumTypeDefinition.EnumPair
+import org.opendaylight.yangtools.yang.common.SimpleDateFormatUtil
+import com.google.common.base.CharMatcher
 
 class YangTemplate {
 
+    // FIXME: this is not thread-safe and seems to be unused!
     private static var Module module = null
 
+    private static val CharMatcher NEWLINE_OR_TAB = CharMatcher.anyOf("\n\t")
+
     def static String generateYangSnipet(SchemaNode schemaNode) {
         if (schemaNode == null)
             return ''
@@ -121,16 +125,11 @@ class YangTemplate {
         '''
     }
 
-    def static formatDate(Date moduleRevision) {
-        val SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-mm-dd")
-        return dateFormat.format(moduleRevision)
-    }
-
     def static writeRevision(Date moduleRevision, String moduleDescription) {
         val revisionIndent = 12
 
         '''
-            revision Â«formatDate(moduleRevision)» {
+            revision Â«SimpleDateFormatUtil.getRevisionFormat.format(moduleRevision)» {
                 description "«formatToParagraph(moduleDescription, revisionIndent)»";
             }
         '''
@@ -736,8 +735,7 @@ class YangTemplate {
         val lineIndent = computeNextLineIndent(nextLineIndent);
 
         formattedText = formattedText.replace("*/", "&#42;&#47;");
-        formattedText = formattedText.replace("\n", "");
-        formattedText = formattedText.replace("\t", "");
+        formattedText = NEWLINE_OR_TAB.removeFrom(formattedText);
         formattedText = formattedText.replaceAll(" +", " ");
 
         val StringTokenizer tokenizer = new StringTokenizer(formattedText, " ", true);
@@ -785,8 +783,7 @@ class YangTemplate {
             val ns = pathElement.namespace
             val localName = pathElement.localName
 
-            sb.append("\\")
-            sb.append('(')
+            sb.append("\\(")
             sb.append(ns)
             sb.append(')')
             sb.append(localName)
index 1b40b8895c57d82eadd8fe32f843e5eab5a8bbda..a69e30ea1f437067035f5ffc459a637ad3c1e958 100644 (file)
@@ -77,7 +77,7 @@ public class BindingRuntimeContext implements Immutable {
         this.strategy = strategy;
         this.schemaContext = schema;
 
-        BindingGeneratorImpl generator = new BindingGeneratorImpl();
+        BindingGeneratorImpl generator = new BindingGeneratorImpl(false);
         generator.generateTypes(schema);
         Map<Module, ModuleContext> modules = generator.getModuleContexts();
 
index a2b60e89d3454151f4388e8a2c3d73f9893d22f6..99f426dcc68c888492f3f730cbab95e8e7e9469d 100644 (file)
@@ -11,6 +11,18 @@ import com.google.common.base.Joiner;
 import com.google.common.base.Preconditions;
 import com.google.common.collect.ImmutableSet;
 import com.google.common.collect.ImmutableSet.Builder;
+
+import java.io.BufferedWriter;
+import java.io.File;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.io.OutputStreamWriter;
+import java.io.Writer;
+import java.util.Collection;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
 import org.apache.maven.plugin.logging.Log;
 import org.apache.maven.project.MavenProject;
 import org.opendaylight.yangtools.binding.generator.util.BindingGeneratorUtil;
@@ -29,17 +41,6 @@ import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.sonatype.plexus.build.incremental.BuildContext;
 
-import java.io.BufferedWriter;
-import java.io.File;
-import java.io.IOException;
-import java.io.OutputStream;
-import java.io.OutputStreamWriter;
-import java.io.Writer;
-import java.util.Collection;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-
 public final class CodeGeneratorImpl implements CodeGenerator, BuildContextAware {
     private static final String FS = File.separator;
     private BuildContext buildContext;
@@ -57,7 +58,7 @@ public final class CodeGeneratorImpl implements CodeGenerator, BuildContextAware
 
         outputBaseDir = outputDir == null ? getDefaultOutputBaseDir() : outputDir;
 
-        final BindingGenerator bindingGenerator = new BindingGeneratorImpl();
+        final BindingGenerator bindingGenerator = new BindingGeneratorImpl(true);
         final List<Type> types = bindingGenerator.generateTypes(context, yangModules);
         final GeneratorJavaFile generator = new GeneratorJavaFile(buildContext, types);
 
@@ -78,8 +79,8 @@ public final class CodeGeneratorImpl implements CodeGenerator, BuildContextAware
         return result;
     }
 
-    private Collection<? extends File> generateModuleInfos(File outputBaseDir, Set<Module> yangModules,
-                                                           SchemaContext context) {
+    private Collection<? extends File> generateModuleInfos(final File outputBaseDir, final Set<Module> yangModules,
+                                                           final SchemaContext context) {
         Builder<File> result = ImmutableSet.builder();
         Builder<String> bindingProviders = ImmutableSet.builder();
         for (Module module : yangModules) {
@@ -96,8 +97,8 @@ public final class CodeGeneratorImpl implements CodeGenerator, BuildContextAware
         return result.build();
     }
 
-    private File writeMetaInfServices(File outputBaseDir, Class<YangModelBindingProvider> serviceClass,
-            ImmutableSet<String> services) {
+    private File writeMetaInfServices(final File outputBaseDir, final Class<YangModelBindingProvider> serviceClass,
+            final ImmutableSet<String> services) {
         File metainfServicesFolder = new File(outputBaseDir, "META-INF" + File.separator + "services");
         metainfServicesFolder.mkdirs();
         File serviceFile = new File(metainfServicesFolder, serviceClass.getName());
@@ -118,38 +119,38 @@ public final class CodeGeneratorImpl implements CodeGenerator, BuildContextAware
         return outputBaseDir;
     }
 
-    private static void setOutputBaseDirAsSourceFolder(File outputBaseDir, MavenProject mavenProject) {
+    private static void setOutputBaseDirAsSourceFolder(final File outputBaseDir, final MavenProject mavenProject) {
         Preconditions.checkNotNull(mavenProject, "Maven project needs to be set in this phase");
         mavenProject.addCompileSourceRoot(outputBaseDir.getPath());
     }
 
     @Override
-    public void setLog(Log log) {
+    public void setLog(final Log log) {
     }
 
     @Override
-    public void setAdditionalConfig(Map<String, String> additionalConfiguration) {
+    public void setAdditionalConfig(final Map<String, String> additionalConfiguration) {
         this.additionalConfig = additionalConfiguration;
     }
 
     @Override
-    public void setResourceBaseDir(File resourceBaseDir) {
+    public void setResourceBaseDir(final File resourceBaseDir) {
         this.resourceBaseDir = resourceBaseDir;
     }
 
     @Override
-    public void setMavenProject(MavenProject project) {
+    public void setMavenProject(final MavenProject project) {
         this.mavenProject = project;
         this.projectBaseDir = project.getBasedir();
     }
 
     @Override
-    public void setBuildContext(BuildContext buildContext) {
+    public void setBuildContext(final BuildContext buildContext) {
         this.buildContext = Preconditions.checkNotNull(buildContext);
     }
 
-    private Set<File> generateYangModuleInfo(File outputBaseDir, Module module, SchemaContext ctx,
-            Builder<String> providerSourceSet) {
+    private Set<File> generateYangModuleInfo(final File outputBaseDir, final Module module, final SchemaContext ctx,
+            final Builder<String> providerSourceSet) {
         Builder<File> generatedFiles = ImmutableSet.<File> builder();
 
         final YangModuleInfoTemplate template = new YangModuleInfoTemplate(module, ctx);
@@ -171,7 +172,7 @@ public final class CodeGeneratorImpl implements CodeGenerator, BuildContextAware
 
     }
 
-    private File writeJavaSource(File packageDir, String className, String source) {
+    private File writeJavaSource(final File packageDir, final String className, final String source) {
         if (!packageDir.exists()) {
             packageDir.mkdirs();
         }
@@ -180,7 +181,7 @@ public final class CodeGeneratorImpl implements CodeGenerator, BuildContextAware
         return file;
     }
 
-    private File writeFile(File file, String source) {
+    private File writeFile(final File file, final String source) {
         try (final OutputStream stream = buildContext.newFileOutputStream(file)) {
             try (final Writer fw = new OutputStreamWriter(stream)) {
                 try (final BufferedWriter bw = new BufferedWriter(fw)) {
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 60dfb90a883a574c95a02e03afa472eb5d6e49d9..ad594e422116463671bb760fd75945ff647f0660 100644 (file)
@@ -6,6 +6,7 @@
  */
 package org.opendaylight.yangtools.yang.model.repo.util;
 
+import com.google.common.annotations.Beta;
 import com.google.common.base.Preconditions;
 import com.google.common.cache.Cache;
 import com.google.common.cache.CacheBuilder;
@@ -22,6 +23,7 @@ import org.opendaylight.yangtools.yang.model.repo.spi.PotentialSchemaSource.Cost
 import org.opendaylight.yangtools.yang.model.repo.spi.SchemaSourceRegistration;
 import org.opendaylight.yangtools.yang.model.repo.spi.SchemaSourceRegistry;
 
+@Beta
 public class InMemorySchemaSourceCache<T extends SchemaSourceRepresentation> extends AbstractSchemaSourceCache<T> {
     private static final class CacheEntry<T extends SchemaSourceRepresentation> {
         private final SchemaSourceRegistration<T> reg;
@@ -42,9 +44,13 @@ public class InMemorySchemaSourceCache<T extends SchemaSourceRepresentation> ext
 
     private final Cache<SourceIdentifier, CacheEntry<T>> cache;
 
-    protected InMemorySchemaSourceCache(final SchemaSourceRegistry consumer, final Class<T> representation, final int maxSize) {
+    protected InMemorySchemaSourceCache(final SchemaSourceRegistry consumer, final Class<T> representation, final CacheBuilder<Object, Object> builder) {
         super(consumer, representation, Costs.IMMEDIATE);
-        cache = CacheBuilder.newBuilder().softValues().maximumSize(maxSize).removalListener(LISTENER).build();
+        cache = builder.removalListener(LISTENER).build();
+    }
+
+    public static <R extends SchemaSourceRepresentation> InMemorySchemaSourceCache<R> createSoftCache(final SchemaSourceRegistry consumer, final Class<R> representation) {
+        return new InMemorySchemaSourceCache<>(consumer, representation, CacheBuilder.newBuilder().softValues());
     }
 
     @Override
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 eea920abc01891933f2ac273662e88aa780adfec..26e2056ee85fc7ef73bc9562a31c04a62db69c15 100644 (file)
@@ -89,7 +89,7 @@ status_stmt : STATUS_KEYWORD status_arg stmtend;
 position_stmt : POSITION_KEYWORD string stmtend;
 bit_stmt : BIT_KEYWORD string (SEMICOLON | (LEFT_BRACE  (identifier_stmt |position_stmt | status_stmt | description_stmt | reference_stmt )* RIGHT_BRACE));
 bits_specification : bit_stmt (bit_stmt | identifier_stmt)*;
-union_specification : type_stmt (identifier_stmt | type_stmt )+;
+union_specification : type_stmt (identifier_stmt | type_stmt )*;
 identityref_specification : base_stmt  ;
 instance_identifier_specification : (require_instance_stmt )?;
 require_instance_arg :string; // TRUE_KEYWORD | FALSE_KEYWORD;
index 1699da75abf9d9516cf156d9bbe0fd8d33f934be..f7004791e2c1d21da4fd77970c28438bfdd5f588 100644 (file)
@@ -19,13 +19,11 @@ public interface AugmentationSchemaBuilder extends DataNodeContainerBuilder,Docu
      * Returns when condition
      *
      * If when condition is present node defined by the parent data definition
-     * statement is only valid when the returned XPath
-     * expression conceptually evaluates to "true"
-     * for a particular instance, then the node defined by the parent data
-     * definition statement is valid; otherwise, it is not.
-     *
+     * statement is only valid when the returned XPath expression conceptually
+     * evaluates to "true" for a particular instance, then the node defined by
+     * the parent data definition statement is valid; otherwise, it is not.
      *
-     * @return
+     * @return when condition as string
      */
     String getWhenCondition();
 
index 196b49deb25a4736bbafd5a09a286ba8025edff4..e122e5978fbec50546e5f57df7461c4ae21d65b2 100644 (file)
@@ -65,7 +65,7 @@ public interface ConstraintsBuilder extends Builder<ConstraintDefinition> {
      *
      * This constraint has meaning only if associated node is list or leaf-list.
      *
-     * @param minElements
+     * @param maxElements
      *            number of maximum required elements.
      */
     void setMaxElements(Integer maxElements);
@@ -119,7 +119,7 @@ public interface ConstraintsBuilder extends Builder<ConstraintDefinition> {
     /**
      * Build constraint definition
      *
-     * @return
+     * @return instance of ConstraintDefinition created from this builder
      */
     ConstraintDefinition toInstance();
 
index 183f9fd05c62d8a19ab451188576cdfee6f29bc0..89237986586239bd6339692db77c379f1645b2f9 100644 (file)
@@ -106,7 +106,7 @@ public interface RefineBuilder extends DocumentedNodeBuilder {
    *
    * This constraint has meaning only if associated node is list or leaf-list.
    *
-   * @param minElements number of maximum required elements.
+   * @param maxElements number of maximum required elements.
    */
    void setMaxElements(Integer maxElements);
 
index e547d440fa9cf8c90f6d0761006bae90fb100162..068130fbf80ddfd4363a59d2ce447f08cc4cd89f 100644 (file)
@@ -69,10 +69,10 @@ public interface TypeDefinitionBuilder extends TypeAwareBuilder, SchemaNodeBuild
     List<PatternConstraint> getPatterns();
 
     /**
-     * Set length restrictions for resulting type definition.
+     * Set pattern restrictions for resulting type definition.
      *
-     * @param lengths
-     *            Length restrictions of resulting type definition.
+     * @param patterns
+     *            patterns restrictions of resulting type definition.
      */
     void setPatterns(List<PatternConstraint> patterns);
 
@@ -86,11 +86,8 @@ public interface TypeDefinitionBuilder extends TypeAwareBuilder, SchemaNodeBuild
     Integer getFractionDigits();
 
     /**
-     *
-     * Sets fractions digits of resulting type if it is derived
-     * from <code>decimal</code> built-in type.
-     *
-     * @return fractions digits of resulting type
+     * Sets fractions digits of resulting type if it is derived from
+     * <code>decimal</code> built-in type.
      */
     void setFractionDigits(Integer fractionDigits);
 
index 3b0cb966cd0ba3873a5145166e390d2a1fad8209..433c0821c02f850fe0532269b0fa94699acd3d77 100644 (file)
@@ -72,7 +72,9 @@ public interface UnknownSchemaNodeBuilder extends SchemaNodeBuilder, DocumentedN
 
     /**
      * Sets extension builder, which declares this unknown node
-     * @param extensionBuilder extension definition, which declares this unknown node
+     *
+     * @param extension
+     *            extension builder, which declares this unknown node
      */
     void setExtensionBuilder(ExtensionBuilder extension);
 
index d2bb65227e8118e779b6f07bc871f4ad2a10983f..759e779eed26e29a079b7e37681515022e8a160a 100644 (file)
@@ -20,8 +20,6 @@ import java.io.FileNotFoundException;
 import java.io.IOException;
 import java.io.InputStream;
 import java.net.URI;
-import java.text.DateFormat;
-import java.text.SimpleDateFormat;
 import java.util.ArrayList;
 import java.util.Collection;
 import java.util.Date;
@@ -81,9 +79,7 @@ import org.slf4j.LoggerFactory;
 
 public final class BuilderUtils {
 
-    private static final DateFormat SIMPLE_DATE_FORMAT = new SimpleDateFormat("yyyy-MM-dd");
     private static final Logger LOG = LoggerFactory.getLogger(BuilderUtils.class);
-    private static final Splitter SLASH_SPLITTER = Splitter.on('/').omitEmptyStrings();
     private static final Splitter COLON_SPLITTER = Splitter.on(':');
     private static final Date NULL_DATE = new Date(0L);
     private static final String INPUT = "input";
@@ -476,7 +472,7 @@ public final class BuilderUtils {
      *            Class to be checked
      * @param optional
      *            Original value
-     * @return
+     * @return Optional object with type argument casted as cls
      */
     private static <T> Optional<T> castOptional(final Class<T> cls, final Optional<?> optional) {
         if (optional.isPresent()) {
@@ -638,10 +634,9 @@ public final class BuilderUtils {
      * Find augment target node and perform augmentation.
      *
      * @param augment
+     *            augment builder to process
      * @param firstNodeParent
      *            parent of first node in path
-     * @param path
-     *            path to augment target
      * @return true if augmentation process succeed, false otherwise
      */
     public static boolean processAugmentation(final AugmentationSchemaBuilder augment,
index 57f1cc963519ef230b14f53e429223329995e748..933ac6b6d4f17f489efb3fa878ea868bbf7bfb94 100644 (file)
@@ -1091,12 +1091,8 @@ public final class ParserListenerUtils {
      *            type body context
      * @param actualPath
      *            current path in schema
-     * @param namespace
-     *            current namespace
-     * @param revision
-     *            current revision
-     * @param prefix
-     *            current prefix
+     * @param moduleQName
+     *            current module qname
      * @param parent
      *            parent builder
      * @return TypeDefinition object based on parsed values.
index ece9226253cb04bb012a19c0fa67b7fae1745619..9de7ce02b4fa5b077b642d1e5214db151b4c7f12 100644 (file)
@@ -127,14 +127,14 @@ public final class YangParserListenerImpl extends YangParserBaseListener {
      * Create a new instance.
      *
      * FIXME: the resulting type needs to be extracted, such that we can reuse
-     *        the "BaseListener" aspect, which need not be exposed to the user.
-     *        Maybe factor out a base class into repo.spi?
+     * the "BaseListener" aspect, which need not be exposed to the user. Maybe
+     * factor out a base class into repo.spi?
      *
      * @param namespaceContext
      * @param sourcePath
      * @param walker
      * @param tree
-     * @return
+     * @return new instance of YangParserListenerImpl
      */
     public static YangParserListenerImpl create(final Map<String, TreeMap<Date, URI>> namespaceContext,
             final String sourcePath, final ParseTreeWalker walker, final ParseTree tree) {
@@ -346,8 +346,7 @@ public final class YangParserListenerImpl extends YangParserBaseListener {
             final ParseTree treeNode = ctx.getChild(i);
             if (treeNode instanceof Prefix_stmtContext) {
                 importPrefix = stringFromNode(treeNode);
-            }
-            if (treeNode instanceof Revision_date_stmtContext) {
+            } else if (treeNode instanceof Revision_date_stmtContext) {
                 String importRevisionStr = stringFromNode(treeNode);
                 try {
                     importRevision = SIMPLE_DATE_FORMAT.parse(importRevisionStr);
index 34c81911321ac42a698252cfdeb02f6b45fbccae..252a782e1567eea80aad6ed7365df494decb9bd4 100644 (file)
@@ -13,6 +13,7 @@ import com.google.common.base.Optional;
 import com.google.common.collect.ImmutableMap;
 import com.google.common.collect.ImmutableMap.Builder;
 import com.google.common.io.ByteSource;
+
 import java.io.IOException;
 import java.io.InputStream;
 import java.net.URL;
@@ -20,8 +21,10 @@ import java.util.Collection;
 import java.util.Map.Entry;
 import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.ConcurrentMap;
+
 import javax.annotation.concurrent.GuardedBy;
 import javax.annotation.concurrent.ThreadSafe;
+
 import org.opendaylight.yangtools.concepts.AbstractObjectRegistration;
 import org.opendaylight.yangtools.concepts.Identifiable;
 import org.opendaylight.yangtools.concepts.ObjectRegistration;
@@ -32,6 +35,11 @@ import org.opendaylight.yangtools.yang.parser.impl.YangParserImpl;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
+/**
+ * @deprecated Use {@link org.opendaylight.yangtools.yang.parser.repo.URLSchemaContextResolver}
+ * instead.
+ */
+@Deprecated
 @ThreadSafe
 public class URLSchemaContextResolver implements AdvancedSchemaSourceProvider<InputStream> {
 
@@ -47,7 +55,7 @@ public class URLSchemaContextResolver implements AdvancedSchemaSourceProvider<In
     /**
      * Register new yang schema when it appears.
      */
-    public synchronized ObjectRegistration<URL> registerSource(URL source) {
+    public synchronized ObjectRegistration<URL> registerSource(final URL source) {
         checkArgument(source != null, "Supplied source must not be null");
         InputStream yangStream = getInputStream(source);
         YangModelDependencyInfo modelInfo = YangModelDependencyInfo.fromInputStream(yangStream);
@@ -63,7 +71,7 @@ public class URLSchemaContextResolver implements AdvancedSchemaSourceProvider<In
     }
 
     @Override
-    public synchronized Optional<InputStream> getSchemaSource(SourceIdentifier key) {
+    public synchronized Optional<InputStream> getSchemaSource(final SourceIdentifier key) {
         SourceContext ctx = availableSources.get(key);
         if (ctx != null) {
             InputStream stream = getInputStream(ctx.getInstance());
@@ -73,11 +81,11 @@ public class URLSchemaContextResolver implements AdvancedSchemaSourceProvider<In
     }
 
     @Override
-    public Optional<InputStream> getSchemaSource(String name, Optional<String> version) {
+    public Optional<InputStream> getSchemaSource(final String name, final Optional<String> version) {
         return getSchemaSource(SourceIdentifier.create(name, version));
     }
 
-    private static InputStream getInputStream(URL source) {
+    private static InputStream getInputStream(final URL source) {
         InputStream stream;
         try {
             stream = source.openStream();
@@ -93,7 +101,7 @@ public class URLSchemaContextResolver implements AdvancedSchemaSourceProvider<In
         final SourceIdentifier identifier;
         final YangModelDependencyInfo dependencyInfo;
 
-        public SourceContext(URL instance, SourceIdentifier identifier, YangModelDependencyInfo modelInfo) {
+        public SourceContext(final URL instance, final SourceIdentifier identifier, final YangModelDependencyInfo modelInfo) {
             super(instance);
             this.identifier = identifier;
             this.dependencyInfo = modelInfo;
@@ -114,7 +122,7 @@ public class URLSchemaContextResolver implements AdvancedSchemaSourceProvider<In
         }
     }
 
-    private synchronized void removeSource(SourceContext sourceContext) {
+    private synchronized void removeSource(final SourceContext sourceContext) {
         boolean removed = availableSources.remove(sourceContext.getIdentifier(), sourceContext);
         if (removed) {
             tryToUpdateSchemaContext();
index bbcd95e220eb34737f50374cadd359c7af17e749..02497a880921dc19edf213ea25e36d09d58fcead 100644 (file)
@@ -13,9 +13,9 @@ import com.google.common.annotations.Beta;
 import com.google.common.base.Objects.ToStringHelper;
 import com.google.common.base.Optional;
 import com.google.common.base.Preconditions;
-import com.google.common.cache.Cache;
-import com.google.common.cache.CacheBuilder;
-import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ArrayListMultimap;
+import com.google.common.collect.ImmutableSet;
+import com.google.common.collect.Multimap;
 import com.google.common.util.concurrent.CheckedFuture;
 import com.google.common.util.concurrent.Futures;
 
@@ -37,30 +37,41 @@ import org.opendaylight.yangtools.yang.model.repo.api.SchemaSourceFilter;
 import org.opendaylight.yangtools.yang.model.repo.api.SourceIdentifier;
 import org.opendaylight.yangtools.yang.model.repo.api.YangTextSchemaSource;
 import org.opendaylight.yangtools.yang.model.repo.spi.PotentialSchemaSource;
+import org.opendaylight.yangtools.yang.model.repo.spi.PotentialSchemaSource.Costs;
+import org.opendaylight.yangtools.yang.model.repo.spi.SchemaListenerRegistration;
 import org.opendaylight.yangtools.yang.model.repo.spi.SchemaSourceProvider;
 import org.opendaylight.yangtools.yang.model.repo.spi.SchemaSourceRegistration;
 import org.opendaylight.yangtools.yang.model.repo.spi.SchemaSourceRegistry;
+import org.opendaylight.yangtools.yang.model.repo.util.InMemorySchemaSourceCache;
 import org.opendaylight.yangtools.yang.parser.util.ASTSchemaSource;
 import org.opendaylight.yangtools.yang.parser.util.TextToASTTransformer;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 @Beta
-public class URLSchemaContextResolver implements SchemaSourceProvider<YangTextSchemaSource> {
+public class URLSchemaContextResolver implements AutoCloseable, SchemaSourceProvider<YangTextSchemaSource> {
     private static final Logger LOG = LoggerFactory.getLogger(URLSchemaContextResolver.class);
 
-    private final Cache<SourceIdentifier, YangTextSchemaSource> sources = CacheBuilder.newBuilder().build();
     private final Collection<SourceIdentifier> requiredSources = new ConcurrentLinkedDeque<>();
+    private final Multimap<SourceIdentifier, YangTextSchemaSource> texts = ArrayListMultimap.create();
     private final AtomicReference<Optional<SchemaContext>> currentSchemaContext =
             new AtomicReference<>(Optional.<SchemaContext>absent());
+    private final InMemorySchemaSourceCache<ASTSchemaSource> cache;
+    private final SchemaListenerRegistration transReg;
     private final SchemaSourceRegistry registry;
     private final SchemaRepository repository;
     private volatile Object version = new Object();
     private volatile Object contextVersion = version;
 
+
     private URLSchemaContextResolver(final SchemaRepository repository, final SchemaSourceRegistry registry) {
         this.repository = Preconditions.checkNotNull(repository);
         this.registry = Preconditions.checkNotNull(registry);
+
+        final TextToASTTransformer t = TextToASTTransformer.create(repository, registry);
+        transReg = registry.registerSchemaSourceListener(t);
+
+        cache = InMemorySchemaSourceCache.createSoftCache(registry, ASTSchemaSource.class);
     }
 
     public static URLSchemaContextResolver create(final String name) {
@@ -96,23 +107,31 @@ public class URLSchemaContextResolver implements SchemaSourceProvider<YangTextSc
         LOG.trace("Resolved URL {} to source {}", url, ast);
 
         final SourceIdentifier resolvedId = ast.getIdentifier();
-        final SchemaSourceRegistration<YangTextSchemaSource> reg = registry.registerSchemaSource(this,
-                PotentialSchemaSource.create(resolvedId, YangTextSchemaSource.class, 0));
-
-        requiredSources.add(resolvedId);
-        LOG.trace("Added source {} to schema context requirements", resolvedId);
-        version = new Object();
 
-        return new AbstractURLRegistration(text) {
-            @Override
-            protected void removeRegistration() {
-                requiredSources.remove(resolvedId);
-                LOG.trace("Removed source {} from schema context requirements", resolvedId);
-                version = new Object();
-                reg.close();
-                sources.invalidate(resolvedId);
-            }
-        };
+        synchronized (this) {
+            texts.put(resolvedId, text);
+            LOG.debug("Populated {} with text", resolvedId);
+
+            final SchemaSourceRegistration<YangTextSchemaSource> reg = registry.registerSchemaSource(this,
+                PotentialSchemaSource.create(resolvedId, YangTextSchemaSource.class, Costs.IMMEDIATE.getValue()));
+            requiredSources.add(resolvedId);
+            cache.schemaSourceEncountered(ast);
+            LOG.debug("Added source {} to schema context requirements", resolvedId);
+            version = new Object();
+
+            return new AbstractURLRegistration(text) {
+                @Override
+                protected void removeRegistration() {
+                    synchronized (URLSchemaContextResolver.this) {
+                        requiredSources.remove(resolvedId);
+                        LOG.trace("Removed source {} from schema context requirements", resolvedId);
+                        version = new Object();
+                        reg.close();
+                        texts.remove(resolvedId, text);
+                    }
+                }
+            };
+        }
     }
 
     /**
@@ -139,7 +158,7 @@ public class URLSchemaContextResolver implements SchemaSourceProvider<YangTextSc
             Collection<SourceIdentifier> sources;
             do {
                 v = version;
-                sources = ImmutableList.copyOf(requiredSources);
+                sources = ImmutableSet.copyOf(requiredSources);
             } while (v != version);
 
             while (true) {
@@ -148,11 +167,13 @@ public class URLSchemaContextResolver implements SchemaSourceProvider<YangTextSc
                     sc = Optional.of(f.checkedGet());
                     break;
                 } catch (SchemaResolutionException e) {
-                    LOG.info("Failed to fully assemble schema context for {}", sources, e);
+                    LOG.debug("Failed to fully assemble schema context for {}", sources, e);
                     sources = e.getResolvedSources();
                 }
             }
 
+            LOG.debug("Resolved schema context for {}", sources);
+
             synchronized (this) {
                 if (contextVersion == cv) {
                     currentSchemaContext.set(sc);
@@ -165,13 +186,20 @@ public class URLSchemaContextResolver implements SchemaSourceProvider<YangTextSc
     }
 
     @Override
-    public CheckedFuture<YangTextSchemaSource, SchemaSourceException> getSource(final SourceIdentifier sourceIdentifier) {
-        final YangTextSchemaSource ret = sources.getIfPresent(sourceIdentifier);
-        if (ret == null) {
+    public synchronized CheckedFuture<YangTextSchemaSource, SchemaSourceException> getSource(final SourceIdentifier sourceIdentifier) {
+        final Collection<YangTextSchemaSource> ret = texts.get(sourceIdentifier);
+
+        LOG.debug("Lookup {} result {}", sourceIdentifier, ret);
+        if (ret.isEmpty()) {
             return Futures.<YangTextSchemaSource, SchemaSourceException>immediateFailedCheckedFuture(
                     new MissingSchemaSourceException("URL for " + sourceIdentifier + " not registered", sourceIdentifier));
         }
 
-        return Futures.immediateCheckedFuture(ret);
+        return Futures.immediateCheckedFuture(ret.iterator().next());
+    }
+
+    @Override
+    public void close() {
+        transReg.close();
     }
 }
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(