Merge "Added generate To File for specified directory."
authorGiovanni Meo <gmeo@cisco.com>
Thu, 2 May 2013 13:51:38 +0000 (13:51 +0000)
committerGerrit Code Review <gerrit@opendaylight.org>
Thu, 2 May 2013 13:51:38 +0000 (13:51 +0000)
22 files changed:
opendaylight/sal/yang-prototype/code-generator/maven-yang-plugin-it/src/test/resources/Correct/pom.xml
opendaylight/sal/yang-prototype/code-generator/maven-yang-plugin-it/src/test/resources/Correct/resources/model/testfile1.yang [deleted file]
opendaylight/sal/yang-prototype/code-generator/maven-yang-plugin-it/src/test/resources/Correct/resources/model/testfile2.yang [deleted file]
opendaylight/sal/yang-prototype/code-generator/maven-yang-plugin-it/src/test/resources/Correct_combined/pom.xml
opendaylight/sal/yang-prototype/code-generator/maven-yang-plugin-it/src/test/resources/Correct_resources/pom.xml
opendaylight/sal/yang-prototype/code-generator/maven-yang-plugin-it/src/test/resources/NoGenerators/pom.xml
opendaylight/sal/yang-prototype/code-generator/maven-yang-plugin-it/src/test/resources/NoGenerators_resources/pom.xml
opendaylight/sal/yang-prototype/code-generator/maven-yang-plugin-it/src/test/resources/UnknownGenerator/pom.xml
opendaylight/sal/yang-prototype/code-generator/maven-yang-plugin-it/src/test/resources/UnknownGenerator_resources/pom.xml
opendaylight/sal/yang-prototype/code-generator/yang-model-parser-impl/src/main/java/org/opendaylight/controller/yang/model/parser/builder/impl/ChoiceBuilder.java
opendaylight/sal/yang-prototype/code-generator/yang-model-parser-impl/src/main/java/org/opendaylight/controller/yang/model/parser/builder/impl/ChoiceCaseBuilder.java
opendaylight/sal/yang-prototype/code-generator/yang-model-parser-impl/src/main/java/org/opendaylight/controller/yang/model/parser/builder/impl/IdentitySchemaNodeBuilder.java
opendaylight/sal/yang-prototype/code-generator/yang-model-parser-impl/src/main/java/org/opendaylight/controller/yang/model/parser/builder/impl/ModuleBuilder.java
opendaylight/sal/yang-prototype/code-generator/yang-model-parser-impl/src/main/java/org/opendaylight/controller/yang/model/parser/builder/impl/UsesNodeBuilderImpl.java
opendaylight/sal/yang-prototype/code-generator/yang-model-parser-impl/src/main/java/org/opendaylight/controller/yang/model/parser/impl/YangModelParserImpl.java
opendaylight/sal/yang-prototype/code-generator/yang-model-parser-impl/src/main/java/org/opendaylight/controller/yang/model/parser/impl/YangModelParserListenerImpl.java
opendaylight/sal/yang-prototype/code-generator/yang-model-parser-impl/src/main/java/org/opendaylight/controller/yang/model/parser/util/ModuleDependencySort.java [new file with mode: 0644]
opendaylight/sal/yang-prototype/code-generator/yang-model-parser-impl/src/main/java/org/opendaylight/controller/yang/model/parser/util/TopologicalSort.java [new file with mode: 0644]
opendaylight/sal/yang-prototype/code-generator/yang-model-parser-impl/src/test/java/org/opendaylight/controller/yang/model/parser/impl/TypesResolutionTest.java
opendaylight/sal/yang-prototype/code-generator/yang-model-parser-impl/src/test/java/org/opendaylight/controller/yang/model/parser/util/ModuleDependencySortTest.java [new file with mode: 0644]
opendaylight/sal/yang-prototype/code-generator/yang-model-parser-impl/src/test/java/org/opendaylight/controller/yang/model/parser/util/TopologicalSortTest.java [new file with mode: 0644]
opendaylight/sal/yang-prototype/code-generator/yang-model-parser-impl/src/test/resources/model/testfile2.yang

index 33d1053f7dccc4c1ac7554c7c482d736428fb3f9..c48f1514993b166c7504d8fee2dbc63937b536c0 100644 (file)
@@ -20,7 +20,7 @@
                             <goal>generate-sources</goal>
                         </goals>
                         <configuration>
-                            <yangFilesRootDir>${basedir}</yangFilesRootDir>
+                            <yangFilesRootDir>${basedir}/../../../../../yang-model-parser-impl/src/test/resources/model</yangFilesRootDir>
                             <codeGenerators>
                                 <generator>
                                     <codeGeneratorClass>
diff --git a/opendaylight/sal/yang-prototype/code-generator/maven-yang-plugin-it/src/test/resources/Correct/resources/model/testfile1.yang b/opendaylight/sal/yang-prototype/code-generator/maven-yang-plugin-it/src/test/resources/Correct/resources/model/testfile1.yang
deleted file mode 100644 (file)
index ba0c15e..0000000
+++ /dev/null
@@ -1,57 +0,0 @@
-module types1 {
-       yang-version 1;
-    namespace "urn:simple.container.demo";
-    prefix "t1";
-    
-    import types2 {
-         prefix "data";
-         revision-date 2013-02-27;
-     }
-    
-    organization "Cisco";
-    contact "WILL-BE-DEFINED-LATER";
-    
-    revision "2013-02-27" {
-        reference " WILL BE DEFINED LATER";
-    }
-    
-    container interfaces {
-         list ifEntry {
-             key "ifIndex";
-
-             leaf ifIndex {
-                 type uint32;
-                 units minutes;
-             }
-             
-             leaf ifMtu {
-                 type int32;
-             }
-         }
-     }
-     
-       leaf testleaf {
-               type data:my-base-int32-type {
-                       range "min..max";
-               }
-       }
-       
-       leaf test-string-leaf {
-               type data:my-string-type-ext;
-       }
-       
-       leaf test-int-leaf {
-               type data:my-int-type-ext;
-       }
-       
-       leaf test-decimal-leaf {
-               type data:my-decimal-type {
-                       fraction-digits 4;
-               }
-       }
-       
-       leaf test-decimal-leaf2 {
-               type data:my-decimal-type-ext;
-       }
-
-}
diff --git a/opendaylight/sal/yang-prototype/code-generator/maven-yang-plugin-it/src/test/resources/Correct/resources/model/testfile2.yang b/opendaylight/sal/yang-prototype/code-generator/maven-yang-plugin-it/src/test/resources/Correct/resources/model/testfile2.yang
deleted file mode 100644 (file)
index 3e9da52..0000000
+++ /dev/null
@@ -1,100 +0,0 @@
-module types2 {
-       yang-version 1;
-    namespace "urn:simple.types.data.demo";
-    prefix "t2";
-    
-    import types1 {
-         prefix "if";
-         revision-date 2013-02-27;
-     }
-
-    organization "Cisco";
-    contact "WILL-BE-DEFINED-LATER";
-    description "This is types-data test description";
-
-    revision "2013-02-27" {
-        reference " WILL BE DEFINED LATER";
-    }
-    
-    typedef my-base-int32-type {
-               type int32 {
-               range "2..20";
-        }
-       }
-
-     typedef my-type1 {
-       type my-base-int32-type {
-               range "11..max";
-       }
-       }
-       
-       typedef my-string-type {
-               type string {
-                       pattern "[a-k]*";
-               }
-       }
-       
-       typedef my-string-type2 {
-               type my-string-type {
-                       pattern "[b-u]*";
-               }
-       }
-       
-       typedef my-string-type-ext {
-               type my-string-type2 {
-                       pattern "[e-z]*";
-               }
-       }
-       
-       typedef my-int-type {
-               type int32 {
-                       range "10..20";
-               }
-       }
-       
-       typedef my-int-type2 {
-               type my-int-type {
-                       range "12..18";
-               }
-       }
-       
-       typedef my-int-type-ext {
-               type my-int-type2 {
-                       range "14..16";
-               }
-       }
-       
-       typedef my-decimal-type {
-               type decimal64 {
-                       fraction-digits 6;
-               }
-       }
-       
-       typedef my-decimal-type-ext {
-               type decimal64 {
-                       fraction-digits 5;
-               }
-       }
-
-    augment "/if:interfaces/if:ifEntry" {
-       when "if:ifType='ds0'";
-        leaf ds0ChannelNumber {
-               type string;
-        }
-       }
-
-    leaf if-name {
-       type leafref {
-               path "/interface/name";
-        }
-    }
-     
-    leaf name {
-       type string;
-    }
-     
-       leaf nested-type-leaf {
-               type my-type1;
-       }
-
-}
index 4fd10ea70f0aeccbdc316a6505b668d379f1ad39..4fbffb69043b97c4766c794c4a5c12eaa5af03c4 100644 (file)
@@ -21,7 +21,7 @@
                             <goal>generate-resources</goal>
                         </goals>
                         <configuration>
