Merge "Bug 1442: Fixed SchemaTracker resolving case children."
authorRobert Varga <rovarga@cisco.com>
Wed, 3 Sep 2014 10:12:43 +0000 (10:12 +0000)
committerGerrit Code Review <gerrit@opendaylight.org>
Wed, 3 Sep 2014 10:12:43 +0000 (10:12 +0000)
34 files changed:
code-generator/binding-generator-impl/src/main/java/org/opendaylight/yangtools/sal/binding/generator/impl/BindingGeneratorImpl.java
code-generator/binding-generator-util/src/main/java/org/opendaylight/yangtools/binding/generator/util/generated/type/builder/EnumerationBuilderImpl.java
code-generator/binding-generator-util/src/main/java/org/opendaylight/yangtools/binding/generator/util/generated/type/builder/GeneratedTOBuilderImpl.java
code-generator/binding-generator-util/src/main/java/org/opendaylight/yangtools/binding/generator/util/generated/type/builder/GeneratedTypeBuilderImpl.java
code-generator/binding-java-api-generator/src/main/java/org/opendaylight/yangtools/sal/java/api/generator/BuilderTemplate.xtend
code-generator/binding-java-api-generator/src/test/resources/compilation/typedef/mod-box.yang [deleted file]
code-generator/binding-model-api/src/main/java/org/opendaylight/yangtools/sal/binding/model/api/BoxableType.java [deleted file]
code-generator/binding-model-api/src/main/java/org/opendaylight/yangtools/sal/binding/model/api/GeneratedType.java
code-generator/binding-model-api/src/main/java/org/opendaylight/yangtools/sal/binding/model/api/type/builder/GeneratedTypeBuilder.java
code-generator/binding-model-api/src/main/java/org/opendaylight/yangtools/sal/binding/model/api/type/builder/GeneratedTypeBuilderBase.java
yang/yang-data-api/src/main/java/org/opendaylight/yangtools/yang/data/api/schema/stream/NormalizedNodeWriter.java
yang/yang-data-api/src/main/java/org/opendaylight/yangtools/yang/data/api/schema/tree/spi/ContainerNode.java
yang/yang-data-api/src/main/java/org/opendaylight/yangtools/yang/data/api/schema/tree/spi/LazyContainerNode.java [new file with mode: 0644]
yang/yang-data-api/src/main/java/org/opendaylight/yangtools/yang/data/api/schema/tree/spi/MaterializedContainerNode.java [new file with mode: 0644]
yang/yang-data-impl/pom.xml
yang/yang-data-impl/src/main/java/org/opendaylight/yangtools/yang/data/impl/codec/xml/ElementIdentityrefParser.java [new file with mode: 0644]
yang/yang-data-impl/src/main/java/org/opendaylight/yangtools/yang/data/impl/codec/xml/ElementInstanceIdentifierParser.java [new file with mode: 0644]
yang/yang-data-impl/src/main/java/org/opendaylight/yangtools/yang/data/impl/codec/xml/InstanceIdentifierForXmlCodec.java
yang/yang-data-impl/src/main/java/org/opendaylight/yangtools/yang/data/impl/codec/xml/RandomPrefix.java
yang/yang-data-impl/src/main/java/org/opendaylight/yangtools/yang/data/impl/codec/xml/RandomPrefixInstanceIdentifierSerializer.java [new file with mode: 0644]
yang/yang-data-impl/src/main/java/org/opendaylight/yangtools/yang/data/impl/codec/xml/XmlStreamUtils.java
yang/yang-data-impl/src/main/java/org/opendaylight/yangtools/yang/data/impl/codec/xml/XmlUtils.java
yang/yang-data-impl/src/test/java/org/opendaylight/yangtools/yang/data/impl/codec/xml/RandomPrefixTest.java
yang/yang-data-impl/src/test/java/org/opendaylight/yangtools/yang/data/impl/codec/xml/XmlStreamUtilsTest.java
yang/yang-model-util/src/test/java/org/opendaylight/yangtools/yang/model/util/BaseConstraintsTest.java [new file with mode: 0644]
yang/yang-model-util/src/test/java/org/opendaylight/yangtools/yang/model/util/BaseTypesTest.java [new file with mode: 0644]
yang/yang-model-util/src/test/java/org/opendaylight/yangtools/yang/model/util/BinaryTypeTest.java [new file with mode: 0644]
yang/yang-model-util/src/test/java/org/opendaylight/yangtools/yang/model/util/BooleanTypeTest.java [new file with mode: 0644]
yang/yang-model-util/src/test/java/org/opendaylight/yangtools/yang/model/util/Decimal64Test.java [new file with mode: 0644]
yang/yang-model-util/src/test/java/org/opendaylight/yangtools/yang/model/util/EmptyTypeTest.java [new file with mode: 0644]
yang/yang-model-util/src/test/java/org/opendaylight/yangtools/yang/model/util/ExtendedTypeTest.java [new file with mode: 0644]
yang/yang-model-util/src/test/java/org/opendaylight/yangtools/yang/model/util/UnionTypeTest.java [new file with mode: 0644]
yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/repo/DependencyResolver.java
yang/yang-parser-impl/src/test/java/org/opendaylight/yangtools/yang/parser/repo/DependencyResolverTest.java

index b98c48c9844f0b5067aeae72cd1894b9efd43b9c..c1fd71df23a3065cebb6206481f52b184f08a986 100644 (file)
@@ -318,61 +318,23 @@ public class BindingGeneratorImpl implements BindingGenerator {
             genCtx.get(module).addChildNodeType(node, genType);
             groupingsToGenTypes(module, ((DataNodeContainer) node).getGroupings());
             processUsesAugments((DataNodeContainer) node, module);
-            if (node.isAddedByUses() || node.isAugmenting())
-                genType.setSuitableForBoxing(false);
         }
         return genType;
     }
 
-    private boolean hasWhenOrMustConstraints(final SchemaNode node) {
-        boolean hasWhenCondition;
-        boolean hasMustConstraints;
-
-        if (node instanceof ContainerSchemaNode) {
-            ContainerSchemaNode contNode = (ContainerSchemaNode)node;
-            hasWhenCondition = contNode.getConstraints().getWhenCondition() != null;
-            hasMustConstraints = !isNullOrEmpty(contNode.getConstraints().getMustConstraints());
-
-            if (hasWhenCondition || hasMustConstraints)
-                return true;
-        }
-        return false;
-    }
-
     private void containerToGenType(final Module module, final String basePackageName,
             final GeneratedTypeBuilder parent, final GeneratedTypeBuilder childOf, final ContainerSchemaNode node) {
         final GeneratedTypeBuilder genType = processDataSchemaNode(module, basePackageName, childOf, node);
-
         if (genType != null) {
             constructGetter(parent, node.getQName().getLocalName(), node.getDescription(), genType);
             resolveDataSchemaNodes(module, basePackageName, genType, genType, node.getChildNodes());
-
-            final String parentName = parent.getName();
-            final String childOfName = childOf.getName();
-
-            if (parent != null && !parent.getName().contains("Data"))
-                genType.setParentType(parent);
-            genType.setSuitableForBoxing(hasOnlyOneChild(node) && !hasWhenOrMustConstraints(node));
-
-            if (parentName.equals(childOfName))
-                genType.setSuitableForBoxing(false);
         }
     }
 
-    private boolean hasOnlyOneChild(final ContainerSchemaNode contNode) {
-        if (!isNullOrEmpty(contNode.getChildNodes()) && contNode.getChildNodes().size() == 1)
-            return true;
-        return false;
-    }
-
     private void listToGenType(final Module module, final String basePackageName, final GeneratedTypeBuilder parent,
             final GeneratedTypeBuilder childOf, final ListSchemaNode node) {
         final GeneratedTypeBuilder genType = processDataSchemaNode(module, basePackageName, childOf, node);
-
         if (genType != null) {
-            if (!parent.getName().equals(childOf) && !parent.getName().contains("Data")) {
-                genType.setParentType(parent);
-            }
             constructGetter(parent, node.getQName().getLocalName(), node.getDescription(), Types.listTypeFor(genType));
 
             final List<String> listKeys = listKeys(node);
@@ -894,7 +856,6 @@ public class BindingGeneratorImpl implements BindingGenerator {
         if (targetTypeBuilder == null) {
             throw new NullPointerException("Target type not yet generated: " + targetSchemaNode);
         }
-        targetTypeBuilder.setSuitableForBoxing(false);
 
         if (!(targetSchemaNode instanceof ChoiceNode)) {
             String packageName = augmentPackageName;
@@ -1195,7 +1156,6 @@ public class BindingGeneratorImpl implements BindingGenerator {
             constructGetter(parent, choiceNode.getQName().getLocalName(), choiceNode.getDescription(),
                     choiceTypeBuilder);
             choiceTypeBuilder.addImplementsType(typeForClass(DataContainer.class));
-            choiceTypeBuilder.setParentType(parent);
             genCtx.get(module).addChildNodeType(choiceNode, choiceTypeBuilder);
             generateTypesFromChoiceCases(module, basePackageName, choiceTypeBuilder.toInstance(), choiceNode);
         }
index ae80a51da4b19351b95b5de666504cb80549f881..cb7f50549e537e6a24f11e5407f35082b8f970ae 100644 (file)
@@ -342,11 +342,6 @@ public final class EnumerationBuilderImpl extends AbstractBaseType implements En
             return values;
         }
 
-        @Override
-        public boolean isSuitableForBoxing() {
-            return false;
-        }
-
         @Override
         public List<AnnotationType> getAnnotations() {
             return annotations;
@@ -523,6 +518,5 @@ public final class EnumerationBuilderImpl extends AbstractBaseType implements En
         public String getModuleName() {
             return moduleName;
         }
-
     }
 }
index 8d1bcea0e80be00fd1ccc4bc9923747474b6f076..270b04ac81161374d337fe03f012d96691939920 100644 (file)
@@ -337,10 +337,5 @@ public final class GeneratedTOBuilderImpl extends AbstractGeneratedTypeBuilder<G
         public String getModuleName() {
             return moduleName;
         }
-
-        @Override
-        public boolean isSuitableForBoxing() {
-            return false;
-        }
     }
 }
index 5b14461dbbd8d029d5af60a323b3c84a2a6d5beb..92c5629eab8861674bb2532957d4ab0bb9239256 100644 (file)
@@ -8,7 +8,6 @@
 package org.opendaylight.yangtools.binding.generator.util.generated.type.builder;
 
 import org.opendaylight.yangtools.sal.binding.model.api.GeneratedType;
-import org.opendaylight.yangtools.sal.binding.model.api.Type;
 import org.opendaylight.yangtools.sal.binding.model.api.type.builder.GeneratedTypeBuilder;
 import org.opendaylight.yangtools.yang.common.QName;
 
@@ -19,8 +18,6 @@ public final class GeneratedTypeBuilderImpl extends AbstractGeneratedTypeBuilder
     private String reference;
     private String moduleName;
     private Iterable<QName> schemaPath;