-                            <yangFilesRootDir>${basedir}/../Correct</yangFilesRootDir>
+                            <yangFilesRootDir>${basedir}/../../../../../yang-model-parser-impl/src/test/resources/model</yangFilesRootDir>
                             <codeGenerators>
                                 <generator>
                                     <codeGeneratorClass>
index acb8e6036a65a415776679a8bdbf49113cdccdaa..2a935158c18591ab72f7c5964161fc4f8759a1a7 100644 (file)
@@ -20,7 +20,7 @@
                             <goal>generate-resources</goal>
                         </goals>
                         <configuration>
-                            <yangFilesRootDir>${basedir}/../Correct</yangFilesRootDir>
+                            <yangFilesRootDir>${basedir}/../../../../../yang-model-parser-impl/src/test/resources/model</yangFilesRootDir>
                             <resourceProviders>
                                 <provider>
                                     <resourceProviderClass>
index 82b2cc5b801031c0642578b62402c9b06197a004..a9ec4893f01927744979d6921478a53b32cf8ec9 100644 (file)
@@ -20,7 +20,7 @@
                             <goal>generate-sources</goal>
                         </goals>
                         <configuration>
-                            <yangFilesRootDir>${basedir}/../Correct</yangFilesRootDir>
+                            <yangFilesRootDir>${basedir}/../../../../../yang-model-parser-impl/src/test/resources/model</yangFilesRootDir>
                             <codeGenerators>
                             </codeGenerators>
                         </configuration>
index 96aadd2ba06917f47e67577a4f1f228e0f2c3dac..74f9dc38e3d4a5ca02d061f30407095bbde3d8ef 100644 (file)
@@ -20,7 +20,7 @@
                             <goal>generate-resources</goal>
                         </goals>
                         <configuration>
-                            <yangFilesRootDir>${basedir}/../Correct</yangFilesRootDir>
+                            <yangFilesRootDir>${basedir}/../../../../../yang-model-parser-impl/src/test/resources/model</yangFilesRootDir>
                             <resourceProviders>
                             </resourceProviders>
                         </configuration>
index 88829dff0c03e8ece2b0be3f9d72d3943bab2924..2c7f9228389f82cb55ea2437e73dceff7106dbdc 100644 (file)
@@ -20,7 +20,7 @@
                             <goal>generate-sources</goal>
                         </goals>
                         <configuration>
-                            <yangFilesRootDir>${basedir}/../Correct</yangFilesRootDir>
+                            <yangFilesRootDir>${basedir}/../../../../../yang-model-parser-impl/src/test/resources/model</yangFilesRootDir>
                             <codeGenerators>
                                 <generator>
                                     <codeGeneratorClass>
index 9d4175d2df287a2ebc754b36e4a992960324bf3e..fb83dc96ec2e90b455e92ad05c40e1c6bda48d34 100644 (file)
@@ -20,7 +20,7 @@
                             <goal>generate-resources</goal>
                         </goals>
                         <configuration>
-                            <yangFilesRootDir>${basedir}/../Correct</yangFilesRootDir>
+                            <yangFilesRootDir>${basedir}/../../../../../yang-model-parser-impl/src/test/resources/model</yangFilesRootDir>
                             <resourceProviders>
                                 <provider>
                                     <resourceProviderClass>
index eb8819657be5e9fac8653b912ce8b2b81ac87fa2..946ba4ae0529352bce572b57a541a1713ad1ce3a 100644 (file)
@@ -31,22 +31,26 @@ import org.opendaylight.controller.yang.model.parser.builder.api.UsesNodeBuilder
 
 public class ChoiceBuilder implements DataSchemaNodeBuilder, ChildNodeBuilder,
         AugmentationTargetBuilder {
+    private final ChoiceNodeImpl instance;
+    // SchemaNode args
     private final QName qname;
     private SchemaPath schemaPath;
-    private final ConstraintsBuilder constraints;
-    private final ChoiceNodeImpl instance;
     private String description;
     private String reference;
     private Status status = Status.CURRENT;
+    private final List<UnknownSchemaNodeBuilder> addedUnknownNodes = new ArrayList<UnknownSchemaNodeBuilder>();
+    // DataSchemaNode args
     private boolean augmenting;
     private boolean configuration;
-    private String defaultCase;
-
-    private final Set<ChoiceCaseBuilder> cases = new HashSet<ChoiceCaseBuilder>();
+    private final ConstraintsBuilder constraints;
+    // DataNodeContainer args
     private final Set<TypeDefinitionBuilder> addedTypedefs = new HashSet<TypeDefinitionBuilder>();
     private final Set<UsesNodeBuilder> addedUsesNodes = new HashSet<UsesNodeBuilder>();
+    // AugmentationTarget args
     private final Set<AugmentationSchemaBuilder> addedAugmentations = new HashSet<AugmentationSchemaBuilder>();
-    private final List<UnknownSchemaNodeBuilder> addedUnknownNodes = new ArrayList<UnknownSchemaNodeBuilder>();
+    // ChoiceNode args
+    private final Set<ChoiceCaseBuilder> cases = new HashSet<ChoiceCaseBuilder>();
+    private String defaultCase;
 
     public ChoiceBuilder(QName qname) {
         this.qname = qname;
@@ -62,6 +66,7 @@ public class ChoiceBuilder implements DataSchemaNodeBuilder, ChildNodeBuilder,
         instance.setStatus(status);
         instance.setAugmenting(augmenting);
         instance.setConfiguration(configuration);
+        instance.setConstraints(constraints.build());
         instance.setDefaultCase(defaultCase);
 
         // CASES
@@ -85,8 +90,6 @@ public class ChoiceBuilder implements DataSchemaNodeBuilder, ChildNodeBuilder,
         }
         instance.setUnknownSchemaNodes(unknownNodes);
 
-        instance.setConstraints(constraints.build());
-
         return instance;
     }
 
@@ -97,7 +100,8 @@ public class ChoiceBuilder implements DataSchemaNodeBuilder, ChildNodeBuilder,
     @Override
     public void addChildNode(DataSchemaNodeBuilder childNode) {
         if (!(childNode instanceof ChoiceCaseBuilder)) {
-            ChoiceCaseBuilder caseBuilder = new ChoiceCaseBuilder(childNode.getQName());
+            ChoiceCaseBuilder caseBuilder = new ChoiceCaseBuilder(
+                    childNode.getQName());
             caseBuilder.addChildNode(childNode);
             cases.add(caseBuilder);
         } else {
index 73d7e3dc0c7d9033f613572a2f5263f7c22b3c61..27cead10f11a0b32eb472be311b1fb9a18ba937d 100644 (file)
@@ -24,18 +24,18 @@ import org.opendaylight.controller.yang.model.parser.builder.api.DataSchemaNodeB
 import org.opendaylight.controller.yang.model.parser.builder.api.TypeDefinitionBuilder;
 import org.opendaylight.controller.yang.model.parser.builder.api.UsesNodeBuilder;
 
-public class ChoiceCaseBuilder extends AbstractChildNodeBuilder implements DataSchemaNodeBuilder {
-
+public final class ChoiceCaseBuilder extends AbstractChildNodeBuilder implements
+        DataSchemaNodeBuilder {
     private final ChoiceCaseNodeImpl instance;
-    private final ConstraintsBuilder constraints;
     private SchemaPath schemaPath;
     private String description;
     private String reference;
     private Status status = Status.CURRENT;
+    private final List<UnknownSchemaNodeBuilder> addedUnknownNodes = new ArrayList<UnknownSchemaNodeBuilder>();
     private boolean augmenting;
+    private final ConstraintsBuilder constraints;
     private final Set<UsesNodeBuilder> addedUsesNodes = new HashSet<UsesNodeBuilder>();
     private final Set<AugmentationSchema> augmentations = new HashSet<AugmentationSchema>();
-    private final List<UnknownSchemaNodeBuilder> addedUnknownNodes = new ArrayList<UnknownSchemaNodeBuilder>();
 
     ChoiceCaseBuilder(QName qname) {
         super(qname);
@@ -110,7 +110,7 @@ public class ChoiceCaseBuilder extends AbstractChildNodeBuilder implements DataS
 
     @Override
     public void setStatus(Status status) {
-        if(status != null) {
+        if (status != null) {
             this.status = status;
         }
     }
@@ -144,12 +144,14 @@ public class ChoiceCaseBuilder extends AbstractChildNodeBuilder implements DataS
 
     @Override
     public void addTypedef(TypeDefinitionBuilder typedefBuilder) {
-        throw new UnsupportedOperationException("Can not add type definition to choice case.");
+        throw new UnsupportedOperationException(
+                "Can not add type definition to choice case.");
     }
 
     @Override
     public void setConfiguration(boolean configuration) {
-        throw new UnsupportedOperationException("Can not add config definition to choice case.");
+        throw new UnsupportedOperationException(
+                "Can not add config definition to choice case.");
     }
 
     @Override
@@ -161,8 +163,7 @@ public class ChoiceCaseBuilder extends AbstractChildNodeBuilder implements DataS
         return augmentations;
     }
 
-
-    private static class ChoiceCaseNodeImpl implements ChoiceCaseNode {
+    private class ChoiceCaseNodeImpl implements ChoiceCaseNode {
         private final QName qname;
         private SchemaPath path;
         private String description;
@@ -217,7 +218,7 @@ public class ChoiceCaseBuilder extends AbstractChildNodeBuilder implements DataS
         }
 
         private void setStatus(Status status) {
-            if(status != null) {
+            if (status != null) {
                 this.status = status;
             }
         }
@@ -251,7 +252,7 @@ public class ChoiceCaseBuilder extends AbstractChildNodeBuilder implements DataS
         }
 
         private void setUnknownSchemaNodes(List<UnknownSchemaNode> unknownNodes) {
-            if(unknownNodes != null) {
+            if (unknownNodes != null) {
                 this.unknownNodes = unknownNodes;
             }
         }
@@ -317,7 +318,6 @@ public class ChoiceCaseBuilder extends AbstractChildNodeBuilder implements DataS
             }
         }
 
-
         @Override
         public int hashCode() {
             final int prime = 31;
index 906afd97a04bbb12b485d8b3cab47072aebb0c05..5cfde8e7a0b7b7cbc21ababcc2c11a90dfcaf0eb 100644 (file)
@@ -7,6 +7,7 @@
  */
 package org.opendaylight.controller.yang.model.parser.builder.impl;
 
+import java.util.ArrayList;
 import java.util.Collections;
 import java.util.List;
 
@@ -17,13 +18,13 @@ import org.opendaylight.controller.yang.model.api.Status;
 import org.opendaylight.controller.yang.model.api.UnknownSchemaNode;
 import org.opendaylight.controller.yang.model.parser.builder.api.SchemaNodeBuilder;
 
-public class IdentitySchemaNodeBuilder implements SchemaNodeBuilder {
-
+public final class IdentitySchemaNodeBuilder implements SchemaNodeBuilder {
+    private final IdentitySchemaNodeImpl instance;
     private final QName qname;
     private SchemaPath schemaPath;
-    private final IdentitySchemaNodeImpl instance;
     private IdentitySchemaNodeBuilder baseIdentity;
     private String baseIdentityName;
+    private final List<UnknownSchemaNodeBuilder> addedUnknownNodes = new ArrayList<UnknownSchemaNodeBuilder>();
 
     IdentitySchemaNodeBuilder(final QName qname) {
         this.qname = qname;
@@ -33,11 +34,17 @@ public class IdentitySchemaNodeBuilder implements SchemaNodeBuilder {
     @Override
     public IdentitySchemaNode build() {
         instance.setPath(schemaPath);
-
         if (baseIdentity != null) {
-            final IdentitySchemaNode base = baseIdentity.build();
-            instance.setBaseIdentity(base);
+            instance.setBaseIdentity(baseIdentity.build());
+        }
+
+        // UNKNOWN NODES
+        final List<UnknownSchemaNode> unknownNodes = new ArrayList<UnknownSchemaNode>();
+        for (UnknownSchemaNodeBuilder b : addedUnknownNodes) {
+            unknownNodes.add(b.build());
         }
+        instance.setUnknownSchemaNodes(unknownNodes);
+
         return instance;
     }
 
@@ -75,8 +82,7 @@ public class IdentitySchemaNodeBuilder implements SchemaNodeBuilder {
 
     @Override
     public void addUnknownSchemaNode(final UnknownSchemaNodeBuilder unknownNode) {
-        throw new IllegalStateException(
-                "Can not add schema node to identity statement");
+        addedUnknownNodes.add(unknownNode);
     }
 
     public String getBaseIdentityName() {
@@ -91,13 +97,14 @@ public class IdentitySchemaNodeBuilder implements SchemaNodeBuilder {
         this.baseIdentity = baseType;
     }
 
-    private class IdentitySchemaNodeImpl implements IdentitySchemaNode {
+    private final class IdentitySchemaNodeImpl implements IdentitySchemaNode {
         private final QName qname;
         private IdentitySchemaNode baseIdentity;
         private String description;
         private String reference;
         private Status status = Status.CURRENT;
         private SchemaPath path;
+        private List<UnknownSchemaNode> unknownNodes = Collections.emptyList();
 
         private IdentitySchemaNodeImpl(final QName qname) {
             this.qname = qname;
@@ -157,7 +164,14 @@ public class IdentitySchemaNodeBuilder implements SchemaNodeBuilder {
 
         @Override
         public List<UnknownSchemaNode> getUnknownSchemaNodes() {
-            return Collections.emptyList();
+            return unknownNodes;
+        }
+
+        private void setUnknownSchemaNodes(
+                List<UnknownSchemaNode> unknownSchemaNodes) {
+            if (unknownSchemaNodes != null) {
+                this.unknownNodes = unknownSchemaNodes;
+            }
         }
 
         @Override
index e0ba03adfb0013f4eb69873ee96973b9f1c2733f..cca505e98505d26907b0c49202285cfda98040d6 100644 (file)
@@ -96,6 +96,8 @@ public class ModuleBuilder implements Builder {
      */
     @Override
     public Module build() {
+        instance.setPrefix(prefix);
+        instance.setRevision(revision);
         instance.setImports(imports);
         instance.setNamespace(namespace);
 
@@ -247,12 +249,10 @@ public class ModuleBuilder implements Builder {
 
     public void setRevision(final Date revision) {
         this.revision = revision;
-        instance.setRevision(revision);
     }
 
     public void setPrefix(final String prefix) {
         this.prefix = prefix;
-        instance.setPrefix(prefix);
     }
 
     public void setYangVersion(final String yangVersion) {
@@ -295,10 +295,8 @@ public class ModuleBuilder implements Builder {
     public ContainerSchemaNodeBuilder addContainerNode(
             final QName containerName, final List<String> parentPath) {
         final List<String> pathToNode = new ArrayList<String>(parentPath);
-
         final ContainerSchemaNodeBuilder containerBuilder = new ContainerSchemaNodeBuilder(
                 containerName);
-
         final ChildNodeBuilder parent = (ChildNodeBuilder) moduleNodes
                 .get(pathToNode);
         if (parent != null) {
@@ -318,10 +316,8 @@ public class ModuleBuilder implements Builder {
     public ListSchemaNodeBuilder addListNode(final QName listName,
             final List<String> parentPath) {
         final List<String> pathToNode = new ArrayList<String>(parentPath);
-
         final ListSchemaNodeBuilder listBuilder = new ListSchemaNodeBuilder(
                 listName);
-
         final ChildNodeBuilder parent = (ChildNodeBuilder) moduleNodes
                 .get(pathToNode);
         if (parent != null) {
@@ -341,10 +337,8 @@ public class ModuleBuilder implements Builder {
     public LeafSchemaNodeBuilder addLeafNode(final QName leafName,
             final List<String> parentPath) {
         final List<String> pathToNode = new ArrayList<String>(parentPath);
-
         final LeafSchemaNodeBuilder leafBuilder = new LeafSchemaNodeBuilder(
                 leafName);
-
         final ChildNodeBuilder parent = (ChildNodeBuilder) moduleNodes
                 .get(pathToNode);
         if (parent != null) {
@@ -364,7 +358,6 @@ public class ModuleBuilder implements Builder {
     public LeafListSchemaNodeBuilder addLeafListNode(final QName leafListName,
             final List<String> parentPath) {
         final List<String> pathToNode = new ArrayList<String>(parentPath);
-
         final LeafListSchemaNodeBuilder leafListBuilder = new LeafListSchemaNodeBuilder(
                 leafListName);
         final ChildNodeBuilder parent = (ChildNodeBuilder) moduleNodes
@@ -386,7 +379,6 @@ public class ModuleBuilder implements Builder {
     public GroupingBuilder addGrouping(final QName qname,
             final List<String> parentPath) {
         final List<String> pathToGroup = new ArrayList<String>(parentPath);
-
         final GroupingBuilder builder = new GroupingBuilderImpl(qname);
         final ChildNodeBuilder parentNodeBuilder = (ChildNodeBuilder) moduleNodes
                 .get(pathToGroup);
@@ -405,7 +397,6 @@ public class ModuleBuilder implements Builder {
     public AugmentationSchemaBuilder addAugment(final String name,
             final List<String> parentPath) {
         final List<String> pathToAugment = new ArrayList<String>(parentPath);
-
         final AugmentationSchemaBuilder builder = new AugmentationSchemaBuilderImpl(
                 name);
 
index 7d3e9293571f25c155f0271f3ca7fe2ae48181d5..05d2faa4099e61e38c47e15fe69447ce79faaa35 100644 (file)
@@ -26,8 +26,7 @@ import org.opendaylight.controller.yang.model.parser.builder.api.SchemaNodeBuild
 import org.opendaylight.controller.yang.model.parser.builder.api.UsesNodeBuilder;\r
 import org.opendaylight.controller.yang.model.parser.util.RefineHolder;\r
 \r
-public class UsesNodeBuilderImpl implements UsesNodeBuilder, Builder {\r
-\r
+final class UsesNodeBuilderImpl implements UsesNodeBuilder, Builder {\r
     private final UsesNodeImpl instance;\r
     private final SchemaPath groupingPath;\r
     private final Set<AugmentationSchemaBuilder> addedAugments = new HashSet<AugmentationSchemaBuilder>();\r
@@ -89,8 +88,8 @@ public class UsesNodeBuilderImpl implements UsesNodeBuilder, Builder {
         refines.add(refine);\r
     }\r
 \r
-    private SchemaPath parseUsesPath(final String augmentPath) {\r
-        final String[] splittedPath = augmentPath.split("/");\r
+    private SchemaPath parseUsesPath(final String groupingPathStr) {\r
+        final String[] splittedPath = groupingPathStr.split("/");\r
         final List<QName> path = new ArrayList<QName>();\r
         QName name;\r
         for (String pathElement : splittedPath) {\r
@@ -103,11 +102,11 @@ public class UsesNodeBuilderImpl implements UsesNodeBuilder, Builder {
             }\r
             path.add(name);\r
         }\r
-        final boolean absolute = augmentPath.startsWith("/");\r
+        final boolean absolute = groupingPathStr.startsWith("/");\r
         return new SchemaPath(path, absolute);\r
     }\r
 \r
-    private static class UsesNodeImpl implements UsesNode {\r
+    private final class UsesNodeImpl implements UsesNode {\r
         private final SchemaPath groupingPath;\r
         private Set<AugmentationSchema> augmentations = Collections.emptySet();\r
         private boolean augmenting;\r
index 50943fa7403110d17e7d811d82c0b82f0337ab39..35c04a8713bcae29908491b443b726a5a83aabe6 100644 (file)
@@ -71,6 +71,8 @@ import org.opendaylight.controller.yang.model.parser.builder.impl.ModuleBuilder;
 import org.opendaylight.controller.yang.model.parser.builder.impl.TypedefBuilder;
 import org.opendaylight.controller.yang.model.parser.builder.impl.UnionTypeBuilder;
 import org.opendaylight.controller.yang.model.parser.builder.impl.UnknownSchemaNodeBuilder;
+import org.opendaylight.controller.yang.model.parser.util.ModuleDependencySort;
+import org.opendaylight.controller.yang.model.parser.util.ModuleDependencySort.ModuleSimple;
 import org.opendaylight.controller.yang.model.parser.util.ParserUtils;
 import org.opendaylight.controller.yang.model.parser.util.RefineHolder;
 import org.opendaylight.controller.yang.model.parser.util.TypeConstraints;
@@ -91,7 +93,7 @@ public class YangModelParserImpl implements YangModelParser {
     public Set<Module> parseYangModels(final List<File> yangFiles) {
         if (yangFiles != null) {
             final List<InputStream> inputStreams = new ArrayList<InputStream>();
-            
+
             for (final File yangFile : yangFiles) {
                 try {
                     inputStreams.add(new FileInputStream(yangFile));
@@ -119,7 +121,7 @@ public class YangModelParserImpl implements YangModelParser {
     }
 
     private Map<String, TreeMap<Date, ModuleBuilder>> resolveModuleBuilders(
-            final List<InputStream>  yangFileStreams) {
+            final List<InputStream> yangFileStreams) {
         final Map<String, TreeMap<Date, ModuleBuilder>> modules = new HashMap<String, TreeMap<Date, ModuleBuilder>>();
         final ParseTreeWalker walker = new ParseTreeWalker();
         final List<ParseTree> trees = parseStreams(yangFileStreams);
@@ -135,6 +137,9 @@ public class YangModelParserImpl implements YangModelParser {
             builders[i] = yangModelParser.getModuleBuilder();
         }
 
+        // module dependency graph sorted
+        List<ModuleSimple> sorted = new ModuleDependencySort(builders).sort();
+
         for (ModuleBuilder builder : builders) {
             final String builderName = builder.getName();
             Date builderRevision = builder.getRevision();
@@ -377,7 +382,7 @@ public class YangModelParserImpl implements YangModelParser {
         tdb.setPatterns(old.getPatterns());
         tdb.setFractionDigits(old.getFractionDigits());
         tdb.setPath(old.getPath());
-        
+
         final TypeDefinition<?> oldType = old.getType();
         if (oldType == null) {
             tdb.setType(old.getTypedef());
index 2023b47de3b960b9da29805440aeecb62b31f3df..98b81bd958d0ed338dc6c6a2521f233fa11928eb 100644 (file)
@@ -652,7 +652,7 @@ public final class YangModelParserListenerImpl extends YangParserBaseListener {
         final String nodeTypeStr = ctx.getChild(0).getText();
         final String[] splittedElement = nodeTypeStr.split(":");
         if (splittedElement.length == 1) {
-            nodeType = new QName(null, null, null, splittedElement[0]);
+            nodeType = new QName(null, null, yangModelPrefix, splittedElement[0]);
         } else {
             nodeType = new QName(null, null, splittedElement[0],
                     splittedElement[1]);
diff --git a/opendaylight/sal/yang-prototype/code-generator/yang-model-parser-impl/src/main/java/org/opendaylight/controller/yang/model/parser/util/ModuleDependencySort.java b/opendaylight/sal/yang-prototype/code-generator/yang-model-parser-impl/src/main/java/org/opendaylight/controller/yang/model/parser/util/ModuleDependencySort.java
new file mode 100644 (file)
index 0000000..5c128d2
--- /dev/null
@@ -0,0 +1,271 @@
+/*
+ * 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.controller.yang.model.parser.util;
+
+import java.util.Date;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import org.opendaylight.controller.yang.model.api.ModuleImport;
+import org.opendaylight.controller.yang.model.parser.builder.impl.ModuleBuilder;
+import org.opendaylight.controller.yang.model.parser.impl.YangModelParserListenerImpl;
+import org.opendaylight.controller.yang.model.parser.util.TopologicalSort.Node;
+import org.opendaylight.controller.yang.model.parser.util.TopologicalSort.NodeImpl;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.annotations.VisibleForTesting;
+import com.google.common.base.Function;
+import com.google.common.collect.Lists;
+import com.google.common.collect.Maps;
+import com.google.common.collect.Sets;
+
+/**
+ * Creates a module dependency graph from provided {@link ModuleBuilder}s and
+ * provides a {@link #sort()} method. It is topological sort and returns modules
+ * in order in which they should be processed (e.g. if A imports B, sort returns
+ * {B, A}).
+ */
+public final class ModuleDependencySort {
+
+    private static final Date DEFAULT_REVISION = new Date(0);
+    private static final Logger logger = LoggerFactory
+            .getLogger(ModuleDependencySort.class);
+
+    private final Map<String, Map<Date, ModuleNodeImpl>> moduleGraph;
+
+    /**
+     *
+     * @param builders
+     *            Source for module dependency graph.
+     * @throws YangValidationException
+     *             if 1. there are module:revision duplicates 2. there is
+     *             imported not existing module 3. module is imported twice
+     */
+    public ModuleDependencySort(ModuleBuilder... builders) {
+        this.moduleGraph = createModuleGraph(builders);
+    }
+
+    @VisibleForTesting
+    Map<String, Map<Date, ModuleNodeImpl>> getModuleGraph() {
+        return moduleGraph;
+    }
+
+    /**
+     * Topological sort of module dependency graph.
+     *
+     * @return Sorted list of modules. Modules can be further processed in
+     *         returned order.
+     */
+    public List<ModuleSimple> sort() {
+        Set<Node> nodes = Sets.newHashSet();
+        for (Map<Date, ModuleNodeImpl> map : moduleGraph.values()) {
+            for (ModuleNodeImpl node : map.values()) {
+                nodes.add(node);
+            }
+        }
+
+        // Cast to ModuleNode from Node
+        return Lists.transform(TopologicalSort.sort(nodes),
+                new Function<Node, ModuleSimple>() {
+
+                    @Override
+                    public ModuleSimple apply(Node input) {
+                        return (ModuleSimple) input;
+                    }
+                });
+    }
+
+    private Map<String, Map<Date, ModuleNodeImpl>> createModuleGraph(
+            ModuleBuilder... builders) {
+        Map<String, Map<Date, ModuleNodeImpl>> moduleGraph = Maps.newHashMap();
+
+        processModules(moduleGraph, builders);
+        processDependencies(moduleGraph, builders);
+
+        return moduleGraph;
+    }
+
+    /**
+     * Extract module:revision from module builders
+     */
+    private void processDependencies(
+            Map<String, Map<Date, ModuleNodeImpl>> moduleGraph,
+            ModuleBuilder... builders) {
+        Map<String, Date> imported = Maps.newHashMap();
+
+        // Create edges in graph
+        for (ModuleBuilder mb : builders) {
+            String fromName = mb.getName();
+            Date fromRevision = mb.getRevision() == null ? DEFAULT_REVISION
+                    : mb.getRevision();
+            for (ModuleImport imprt : mb.getModuleImports()) {
+                String toName = imprt.getModuleName();
+                Date toRevision = imprt.getRevision() == null ? DEFAULT_REVISION
+                        : imprt.getRevision();
+
+                ModuleNodeImpl from = moduleGraph.get(fromName).get(
+                        fromRevision);
+
+                ModuleNodeImpl to = getModuleByNameAndRevision(moduleGraph,
+                        fromName, fromRevision, toName, toRevision);
+
+                /*
+                 * Check imports: If module is imported twice with different
+                 * revisions then throw exception
+                 */
+                if (imported.get(toName) != null
+                        && !imported.get(toName).equals(toRevision))
+                    ex(String
+                            .format("Module:%s imported twice with different revisions:%s, %s",
+                                    toName,
+                                    formatRevDate(imported.get(toName)),
+                                    formatRevDate(toRevision)));
+                imported.put(toName, toRevision);
+
+                from.addEdge(to);
+            }
+        }
+    }
+
+    /**
+     * Get imported module by its name and revision from moduleGraph
+     */
+    private ModuleNodeImpl getModuleByNameAndRevision(
+            Map<String, Map<Date, ModuleNodeImpl>> moduleGraph,
+            String fromName, Date fromRevision, String toName, Date toRevision) {
+        ModuleNodeImpl to = null;
+
+        if (moduleGraph.get(toName) == null
+                || !moduleGraph.get(toName).containsKey(toRevision)) {
+            // If revision is not specified in import, but module exists
+            // with different revisions, take first
+            if (moduleGraph.get(toName) != null
+                    && !moduleGraph.get(toName).isEmpty()
+                    && toRevision.equals(DEFAULT_REVISION)) {
+                to = moduleGraph.get(toName).values().iterator().next();
+                logger.warn(String
+                        .format("Import:%s:%s by module:%s:%s does not specify revision, using:%s:%s for module dependency sort",
+                                toName, formatRevDate(toRevision), fromName,
+                                formatRevDate(fromRevision), to.getName(),
+                                formatRevDate(to.getRevision())));
+            } else
+                ex(String.format("Not existing module imported:%s:%s by:%s:%s",
+                        toName, formatRevDate(toRevision), fromName,
+                        formatRevDate(fromRevision)));
+        } else {
+            to = moduleGraph.get(toName).get(toRevision);
+        }
+        return to;
+    }
+
+    private void ex(String message) {
+        throw new YangValidationException(message);
+    }
+
+    /**
+     * Extract dependencies from module builders to fill dependency graph
+     */
+    private void processModules(
+            Map<String, Map<Date, ModuleNodeImpl>> moduleGraph,
+            ModuleBuilder... builders) {
+
+        // Process nodes
+        for (ModuleBuilder mb : builders) {
+            String name = mb.getName();
+
+            Date rev = mb.getRevision();
+            if (rev == null)
+                rev = DEFAULT_REVISION;
+
+            if (moduleGraph.get(name) == null)
+                moduleGraph.put(name, Maps.<Date, ModuleNodeImpl> newHashMap());
+
+            if (moduleGraph.get(name).get(rev) != null)
+                ex(String.format("Module:%s with revision:%s declared twice",
+                        name, formatRevDate(rev)));
+
+            moduleGraph.get(name).put(rev, new ModuleNodeImpl(name, rev));
+        }
+    }
+
+    private static String formatRevDate(Date rev) {
+        return rev == DEFAULT_REVISION ? "default"
+                : YangModelParserListenerImpl.simpleDateFormat.format(rev);
+    }
+
+    /**
+     * Simple representation of module. Contains name and revision.
+     */
+    public interface ModuleSimple {
+        String getName();
+
+        Date getRevision();
+    }
+
+    static class ModuleNodeImpl extends NodeImpl implements ModuleSimple {
+        private final String name;
+        private final Date revision;
+
+        public ModuleNodeImpl(String name, Date revision) {
+            this.name = name;
+            this.revision = revision;
+        }
+
+        @Override
+        public String getName() {
+            return name;
+        }
+
+        @Override
+        public Date getRevision() {
+            return revision;
+        }
+
+        @Override
+        public int hashCode() {
+            final int prime = 31;
+            int result = 1;
+            result = prime * result + ((name == null) ? 0 : name.hashCode());
+            result = prime * result
+                    + ((revision == null) ? 0 : revision.hashCode());
+            return result;
+        }
+
+        @Override
+        public boolean equals(Object obj) {
+            if (this == obj)
+                return true;
+            if (obj == null)
+                return false;
+            if (getClass() != obj.getClass())
+                return false;
+            ModuleNodeImpl other = (ModuleNodeImpl) obj;
+            if (name == null) {
+                if (other.name != null)
+                    return false;
+            } else if (!name.equals(other.name))
+                return false;
+            if (revision == null) {
+                if (other.revision != null)
+                    return false;
+            } else if (!revision.equals(other.revision))
+                return false;
+            return true;
+        }
+
+        @Override
+        public String toString() {
+            return "Module [name=" + name + ", revision="
+                    + formatRevDate(revision) + "]";
+        }
+
+    }
+
+}
diff --git a/opendaylight/sal/yang-prototype/code-generator/yang-model-parser-impl/src/main/java/org/opendaylight/controller/yang/model/parser/util/TopologicalSort.java b/opendaylight/sal/yang-prototype/code-generator/yang-model-parser-impl/src/main/java/org/opendaylight/controller/yang/model/parser/util/TopologicalSort.java
new file mode 100644 (file)
index 0000000..333137c
--- /dev/null
@@ -0,0 +1,184 @@
+/*
+ * 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.controller.yang.model.parser.util;
+
+import java.util.List;
+import java.util.Set;
+
+import com.google.common.base.Preconditions;
+import com.google.common.collect.Lists;
+import com.google.common.collect.Sets;
+
+/**
+ * Utility class that provides topological sort
+ */
+public class TopologicalSort {
+
+    /**
+     * Topological sort of dependent nodes in acyclic graphs.
+     *
+     * @return Sorted {@link List} of {@link Node}s. Order: Nodes with no
+     *         dependencies starting.
+     * @throws IllegalStateException
+     *             when cycle is present in the graph
+     */
+    public static List<Node> sort(Set<Node> nodes) {
+        List<Node> sortedNodes = Lists.newArrayList();
+
+        Set<Node> dependentNodes = getDependentNodes(nodes);
+
+        while (!dependentNodes.isEmpty()) {
+            Node n = dependentNodes.iterator().next();
+            dependentNodes.remove(n);
+
+            sortedNodes.add(n);
+
+            for (Edge e : n.getInEdges()) {
+                Node m = e.getFrom();
+                m.getOutEdges().remove(e);
+
+                if (m.getOutEdges().isEmpty()) {
+                    dependentNodes.add(m);
+                }
+            }
+        }
+
+        detectCycles(nodes);
+
+        return sortedNodes;
+    }
+
+    private static Set<Node> getDependentNodes(Set<Node> nodes) {
+        Set<Node> S = Sets.newHashSet();
+        for (Node n : nodes) {
+            if (n.getOutEdges().size() == 0) {
+                S.add(n);
+            }
+        }
+        return S;
+    }
+
+    private static void detectCycles(Set<Node> nodes) {
+        // Detect cycles
+        boolean cycle = false;
+        Node cycledNode = null;
+
+        for (Node n : nodes) {
+            if (!n.getOutEdges().isEmpty()) {
+                cycle = true;
+                cycledNode = n;
+                break;
+            }
+        }
+        Preconditions.checkState(cycle == false,
+                "Cycle detected in graph around node: " + cycledNode);
+    }
+
+    /**
+     * Interface for nodes in graph that can be sorted topologically
+     */
+    public static interface Node {
+        Set<Edge> getInEdges();
+
+        Set<Edge> getOutEdges();
+    }
+
+    /**
+     * Interface for edges in graph that can be sorted topologically
+     */
+    public static interface Edge {
+        Node getFrom();
+
+        Node getTo();
+    }
+
+    /**
+     * Basic Node implementation.
+     */
+    public static class NodeImpl implements Node {
+        private final Set<Edge> inEdges;
+        private final Set<Edge> outEdges;
+
+        @Override
+        public Set<Edge> getInEdges() {
+            return inEdges;
+        }
+
+        @Override
+        public Set<Edge> getOutEdges() {
+            return outEdges;
+        }
+
+        public void addEdge(Node to) {
+            Edge e = new EdgeImpl(this, to);
+            outEdges.add(e);
+            to.getInEdges().add(e);
+        }
+
+        public NodeImpl() {
+            inEdges = Sets.newHashSet();
+            outEdges = Sets.newHashSet();
+        }
+    }
+
+    /**
+     * Basic Edge implementation
+     */
+    public static class EdgeImpl implements Edge {
+        private final Node from;
+        private final Node to;
+
+        @Override
+        public Node getFrom() {
+            return from;
+        }
+
+        @Override
+        public Node getTo() {
+            return to;
+        }
+
+        public EdgeImpl(Node from, Node to) {
+            this.from = from;
+            this.to = to;
+
+        }
+
+        @Override
+        public int hashCode() {
+            final int prime = 31;
+            int result = 1;
+            result = prime * result + ((from == null) ? 0 : from.hashCode());
+            result = prime * result + ((to == null) ? 0 : to.hashCode());
+            return result;
+        }
+
+        @Override
+        public boolean equals(Object obj) {
+            if (this == obj)
+                return true;
+            if (obj == null)
+                return false;
+            if (getClass() != obj.getClass())
+                return false;
+            EdgeImpl other = (EdgeImpl) obj;
+            if (from == null) {
+                if (other.from != null)
+                    return false;
+            } else if (!from.equals(other.from))
+                return false;
+            if (to == null) {
+                if (other.to != null)
+                    return false;
+            } else if (!to.equals(other.to))
+                return false;
+            return true;
+        }
+    }
+
+}
index 7acf7cbbe4cab1adf623a30df4d44deaa6631df6..4a48a4e2da477264e2d0de97f5369010aa889fbc 100644 (file)
@@ -19,7 +19,6 @@ import org.opendaylight.controller.yang.common.QName;
 import org.opendaylight.controller.yang.model.api.IdentitySchemaNode;
 import org.opendaylight.controller.yang.model.api.LeafSchemaNode;
 import org.opendaylight.controller.yang.model.api.Module;
-import org.opendaylight.controller.yang.model.api.Status;
 import org.opendaylight.controller.yang.model.api.TypeDefinition;
 import org.opendaylight.controller.yang.model.api.type.BitsTypeDefinition.Bit;
 import org.opendaylight.controller.yang.model.api.type.EnumTypeDefinition.EnumPair;
diff --git a/opendaylight/sal/yang-prototype/code-generator/yang-model-parser-impl/src/test/java/org/opendaylight/controller/yang/model/parser/util/ModuleDependencySortTest.java b/opendaylight/sal/yang-prototype/code-generator/yang-model-parser-impl/src/test/java/org/opendaylight/controller/yang/model/parser/util/ModuleDependencySortTest.java
new file mode 100644 (file)
index 0000000..216d778
--- /dev/null
@@ -0,0 +1,192 @@
+/*
+ * 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.controller.yang.model.parser.util;
+
+import static org.hamcrest.core.AnyOf.*;
+import static org.hamcrest.core.Is.*;
+import static org.junit.Assert.*;
+import static org.junit.matchers.JUnitMatchers.*;
+import static org.mockito.Mockito.*;
+
+import java.util.Date;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Set;
+
+import org.hamcrest.Matcher;
+import org.junit.Test;
+import org.opendaylight.controller.yang.model.api.ModuleImport;
+import org.opendaylight.controller.yang.model.parser.builder.impl.ModuleBuilder;
+import org.opendaylight.controller.yang.model.parser.impl.YangModelParserListenerImpl;
+import org.opendaylight.controller.yang.model.parser.util.ModuleDependencySort.ModuleNodeImpl;
+import org.opendaylight.controller.yang.model.parser.util.ModuleDependencySort.ModuleSimple;
+import org.opendaylight.controller.yang.model.parser.util.TopologicalSort.Edge;
+
+import com.google.common.collect.Sets;
+
+public class ModuleDependencySortTest {
+
+    private ModuleBuilder a = mockModule("a", null);
+    private ModuleBuilder b = mockModule("b", null);
+    private ModuleBuilder c = mockModule("c", null);
+    private ModuleBuilder d = mockModule("d", null);
+
+    @Test
+    public void testValid() throws Exception {
+
+        mockDependency(a, b);
+        mockDependency(b, c);
+        mockDependency(b, d);
+
+        ModuleBuilder[] builders = new ModuleBuilder[] { d, b, c, a };
+        ModuleDependencySort sort = new ModuleDependencySort(builders);
+
+        assertDependencyGraph(sort.getModuleGraph());
+
+        List<ModuleSimple> l = sort.sort();
+
+        @SuppressWarnings("unchecked")
+        Matcher<String> cOrD = anyOf(is(c.getName()), is(d.getName()));
+
+        assertThat(l.get(0).getName(), cOrD);
+        assertThat(l.get(1).getName(), cOrD);
+        assertThat(l.get(2).getName(), is(b.getName()));
+        assertThat(l.get(3).getName(), is(a.getName()));
+    }
+
+    @Test(expected = YangValidationException.class)
+    public void testModuleTwice() throws Exception {
+        ModuleBuilder a2 = mockModule("a", null);
+
+        ModuleBuilder[] builders = new ModuleBuilder[] { a, a2 };
+        try {
+            new ModuleDependencySort(builders);
+        } catch (YangValidationException e) {
+            assertThat(e.getMessage(),
+                    containsString("Module:a with revision:default declared twice"));
+            throw e;
+        }
+    }
+
+    @Test(expected = YangValidationException.class)
+    public void testImportNotExistingModule() throws Exception {
+        mockDependency(a, b);
+
+        ModuleBuilder[] builders = new ModuleBuilder[] { a };
+        try {
+            new ModuleDependencySort(builders);
+        } catch (YangValidationException e) {
+            assertThat(e.getMessage(),
+                    containsString("Not existing module imported:b:default by:a:default"));
+            throw e;
+        }
+    }
+
+    @Test
+    public void testImportTwice() throws Exception {
+        mockDependency(a, b);
+        mockDependency(c, b);
+
+        ModuleBuilder[] builders = new ModuleBuilder[] { a, b, c };
+        new ModuleDependencySort(builders);
+    }
+
+    @Test(expected = YangValidationException.class)
+    public void testImportTwiceDifferentRevision() throws Exception {
+        Date date = new Date();
+        ModuleBuilder b2 = mockModule("b", date);
+
+        mockDependency(a, b);
+        mockDependency(c, b2);
+
+        ModuleBuilder[] builders = new ModuleBuilder[] { a, c, b, b2 };
+        try {
+            ModuleDependencySort aaa = new ModuleDependencySort(builders);
+            System.out.println(aaa.getModuleGraph());
+        } catch (YangValidationException e) {
+            assertThat(e.getMessage(),
+                    containsString("Module:b imported twice with different revisions:default, "
+                            + YangModelParserListenerImpl.simpleDateFormat
+                                    .format(date)));
+            throw e;
+        }
+    }
+
+    @Test
+    public void testModuleTwiceWithDifferentRevs() throws Exception {
+        ModuleBuilder a2 = mockModule("a", new Date());
+
+        ModuleBuilder[] builders = new ModuleBuilder[] { a, a2 };
+        new ModuleDependencySort(builders);
+    }
+
+    @Test(expected = YangValidationException.class)
+    public void testModuleTwice2() throws Exception {
+        Date rev = new Date();
+        ModuleBuilder a2 = mockModule("a", rev);
+        ModuleBuilder a3 = mockModule("a", rev);
+
+        ModuleBuilder[] builders = new ModuleBuilder[] { a, a2, a3 };
+        try {
+            new ModuleDependencySort(builders);
+        } catch (YangValidationException e) {
+            assertThat(e.getMessage(), containsString("Module:a with revision:"
+                    + YangModelParserListenerImpl.simpleDateFormat.format(rev)
+                    + " declared twice"));
+            throw e;
+        }
+    }
+
+    private void assertDependencyGraph(
+            Map<String, Map<Date, ModuleNodeImpl>> moduleGraph) {
+        for (Entry<String, Map<Date, ModuleNodeImpl>> node : moduleGraph
+                .entrySet()) {
+            String name = node.getKey();
+
+            // Expects only one module revision
+
+            Set<Edge> inEdges = node.getValue().values().iterator().next()
+                    .getInEdges();
+            Set<Edge> outEdges = node.getValue().values().iterator().next()
+                    .getOutEdges();
+
+            if (name.equals("a")) {
+                assertEdgeCount(inEdges, 0, outEdges, 1);
+            } else if (name.equals("b")) {
+                assertEdgeCount(inEdges, 1, outEdges, 2);
+            } else {
+                assertEdgeCount(inEdges, 1, outEdges, 0);
+            }
+        }
+    }
+
+    private void assertEdgeCount(Set<Edge> inEdges, int i, Set<Edge> outEdges,
+            int j) {
+        assertThat(inEdges.size(), is(i));
+        assertThat(outEdges.size(), is(j));
+    }
+
+    private void mockDependency(ModuleBuilder a, ModuleBuilder b) {
+        ModuleImport imprt = mock(ModuleImport.class);
+        doReturn(b.getName()).when(imprt).getModuleName();
+        doReturn(b.getRevision()).when(imprt).getRevision();
+        a.getModuleImports().add(imprt);
+    }
+
+    private ModuleBuilder mockModule(String name, Date rev) {
+        ModuleBuilder a = mock(ModuleBuilder.class);
+        doReturn(name).when(a).getName();
+        Set<ModuleImport> set = Sets.newHashSet();
+        doReturn(set).when(a).getModuleImports();
+        if (rev != null) {
+            doReturn(rev).when(a).getRevision();
+        }
+        return a;
+    }
+}
diff --git a/opendaylight/sal/yang-prototype/code-generator/yang-model-parser-impl/src/test/java/org/opendaylight/controller/yang/model/parser/util/TopologicalSortTest.java b/opendaylight/sal/yang-prototype/code-generator/yang-model-parser-impl/src/test/java/org/opendaylight/controller/yang/model/parser/util/TopologicalSortTest.java
new file mode 100644 (file)
index 0000000..bfb94e5
--- /dev/null
@@ -0,0 +1,72 @@
+/*
+ * 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.controller.yang.model.parser.util;
+
+import static org.hamcrest.core.Is.*;
+import static org.junit.Assert.*;
+
+import java.util.List;
+import java.util.Set;
+
+import org.junit.Test;
+import org.opendaylight.controller.yang.model.parser.util.TopologicalSort.Node;
+import org.opendaylight.controller.yang.model.parser.util.TopologicalSort.NodeImpl;
+
+import com.google.common.collect.Sets;
+
+public class TopologicalSortTest {
+
+    @Test(expected = IllegalStateException.class)
+    public void test() throws Exception {
+        Set<Node> nodes = Sets.newHashSet();
+
+        NodeImpl node1 = new NodeImpl();
+        nodes.add(node1);
+        NodeImpl node2 = new NodeImpl();
+        nodes.add(node2);
+        NodeImpl node3 = new NodeImpl();
+        nodes.add(node3);
+
+        node1.addEdge(node2);
+        node2.addEdge(node3);
+        node3.addEdge(node1);
+
+        try {
+            TopologicalSort.sort(nodes);
+        } catch (IllegalStateException e) {
+            throw e;
+        }
+    }
+
+    @Test
+    public void testValidSimple() throws Exception {
+        Set<Node> nodes = Sets.newHashSet();
+
+        Node node1 = new NodeImpl();
+        nodes.add(node1);
+        Node node2 = new NodeImpl();
+        nodes.add(node2);
+        Node node3 = new NodeImpl();
+        nodes.add(node3);
+        Node node4 = new NodeImpl();
+        nodes.add(node4);
+
+        ((NodeImpl) node1).addEdge(node2);
+        ((NodeImpl) node1).addEdge(node3);
+        ((NodeImpl) node2).addEdge(node4);
+        ((NodeImpl) node3).addEdge(node2);
+
+        List<Node> sorted = TopologicalSort.sort(nodes);
+
+        assertThat(sorted.get(0), is(node4));
+        assertThat(sorted.get(1), is(node2));
+        assertThat(sorted.get(2), is(node3));
+        assertThat(sorted.get(3), is(node1));
+    }
+
+}
index 4f146f705d0b692d9ed3deda75ccf3f9346f540b..1a7b45ecb153e71d33c90036b26e14d2b1fba45d 100644 (file)
@@ -3,11 +3,6 @@ module types2 {
     namespace "urn:simple.types.data.demo";
     prefix "t2";
     
-    import types1 {
-         prefix "if";
-         revision-date 2013-02-27;
-     }
-
     organization "opendaylight";
     contact "http://www.opendaylight.org/";