-    private boolean isSuitableForBoxing;
-    private GeneratedTypeBuilder parentType;
 
     public GeneratedTypeBuilderImpl(final String packageName, final String name) {
         super(packageName, name);
@@ -52,21 +49,6 @@ public final class GeneratedTypeBuilderImpl extends AbstractGeneratedTypeBuilder
         this.reference = reference;
     }
 
-    @Override
-    public void setSuitableForBoxing(boolean value) {
-        this.isSuitableForBoxing = value;
-    }
-
-    @Override
-    public void setParentType(GeneratedTypeBuilder parent) {
-        this.parentType = parent;
-    }
-
-    @Override
-    public Type getParent() {
-        return this.parentType;
-    }
-
     @Override
     public String toString() {
         StringBuilder builder = new StringBuilder();
@@ -104,8 +86,6 @@ public final class GeneratedTypeBuilderImpl extends AbstractGeneratedTypeBuilder
         private final String reference;
         private final String moduleName;
         private final Iterable<QName> schemaPath;
-        private final boolean isSuitableForBoxing;
-        private final GeneratedTypeBuilder parentType;
 
         public GeneratedTypeImpl(GeneratedTypeBuilderImpl builder) {
             super(builder);
@@ -114,8 +94,6 @@ public final class GeneratedTypeBuilderImpl extends AbstractGeneratedTypeBuilder
             this.reference = builder.reference;
             this.moduleName = builder.moduleName;
             this.schemaPath = builder.schemaPath;
-            this.isSuitableForBoxing = builder.isSuitableForBoxing;
-            this.parentType = builder.parentType;
         }
 
         @Override
@@ -137,11 +115,5 @@ public final class GeneratedTypeBuilderImpl extends AbstractGeneratedTypeBuilder
         public String getModuleName() {
             return moduleName;
         }
-
-        @Override
-        public boolean isSuitableForBoxing() {
-            return isSuitableForBoxing;
-        }
     }
-
 }
index 66b72cf9e62647a475bc359744bff63b7386f67a..d322833ad81ab9c69e8309462779a1f24c1a37fc 100644 (file)
@@ -29,7 +29,6 @@ import org.opendaylight.yangtools.sal.binding.model.api.GeneratedType
 import org.opendaylight.yangtools.sal.binding.model.api.MethodSignature
 import org.opendaylight.yangtools.sal.binding.model.api.Type
 import org.opendaylight.yangtools.yang.binding.Augmentable
-import org.opendaylight.yangtools.yang.binding.ChildOf
 import org.opendaylight.yangtools.yang.binding.DataObject
 import org.opendaylight.yangtools.yang.binding.Identifiable
 
@@ -226,9 +225,9 @@ class BuilderTemplate extends BaseTemplate {
 
             Â«generateSetters»
 
-            Â«generateBuildMethod»
-
-            Â«generateBuildBoxedMethod»
+            public Â«type.name» build() {
+                return new Â«type.name»«IMPL»(this);
+            }
 
             private static final class Â«type.name»«IMPL» implements Â«type.name» {
 
@@ -252,53 +251,6 @@ class BuilderTemplate extends BaseTemplate {
         }
     '''
 
-    def private generateBuildMethod() '''
-        public Â«type.name» build() {
-            return new Â«type.name»«IMPL»(this);
-        }
-    '''
-
-    def private generateBuildBoxedMethod() {
-        if(type.suitableForBoxing && type.parentType != null && isContainerAndIsNotList(type)) {
-            val parentTypeBuilder = createParentTypeBuilder()
-            if (countMatches(parentTypeBuilder, "org") < 2) {
-                return '''
-                    public Â«type.parentType.importedName» buildBoxed() {
-                        return new Â«parentTypeBuilder»().set«type.name»(build()).build();
-                    }
-                '''
-            }
-        }
-        return ''
-    }
-
-    def private int countMatches(String string, String subString) {
-        if (string.nullOrEmpty || subString.nullOrEmpty) {
-            return 0
-        }
-        var int count = 0;
-        var int idx = 0;
-        while ((idx = string.indexOf(subString, idx)) != -1) {
-            count = count + 1;
-            idx = idx + subString.length();
-        }
-        return count;
-    }
-
-    def private createParentTypeBuilder() {
-        return type.parentType.packageName + "." + type.parentType.importedName + "Builder"
-    }
-
-    def private boolean isContainerAndIsNotList(GeneratedType type) {
-        val isList = implementsIfc(type, Types.parameterizedTypeFor(Types.typeForClass(Identifiable), type))
-        val implementsChildOf = implementsIfc(type, Types.parameterizedTypeFor(Types.typeForClass(ChildOf), type))
-
-        if (implementsChildOf && !isList) {
-            return true
-        }
-        return false;
-    }
-
     /**
      * Generate default constructor and constructor for every implemented interface from uses statements.
      */
diff --git a/code-generator/binding-java-api-generator/src/test/resources/compilation/typedef/mod-box.yang b/code-generator/binding-java-api-generator/src/test/resources/compilation/typedef/mod-box.yang
deleted file mode 100644 (file)
index 1334298..0000000
+++ /dev/null
@@ -1,21 +0,0 @@
-
-module mod-box {
-    yang-version 1;
-    namespace "urn:opendaylight:mod:box";
-    prefix "box";
-
-    revision 2014-08-05 {
-   }
-
-       container cont1 {
-           choice choice1 {
-                       case case1 {
-                               container cont2 {
-                                       leaf leaf1 {
-                                               type string;
-                                       }
-                               }
-                       }
-           }
-       }
-}
diff --git a/code-generator/binding-model-api/src/main/java/org/opendaylight/yangtools/sal/binding/model/api/BoxableType.java b/code-generator/binding-model-api/src/main/java/org/opendaylight/yangtools/sal/binding/model/api/BoxableType.java
deleted file mode 100644 (file)
index 258c53d..0000000
+++ /dev/null
@@ -1,34 +0,0 @@
-/*
- * 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.sal.binding.model.api;
-
-/**
- * Implementing this interface allows an object to hold information about that if
- * is generated type suitable for boxing.
- *
- * Example:
- * choice foo-choice {
- *   case foo-case {
- *     container foo {
- *           ...
- *     }
- *   }
- * }
- *
- * Suitable type have to implements ChildOf<T>, where !(T instanceof Identifiable) and
- * T does not place any structural requirements (must/when) on existence/value Foo.
- */
-public interface BoxableType {
-
-    /**
-     * Check if generated type is suitable for boxing.
-     *
-     * @return true if generated type is suitable for boxing, false otherwise.
-     */
-    boolean isSuitableForBoxing();
-}
index ef2fdcdd7e6d4e942526937a670a28c5828dccf3..0e9b51ee741f42bb5952961421d046c7c52efa2a 100644 (file)
@@ -33,7 +33,7 @@ import java.util.List;
  * definitions MUST be public, so there is no need to specify the scope of
  * visibility.
  */
-public interface GeneratedType extends Type, DocumentedType, BoxableType {
+public interface GeneratedType extends Type, DocumentedType {
 
     /**
      * Returns the parent type if Generated Type is defined as enclosing type,
index ea2ab258e06f12a06e7c2bf8f9ea71bf021f7f39..9756bd209250b207e0689bc841fd1ce5bc185903 100644 (file)
@@ -12,29 +12,16 @@ import org.opendaylight.yangtools.sal.binding.model.api.GeneratedType;
 /**
  * Generated Type Builder interface is helper interface for building and
  * defining the GeneratedType.
- *
+ * 
  * @see GeneratedType
  */
 public interface GeneratedTypeBuilder extends GeneratedTypeBuilderBase<GeneratedTypeBuilder> {
 
     /**
      * Returns the <code>new</code> <i>immutable</i> instance of Generated Type.
-     *
+     * 
      * @return the <code>new</code> <i>immutable</i> instance of Generated Type.
      */
     GeneratedType toInstance();
 
-    /**
-     * Set true if generated type is suitable for boxing, false otherwise.
-     *
-     * @param value
-     */
-    public void setSuitableForBoxing(boolean value);
-
-    /**
-     * Set parent for current generated type.
-     *
-     * @param parent
-     */
-    public void setParentType(GeneratedTypeBuilder parent);
 }
index 70d0856fb70420784dfd897385a0cf72a9ecae37..f4052150595da7b4f1043c5c5ac753c901d71ff9 100644 (file)
@@ -8,6 +8,7 @@
 package org.opendaylight.yangtools.sal.binding.model.api.type.builder;
 
 import java.util.List;
+
 import org.opendaylight.yangtools.sal.binding.model.api.Constant;
 import org.opendaylight.yangtools.sal.binding.model.api.Type;
 import org.opendaylight.yangtools.yang.common.QName;
index b0c05243ea143b3d612626b143f28089329a00e3..6a19b45f376a02b5d0346f3a28a7b704f0c6e098 100644 (file)
@@ -10,14 +10,21 @@ 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.Optional;
 import com.google.common.base.Preconditions;
+import com.google.common.base.Predicate;
+import com.google.common.collect.Iterables;
 
 import java.io.Closeable;
 import java.io.Flushable;
 import java.io.IOException;
+import java.util.Collection;
+import java.util.Set;
 
 import javax.xml.stream.XMLStreamReader;
 
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifier;
 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;
@@ -31,6 +38,8 @@ 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;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 
 /**
  * This is an experimental iterator over a {@link NormalizedNode}. This is essentially
@@ -39,21 +48,47 @@ import org.opendaylight.yangtools.yang.data.api.schema.UnkeyedListNode;
  * us to write multiple nodes.
  */
 @Beta
-public final class NormalizedNodeWriter implements Closeable, Flushable {
+public class NormalizedNodeWriter implements Closeable, Flushable {
     private final NormalizedNodeStreamWriter writer;
 
     private NormalizedNodeWriter(final NormalizedNodeStreamWriter writer) {
         this.writer = Preconditions.checkNotNull(writer);
     }
 
+    protected final NormalizedNodeStreamWriter getWriter() {
+        return writer;
+    }
+
     /**
      * Create a new writer backed by a {@link NormalizedNodeStreamWriter}.
      *
-     * @param writer Backend writer
+     * @param writer Back-end writer
      * @return A new instance.
      */
     public static NormalizedNodeWriter forStreamWriter(final NormalizedNodeStreamWriter writer) {
-        return new NormalizedNodeWriter(writer);
+        return forStreamWriter(writer, true);
+    }
+
+    /**
+     * Create a new writer backed by a {@link NormalizedNodeStreamWriter}. Unlike the simple {@link #forStreamWriter(NormalizedNodeStreamWriter)}
+     * method, this allows the caller to switch off RFC6020 XML compliance, providing better
+     * throughput. The reason is that the XML mapping rules in RFC6020 require the encoding
+     * to emit leaf nodes which participate in a list's key first and in the order in which
+     * they are defined in the key. For JSON, this requirement is completely relaxed and leaves
+     * can be ordered in any way we see fit. The former requires a bit of work: first a lookup
+     * for each key and then for each emitted node we need to check whether it was already
+     * emitted.
+     *
+     * @param writer Back-end writer
+     * @param orderKeyLeaves whether the returned instance should be RFC6020 XML compliant.
+     * @return A new instance.
+     */
+    public static NormalizedNodeWriter forStreamWriter(final NormalizedNodeStreamWriter writer, final boolean orderKeyLeaves) {
+        if (orderKeyLeaves) {
+            return new OrderedNormalizedNodeWriter(writer);
+        } else {
+            return new NormalizedNodeWriter(writer);
+        }
     }
 
     /**
@@ -64,7 +99,7 @@ public final class NormalizedNodeWriter implements Closeable, Flushable {
      * @return
      * @throws IOException when thrown from the backing writer.
      */
-    public NormalizedNodeWriter write(final NormalizedNode<?, ?> node) throws IOException {
+    public final NormalizedNodeWriter write(final NormalizedNode<?, ?> node) throws IOException {
         if (wasProcessedAsCompositeNode(node)) {
             return this;
         }
@@ -76,6 +111,29 @@ public final class NormalizedNodeWriter implements Closeable, Flushable {
         throw new IllegalStateException("It wasn't possible to serialize node " + node);
     }
 
+    @Override
+    public void flush() throws IOException {
+        writer.flush();
+    }
+
+    @Override
+    public void close() throws IOException {
+        writer.flush();
+        writer.close();
+    }
+
+    /**
+     * Emit a best guess of a hint for a particular set of children. It evaluates the
+     * iterable to see if the size can be easily gotten to. If it is, we hint at the
+     * real number of child nodes. Otherwise we emit UNKNOWN_SIZE.
+     *
+     * @param children Child nodes
+     * @return Best estimate of the collection size required to hold all the children.
+     */
+    static final int childSizeHint(final Iterable<?> children) {
+        return (children instanceof Collection) ? ((Collection<?>) children).size() : UNKNOWN_SIZE;
+    }
+
     private boolean wasProcessAsSimpleNode(final NormalizedNode<?, ?> node) throws IOException {
         if (node instanceof LeafSetEntryNode) {
             final LeafSetEntryNode<?> nodeAsLeafList = (LeafSetEntryNode<?>)node;
@@ -94,57 +152,113 @@ public final class NormalizedNodeWriter implements Closeable, Flushable {
         return false;
     }
 
+    /**
+     * Emit events for all children and then emit an endNode() event.
+     *
+     * @param children Child iterable
+     * @return True
+     * @throws IOException when the writer reports it
+     */
+    protected final boolean writeChildren(final Iterable<? extends NormalizedNode<?, ?>> children) throws IOException {
+        for (NormalizedNode<?, ?> child : children) {
+            write(child);
+        }
+
+        writer.endNode();
+        return true;
+    }
+
+    protected boolean writeMapEntryNode(final MapEntryNode node) throws IOException {
+        writer.startMapEntryNode(node.getIdentifier(), childSizeHint(node.getValue()));
+        return writeChildren(node.getValue());
+    }
+
     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;
+            final ContainerNode n = (ContainerNode) node;
+            writer.startContainerNode(n.getIdentifier(), childSizeHint(n.getValue()));
+            return writeChildren(n.getValue());
+        }
+        if (node instanceof MapEntryNode) {
+            return writeMapEntryNode((MapEntryNode) node);
+        }
+        if (node instanceof UnkeyedListEntryNode) {
+            final UnkeyedListEntryNode n = (UnkeyedListEntryNode) node;
+            writer.startUnkeyedListItem(n.getIdentifier(), childSizeHint(n.getValue()));
+            return writeChildren(n.getValue());
+        }
+        if (node instanceof ChoiceNode) {
+            final ChoiceNode n = (ChoiceNode) node;
+            writer.startChoiceNode(n.getIdentifier(), childSizeHint(n.getValue()));
+            return writeChildren(n.getValue());
+        }
+        if (node instanceof AugmentationNode) {
+            final AugmentationNode n = (AugmentationNode) node;
+            writer.startAugmentationNode(n.getIdentifier());
+            return writeChildren(n.getValue());
+        }
+        if (node instanceof UnkeyedListNode) {
+            final UnkeyedListNode n = (UnkeyedListNode) node;
+            writer.startUnkeyedList(n.getIdentifier(), childSizeHint(n.getValue()));
+            return writeChildren(n.getValue());
+        }
+        if (node instanceof OrderedMapNode) {
+            final OrderedMapNode n = (OrderedMapNode) node;
+            writer.startOrderedMapNode(n.getIdentifier(), childSizeHint(n.getValue()));
+            return writeChildren(n.getValue());
+        }
+        if (node instanceof MapNode) {
+            final MapNode n = (MapNode) node;
+            writer.startMapNode(n.getIdentifier(), childSizeHint(n.getValue()));
+            return writeChildren(n.getValue());
+        }
+        if (node instanceof LeafSetNode) {
+            //covers also OrderedLeafSetNode for which doesn't exist start* method
+            final LeafSetNode<?> n = (LeafSetNode<?>) node;
+            writer.startLeafSet(n.getIdentifier(), childSizeHint(n.getValue()));
+            return writeChildren(n.getValue());
         }
-        return false;
 
+        return false;
     }
 
-    @Override
-    public void flush() throws IOException {
-        writer.flush();
-    }
+    private static final class OrderedNormalizedNodeWriter extends NormalizedNodeWriter {
+        private static final Logger LOG = LoggerFactory.getLogger(OrderedNormalizedNodeWriter.class);
 
-    @Override
-    public void close() throws IOException {
-        writer.close();
+        OrderedNormalizedNodeWriter(final NormalizedNodeStreamWriter writer) {
+            super(writer);
+        }
+
+        @Override
+        protected boolean writeMapEntryNode(final MapEntryNode node) throws IOException {
+            getWriter().startMapEntryNode(node.getIdentifier(), childSizeHint(node.getValue()));
+
+            final Set<QName> qnames = node.getIdentifier().getKeyValues().keySet();
+            // Write out all the key children
+            for (QName qname : qnames) {
+                final Optional<? extends NormalizedNode<?, ?>> child = node.getChild(new NodeIdentifier(qname));
+                if (child.isPresent()) {
+                    write(child.get());
+                } else {
+                    LOG.info("No child for key element {} found", qname);
+                }
+            }
+
+            // Write all the rest
+            return writeChildren(Iterables.filter(node.getValue(), new Predicate<NormalizedNode<?, ?>>() {
+                @Override
+                public boolean apply(final NormalizedNode<?, ?> input) {
+                    if (input instanceof AugmentationNode) {
+                        return true;
+                    }
+                    if (!qnames.contains(input.getNodeType())) {
+                        return true;
+                    }
+
+                    LOG.debug("Skipping key child {}", input);
+                    return false;
+                }
+            }));
+        }
     }
 }
index 588b884d8a9edf563af6d6b88d8977a56d7d68d0..2f4d2a40f1238f5c29f97b0f863dfa6321fc7201 100644 (file)
@@ -7,6 +7,9 @@
  */
 package org.opendaylight.yangtools.yang.data.api.schema.tree.spi;
 
+import com.google.common.base.Optional;
+import com.google.common.base.Preconditions;
+
 import java.util.HashMap;
 import java.util.Map;
 
@@ -16,81 +19,34 @@ import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
 import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNodeContainer;
 import org.opendaylight.yangtools.yang.data.api.schema.OrderedNodeContainer;
 
-import com.google.common.base.Optional;
-import com.google.common.base.Preconditions;
-
 /**
  * A TreeNode capable of holding child nodes. The fact that any of the children
  * changed is tracked by the subtree version.
  */
-final class ContainerNode extends AbstractTreeNode {
-    private final Map<PathArgument, TreeNode> children;
+abstract class ContainerNode extends AbstractTreeNode {
     private final Version subtreeVersion;
 
-    protected ContainerNode(final NormalizedNode<?, ?> data, final Version version,
-            final Map<PathArgument, TreeNode> children, final Version subtreeVersion) {
+    protected ContainerNode(final NormalizedNode<?, ?> data, final Version version, final Version subtreeVersion) {
         super(data, version);
-        this.children = Preconditions.checkNotNull(children);
         this.subtreeVersion = Preconditions.checkNotNull(subtreeVersion);
     }
 
     @Override
-    public Version getSubtreeVersion() {
+    public final Version getSubtreeVersion() {
         return subtreeVersion;
     }
 
-    @Override
-    public Optional<TreeNode> getChild(final PathArgument key) {
-        Optional<TreeNode> explicitNode = Optional.fromNullable(children.get(key));
-        if (explicitNode.isPresent()) {
-            return explicitNode;
-        }
-        final NormalizedNodeContainer<?, PathArgument, NormalizedNode<?, ?>> castedData = (NormalizedNodeContainer<?, PathArgument, NormalizedNode<?, ?>>) getData();
-        Optional<NormalizedNode<?, ?>> value = castedData.getChild(key);
-        if (value.isPresent()) {
-            //FIXME: consider caching created Tree Nodes.
-            //We are safe to not to cache them, since written Tree Nodes are in read only snapshot.
-            return Optional.of(TreeNodeFactory.createTreeNode(value.get(), getVersion()));
-        }
-        return Optional.absent();
-    }
-
-    @Override
-    public MutableTreeNode mutable() {
-        return new Mutable(this);
-    }
-
-    private static final class Mutable implements MutableTreeNode {
+    protected static final class Mutable implements MutableTreeNode {
         private final Version version;
         private Map<PathArgument, TreeNode> children;
         private NormalizedNode<?, ?> data;
         private Version subtreeVersion;
 
-        private Mutable(final ContainerNode parent) {
+        Mutable(final ContainerNode parent, final Map<PathArgument, TreeNode> children) {
             this.data = parent.getData();
-            this.children = MapAdaptor.getDefaultInstance().takeSnapshot(parent.children);
-            this.subtreeVersion = parent.getSubtreeVersion();
             this.version = parent.getVersion();
-            materializeChildVersion();
-        }
-
-        /**
-         * Traverse whole data tree and instantiate children for each data node. Set version of each MutableTreeNode
-         * accordingly to version in data node.
-         *
-         * Use this method if TreeNode is lazy initialized.
-         */
-        private void materializeChildVersion() {
-            Preconditions.checkState(data instanceof NormalizedNodeContainer);
-            NormalizedNodeContainer<?, ?, NormalizedNode<?, ?>> castedData = (NormalizedNodeContainer<?, ?, NormalizedNode<?, ?>>) data;
-
-            for(NormalizedNode<?, ?> childData : castedData.getValue()) {
-                PathArgument id = childData.getIdentifier();
-
-                if (!children.containsKey(id)) {
-                    children.put(id, TreeNodeFactory.createTreeNode(childData, version));
-                }
-            }
+            this.subtreeVersion = parent.getSubtreeVersion();
+            this.children = Preconditions.checkNotNull(children);
         }
 
         @Override
@@ -115,7 +71,7 @@ final class ContainerNode extends AbstractTreeNode {
 
         @Override
         public TreeNode seal() {
-            final TreeNode ret = new ContainerNode(data, version, MapAdaptor.getDefaultInstance().optimize(children), subtreeVersion);
+            final TreeNode ret = new MaterializedContainerNode(data, version, MapAdaptor.getDefaultInstance().optimize(children), subtreeVersion);
 
             // This forces a NPE if this class is accessed again. Better than corruption.
             children = null;
@@ -151,7 +107,7 @@ final class ContainerNode extends AbstractTreeNode {
             map.put(child.getIdentifier(), TreeNodeFactory.createTreeNodeRecursively(child, version));
         }
 
-        return new ContainerNode(data, version, map, version);
+        return new MaterializedContainerNode(data, version, map, version);
     }
 
     /**
@@ -197,7 +153,7 @@ final class ContainerNode extends AbstractTreeNode {
      */
     public static ContainerNode createNormalizedNode(final Version version,
         final NormalizedNodeContainer<?, ?, NormalizedNode<?, ?>> container) {
-        return createNode(version, container);
+        return new LazyContainerNode(container, version);
     }
 
     /**
@@ -209,18 +165,6 @@ final class ContainerNode extends AbstractTreeNode {
      */
     public static ContainerNode createOrderedNode(final Version version,
         final OrderedNodeContainer<NormalizedNode<?, ?>> container) {
-        return createNode(version, container);
-    }
-
-    /**
-     * Creates and returns single instance of {@link ContainerNode} with provided version and data reference stored in NormalizedNode.
-     *
-     * @param version version of indexed data
-     * @param data NormalizedNode data container
-     * @return single instance of {@link ContainerNode} with provided version and data reference stored in NormalizedNode.
-     */
-    private static ContainerNode createNode(final Version version, final NormalizedNode<?, ?> data) {
-        final Map<PathArgument, TreeNode> map = new HashMap<>();
-        return new ContainerNode(data, version, map, version);
+        return new LazyContainerNode(container, version);
     }
 }
diff --git a/yang/yang-data-api/src/main/java/org/opendaylight/yangtools/yang/data/api/schema/tree/spi/LazyContainerNode.java b/yang/yang-data-api/src/main/java/org/opendaylight/yangtools/yang/data/api/schema/tree/spi/LazyContainerNode.java
new file mode 100644 (file)
index 0000000..a2bc1cb
--- /dev/null
@@ -0,0 +1,58 @@
+/*
+ * 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.tree.spi;
+
+import com.google.common.base.Optional;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.PathArgument;
+import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
+import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNodeContainer;
+
+final class LazyContainerNode extends ContainerNode {
+    protected LazyContainerNode(final NormalizedNode<?, ?> data, final Version version) {
+        super(data, version, version);
+    }
+
+    @Override
+    public Optional<TreeNode> getChild(final PathArgument key) {
+        // We do not cache the instantiated node as it is dirt cheap
+        final Optional<NormalizedNode<?, ?>> child = castData().getChild(key);
+        if (child.isPresent()) {
+            return Optional.of(TreeNodeFactory.createTreeNode(child.get(), getVersion()));
+        }
+
+        return Optional.absent();
+    }
+
+    @Override
+    public MutableTreeNode mutable() {
+        /*
+         * We are creating a mutable view of the data, which means that the version
+         * is going to probably change -- and we need to make sure any unmodified
+         * children retain it.
+         *
+         * The simplest thing to do is to just flush the amortized work and be done
+         * with it.
+         */
+        final Map<PathArgument, TreeNode> children = new HashMap<>();
+        for (NormalizedNode<?, ?> child : castData().getValue()) {
+            PathArgument id = child.getIdentifier();
+            children.put(id, TreeNodeFactory.createTreeNode(child, getVersion()));
+        }
+
+        return new Mutable(this, children);
+    }
+
+    @SuppressWarnings("unchecked")
+    private final NormalizedNodeContainer<?, PathArgument, NormalizedNode<?, ?>> castData() {
+        return (NormalizedNodeContainer<?, PathArgument, NormalizedNode<?, ?>>) getData();
+    }
+}
diff --git a/yang/yang-data-api/src/main/java/org/opendaylight/yangtools/yang/data/api/schema/tree/spi/MaterializedContainerNode.java b/yang/yang-data-api/src/main/java/org/opendaylight/yangtools/yang/data/api/schema/tree/spi/MaterializedContainerNode.java
new file mode 100644 (file)
index 0000000..a98cd33
--- /dev/null
@@ -0,0 +1,37 @@
+/*
+ * 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.tree.spi;
+
+import com.google.common.base.Optional;
+import com.google.common.base.Preconditions;
+
+import java.util.Map;
+
+import org.opendaylight.yangtools.util.MapAdaptor;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.PathArgument;
+import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
+
+final class MaterializedContainerNode extends ContainerNode {
+    private final Map<PathArgument, TreeNode> children;
+
+    protected MaterializedContainerNode(final NormalizedNode<?, ?> data, final Version version,
+            final Map<PathArgument, TreeNode> children, final Version subtreeVersion) {
+        super(data, version, subtreeVersion);
+        this.children = Preconditions.checkNotNull(children);
+    }
+
+    @Override
+    public Optional<TreeNode> getChild(final PathArgument key) {
+        return Optional.fromNullable(children.get(key));
+    }
+
+    @Override
+    public MutableTreeNode mutable() {
+        return new Mutable(this, MapAdaptor.getDefaultInstance().takeSnapshot(children));
+    }
+}
index fb6c537e832460bfb9ee6acfdfbe13116adb0e77..1200c3735169227c740f4b6e522f25d4656fbac3 100644 (file)
             <groupId>${project.groupId}</groupId>
             <artifactId>yang-data-api</artifactId>
         </dependency>
+        <dependency>
+            <groupId>${project.groupId}</groupId>
+            <artifactId>yang-data-util</artifactId>
+        </dependency>
         <dependency>
             <groupId>${project.groupId}</groupId>
             <artifactId>yang-model-api</artifactId>
diff --git a/yang/yang-data-impl/src/main/java/org/opendaylight/yangtools/yang/data/impl/codec/xml/ElementIdentityrefParser.java b/yang/yang-data-impl/src/main/java/org/opendaylight/yangtools/yang/data/impl/codec/xml/ElementIdentityrefParser.java
new file mode 100644 (file)
index 0000000..fcfaca5
--- /dev/null
@@ -0,0 +1,45 @@
+/*
+ * 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.impl.codec.xml;
+
+import com.google.common.base.Preconditions;
+
+import java.net.URI;
+
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.data.util.AbstractStringIdentityrefCodec;
+import org.opendaylight.yangtools.yang.model.api.Module;
+import org.opendaylight.yangtools.yang.model.api.SchemaContext;
+import org.w3c.dom.Element;
+
+final class ElementIdentityrefParser extends AbstractStringIdentityrefCodec {
+    private final SchemaContext schema;
+    private final Element element;
+
+    ElementIdentityrefParser(final SchemaContext schema, final Element element) {
+        this.element = Preconditions.checkNotNull(element);
+        this.schema = Preconditions.checkNotNull(schema);
+    }
+
+    @Override
+    protected String prefixForNamespace(final URI namespace) {
+        return element.lookupPrefix(namespace.toString());
+    }
+
+    @Override
+    protected QName createQName(final String prefix, final String localName) {
+        final String namespace = element.lookupNamespaceURI(prefix);
+        Preconditions.checkArgument(namespace != null, "Failed to lookup prefix %s", prefix);
+
+        final URI ns = URI.create(namespace);
+        final Module module = schema.findModuleByNamespaceAndRevision(ns, null);
+        Preconditions.checkArgument(module != null, "Namespace %s is not owned by a module", ns);
+        return QName.create(module.getQNameModule(), localName);
+    }
+
+}
diff --git a/yang/yang-data-impl/src/main/java/org/opendaylight/yangtools/yang/data/impl/codec/xml/ElementInstanceIdentifierParser.java b/yang/yang-data-impl/src/main/java/org/opendaylight/yangtools/yang/data/impl/codec/xml/ElementInstanceIdentifierParser.java
new file mode 100644 (file)
index 0000000..11944fa
--- /dev/null
@@ -0,0 +1,45 @@
+/*
+ * 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.impl.codec.xml;
+
+import com.google.common.base.Preconditions;
+
+import java.net.URI;
+
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.data.util.AbstractStringInstanceIdentifierCodec;
+import org.opendaylight.yangtools.yang.model.api.Module;
+import org.opendaylight.yangtools.yang.model.api.SchemaContext;
+import org.w3c.dom.Element;
+
+final class ElementInstanceIdentifierParser extends AbstractStringInstanceIdentifierCodec {
+    private final SchemaContext schema;
+    private final Element element;
+
+    ElementInstanceIdentifierParser(final SchemaContext schema, final Element element) {
+        this.element = Preconditions.checkNotNull(element);
+        this.schema = Preconditions.checkNotNull(schema);
+    }
+
+    @Override
+    protected String prefixForNamespace(final URI namespace) {
+        return element.lookupPrefix(namespace.toString());
+    }
+
+    @Override
+    protected QName createQName(final String prefix, final String localName) {
+        final String namespace = element.lookupNamespaceURI(prefix);
+        Preconditions.checkArgument(namespace != null, "Failed to lookup prefix %s", prefix);
+
+        final URI ns = URI.create(namespace);
+        final Module module = schema.findModuleByNamespaceAndRevision(ns, null);
+        Preconditions.checkArgument(module != null, "Namespace %s is not owned by a module", ns);
+        return QName.create(module.getQNameModule(), localName);
+    }
+
+}
index 7f8167e451559e0643d310a2967272c8c0a043fd..347cc42cdc0d0d811a5f92db9d2a564bba62dd4f 100644 (file)
@@ -7,69 +7,29 @@
  */
 package org.opendaylight.yangtools.yang.data.impl.codec.xml;
 
-import com.google.common.base.Preconditions;
-import com.google.common.base.Splitter;
-
 import java.net.URI;
-import java.net.URISyntaxException;
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.Iterator;
-import java.util.List;
-import java.util.Map;
 import java.util.Map.Entry;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
 
 import org.opendaylight.yangtools.yang.common.QName;
 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
-import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.PathArgument;
-import org.opendaylight.yangtools.yang.model.api.Module;
 import org.opendaylight.yangtools.yang.model.api.SchemaContext;
 import org.w3c.dom.Element;
 
 public final class InstanceIdentifierForXmlCodec {
-    private static final Pattern PREDICATE_PATTERN = Pattern.compile("\\[(.*?)\\]");
-    private static final Splitter SLASH_SPLITTER = Splitter.on('/');
-    private static final Splitter COLON_SPLITTER = Splitter.on(':');
-
     private InstanceIdentifierForXmlCodec() {
         throw new UnsupportedOperationException("Utility class");
     }
 
     public static YangInstanceIdentifier deserialize(final Element element, final SchemaContext schemaContext) {
-        Preconditions.checkNotNull(element, "Value of element for deserialization can't be null");
-        Preconditions.checkNotNull(schemaContext,
-                "Schema context for deserialization of instance identifier type can't be null");
-
-        final String valueTrimmed = element.getTextContent().trim();
-        final Iterator<String> xPathParts = SLASH_SPLITTER.split(valueTrimmed).iterator();
-
-        // must be at least "/pr:node"
-        if (!xPathParts.hasNext() || !xPathParts.next().isEmpty() || !xPathParts.hasNext()) {
-            return null;
-        }
-
-        List<PathArgument> result = new ArrayList<>();
-        while (xPathParts.hasNext()) {
-            String xPathPartTrimmed = xPathParts.next().trim();
-
-            PathArgument pathArgument = toPathArgument(xPathPartTrimmed, element, schemaContext);
-            if (pathArgument != null) {
-                result.add(pathArgument);
-            }
-        }
-        return YangInstanceIdentifier.create(result);
+        final ElementInstanceIdentifierParser codec = new ElementInstanceIdentifierParser(schemaContext, element);
+        return codec.deserialize(element.getTextContent().trim());
     }
 
     public static Element serialize(final YangInstanceIdentifier id, final Element element) {
-        Preconditions.checkNotNull(id, "Variable should contain instance of instance identifier and can't be null");
-        Preconditions.checkNotNull(element, "DOM element can't be null");
+        final RandomPrefixInstanceIdentifierSerializer codec = new RandomPrefixInstanceIdentifierSerializer();
+        final String str = codec.serialize(id);
 
-        final RandomPrefix prefixes = new RandomPrefix();
-        final String str = XmlUtils.encodeIdentifier(prefixes, id);
-
-        for (Entry<URI, String> e: prefixes.getPrefixes()) {
+        for (Entry<URI, String> e : codec.getPrefixes()) {
             element.setAttribute("xmlns:" + e.getValue(), e.getKey().toString());
         }
         element.setTextContent(str);
@@ -81,104 +41,9 @@ public final class InstanceIdentifierForXmlCodec {
         return predicateStartIndex == -1 ? pathPart : pathPart.substring(0, predicateStartIndex);
     }
 
-    private static PathArgument toPathArgument(final String xPathArgument, final Element element, final SchemaContext schemaContext) {
-        final QName mainQName = toIdentity(xPathArgument, element, schemaContext);
-
-        // predicates
-        final Matcher matcher = PREDICATE_PATTERN.matcher(xPathArgument);
-        final Map<QName, Object> predicates = new HashMap<>();
-        QName currentQName = mainQName;
-
-        while (matcher.find()) {
-            final String predicateStr = matcher.group(1).trim();
-            final int indexOfEqualityMark = predicateStr.indexOf('=');
-            if (indexOfEqualityMark != -1) {
-                final String predicateValue = toPredicateValue(predicateStr.substring(indexOfEqualityMark + 1));
-                if (predicateValue == null) {
-                    return null;
-                }
-
-                if (predicateStr.charAt(0) != '.') {
-                    // target is not a leaf-list
-                    currentQName = toIdentity(predicateStr.substring(0, indexOfEqualityMark), element, schemaContext);
-                    if (currentQName == null) {
-                        return null;
-                    }
-                }
-                predicates.put(currentQName, predicateValue);
-            }
-        }
-
-        if (predicates.isEmpty()) {
-            return new YangInstanceIdentifier.NodeIdentifier(mainQName);
-        } else {
-            return new YangInstanceIdentifier.NodeIdentifierWithPredicates(mainQName, predicates);
-        }
-
-    }
-
     public static QName toIdentity(final String xPathArgument, final Element element, final SchemaContext schemaContext) {
-        final String xPathPartTrimmed = getIdAndPrefixAsStr(xPathArgument).trim();
-        final Iterator<String> it = COLON_SPLITTER.split(xPathPartTrimmed).iterator();
-
-        // Empty string
-        if (!it.hasNext()) {
-            return null;
-        }
-
-        final String prefix = it.next().trim();
-        if (prefix.isEmpty()) {
-            return null;
-        }
-
-        // it is not "prefix:value"
-        if (!it.hasNext()) {
-            return null;
-        }
-
-        final String identifier = it.next().trim();
-        if (identifier.isEmpty()) {
-            return null;
-        }
-
-        URI namespace = null;
-        String namespaceStr = null;
-        try {
-            namespaceStr = element.lookupNamespaceURI(prefix);
-            namespace = new URI(namespaceStr);
-        } catch (URISyntaxException e) {
-            throw new IllegalArgumentException("It wasn't possible to convert " + namespaceStr + " to URI object.");
-        } catch (NullPointerException e) {
-            throw new IllegalArgumentException("It wasn't possible to get namespace for prefix " + prefix);
-        }
-
-        final Module module = schemaContext.findModuleByNamespaceAndRevision(namespace, null);
-        Preconditions.checkNotNull(module, "Unknown module: %s, cannot parse identity %s", namespace, xPathArgument);
-        return QName.create(module.getQNameModule(), identifier);
-    }
-
-    private static String trimIfEndIs(final String str, final char end) {
-        final int l = str.length() - 1;
-        if (str.charAt(l) != end) {
-            return null;
-        }
-
-        return str.substring(1, l);
+        final ElementIdentityrefParser codec = new ElementIdentityrefParser(schemaContext, element);
+        return codec.deserialize(getIdAndPrefixAsStr(xPathArgument).trim());
     }
 
-    private static String toPredicateValue(final String predicatedValue) {
-        final String predicatedValueTrimmed = predicatedValue.trim();
-        if (predicatedValue.isEmpty()) {
-            return null;
-        }
-
-        switch (predicatedValueTrimmed.charAt(0)) {
-        case '"':
-            return trimIfEndIs(predicatedValueTrimmed, '"');
-        case '\'':
-            return trimIfEndIs(predicatedValueTrimmed, '\'');
-        default:
-            return null;
-        }
-    }
 }
index 00fc7d708e03f0000428439865055e7afc58b6ce..518e796808d9676519e201d89db4dfabc1e90140 100644 (file)
@@ -8,95 +8,78 @@
 package org.opendaylight.yangtools.yang.data.impl.codec.xml;
 
 import com.google.common.annotations.VisibleForTesting;
-import com.google.common.base.Strings;
+import com.google.common.base.Preconditions;
 import com.google.common.collect.BiMap;
 import com.google.common.collect.HashBiMap;
+
 import java.net.URI;
 import java.util.Map;
-import org.opendaylight.yangtools.yang.common.QName;
-
-final class RandomPrefix {
 
-    public static final char STARTING_CHAR = 'a';
-    public static final int CHARACTER_RANGE = 26;
-    public static final int PREFIX_MAX_LENGTH = 4;
+import javax.xml.namespace.NamespaceContext;
 
-    public static final int MAX_COUNTER_VALUE = (int) Math.pow(CHARACTER_RANGE, PREFIX_MAX_LENGTH);
-    private static final int STARTING_WITH_XML = decode("xml");
+class RandomPrefix {
+    // 32 characters, carefully chosen
+    private static final String LOOKUP = "abcdefghiknoprstABCDEFGHIKNOPRST";
+    private static final int MASK = 0x1f;
+    private static final int SHIFT = 5;
 
     private int counter = 0;
 
     // BiMap to make values lookup faster
     private final BiMap<URI, String> prefixes = HashBiMap.create();
+    private final NamespaceContext context;
 
-    Iterable<Map.Entry<URI, String>> getPrefixes() {
-        return prefixes.entrySet();
+    RandomPrefix() {
+        this.context = null;
     }
 
-    String encodeQName(final QName qname) {
-        return encodePrefix(qname) + ':' + qname.getLocalName();
+    RandomPrefix(final NamespaceContext context) {
+        this.context = Preconditions.checkNotNull(context);
+    }
+
+    Iterable<Map.Entry<URI, String>> getPrefixes() {
+        return prefixes.entrySet();
     }
 
-    String encodePrefix(final QName qname) {
-        String prefix = prefixes.get(qname.getNamespace());
+    String encodePrefix(final URI namespace) {
+        String prefix = prefixes.get(namespace);
         if (prefix != null) {
             return prefix;
         }
 
-        // Reuse prefix from QName if possible
-        final String qNamePrefix = qname.getPrefix();
-
-        if (!Strings.isNullOrEmpty(qNamePrefix) && !qNamePrefix.startsWith("xml") && !alreadyUsedPrefix(qNamePrefix)) {
-            prefix = qNamePrefix;
-        } else {
-
-            do {
-                // Skip values starting with xml (Expecting only 4 chars max since division is calculated only once)
-                while (counter == STARTING_WITH_XML
-                        || counter / CHARACTER_RANGE == STARTING_WITH_XML) {
-                    counter++;
-                }
-
-                // Reset in case of max prefix generated
-                if (counter >= MAX_COUNTER_VALUE) {
-                    counter = 0;
-                    prefixes.clear();
-                }
-
-                prefix = encode(counter);
-                counter++;
-            } while (alreadyUsedPrefix(prefix));
-        }
+        do {
+            prefix = encode(counter);
+            counter++;
+        } while (alreadyUsedPrefix(prefix));
 
-        prefixes.put(qname.getNamespace(), prefix);
+        prefixes.put(namespace, prefix);
         return prefix;
     }
 
     private boolean alreadyUsedPrefix(final String prefix) {
-        return prefixes.values().contains(prefix);
+        return context != null && context.getNamespaceURI(prefix) != null;
     }
 
     @VisibleForTesting
-    static int decode(final String s) {
-        int num = 0;
-        for (final char ch : s.toCharArray()) {
-            num *= CHARACTER_RANGE;
-            num += (ch - STARTING_CHAR);
+    static int decode(final String str) {
+        int ret = 0;
+        for (char c : str.toCharArray()) {
+            int idx = LOOKUP.indexOf(c);
+            Preconditions.checkArgument(idx != -1, "Invalid string %s", str);
+            ret = (ret << SHIFT) + idx;
         }
-        return num;
+
+        return ret;
     }
 
     @VisibleForTesting
     static String encode(int num) {
-        if (num == 0) {
-            return "a";
-        }
-
         final StringBuilder sb = new StringBuilder();
-        while (num != 0) {
-            sb.append(((char) (num % CHARACTER_RANGE + STARTING_CHAR)));
-            num /= CHARACTER_RANGE;
-        }
+
+        do {
+            sb.append(LOOKUP.charAt(num & MASK));
+            num >>>= SHIFT;
+        } while (num != 0);
 
         return sb.reverse().toString();
     }
diff --git a/yang/yang-data-impl/src/main/java/org/opendaylight/yangtools/yang/data/impl/codec/xml/RandomPrefixInstanceIdentifierSerializer.java b/yang/yang-data-impl/src/main/java/org/opendaylight/yangtools/yang/data/impl/codec/xml/RandomPrefixInstanceIdentifierSerializer.java
new file mode 100644 (file)
index 0000000..a6fa1c0
--- /dev/null
@@ -0,0 +1,33 @@
+/*
+ * 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.impl.codec.xml;
+
+import java.net.URI;
+import java.util.Map;
+
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.data.util.AbstractStringInstanceIdentifierCodec;
+
+final class RandomPrefixInstanceIdentifierSerializer extends AbstractStringInstanceIdentifierCodec {
+    private final RandomPrefix prefixes = new RandomPrefix();
+
+    Iterable<Map.Entry<URI, String>> getPrefixes() {
+        return prefixes.getPrefixes();
+    }
+
+    @Override
+    protected String prefixForNamespace(final URI namespace) {
+        return prefixes.encodePrefix(namespace);
+    }
+
+    @Override
+    protected QName createQName(final String prefix, final String localName) {
+        throw new UnsupportedOperationException("Not implemented");
+    }
+
+}
index a9993778d5445765d56a281bd205e72099f6a3fe..14b5c8593f5d85b68533d95bd496929653a03cd6 100644 (file)
@@ -204,7 +204,7 @@ public class XmlStreamUtils {
     static void writeAttribute(final XMLStreamWriter writer, final Entry<QName, String> attribute, final RandomPrefix randomPrefix)
             throws XMLStreamException {
         final QName key = attribute.getKey();
-        final String prefix = randomPrefix.encodePrefix(key);
+        final String prefix = randomPrefix.encodePrefix(key.getNamespace());
         writer.writeAttribute("xmlns:" + prefix, key.getNamespace().toString());
         writer.writeAttribute(prefix, key.getNamespace().toString(), key.getLocalName(), attribute.getValue());
     }
index 7312c363829832466c593d488f6bac31f7356621..e6cfd58e7ddb7b4b43105190646fbcf62c2dd321 100644 (file)
@@ -8,7 +8,9 @@
 package org.opendaylight.yangtools.yang.data.impl.codec.xml;
 
 import java.util.Map;
+
 import javax.annotation.Nonnull;
+
 import org.opendaylight.yangtools.yang.common.QName;
 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifierWithPredicates;
@@ -44,16 +46,23 @@ public final class XmlUtils {
         StringBuilder textContent = new StringBuilder();
         for (PathArgument pathArgument : id.getPathArguments()) {
             textContent.append('/');
-            textContent.append(prefixes.encodeQName(pathArgument.getNodeType()));
+
+            final QName nt = pathArgument.getNodeType();
+            textContent.append(prefixes.encodePrefix(nt.getNamespace()));
+            textContent.append(':');
+            textContent.append(nt.getLocalName());
+
             if (pathArgument instanceof NodeIdentifierWithPredicates) {
                 Map<QName, Object> predicates = ((NodeIdentifierWithPredicates) pathArgument).getKeyValues();
 
                 for (Map.Entry<QName, Object> entry : predicates.entrySet()) {
-                    String predicateValue = String.valueOf(entry.getValue());
+                    final QName key = entry.getKey();
                     textContent.append('[');
-                    textContent.append(prefixes.encodeQName(entry.getKey()));
+                    textContent.append(prefixes.encodePrefix(key.getNamespace()));
+                    textContent.append(':');
+                    textContent.append(key.getLocalName());
                     textContent.append("='");
-                    textContent.append(predicateValue);
+                    textContent.append(String.valueOf(entry.getValue()));
                     textContent.append("']");
                 }
             } else if (pathArgument instanceof NodeWithValue) {
index 95d8ac6bea14e6587a616cb018019b2e01ac2b7b..73e3ad6f25c686006a5e24d05cb4e3e310ca5c2c 100644 (file)
@@ -13,29 +13,32 @@ import static org.junit.Assert.assertThat;
 import com.google.common.collect.Iterables;
 import com.google.common.collect.Lists;
 import com.google.common.collect.Sets;
+
 import java.net.URI;
 import java.util.Date;
 import java.util.List;
+
 import org.hamcrest.CoreMatchers;
 import org.junit.Test;
 import org.opendaylight.yangtools.yang.common.QName;
 import org.opendaylight.yangtools.yang.common.QNameModule;
 
 public class RandomPrefixTest {
+    static final int MAX_COUNTER = 4000;
 
     @Test
     public void testEncodeDecode() throws Exception {
+
         final List<String> allGenerated = Lists.newArrayList();
-        for (int i = 0; i < RandomPrefix.MAX_COUNTER_VALUE; i++) {
+        for (int i = 0; i < MAX_COUNTER; i++) {
             final String encoded = RandomPrefix.encode(i);
             assertEquals(RandomPrefix.decode(encoded), i);
             allGenerated.add(encoded);
         }
 
-        assertEquals(allGenerated.size(), RandomPrefix.MAX_COUNTER_VALUE);
-        assertEquals("zzzz", allGenerated.get(RandomPrefix.MAX_COUNTER_VALUE - 1));
+        assertEquals(allGenerated.size(), MAX_COUNTER);
+        assertEquals("dPT", allGenerated.get(MAX_COUNTER - 1));
         assertEquals("a", allGenerated.get(0));
-        assertEquals("xml", allGenerated.get(RandomPrefix.decode("xml")));
         assertEquals(allGenerated.size(), Sets.newHashSet(allGenerated).size());
     }
 
@@ -44,22 +47,22 @@ public class RandomPrefixTest {
         final RandomPrefix a = new RandomPrefix();
 
         final List<String> allGenerated = Lists.newArrayList();
-        for (int i = 0; i < RandomPrefix.MAX_COUNTER_VALUE; i++) {
+        for (int i = 0; i < MAX_COUNTER; i++) {
             final String prefix = RandomPrefix.encode(i);
             final URI uri = new URI("localhost:" + prefix);
-            final QName qName = QName.create(QNameModule.create(uri, new Date()), prefix, "local-name");
-            allGenerated.add(a.encodePrefix(qName));
+            final QName qName = QName.create(QNameModule.create(uri, new Date()), "local-name");
+            allGenerated.add(a.encodePrefix(qName.getNamespace()));
         }
 
-        assertEquals(RandomPrefix.MAX_COUNTER_VALUE, allGenerated.size());
+        assertEquals(MAX_COUNTER, allGenerated.size());
         // We are generating MAX_COUNTER_VALUE + 27 prefixes total, so we should encounter a reset in prefix a start from 0 at some point
         // At the end, there should be only 27 values in RandomPrefix cache
-        assertEquals(27, Iterables.size(a.getPrefixes()));
+        assertEquals(MAX_COUNTER, Iterables.size(a.getPrefixes()));
         assertThat(allGenerated, CoreMatchers.not(CoreMatchers.hasItem("xml")));
         assertThat(allGenerated, CoreMatchers.not(CoreMatchers.hasItem("xmla")));
         assertThat(allGenerated, CoreMatchers.not(CoreMatchers.hasItem("xmlz")));
 
-        assertEquals(2, Iterables.frequency(allGenerated, "a"));
+        assertEquals(1, Iterables.frequency(allGenerated, "a"));
     }
 
     @Test
@@ -70,7 +73,7 @@ public class RandomPrefixTest {
         final QName qName = QName.create(QNameModule.create(uri, new Date()), "p1", "local-name");
         final QName qName2 = QName.create(QNameModule.create(uri, new Date()), "p2", "local-name");
 
-        assertEquals(a.encodePrefix(qName), a.encodePrefix(qName2));
+        assertEquals(a.encodePrefix(qName.getNamespace()), a.encodePrefix(qName2.getNamespace()));
     }
 
     @Test
@@ -79,11 +82,11 @@ public class RandomPrefixTest {
 
         final URI uri = URI.create("localhost");
         QName qName = QName.create(uri, new Date(), "local-name");
-        assertEquals("a", a.encodePrefix(qName));
+        assertEquals("a", a.encodePrefix(qName.getNamespace()));
         qName = QName.create(QNameModule.create(uri, new Date()), "", "local-name");
-        assertEquals("a", a.encodePrefix(qName));
+        assertEquals("a", a.encodePrefix(qName.getNamespace()));
         qName = QName.create(QNameModule.create(URI.create("second"), new Date()), "", "local-name");
-        assertEquals("b", a.encodePrefix(qName));
+        assertEquals("b", a.encodePrefix(qName.getNamespace()));
 
     }
 }
index dbdfadb3453218f70ea1b3d36d2695e268481d2d..479a47f1069fb12d55d12ce8201b96f5c6b785fe 100644 (file)
@@ -59,7 +59,7 @@ public class XmlStreamUtilsTest {
         assertEquals(2, mappedPrefixes.size());
         final String randomPrefixValue = mappedPrefixes.get("namespace2");
 
-        final String expectedXmlAsString = "<element xmlns:prefix=\"namespace\" prefix:attr=\"value\" xmlns:" + randomPrefixValue + "=\"namespace2\" " + randomPrefixValue + ":attr=\"value\"></element>";
+        final String expectedXmlAsString = "<element xmlns:a=\"namespace\" a:attr=\"value\" xmlns:" + randomPrefixValue + "=\"namespace2\" " + randomPrefixValue + ":attr=\"value\"></element>";
 
         XMLUnit.setIgnoreAttributeOrder(true);
         final Document control = XMLUnit.buildControlDocument(expectedXmlAsString);
diff --git a/yang/yang-model-util/src/test/java/org/opendaylight/yangtools/yang/model/util/BaseConstraintsTest.java b/yang/yang-model-util/src/test/java/org/opendaylight/yangtools/yang/model/util/BaseConstraintsTest.java
new file mode 100644 (file)
index 0000000..5948d00
--- /dev/null
@@ -0,0 +1,42 @@
+/*
+ * 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
+ */
+package org.opendaylight.yangtools.yang.model.util;
+
+import com.google.common.base.Optional;
+import org.junit.Test;
+import org.opendaylight.yangtools.yang.model.api.type.LengthConstraint;
+import org.opendaylight.yangtools.yang.model.api.type.PatternConstraint;
+
+import static org.junit.Assert.assertEquals;
+
+public class BaseConstraintsTest {
+
+    @Test
+    public void canCreateConstraints() {
+        Number min = 5;
+        Number max = 99;
+        String description = "Any description";
+        String reference = "any_ref";
+        String reg_exp = "x|z";
+        Optional<String> desc = Optional.of(description);
+        Optional<String> ref = Optional.of(reference);
+
+        LengthConstraint lengthCons = BaseConstraints.newLengthConstraint(min, max, desc, ref);
+
+        assertEquals("LengthConstraints Get min", min, lengthCons.getMin());
+        assertEquals("LengthConstraints Get max", max, lengthCons.getMax());
+        assertEquals("LengthConstraints Get description", description, lengthCons.getDescription());
+        assertEquals("LengthConstraints Get reference", reference, lengthCons.getReference());
+
+        PatternConstraint patternCons = BaseConstraints.newPatternConstraint(reg_exp, desc, ref);
+
+        assertEquals("PatternConstraints Get regex", reg_exp, patternCons.getRegularExpression());
+        assertEquals("PatternConstraints Get description", description, patternCons.getDescription());
+        assertEquals("PatternConstraints Get reference", reference, patternCons.getReference());
+    }
+}
\ No newline at end of file
diff --git a/yang/yang-model-util/src/test/java/org/opendaylight/yangtools/yang/model/util/BaseTypesTest.java b/yang/yang-model-util/src/test/java/org/opendaylight/yangtools/yang/model/util/BaseTypesTest.java
new file mode 100644 (file)
index 0000000..1f0d806
--- /dev/null
@@ -0,0 +1,73 @@
+/*
+ * 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
+ */
+package org.opendaylight.yangtools.yang.model.util;
+
+import com.google.common.base.Optional;
+import org.junit.Test;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.assertFalse;
+
+public class BaseTypesTest {
+
+    @Test
+    public void canCreateBaseTypes() {
+        Optional<?> int8 = BaseTypes.defaultBaseTypeFor("int8");
+        assertEquals(Optional.of(Int8.getInstance()), int8);
+
+        Optional<?> int16 = BaseTypes.defaultBaseTypeFor("int16");
+        assertEquals(Optional.of(Int16.getInstance()), int16);
+
+        Optional<?> int32 = BaseTypes.defaultBaseTypeFor("int32");
+        assertEquals(Optional.of(Int32.getInstance()), int32);
+
+        Optional<?> int64 = BaseTypes.defaultBaseTypeFor("int64");
+        assertEquals(Optional.of(Int64.getInstance()), int64);
+
+        Optional<?> int128 = BaseTypes.defaultBaseTypeFor("int128");
+        assertEquals("wrong type", Optional.absent(), int128);
+
+        Optional<?> uint8 = BaseTypes.defaultBaseTypeFor("uint8");
+        assertEquals(Optional.of(Uint8.getInstance()), uint8);
+
+        Optional<?> uint16 = BaseTypes.defaultBaseTypeFor("uint16");
+        assertEquals(Optional.of(Uint16.getInstance()), uint16);
+
+        Optional<?> uint32 =  BaseTypes.defaultBaseTypeFor("uint32");
+        assertEquals(Optional.of(Uint32.getInstance()), uint32);
+
+        Optional<?> uint64 = BaseTypes.defaultBaseTypeFor("uint64");
+        assertEquals(Optional.of(Uint64.getInstance()), uint64);
+
+        Optional<?> uint128 = BaseTypes.defaultBaseTypeFor("uint128");
+        assertEquals("wrong type", Optional.absent(), uint128);
+
+        Optional<?> stringType = BaseTypes.defaultBaseTypeFor("string");
+        assertEquals(Optional.of(StringType.getInstance()), stringType);
+
+        Optional<?> binaryType = BaseTypes.defaultBaseTypeFor("binary");
+        assertEquals(Optional.of(BinaryType.getInstance()), binaryType);
+
+        Optional<?> booleanType = BaseTypes.defaultBaseTypeFor("boolean");
+        assertEquals(Optional.of(BooleanType.getInstance()), booleanType);
+
+        Optional<?> emptyType = BaseTypes.defaultBaseTypeFor("empty");
+        assertEquals(Optional.of(EmptyType.getInstance()), emptyType);
+
+        Optional<?> instance_identifier = BaseTypes.defaultBaseTypeFor("instance_identifier");
+        assertEquals(Optional.absent(), instance_identifier);
+
+        Optional<?> whatever = BaseTypes.defaultBaseTypeFor("whatever");
+        assertEquals("wrong type", Optional.absent(), whatever);
+
+        assertFalse("whatever is not build-in type", BaseTypes.isYangBuildInType("whatever"));
+        assertTrue("int8 is build-in type", BaseTypes.isYangBuildInType("int8"));
+    }
+
+}
\ No newline at end of file
diff --git a/yang/yang-model-util/src/test/java/org/opendaylight/yangtools/yang/model/util/BinaryTypeTest.java b/yang/yang-model-util/src/test/java/org/opendaylight/yangtools/yang/model/util/BinaryTypeTest.java
new file mode 100644 (file)
index 0000000..90dd72f
--- /dev/null
@@ -0,0 +1,53 @@
+/*
+ * 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
+ */
+package org.opendaylight.yangtools.yang.model.util;
+
+import org.junit.Test;
+import org.opendaylight.yangtools.yang.model.api.Status;
+import org.opendaylight.yangtools.yang.model.api.type.LengthConstraint;
+import java.util.Collections;
+import java.util.List;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.assertFalse;
+
+public class BinaryTypeTest {
+
+    @Test
+    public void canCreateBinaryType() {
+        BinaryType binType = BinaryType.getInstance();
+        BinaryType binType1 = BinaryType.getInstance();
+        String stringBinType = binType.toString();
+
+
+        List<LengthConstraint> lengthConstraints = binType.getLengthConstraints();
+        assertTrue(lengthConstraints.toString().contains("max=9223372036854775807"));
+        assertTrue(lengthConstraints.toString().contains("min=0"));
+
+        assertEquals("Default value is []", Collections.EMPTY_LIST, binType.getDefaultValue());
+        assertEquals("CURRENT", Status.CURRENT, binType.getStatus());
+        assertEquals("Base type is null", null, binType.getBaseType());
+        assertEquals("getQName gives BINARY_QNAME", BaseTypes.BINARY_QNAME, binType.getQName());
+        assertEquals("empty string", "", binType.getUnits());
+        assertEquals("getPath gives List of BINARY_QNAME",
+                Collections.singletonList(BaseTypes.BINARY_QNAME), binType.getPath().getPathFromRoot());
+
+        assertTrue("BinType.toString should contain Description", stringBinType.contains(binType.getDescription()));
+        assertTrue("BinType.toString should contain Reference", stringBinType.contains(binType.getReference()));
+
+        assertTrue("binType1 should equal to binType",
+                binType.equals(binType1) && binType1.equals(binType));
+        assertTrue("Hash code of binType and binType1 should be equal",
+                binType.hashCode() == binType1.hashCode());
+        assertEquals("binType should equals to itself", binType, binType);
+        assertFalse("binType shouldn't equal to null", binType.equals(null));
+        assertFalse("binType shouldn't equal to object of other type", binType.equals("str"));
+    }
+
+}
\ No newline at end of file
diff --git a/yang/yang-model-util/src/test/java/org/opendaylight/yangtools/yang/model/util/BooleanTypeTest.java b/yang/yang-model-util/src/test/java/org/opendaylight/yangtools/yang/model/util/BooleanTypeTest.java
new file mode 100644 (file)
index 0000000..431e666
--- /dev/null
@@ -0,0 +1,45 @@
+/*
+ * 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
+ */
+package org.opendaylight.yangtools.yang.model.util;
+
+import org.junit.Test;
+import org.opendaylight.yangtools.yang.model.api.Status;
+
+import java.util.Collections;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+public class BooleanTypeTest {
+
+    @Test
+    public void canCreateBooleanType() {
+        BooleanType boolType = BooleanType.getInstance();
+        String stringBoolType = boolType.toString();
+
+        assertEquals("getPath gives List of BOOLEAN_QNAME",
+                Collections.singletonList(BaseTypes.BOOLEAN_QNAME), boolType.getPath().getPathFromRoot());
+
+        assertEquals("getQName gives BOOLEAN_QNAME", BaseTypes.BOOLEAN_QNAME, boolType.getQName());
+
+        assertEquals("The boolean built-in type represents a boolean value.", boolType.getDescription());
+
+        String strPath = boolType.getPath().toString();
+        assertTrue("Should contain string of getPath", stringBoolType.contains(strPath));
+
+        assertEquals("Should be empty string", "", boolType.getUnits());
+
+        assertEquals("Base type is null", null, boolType.getBaseType());
+
+        assertEquals("Default value is false", false, boolType.getDefaultValue());
+
+        assertEquals("Status CURRENT", Status.CURRENT, boolType.getStatus());
+
+        assertEquals("Should contain empty list", Collections.EMPTY_LIST, boolType.getUnknownSchemaNodes());
+    }
+}
\ No newline at end of file
diff --git a/yang/yang-model-util/src/test/java/org/opendaylight/yangtools/yang/model/util/Decimal64Test.java b/yang/yang-model-util/src/test/java/org/opendaylight/yangtools/yang/model/util/Decimal64Test.java
new file mode 100644 (file)
index 0000000..8f4e678
--- /dev/null
@@ -0,0 +1,62 @@
+/*
+ * 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
+ */
+package org.opendaylight.yangtools.yang.model.util;
+
+import org.junit.Test;
+import org.opendaylight.yangtools.yang.model.api.SchemaPath;
+import org.opendaylight.yangtools.yang.model.api.Status;
+
+import java.util.Collections;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotEquals;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.assertFalse;
+
+public class Decimal64Test {
+
+    @Test
+    public void canCreateDecimal64() {
+        Integer fractionDig = 2;
+        Decimal64 decimal64 = Decimal64.create(SchemaPath.ROOT, fractionDig);
+
+        assertEquals("Status should be CURRENT", Status.CURRENT, decimal64.getStatus());
+
+        assertEquals("Default value should be null", null, decimal64.getDefaultValue());
+
+        assertEquals("Should be empty list", Collections.EMPTY_LIST, decimal64.getUnknownSchemaNodes());
+
+        assertEquals("Should be null", null, decimal64.getBaseType());
+
+        assertNotEquals("Description is not null", null, decimal64.getDescription());
+
+        assertNotEquals("Reference is not null", null, decimal64.getReference());
+
+        assertEquals("Should be empty string", "", decimal64.getUnits());
+
+        assertTrue("Should contain factionDigits=2", decimal64.toString().contains("fractionDigits="+fractionDig));
+
+        assertEquals("Should get farctionDig", fractionDig, decimal64.getFractionDigits());
+
+        assertEquals("Should be empty list",
+                Collections.EMPTY_LIST, decimal64.getPath().getPathFromRoot());
+
+        assertEquals("Should be DECIMAL64_QNAME", BaseTypes.DECIMAL64_QNAME, decimal64.getQName());
+
+        assertTrue("Should contain max", decimal64.getRangeConstraints().toString().contains("max=922337203685477580.7"));
+        assertTrue("Should contain min", decimal64.getRangeConstraints().toString().contains("min=-922337203685477580.8"));
+
+        Decimal64 decimal641 = decimal64;
+        assertTrue("Hash code of decimal64 and decimal641 should be equal",
+                    decimal64.hashCode() == decimal641.hashCode());
+
+        assertFalse("Decimal64 shouldn't equal to null", decimal64.equals(null));
+        assertEquals("Decimal64 should equals to itself", decimal64, decimal64);
+        assertFalse("Decimal64 shouldn't equal to object of other type", decimal64.equals("str"));
+    }
+}
\ No newline at end of file
diff --git a/yang/yang-model-util/src/test/java/org/opendaylight/yangtools/yang/model/util/EmptyTypeTest.java b/yang/yang-model-util/src/test/java/org/opendaylight/yangtools/yang/model/util/EmptyTypeTest.java
new file mode 100644 (file)
index 0000000..f892483
--- /dev/null
@@ -0,0 +1,37 @@
+/*
+ * 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
+ */
+package org.opendaylight.yangtools.yang.model.util;
+
+import org.junit.Test;
+import org.opendaylight.yangtools.yang.model.api.Status;
+
+import java.util.Collections;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotEquals;
+import static org.junit.Assert.assertTrue;
+
+public class EmptyTypeTest {
+
+    @Test
+    public void canCreateEmptyType() {
+        EmptyType emptyType = EmptyType.getInstance();
+
+        assertEquals("QName", BaseTypes.EMPTY_QNAME, emptyType.getQName());
+        assertEquals("Path", Collections.singletonList(BaseTypes.EMPTY_QNAME),
+                emptyType.getPath().getPathFromRoot());
+        assertEquals("BaseType", null, emptyType.getBaseType());
+        assertEquals("DefaultValue", null, emptyType.getDefaultValue());
+        assertEquals("Status", Status.CURRENT, emptyType.getStatus());
+        assertTrue("Reference", emptyType.getReference().contains("rfc6020"));
+        assertEquals("Units", null, emptyType.getUnits());
+        assertNotEquals("Description is not null", null, emptyType.getDescription());
+        assertEquals("UnknownSchemaNodes", Collections.EMPTY_LIST, emptyType.getUnknownSchemaNodes());
+        assertTrue("toString", emptyType.toString().contains("empty"));
+    }
+}
\ No newline at end of file
diff --git a/yang/yang-model-util/src/test/java/org/opendaylight/yangtools/yang/model/util/ExtendedTypeTest.java b/yang/yang-model-util/src/test/java/org/opendaylight/yangtools/yang/model/util/ExtendedTypeTest.java
new file mode 100644 (file)
index 0000000..3eb7a30
--- /dev/null
@@ -0,0 +1,77 @@
+/*
+ * 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
+ */
+package org.opendaylight.yangtools.yang.model.util;
+
+import com.google.common.base.Optional;
+import org.junit.Test;
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.model.api.SchemaPath;
+import org.opendaylight.yangtools.yang.model.api.Status;
+import org.opendaylight.yangtools.yang.model.api.type.LengthConstraint;
+
+import java.util.Collections;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.assertFalse;
+
+public class ExtendedTypeTest {
+    @Test
+    public void canCreateExtendedType() {
+        String namespace = "TestType";
+        String revision = "2014-08-26";
+        String localName = "testType";
+        QName testType = QName.create(namespace, revision, localName);
+        Int32 int32 = Int32.getInstance();
+        String description = "This type is used for testing purpose";
+        Optional<String> desc = Optional.of(description);
+        String reference = "Test Reference";
+        Optional<String> ref = Optional.of(reference);
+
+        ExtendedType.Builder extendedTypeBuilder = ExtendedType.builder(testType, int32, desc, ref, SchemaPath.ROOT);
+
+        int defValue = 12;
+        extendedTypeBuilder.defaultValue(defValue);
+
+        extendedTypeBuilder.status(Status.OBSOLETE);
+        extendedTypeBuilder.addedByUses(false);
+
+        int digits = 2;
+        extendedTypeBuilder.fractionDigits(digits);
+
+        String units = "KiloTest";
+        extendedTypeBuilder.units(units);
+
+        Number min = 3;
+        Number max = 15;
+        LengthConstraint lengthCons = BaseConstraints.newLengthConstraint(min, max, desc, ref);
+        extendedTypeBuilder.lengths(Collections.singletonList(lengthCons));
+
+        ExtendedType extendedType = extendedTypeBuilder.build();
+
+        assertEquals("BaseType is int32", int32, extendedType.getBaseType());
+        assertEquals("Description", description, extendedType.getDescription());
+        assertEquals("Reference", reference, extendedType.getReference());
+        assertEquals("Path", SchemaPath.ROOT, extendedType.getPath());
+        assertEquals("Default Value is 12", defValue, extendedType.getDefaultValue());
+        assertEquals("Status is OBSOLETE", Status.OBSOLETE, extendedType.getStatus());
+        assertFalse("AddedByUses", extendedType.isAddedByUses());
+        assertTrue("should be 2", digits == extendedType.getFractionDigits());
+        assertTrue("Should contain description", extendedType.toString().contains(description));
+        assertEquals("Units", units, extendedType.getUnits());
+        assertEquals("Length Constraints", Collections.singletonList(lengthCons), extendedType.getLengthConstraints());
+        assertTrue("Should contain name of type", extendedType.getQName().toString().contains(localName));
+
+        assertEquals("extendedType should equals to itself",extendedType, extendedType);
+        assertFalse("extendedType shouldn't equal to null", extendedType.equals(null));
+        assertTrue("Hash code of unionType should be equal to itself",
+                extendedType.hashCode() == extendedType.hashCode());
+
+    }
+
+}
\ No newline at end of file
diff --git a/yang/yang-model-util/src/test/java/org/opendaylight/yangtools/yang/model/util/UnionTypeTest.java b/yang/yang-model-util/src/test/java/org/opendaylight/yangtools/yang/model/util/UnionTypeTest.java
new file mode 100644 (file)
index 0000000..9a2f913
--- /dev/null
@@ -0,0 +1,51 @@
+/*
+ * 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
+ */
+package org.opendaylight.yangtools.yang.model.util;
+
+import org.junit.Test;
+import org.opendaylight.yangtools.yang.model.api.Status;
+import org.opendaylight.yangtools.yang.model.api.TypeDefinition;
+
+import java.util.Collections;
+import java.util.List;
+import java.util.ArrayList;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotEquals;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.assertFalse;
+
+public class UnionTypeTest {
+
+    @Test
+    public void canCreateUnion() {
+        List<TypeDefinition<?>> listTypes = new ArrayList<>();
+        Int32 int32 = Int32.getInstance();
+        listTypes.add(int32);
+        UnionType unionType = UnionType.create(listTypes);
+
+        assertEquals("GetUnits should be null", null, unionType.getUnits());
+        assertTrue("String should contain int32", unionType.toString().contains("int32"));
+        assertEquals("Should be empty list", Collections.EMPTY_LIST, unionType.getUnknownSchemaNodes());
+        assertNotEquals("Description should not be null", null, unionType.getDescription());
+        assertNotEquals("Ref should not be null", null, unionType.getReference());
+        assertEquals("Should be CURRENT", Status.CURRENT, unionType.getStatus());
+        assertEquals("Should be int32 in list", Collections.singletonList(int32), unionType.getTypes());
+        assertEquals("Base type should be null", null, unionType.getBaseType());
+        assertEquals("Default value should be null", null, unionType.getDefaultValue());
+        assertEquals("Should be same as list of BaseTypes",
+                Collections.singletonList(BaseTypes.UNION_QNAME), unionType.getPath().getPathFromRoot());
+        assertEquals("Should be BaseTypes", BaseTypes.UNION_QNAME, unionType.getQName());
+
+        assertEquals("unionType should equals to itself", unionType, unionType);
+        assertFalse("unionType shouldn't equal to null", unionType.equals(null));
+        assertTrue("Hash code of unionType should be equal to itself",
+                unionType.hashCode() == unionType.hashCode());
+    }
+
+}
\ No newline at end of file
index f44e5fd7120468e565232c2f97e50b561b2dbe19..d9b74fe93aff48079fc33dc3660d8dd83da79da4 100644 (file)
@@ -7,17 +7,14 @@
  */
 package org.opendaylight.yangtools.yang.parser.repo;
 
-import com.google.common.base.Optional;
-import com.google.common.base.Preconditions;
-import com.google.common.collect.ArrayListMultimap;
-import com.google.common.collect.ImmutableMultimap;
-import com.google.common.collect.Multimap;
-
+import com.google.common.collect.Sets;
 import java.util.ArrayList;
 import java.util.Collection;
 import java.util.Collections;
+import java.util.Date;
 import java.util.Iterator;
 import java.util.Map;
+import java.util.Set;
 
 import org.opendaylight.yangtools.yang.common.QName;
 import org.opendaylight.yangtools.yang.model.api.ModuleImport;
@@ -26,6 +23,12 @@ import org.opendaylight.yangtools.yang.parser.impl.util.YangModelDependencyInfo;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
+import com.google.common.base.Optional;
+import com.google.common.base.Preconditions;
+import com.google.common.collect.ArrayListMultimap;
+import com.google.common.collect.ImmutableMultimap;
+import com.google.common.collect.Multimap;
+
 /**
  * Inter-module dependency resolved. Given a set of schema source identifiers and their
  * corresponding dependency information, the {@link #create(Map)} method creates a
@@ -88,7 +91,17 @@ final class DependencyResolver {
                 final YangModelDependencyInfo dep = depInfo.get(id);
 
                 boolean okay = true;
-                for (ModuleImport mi : dep.getDependencies()) {
+
+                Set<ModuleImport> dependencies = dep.getDependencies();
+
+                // in case of submodule, make its parent also a dependency
+                if(dep instanceof YangModelDependencyInfo.SubmoduleDependencyInfo) {
+                    final String parent = ((YangModelDependencyInfo.SubmoduleDependencyInfo) dep).getParentModule();
+                    dependencies = Sets.newHashSet(dependencies);
+                    dependencies.add(new BelongsToDependency(parent));
+                }
+
+                for (ModuleImport mi : dependencies) {
                     if (!isKnown(resolved, mi)) {
                         LOG.debug("Source {} is missing import {}", id, mi);
                         okay = false;
@@ -161,4 +174,27 @@ final class DependencyResolver {
     Multimap<SourceIdentifier, ModuleImport> getUnsatisfiedImports() {
         return unsatisfiedImports;
     }
+
+    private static class BelongsToDependency implements ModuleImport {
+        private final String parent;
+
+        public BelongsToDependency(final String parent) {
+            this.parent = parent;
+        }
+
+        @Override
+        public String getModuleName() {
+            return parent;
+        }
+
+        @Override
+        public Date getRevision() {
+            return null;
+        }
+
+        @Override
+        public String getPrefix() {
+            return null;
+        }
+    }
 }
index 1ab6198e6aee037db593694baf9938cde41f089b..3f1265b0e1c63acd99cc36e55ee1b74dcf6e535d 100644 (file)
@@ -8,10 +8,11 @@
 
 package org.opendaylight.yangtools.yang.parser.repo;
 
+import static org.junit.Assert.assertEquals;
+
 import com.google.common.base.Optional;
 import java.util.HashMap;
 import java.util.Map;
-import junit.framework.Assert;
 import org.junit.Test;
 import org.opendaylight.yangtools.yang.model.repo.api.SourceIdentifier;
 import org.opendaylight.yangtools.yang.parser.impl.util.YangModelDependencyInfo;
@@ -28,8 +29,23 @@ public class DependencyResolverTest {
 
         final DependencyResolver resolved = DependencyResolver.create(map);
 
-        Assert.assertEquals(0, resolved.getUnresolvedSources().size());
-        Assert.assertEquals(0, resolved.getUnsatisfiedImports().size());
+        assertEquals(0, resolved.getUnresolvedSources().size());
+        assertEquals(0, resolved.getUnsatisfiedImports().size());
+    }
+
+    @Test
+    public void testSubmoduleNoModule() throws Exception {
+        final Map<SourceIdentifier, YangModelDependencyInfo> map = new HashMap<>();
+
+        // Subfoo does not have parent in reactor
+        addToMap(map, YangModelDependencyInfo.ModuleDependencyInfo.fromInputStream(getClass().getResourceAsStream("/model/subfoo.yang")));
+        addToMap(map, YangModelDependencyInfo.ModuleDependencyInfo.fromInputStream(getClass().getResourceAsStream("/model/bar.yang")));
+        addToMap(map, YangModelDependencyInfo.ModuleDependencyInfo.fromInputStream(getClass().getResourceAsStream("/model/baz.yang")));
+
+        final DependencyResolver resolved = DependencyResolver.create(map);
+
+        assertEquals(1, resolved.getUnresolvedSources().size());
+        assertEquals(0, resolved.getUnsatisfiedImports().size());
     }
 
     private void addToMap(final Map<SourceIdentifier, YangModelDependencyInfo> map, final YangModelDependencyInfo yangModelDependencyInfo) {