Added support for parsing submodules & added dependency utility parser 70/4170/2
authorMartin Vitez <mvitez@cisco.com>
Mon, 13 Jan 2014 10:06:22 +0000 (11:06 +0100)
committerTony Tkacik <ttkacik@cisco.com>
Tue, 14 Jan 2014 09:49:09 +0000 (10:49 +0100)
All nodes defined in submodule are added to module to which submodule belongs.

Dependency utility parser is small YANG parser which extracts module identifier
(module name,revision) and all imports / includes, so it is easier for
implementations using YANG parser to check if all dependencies are available.

Change-Id: If1c4c5544aaf54e9ba7d8000a6f31cce83a7f9f1
Signed-off-by: Martin Vitez <mvitez@cisco.com>
Signed-off-by: Tony Tkaciik <ttkacik@cisco.com>
22 files changed:
code-generator/binding-generator-impl/src/test/java/org/opendaylight/yangtools/sal/binding/generator/impl/RefineTest.java
yang/yang-common/src/main/java/org/opendaylight/yangtools/yang/common/QName.java
yang/yang-model-util/src/main/java/org/opendaylight/yangtools/yang/model/util/repo/AbstractCachingSchemaSourceProvider.java
yang/yang-model-util/src/main/java/org/opendaylight/yangtools/yang/model/util/repo/FilesystemSchemaCachingProvider.java
yang/yang-model-util/src/main/java/org/opendaylight/yangtools/yang/model/util/repo/SchemaSourceProvider.java
yang/yang-model-util/src/main/java/org/opendaylight/yangtools/yang/model/util/repo/SchemaSourceProviders.java
yang/yang-model-util/src/main/java/org/opendaylight/yangtools/yang/model/util/repo/SourceIdentifier.java [new file with mode: 0644]
yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/builder/api/AbstractDataNodeContainerBuilder.java
yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/builder/api/DataNodeContainerBuilder.java
yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/builder/impl/GroupingBuilderImpl.java
yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/builder/impl/ModuleBuilder.java
yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/impl/YangParserImpl.java
yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/impl/YangParserListenerImpl.java
yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/impl/util/YangModelDependencyInfo.java [new file with mode: 0644]
yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/impl/util/YangSourceContext.java [new file with mode: 0644]
yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/util/CopyUtils.java
yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/util/GroupingSort.java
yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/util/GroupingUtils.java
yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/util/ParserListenerUtils.java
yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/util/ParserUtils.xtend
yang/yang-parser-impl/src/test/java/org/opendaylight/yangtools/yang/parser/impl/YangParserTest.java
yang/yang-parser-impl/src/test/resources/submodule-test/subfoo.yang [new file with mode: 0644]

index 851794ac4d116763f3069ac8d856e535782732e6..bfd51620fe94e5bd475c61030394c98d8cde931d 100644 (file)
@@ -74,7 +74,7 @@ public class RefineTest {
         loadTestResources();
         assertEquals("Incorrect number of test files.", 1, testModels.size());
 
-        Set<UsesNodeBuilder> usesNodeBuilders = getModuleBuilder().getUsesNodes();
+        Set<UsesNodeBuilder> usesNodeBuilders = getModuleBuilder().getUsesNodeBuilders();
         List<RefineHolder> refineHolders = null;
         Set<DataSchemaNodeBuilder> dataSchemaNodeBuilders = null;
         for (UsesNodeBuilder usesNodeBuilder : usesNodeBuilders) {
@@ -82,7 +82,7 @@ public class RefineTest {
                 refineHolders = usesNodeBuilder.getRefines();
                 // FIXME
                 //GroupingUtils.updateUsesParent(usesNodeBuilder);
-                dataSchemaNodeBuilders = usesNodeBuilder.getParent().getChildNodes();
+                dataSchemaNodeBuilders = usesNodeBuilder.getParent().getChildNodeBuilders();
                 break;
             }
         }
index f52b21495ac18c6ffe0bbf91452da8387b0ba739..01b20a3b540d4392235c308eead1934a51569c43 100644 (file)
@@ -13,6 +13,7 @@ import java.net.URISyntaxException;
 import java.text.ParseException;
 import java.text.SimpleDateFormat;
 import java.util.Date;
+import java.util.Objects;
 
 import org.opendaylight.yangtools.concepts.Immutable;
 import org.slf4j.Logger;
@@ -238,11 +239,9 @@ public final class QName implements Immutable,Serializable {
     public static QName create(String namespace, String revision, String localName) throws IllegalArgumentException{
         try {
             URI namespaceUri = new URI(namespace);
-            Date revisionDate = REVISION_FORMAT.get().parse(revision);
+            Date revisionDate = parseRevision(revision);
             return create(namespaceUri, revisionDate, localName);
-        } catch (ParseException pe) {
-            throw new IllegalArgumentException("Revision is not in supported format", pe);
-        } catch (URISyntaxException ue) {
+        }  catch (URISyntaxException ue) {
             throw new IllegalArgumentException("Namespace is is not valid URI", ue);
         }
     }
@@ -301,4 +300,23 @@ public final class QName implements Immutable,Serializable {
     public QName withoutRevision() {
         return QName.create(namespace, null, localName);
     }
+
+    public static Date parseRevision(String formatedDate) {
+        try {
+            return REVISION_FORMAT.get().parse(formatedDate);
+        } catch (ParseException e) {
+            throw new IllegalArgumentException("Revision is not in supported format",e);
+        }
+    }
+
+    public static String formattedRevision(Date revision) {
+        if(revision == null) {
+            return null;
+        }
+        return REVISION_FORMAT.get().format(revision);
+    }
+
+    public boolean isEqualWithoutRevision(QName other) {
+        return localName.equals(other.getLocalName()) && Objects.equals(namespace, other.getNamespace());
+    }
 }
index 021531e21f5ca254f441a8e8c340c8423cbd6ef7..ae03a49e0008c8cc7d396e287cc3cfcb894c12db 100644 (file)
@@ -18,25 +18,31 @@ public abstract class AbstractCachingSchemaSourceProvider<I, O> implements Schem
 
     @Override
     public Optional<O> getSchemaSource(String moduleName, Optional<String> revision) {
-        return getSchemaSourceImpl(moduleName, revision, defaultDelegate);
+        checkNotNull(moduleName, "Module name should not be null.");
+        checkNotNull(revision, "Revision should not be null");
+        return getSchemaSource(SourceIdentifier.create(moduleName, revision));
+    }
+    
+    @Override
+    public Optional<O> getSchemaSource(SourceIdentifier sourceIdentifier) {
+        return getSchemaSourceImpl(sourceIdentifier, defaultDelegate);
     }
 
-    private Optional<O> getSchemaSourceImpl(String moduleName, Optional<String> revision,
+    protected final Optional<O> getSchemaSourceImpl(SourceIdentifier identifier,
             SchemaSourceProvider<I> delegate) {
-        checkNotNull(moduleName, "Module name should not be null.");
-        checkNotNull(revision, "Revision should not be null");
+        checkNotNull(identifier, "Source identifier name should not be null.");
 
-        Optional<O> cached = getCachedSchemaSource(moduleName, revision);
+        Optional<O> cached = getCachedSchemaSource(identifier);
         if (cached.isPresent()) {
             return cached;
         }
-        Optional<I> live = delegate.getSchemaSource(moduleName, revision);
-        return cacheSchemaSource(moduleName, revision, live);
+        Optional<I> live = delegate.getSchemaSource(identifier);
+        return cacheSchemaSource(identifier, live);
     }
 
-    abstract protected Optional<O> cacheSchemaSource(String moduleName, Optional<String> revision, Optional<I> stream);
+    abstract protected Optional<O> cacheSchemaSource(SourceIdentifier identifier, Optional<I> stream);
 
-    abstract protected Optional<O> getCachedSchemaSource(String moduleName, Optional<String> revision);
+    abstract protected Optional<O> getCachedSchemaSource(SourceIdentifier identifier);
 
     public SchemaSourceProvider<I> getDelegate() {
         return defaultDelegate;
@@ -47,7 +53,9 @@ public abstract class AbstractCachingSchemaSourceProvider<I, O> implements Schem
         return new SchemaSourceProviderInstance(delegate);
     }
 
-    private class SchemaSourceProviderInstance implements SchemaSourceProvider<O>, Delegator<SchemaSourceProvider<I>> {
+    private class SchemaSourceProviderInstance implements //
+    SchemaSourceProvider<O>, 
+    Delegator<SchemaSourceProvider<I>> {
 
         private final SchemaSourceProvider<I> delegate;
 
@@ -58,12 +66,17 @@ public abstract class AbstractCachingSchemaSourceProvider<I, O> implements Schem
 
         @Override
         public Optional<O> getSchemaSource(String moduleName, Optional<String> revision) {
-            return getSchemaSourceImpl(moduleName, revision, getDelegate());
+            return getSchemaSource(SourceIdentifier.create(moduleName, revision));
         }
 
         @Override
         public SchemaSourceProvider<I> getDelegate() {
             return delegate;
         }
+
+        @Override
+        public Optional<O> getSchemaSource(SourceIdentifier sourceIdentifier) {
+            return getSchemaSourceImpl(sourceIdentifier, getDelegate());
+        }
     }
 }
index 0fdf05a227dd96f9a354f17bb29788218ac62b9c..7794f1d2e387e1fce85bf779c292c19a9c06d3c7 100644 (file)
@@ -26,8 +26,8 @@ public class FilesystemSchemaCachingProvider<I> extends AbstractCachingSchemaSou
     }
 
     @Override
-    protected synchronized Optional<InputStream> cacheSchemaSource(String moduleName, Optional<String> revision, Optional<I> source) {
-        File schemaFile = toFile(moduleName, revision);
+    protected synchronized Optional<InputStream> cacheSchemaSource(SourceIdentifier identifier, Optional<I> source) {
+        File schemaFile = toFile(identifier);
         try {
             if(source.isPresent() && schemaFile.createNewFile()) {
                 try (
@@ -59,8 +59,8 @@ public class FilesystemSchemaCachingProvider<I> extends AbstractCachingSchemaSou
     }
 
     @Override
-    protected Optional<InputStream> getCachedSchemaSource(String moduleName, Optional<String> revision) {
-        File inputFile = toFile(moduleName, revision);
+    protected Optional<InputStream> getCachedSchemaSource(SourceIdentifier identifier) {
+        File inputFile = toFile(identifier);
         try {
             if (inputFile.exists() && inputFile.canRead()) {
                 InputStream stream = new FileInputStream(inputFile);
@@ -72,19 +72,11 @@ public class FilesystemSchemaCachingProvider<I> extends AbstractCachingSchemaSou
         return Optional.absent();
     }
 
-    private File toFile(String moduleName, Optional<String> revision) {
-        return new File(storageDirectory, toYangFileName(moduleName, revision));
+    private File toFile(SourceIdentifier identifier) {
+        return new File(storageDirectory, identifier.toYangFilename());
     }
 
-    public static final String toYangFileName(String moduleName, Optional<String> revision) {
-        StringBuilder filename = new StringBuilder(moduleName);
-        if (revision.isPresent()) {
-            filename.append("@");
-            filename.append(revision.get());
-        }
-        filename.append(".yang");
-        return filename.toString();
-    }
+
 
     private static final Function<String, String> NOOP_TRANSFORMATION = new Function<String, String>() {
         @Override
index f8f6efbc8365d8bde9249e7eb7ddb78c79813258..eeb59ae3a985143d623a52fd312974220df97487 100644 (file)
@@ -1,11 +1,11 @@
 package org.opendaylight.yangtools.yang.model.util.repo;
 
-import java.io.InputStream;
-
 import com.google.common.base.Optional;
 
 public interface SchemaSourceProvider<F> {
 
     Optional<F> getSchemaSource(String moduleName, Optional<String> revision);
+    
+    Optional<F> getSchemaSource(SourceIdentifier sourceIdentifier);
 
 }
index 78cb713969b306a264d9fed52749626c1a6b9739..dbed32c7d57da50950fbc7100d25eab2c4296ed3 100644 (file)
@@ -1,5 +1,10 @@
 package org.opendaylight.yangtools.yang.model.util.repo;
 
+import java.io.InputStream;
+import java.io.StringBufferInputStream;
+
+import org.opendaylight.yangtools.concepts.Delegator;
+
 import com.google.common.base.Optional;
 
 public class SchemaSourceProviders {
@@ -12,6 +17,11 @@ public class SchemaSourceProviders {
             return Optional.absent();
         }
 
+        @Override
+        public Optional getSchemaSource(SourceIdentifier sourceIdentifier) {
+            return Optional.absent();
+        }
+
     };
 
     @SuppressWarnings("unchecked")
@@ -19,4 +29,39 @@ public class SchemaSourceProviders {
         return (SchemaSourceProvider<T>) NOOP_PROVIDER;
     }
 
+    public static SchemaSourceProvider<InputStream> inputStreamProviderfromStringProvider(
+            SchemaSourceProvider<String> delegate) {
+        return new StringToInputStreamSchemaSourceProvider(delegate);
+    }
+
+    private final static class StringToInputStreamSchemaSourceProvider implements //
+            SchemaSourceProvider<InputStream>, Delegator<SchemaSourceProvider<String>> {
+
+        private SchemaSourceProvider<String> delegate;
+
+        public StringToInputStreamSchemaSourceProvider(SchemaSourceProvider<String> delegate) {
+            this.delegate = delegate;
+        }
+
+        @Override
+        public SchemaSourceProvider<String> getDelegate() {
+            return delegate;
+        }
+
+        @Override
+        public Optional<InputStream> getSchemaSource(SourceIdentifier sourceIdentifier) {
+            Optional<String> potential = getDelegate().getSchemaSource(sourceIdentifier);
+            if (potential.isPresent()) {
+                String stringStream = potential.get();
+                return Optional.<InputStream> of(new StringBufferInputStream(stringStream));
+            }
+            return Optional.absent();
+        }
+
+        @Override
+        public Optional<InputStream> getSchemaSource(String moduleName, Optional<String> revision) {
+            return getSchemaSource(SourceIdentifier.create(moduleName, revision));
+        }
+    }
+
 }
diff --git a/yang/yang-model-util/src/main/java/org/opendaylight/yangtools/yang/model/util/repo/SourceIdentifier.java b/yang/yang-model-util/src/main/java/org/opendaylight/yangtools/yang/model/util/repo/SourceIdentifier.java
new file mode 100644 (file)
index 0000000..9105765
--- /dev/null
@@ -0,0 +1,78 @@
+package org.opendaylight.yangtools.yang.model.util.repo;
+
+import com.google.common.base.Optional;
+
+public final class SourceIdentifier {
+
+    private final String name;
+    private final String revision;
+
+    public SourceIdentifier(String name, Optional<String> formattedRevision) {
+        super();
+        this.name = name;
+        this.revision = formattedRevision.orNull();
+    }
+
+    @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;
+        SourceIdentifier other = (SourceIdentifier) 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;
+    }
+
+    public String getName() {
+        return name;
+    }
+
+    public String getRevision() {
+        return revision;
+    }
+
+    public static SourceIdentifier create(String moduleName, Optional<String> revision) {
+        return new SourceIdentifier(moduleName, revision);
+    }
+    
+    public String toYangFilename() {
+        return toYangFileName(name, Optional.fromNullable(revision));
+    }
+    
+    @Override
+    public String toString() {
+        return "SourceIdentifier [name=" + name + "@" + revision + "]";
+    }
+
+    public static final String toYangFileName(String moduleName, Optional<String> revision) {
+        StringBuilder filename = new StringBuilder(moduleName);
+        if (revision.isPresent()) {
+            filename.append("@");
+            filename.append(revision.get());
+        }
+        filename.append(".yang");
+        return filename.toString();
+    }
+
+}
\ No newline at end of file
index 575af04dbbbdcb761bc904840300b757048b0e18..39c4c5e78af6883458f551327048b4c4f1b400af 100644 (file)
@@ -50,8 +50,12 @@ public abstract class AbstractDataNodeContainerBuilder extends AbstractBuilder i
         return qname;
     }
 
+    public Map<QName, DataSchemaNode> getChildNodes() {
+        return childNodes;
+    }
+
     @Override
-    public Set<DataSchemaNodeBuilder> getChildNodes() {
+    public Set<DataSchemaNodeBuilder> getChildNodeBuilders() {
         return addedChildNodes;
     }
 
@@ -121,7 +125,16 @@ public abstract class AbstractDataNodeContainerBuilder extends AbstractBuilder i
     }
 
     @Override
-    public Set<UsesNodeBuilder> getUsesNodes() {
+    public Set<TypeDefinition<?>> getTypeDefinitions() {
+        return typedefs;
+    }
+
+    public Set<UsesNode> getUsesNodes() {
+        return usesNodes;
+    }
+
+    @Override
+    public Set<UsesNodeBuilder> getUsesNodeBuilders() {
         return addedUsesNodes;
     }
 
index e2eac3fc1c7f8814883b4ff0b705abdf26fd8407..ecedd8ef489b0a9d033a34d66441aee485e7e536 100644 (file)
@@ -13,6 +13,7 @@ import org.opendaylight.yangtools.yang.common.QName;
 import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
 import org.opendaylight.yangtools.yang.model.api.GroupingDefinition;
 import org.opendaylight.yangtools.yang.model.api.SchemaPath;
+import org.opendaylight.yangtools.yang.model.api.TypeDefinition;
 
 /**
  * Interface for all yang data-node containers [augment, case, container,
@@ -39,7 +40,7 @@ public interface DataNodeContainerBuilder extends Builder {
      *
      * @return collection child nodes builders
      */
-    Set<DataSchemaNodeBuilder> getChildNodes();
+    Set<DataSchemaNodeBuilder> getChildNodeBuilders();
 
     /**
      * Get child node by name.
@@ -87,7 +88,7 @@ public interface DataNodeContainerBuilder extends Builder {
      *
      * @return collection of uses builders
      */
-    Set<UsesNodeBuilder> getUsesNodes();
+    Set<UsesNodeBuilder> getUsesNodeBuilders();
 
     /**
      * Add builder of uses statement to this node.
@@ -96,6 +97,8 @@ public interface DataNodeContainerBuilder extends Builder {
      */
     void addUsesNode(UsesNodeBuilder usesBuilder);
 
+    Set<TypeDefinition<?>> getTypeDefinitions();
+
     /**
      * Get builders of typedef statement defined in this node.
      *
index f18b784666057ccc8d7c44621f6b12afabc03759..e8ff3040eb082354710b665ea6000c1778326813 100644 (file)
@@ -138,7 +138,7 @@ public final class GroupingBuilderImpl extends AbstractDataNodeContainerBuilder
         for (GroupingBuilder node : addedGroupings) {
             GroupingBuilder copy = CopyUtils.copy(node, newParent, true);
             copy.setAddedByUses(true);
-            for (DataSchemaNodeBuilder childNode : copy.getChildNodes()) {
+            for (DataSchemaNodeBuilder childNode : copy.getChildNodeBuilders()) {
                 ParserUtils.setNodeAddedByUses(childNode);
             }
             nodes.add(copy);
index 13372b1c38d8452173fd4ad893e38aef307effee..15969e6677821ad4deb00362787b594a454e148e 100644 (file)
@@ -32,6 +32,18 @@ public class ModuleBuilder extends AbstractDataNodeContainerBuilder {
     private String prefix;
     private Date revision;
 
+    private final boolean submodule;
+    private String belongsTo;
+    private ModuleBuilder parent;
+
+    public ModuleBuilder getParent() {
+        return parent;
+    }
+
+    public void setParent(ModuleBuilder parent) {
+        this.parent = parent;
+    }
+
     private final Deque<Builder> actualPath = new LinkedList<>();
     private final Set<TypeAwareBuilder> dirtyNodes = new HashSet<>();
 
@@ -66,10 +78,15 @@ public class ModuleBuilder extends AbstractDataNodeContainerBuilder {
     private final List<UnknownSchemaNodeBuilder> allUnknownNodes = new ArrayList<UnknownSchemaNodeBuilder>();
 
     public ModuleBuilder(final String name) {
+        this(name, false);
+    }
+
+    public ModuleBuilder(final String name, final boolean submodule) {
         super(name, 0, null);
         this.name = name;
         schemaPath = new SchemaPath(Collections.<QName> emptyList(), true);
         instance = new ModuleImpl(name);
+        this.submodule = submodule;
         actualPath.push(this);
     }
 
@@ -78,6 +95,7 @@ public class ModuleBuilder extends AbstractDataNodeContainerBuilder {
         this.name = base.getName();
         schemaPath = new SchemaPath(Collections.<QName> emptyList(), true);
         instance = new ModuleImpl(base.getName());
+        submodule = false;
         actualPath.push(this);
 
         namespace = base.getNamespace();
@@ -235,14 +253,34 @@ public class ModuleBuilder extends AbstractDataNodeContainerBuilder {
         return dirtyNodes;
     }
 
+    public Set<AugmentationSchema> getAugments() {
+        return augments;
+    }
+
+    public List<AugmentationSchemaBuilder> getAugmentBuilders() {
+        return augmentBuilders;
+    }
+
     public List<AugmentationSchemaBuilder> getAllAugments() {
         return allAugments;
     }
 
-    public Set<IdentitySchemaNodeBuilder> getIdentities() {
+    public Set<IdentitySchemaNode> getIdentities() {
+        return identities;
+    }
+
+    public Set<IdentitySchemaNodeBuilder> getAddedIdentities() {
         return addedIdentities;
     }
 
+    public Set<FeatureDefinition> getFeatures() {
+        return features;
+    }
+
+    public Set<FeatureBuilder> getAddedFeatures() {
+        return addedFeatures;
+    }
+
     public List<GroupingBuilder> getAllGroupings() {
         return allGroupings;
     }
@@ -251,11 +289,19 @@ public class ModuleBuilder extends AbstractDataNodeContainerBuilder {
         return allUsesNodes;
     }
 
-    public Set<DeviationBuilder> getDeviations() {
+    public Set<Deviation> getDeviations() {
+        return deviations;
+    }
+
+    public Set<DeviationBuilder> getDeviationBuilders() {
         return deviationBuilders;
     }
 
-    public List<ExtensionBuilder> getExtensions() {
+    public List<ExtensionDefinition> getExtensions() {
+        return extensions;
+    }
+
+    public List<ExtensionBuilder> getAddedExtensions() {
         return addedExtensions;
     }
 
@@ -283,6 +329,18 @@ public class ModuleBuilder extends AbstractDataNodeContainerBuilder {
         return revision;
     }
 
+    public boolean isSubmodule() {
+        return submodule;
+    }
+
+    public String getBelongsTo() {
+        return belongsTo;
+    }
+
+    public void setBelongsTo(String belongsTo) {
+        this.belongsTo = belongsTo;
+    }
+
     public void markActualNodeDirty() {
         final TypeAwareBuilder nodeBuilder = (TypeAwareBuilder) getActualNode();
         dirtyNodes.add(nodeBuilder);
@@ -794,11 +852,19 @@ public class ModuleBuilder extends AbstractDataNodeContainerBuilder {
         return builder;
     }
 
-    public Set<RpcDefinitionBuilder> getRpcs() {
+    public Set<RpcDefinition> getRpcs() {
+        return rpcs;
+    }
+
+    public Set<RpcDefinitionBuilder> getAddedRpcs() {
         return addedRpcs;
     }
 
-    public Set<NotificationBuilder> getNotifications() {
+    public Set<NotificationDefinition> getNotifications() {
+        return notifications;
+    }
+
+    public Set<NotificationBuilder> getAddedNotifications() {
         return addedNotifications;
     }
 
@@ -1232,7 +1298,7 @@ public class ModuleBuilder extends AbstractDataNodeContainerBuilder {
         // defined only under module or submodule
         if (parent instanceof DataNodeContainerBuilder) {
             DataNodeContainerBuilder parentNode = (DataNodeContainerBuilder) parent;
-            for (DataSchemaNodeBuilder childNode : parentNode.getChildNodes()) {
+            for (DataSchemaNodeBuilder childNode : parentNode.getChildNodeBuilders()) {
                 if (childNode.getQName().getLocalName().equals(childName)) {
                     raiseYangParserException("'" + child + "'", "node", childName, lineNum, childNode.getLine());
                 }
index 54a4b62dd7f847022c1bb7c33c52de02cfe9895f..c63a52bd218fc7d8b2fcef35138682c577d02c59 100644 (file)
@@ -27,6 +27,7 @@ import org.antlr.v4.runtime.tree.ParseTree;
 import org.antlr.v4.runtime.tree.ParseTreeWalker;
 import org.opendaylight.yangtools.antlrv4.code.gen.YangLexer;
 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser;
+import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.YangContext;
 import org.opendaylight.yangtools.yang.common.QName;
 import org.opendaylight.yangtools.yang.model.api.*;
 import org.opendaylight.yangtools.yang.model.parser.api.YangModelParser;
@@ -39,15 +40,7 @@ import org.opendaylight.yangtools.yang.parser.builder.api.SchemaNodeBuilder;
 import org.opendaylight.yangtools.yang.parser.builder.api.TypeAwareBuilder;
 import org.opendaylight.yangtools.yang.parser.builder.api.TypeDefinitionBuilder;
 import org.opendaylight.yangtools.yang.parser.builder.api.UsesNodeBuilder;
-import org.opendaylight.yangtools.yang.parser.builder.impl.ChoiceBuilder;
-import org.opendaylight.yangtools.yang.parser.builder.impl.ChoiceCaseBuilder;
-import org.opendaylight.yangtools.yang.parser.builder.impl.DeviationBuilder;
-import org.opendaylight.yangtools.yang.parser.builder.impl.ExtensionBuilder;
-import org.opendaylight.yangtools.yang.parser.builder.impl.IdentitySchemaNodeBuilder;
-import org.opendaylight.yangtools.yang.parser.builder.impl.IdentityrefTypeBuilder;
-import org.opendaylight.yangtools.yang.parser.builder.impl.ModuleBuilder;
-import org.opendaylight.yangtools.yang.parser.builder.impl.UnionTypeBuilder;
-import org.opendaylight.yangtools.yang.parser.builder.impl.UnknownSchemaNodeBuilder;
+import org.opendaylight.yangtools.yang.parser.builder.impl.*;
 import org.opendaylight.yangtools.yang.parser.util.GroupingSort;
 import org.opendaylight.yangtools.yang.parser.util.GroupingUtils;
 import org.opendaylight.yangtools.yang.parser.util.ModuleDependencySort;
@@ -98,17 +91,18 @@ public final class YangParserImpl implements YangModelParser {
             }
         }
 
-        Map<InputStream, ModuleBuilder> parsedBuilders = parseModuleBuilders(new ArrayList<>(streamToFileMap.keySet()),
+        Map<InputStream, ModuleBuilder> parsedBuilders = parseBuilders(new ArrayList<>(streamToFileMap.keySet()),
                 new HashMap<ModuleBuilder, InputStream>());
         ModuleBuilder main = parsedBuilders.get(yangFileStream);
 
         List<ModuleBuilder> moduleBuilders = new ArrayList<>();
         moduleBuilders.add(main);
         filterImports(main, new ArrayList<>(parsedBuilders.values()), moduleBuilders);
+        Collection<ModuleBuilder> result = resolveSubmodules(moduleBuilders);
 
         // module builders sorted by dependencies
-        ModuleBuilder[] builders = new ModuleBuilder[moduleBuilders.size()];
-        moduleBuilders.toArray(builders);
+        ModuleBuilder[] builders = new ModuleBuilder[result.size()];
+        result.toArray(builders);
         List<ModuleBuilder> sortedBuilders = ModuleDependencySort.sort(builders);
         LinkedHashMap<String, TreeMap<Date, ModuleBuilder>> modules = orderModules(sortedBuilders);
         Collection<Module> unsorted = build(modules).values();
@@ -250,7 +244,13 @@ public final class YangParserImpl implements YangModelParser {
 
     private Map<InputStream, ModuleBuilder> parseModuleBuilders(List<InputStream> inputStreams,
             Map<ModuleBuilder, InputStream> streamToBuilderMap) {
+        Map<InputStream, ModuleBuilder> modules = parseBuilders(inputStreams, streamToBuilderMap);
+        Map<InputStream, ModuleBuilder> result = resolveSubmodules(modules);
+        return result;
+    }
 
+    private Map<InputStream, ModuleBuilder> parseBuilders(List<InputStream> inputStreams,
+            Map<ModuleBuilder, InputStream> streamToBuilderMap) {
         final ParseTreeWalker walker = new ParseTreeWalker();
         final Map<InputStream, ParseTree> trees = parseStreams(inputStreams);
         final Map<InputStream, ModuleBuilder> builders = new LinkedHashMap<>();
@@ -266,12 +266,90 @@ public final class YangParserImpl implements YangModelParser {
 
             // We expect the order of trees and streams has to be the same
             streamToBuilderMap.put(moduleBuilder, entry.getKey());
+
             builders.put(entry.getKey(), moduleBuilder);
         }
 
         return builders;
     }
 
+    private Map<InputStream, ModuleBuilder> resolveSubmodules(Map<InputStream, ModuleBuilder> builders) {
+        Map<InputStream, ModuleBuilder> modules = new HashMap<>();
+        Set<ModuleBuilder> submodules = new HashSet<>();
+        for (Map.Entry<InputStream, ModuleBuilder> entry : builders.entrySet()) {
+            ModuleBuilder moduleBuilder = entry.getValue();
+            if (moduleBuilder.isSubmodule()) {
+                submodules.add(moduleBuilder);
+            } else {
+                modules.put(entry.getKey(), moduleBuilder);
+            }
+        }
+
+        Collection<ModuleBuilder> values = modules.values();
+        for (ModuleBuilder submodule : submodules) {
+            for (ModuleBuilder module : values) {
+                if (module.getName().equals(submodule.getBelongsTo())) {
+                    addSubmoduleToModule(submodule, module);
+                }
+            }
+        }
+        return modules;
+    }
+
+    private Collection<ModuleBuilder> resolveSubmodules(Collection<ModuleBuilder> builders) {
+        Collection<ModuleBuilder> modules = new HashSet<>();
+        Set<ModuleBuilder> submodules = new HashSet<>();
+        for (ModuleBuilder moduleBuilder : builders) {
+            if (moduleBuilder.isSubmodule()) {
+                submodules.add(moduleBuilder);
+            } else {
+                modules.add(moduleBuilder);
+            }
+        }
+
+        for (ModuleBuilder submodule : submodules) {
+            for (ModuleBuilder module : modules) {
+                if (module.getName().equals(submodule.getBelongsTo())) {
+                    addSubmoduleToModule(submodule, module);
+                }
+            }
+        }
+        return modules;
+    }
+
+    private void addSubmoduleToModule(ModuleBuilder submodule, ModuleBuilder module) {
+        submodule.setParent(module);
+        module.getDirtyNodes().addAll(submodule.getDirtyNodes());
+        module.getModuleImports().addAll(submodule.getModuleImports());
+        module.getAugments().addAll(submodule.getAugments());
+        module.getAugmentBuilders().addAll(submodule.getAugmentBuilders());
+        module.getAllAugments().addAll(submodule.getAllAugments());
+        module.getChildNodeBuilders().addAll(submodule.getChildNodeBuilders());
+        module.getChildNodes().putAll(submodule.getChildNodes());
+        module.getGroupings().addAll(submodule.getGroupings());
+        module.getGroupingBuilders().addAll(submodule.getGroupingBuilders());
+        module.getTypeDefinitions().addAll(submodule.getTypeDefinitions());
+        module.getTypeDefinitionBuilders().addAll(submodule.getTypeDefinitionBuilders());
+        module.getUsesNodes().addAll(submodule.getUsesNodes());
+        module.getUsesNodeBuilders().addAll(submodule.getUsesNodeBuilders());
+        module.getAllGroupings().addAll(submodule.getAllGroupings());
+        module.getAllUsesNodes().addAll(submodule.getAllUsesNodes());
+        module.getRpcs().addAll(submodule.getRpcs());
+        module.getAddedRpcs().addAll(submodule.getAddedRpcs());
+        module.getNotifications().addAll(submodule.getNotifications());
+        module.getAddedNotifications().addAll(submodule.getAddedNotifications());
+        module.getIdentities().addAll(submodule.getIdentities());
+        module.getAddedIdentities().addAll(submodule.getAddedIdentities());
+        module.getFeatures().addAll(submodule.getFeatures());
+        module.getAddedFeatures().addAll(submodule.getAddedFeatures());
+        module.getDeviations().addAll(submodule.getDeviations());
+        module.getDeviationBuilders().addAll(submodule.getDeviationBuilders());
+        module.getExtensions().addAll(submodule.getExtensions());
+        module.getAddedExtensions().addAll(submodule.getAddedExtensions());
+        module.getUnknownNodes().addAll(submodule.getUnknownNodes());
+        module.getAllUnknownNodes().addAll(submodule.getAllUnknownNodes());
+    }
+
     private Map<String, TreeMap<Date, ModuleBuilder>> resolveModuleBuilders(final List<InputStream> yangFileStreams,
             final Map<ModuleBuilder, InputStream> streamToBuilderMap, final SchemaContext context) {
         Map<InputStream, ModuleBuilder> parsedBuilders = parseModuleBuilders(yangFileStreams, streamToBuilderMap);
@@ -317,7 +395,22 @@ public final class YangParserImpl implements YangModelParser {
     }
 
     private void filterImports(ModuleBuilder main, List<ModuleBuilder> other, List<ModuleBuilder> filtered) {
-        for (ModuleImport mi : main.getModuleImports()) {
+        Set<ModuleImport> imports = main.getModuleImports();
+
+        // if this is submodule, add parent to filtered and pick its imports
+        if (main.isSubmodule()) {
+            TreeMap<Date, ModuleBuilder> dependencies = new TreeMap<>();
+            for (ModuleBuilder mb : other) {
+                if (mb.getName().equals(main.getBelongsTo())) {
+                    dependencies.put(mb.getRevision(), mb);
+                }
+            }
+            ModuleBuilder parent = dependencies.get(dependencies.firstKey());
+            filtered.add(parent);
+            imports.addAll(parent.getModuleImports());
+        }
+
+        for (ModuleImport mi : imports) {
             for (ModuleBuilder builder : other) {
                 if (mi.getModuleName().equals(builder.getModuleName())) {
                     if (mi.getRevision() == null) {
@@ -363,6 +456,21 @@ public final class YangParserImpl implements YangModelParser {
         }
         return result;
     }
+    
+    public static YangContext parseStreamWithoutErrorListeners(final InputStream yangStream) {
+        YangContext result = null;
+        try {
+            final ANTLRInputStream input = new ANTLRInputStream(yangStream);
+            final YangLexer lexer = new YangLexer(input);
+            final CommonTokenStream tokens = new CommonTokenStream(lexer);
+            final YangParser parser = new YangParser(tokens);
+            parser.removeErrorListeners();
+            result = parser.yang();
+        } catch (IOException e) {
+            LOG.warn("Exception while reading yang file: " + yangStream, e);
+        }
+        return result;
+    }
 
     private Map<ModuleBuilder, Module> build(final Map<String, TreeMap<Date, ModuleBuilder>> modules) {
         // fix unresolved nodes
@@ -568,7 +676,7 @@ public final class YangParserImpl implements YangModelParser {
         }
         augment.setTargetNodeSchemaPath(new SchemaPath(newPath, augment.getTargetPath().isAbsolute()));
 
-        for (DataSchemaNodeBuilder childNode : augment.getChildNodes()) {
+        for (DataSchemaNodeBuilder childNode : augment.getChildNodeBuilders()) {
             correctPathForAugmentNodes(childNode, augment.getTargetNodeSchemaPath());
         }
     }
@@ -577,7 +685,7 @@ public final class YangParserImpl implements YangModelParser {
         SchemaPath newPath = ParserUtils.createSchemaPath(parentPath, node.getQName());
         node.setPath(newPath);
         if (node instanceof DataNodeContainerBuilder) {
-            for (DataSchemaNodeBuilder child : ((DataNodeContainerBuilder) node).getChildNodes()) {
+            for (DataSchemaNodeBuilder child : ((DataNodeContainerBuilder) node).getChildNodeBuilders()) {
                 correctPathForAugmentNodes(child, node.getPath());
             }
         }
@@ -606,7 +714,7 @@ public final class YangParserImpl implements YangModelParser {
                 continue;
             }
 
-            for (DataSchemaNodeBuilder childNode : augment.getChildNodes()) {
+            for (DataSchemaNodeBuilder childNode : augment.getChildNodeBuilders()) {
                 if (childNode.getConstraints().isMandatory()) {
                     throw new YangParseException(augment.getModuleName(), augment.getLine(),
                             "Error in augment parsing: cannot augment mandatory node "
@@ -749,7 +857,7 @@ public final class YangParserImpl implements YangModelParser {
      *            module being resolved
      */
     private void resolveIdentities(final Map<String, TreeMap<Date, ModuleBuilder>> modules, final ModuleBuilder module) {
-        final Set<IdentitySchemaNodeBuilder> identities = module.getIdentities();
+        final Set<IdentitySchemaNodeBuilder> identities = module.getAddedIdentities();
         for (IdentitySchemaNodeBuilder identity : identities) {
             final String baseIdentityName = identity.getBaseIdentityName();
             final int line = identity.getLine();
@@ -778,7 +886,7 @@ public final class YangParserImpl implements YangModelParser {
      */
     private void resolveIdentitiesWithContext(final Map<String, TreeMap<Date, ModuleBuilder>> modules,
             final ModuleBuilder module, final SchemaContext context) {
-        final Set<IdentitySchemaNodeBuilder> identities = module.getIdentities();
+        final Set<IdentitySchemaNodeBuilder> identities = module.getAddedIdentities();
         for (IdentitySchemaNodeBuilder identity : identities) {
             final String baseIdentityName = identity.getBaseIdentityName();
             final int line = identity.getLine();
@@ -875,7 +983,7 @@ public final class YangParserImpl implements YangModelParser {
                     resolveUsesAugment(augment, module, modules, context);
                 }
             } else {
-                parent.getChildNodes().addAll(target.instantiateChildNodes(parent));
+                parent.getChildNodeBuilders().addAll(target.instantiateChildNodes(parent));
                 parent.getTypeDefinitionBuilders().addAll(target.instantiateTypedefs(parent));
                 parent.getGroupingBuilders().addAll(target.instantiateGroupings(parent));
                 parent.getUnknownNodes().addAll(target.instantiateUnknownNodes(parent));
@@ -916,7 +1024,7 @@ public final class YangParserImpl implements YangModelParser {
 
         Set<DataSchemaNodeBuilder> childNodes = wrapChildNodes(module.getModuleName(), line,
                 gd.getChildNodes(), parentPath, ns, rev, pref);
-        parent.getChildNodes().addAll(childNodes);
+        parent.getChildNodeBuilders().addAll(childNodes);
         for (DataSchemaNodeBuilder childNode : childNodes) {
             setNodeAddedByUses(childNode);
         }
@@ -949,7 +1057,7 @@ public final class YangParserImpl implements YangModelParser {
             try {
                 ModuleBuilder dependentModule = findModuleFromBuilders(modules, module, nodeType.getPrefix(),
                         usnb.getLine());
-                for (ExtensionBuilder extension : dependentModule.getExtensions()) {
+                for (ExtensionBuilder extension : dependentModule.getAddedExtensions()) {
                     if (extension.getQName().getLocalName().equals(nodeType.getLocalName())) {
                         usnb.setNodeType(extension.getQName());
                         usnb.setExtensionBuilder(extension);
@@ -983,7 +1091,7 @@ public final class YangParserImpl implements YangModelParser {
                         }
                     }
                 } else {
-                    for (ExtensionBuilder extension : dependentModuleBuilder.getExtensions()) {
+                    for (ExtensionBuilder extension : dependentModuleBuilder.getAddedExtensions()) {
                         if (extension.getQName().getLocalName().equals(nodeType.getLocalName())) {
                             usnb.setExtensionBuilder(extension);
                             break;
@@ -1023,7 +1131,7 @@ public final class YangParserImpl implements YangModelParser {
      *            module in which resolve deviations
      */
     private void resolveDeviation(final Map<String, TreeMap<Date, ModuleBuilder>> modules, final ModuleBuilder module) {
-        for (DeviationBuilder dev : module.getDeviations()) {
+        for (DeviationBuilder dev : module.getDeviationBuilders()) {
             int line = dev.getLine();
             SchemaPath targetPath = dev.getTargetPath();
             List<QName> path = targetPath.getPath();
@@ -1070,7 +1178,7 @@ public final class YangParserImpl implements YangModelParser {
      */
     private void resolveDeviationWithContext(final Map<String, TreeMap<Date, ModuleBuilder>> modules,
             final ModuleBuilder module, final SchemaContext context) {
-        for (DeviationBuilder dev : module.getDeviations()) {
+        for (DeviationBuilder dev : module.getDeviationBuilders()) {
             int line = dev.getLine();
             SchemaPath targetPath = dev.getTargetPath();
             List<QName> path = targetPath.getPath();
index f59f6881ae99b455cc7da825b317a2f8f5d6dad9..12c230d5bc3894d649990fb7d458fd978a8e17a0 100644 (file)
@@ -110,6 +110,41 @@ public final class YangParserListenerImpl extends YangParserBaseListener {
         actualPath.pop();
     }
 
+    @Override public void enterSubmodule_stmt(YangParser.Submodule_stmtContext ctx) {
+        moduleName = stringFromNode(ctx);
+        LOGGER.debug("entering submodule " + moduleName);
+        enterLog("submodule", moduleName, 0);
+        actualPath.push(new Stack<QName>());
+
+        moduleBuilder = new ModuleBuilder(moduleName, true);
+
+        String description = null;
+        String reference = null;
+        for (int i = 0; i < ctx.getChildCount(); i++) {
+            ParseTree child = ctx.getChild(i);
+            if (child instanceof Description_stmtContext) {
+                description = stringFromNode(child);
+            } else if (child instanceof Reference_stmtContext) {
+                reference = stringFromNode(child);
+            } else {
+                if (description != null && reference != null) {
+                    break;
+                }
+            }
+        }
+        moduleBuilder.setDescription(description);
+        moduleBuilder.setReference(reference);
+    }
+
+    @Override public void exitSubmodule_stmt(YangParser.Submodule_stmtContext ctx) {
+        exitLog("submodule", "");
+        actualPath.pop();
+    }
+
+    @Override public void enterBelongs_to_stmt(YangParser.Belongs_to_stmtContext ctx) {
+        moduleBuilder.setBelongsTo(stringFromNode(ctx));
+    }
+
     @Override
     public void enterModule_header_stmts(Module_header_stmtsContext ctx) {
         enterLog("module_header", "", ctx.getStart().getLine());
diff --git a/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/impl/util/YangModelDependencyInfo.java b/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/impl/util/YangModelDependencyInfo.java
new file mode 100644 (file)
index 0000000..741d4df
--- /dev/null
@@ -0,0 +1,274 @@
+package org.opendaylight.yangtools.yang.parser.impl.util;
+
+import static org.opendaylight.yangtools.yang.parser.util.ParserListenerUtils.getArgumentString;
+import static org.opendaylight.yangtools.yang.parser.util.ParserListenerUtils.getFirstContext;
+
+import java.io.InputStream;
+import java.util.Date;
+import java.util.List;
+
+import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Belongs_to_stmtContext;
+import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Import_stmtContext;
+import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Include_stmtContext;
+import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Module_stmtContext;
+import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Revision_date_stmtContext;
+import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Revision_stmtContext;
+import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Revision_stmtsContext;
+import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Submodule_stmtContext;
+import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.YangContext;
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.model.api.ModuleImport;
+import org.opendaylight.yangtools.yang.parser.impl.YangParserImpl;
+
+import com.google.common.base.Optional;
+import com.google.common.collect.ImmutableSet;
+
+public abstract class YangModelDependencyInfo {
+
+    private final String name;
+    private final String formattedRevision;
+    private final Date revision;
+    private final ImmutableSet<ModuleImport> submoduleIncludes;
+    private final ImmutableSet<ModuleImport> moduleImports;
+    private final ImmutableSet<ModuleImport> dependencies;
+
+    public YangModelDependencyInfo(String name, String formattedRevision, ImmutableSet<ModuleImport> imports,
+            ImmutableSet<ModuleImport> includes) {
+        this.name = name;
+        this.formattedRevision = formattedRevision;
+        this.revision = QName.parseRevision(formattedRevision);
+        this.moduleImports = imports;
+        this.submoduleIncludes = includes;
+        this.dependencies = ImmutableSet.<ModuleImport> builder() //
+                .addAll(moduleImports) //
+                .addAll(submoduleIncludes) //
+                .build();
+    }
+
+    public ImmutableSet<ModuleImport> getDependencies() {
+        return dependencies;
+    }
+
+    public String getName() {
+        return name;
+    }
+
+    public String getFormattedRevision() {
+        return formattedRevision;
+    }
+
+    public Date getRevision() {
+        return revision;
+    }
+
+    @Override
+    public int hashCode() {
+        final int prime = 31;
+        int result = 1;
+        result = prime * result + ((formattedRevision == null) ? 0 : formattedRevision.hashCode());
+        result = prime * result + ((name == null) ? 0 : name.hashCode());
+        return result;
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj)
+            return true;
+        if (obj == null)
+            return false;
+        if (!(obj instanceof YangModelDependencyInfo))
+            return false;
+        YangModelDependencyInfo other = (YangModelDependencyInfo) obj;
+        if (formattedRevision == null) {
+            if (other.formattedRevision != null)
+                return false;
+        } else if (!formattedRevision.equals(other.formattedRevision))
+            return false;
+        if (name == null) {
+            if (other.name != null)
+                return false;
+        } else if (!name.equals(other.name))
+            return false;
+        return true;
+    }
+
+    public static YangModelDependencyInfo fromInputStream(InputStream yangStream) {
+        YangContext yangContext = YangParserImpl.parseStreamWithoutErrorListeners(yangStream);
+
+        Optional<Module_stmtContext> moduleCtx = getFirstContext(yangContext, Module_stmtContext.class);
+        if (moduleCtx.isPresent()) {
+            return fromModuleContext(moduleCtx.get());
+        }
+        Optional<Submodule_stmtContext> submoduleCtx = getFirstContext(yangContext, Submodule_stmtContext.class);
+        if (submoduleCtx.isPresent()) {
+            return fromSubmoduleContext(submoduleCtx.get());
+        }
+        throw new IllegalArgumentException("Supplied stream is not valid yang file.");
+    }
+
+    private static YangModelDependencyInfo fromModuleContext(Module_stmtContext module) {
+        String name = getArgumentString(module);
+        // String prefix =
+        // getArgumentString(module.module_header_stmts().prefix_stmt(0));
+        String namespace = getArgumentString(module.module_header_stmts().namespace_stmt(0));
+        String latestRevision = getLatestRevision(module.revision_stmts());
+        ImmutableSet<ModuleImport> imports = getImports(module.linkage_stmts().import_stmt());
+        ImmutableSet<ModuleImport> includes = getIncludes(module.linkage_stmts().include_stmt());
+
+        return new ModuleDependencyInfo(name, latestRevision, namespace, imports, includes);
+    }
+
+    private static ImmutableSet<ModuleImport> getImports(List<Import_stmtContext> importStatements) {
+        ImmutableSet.Builder<ModuleImport> builder = ImmutableSet.builder();
+        for (Import_stmtContext importStmt : importStatements) {
+            String moduleName = getArgumentString(importStmt);
+            Date revision = getRevision(importStmt.revision_date_stmt());
+            String prefix = getArgumentString(importStmt.prefix_stmt());
+            builder.add(new ModuleImportImpl(moduleName, revision));
+        }
+        return builder.build();
+    }
+
+    private static String getLatestRevision(Revision_stmtsContext revision_stmts) {
+        List<Revision_stmtContext> revisions = revision_stmts.getRuleContexts(Revision_stmtContext.class);
+        String latestRevision = null;
+        for (Revision_stmtContext revisionStmt : revisions) {
+            String currentRevision = getArgumentString(revisionStmt);
+            if (latestRevision == null || latestRevision.compareTo(currentRevision) == 1) {
+                latestRevision = currentRevision;
+            }
+        }
+        return latestRevision;
+    }
+
+    private static YangModelDependencyInfo fromSubmoduleContext(Submodule_stmtContext submodule) {
+        String name = getArgumentString(submodule);
+        Belongs_to_stmtContext belongsToStmt = submodule.submodule_header_stmts().belongs_to_stmt(0);
+        String belongsTo = getArgumentString(belongsToStmt);
+
+        String latestRevision = getLatestRevision(submodule.revision_stmts());
+        ImmutableSet<ModuleImport> imports = getImports(submodule.linkage_stmts().import_stmt());
+        ImmutableSet<ModuleImport> includes = getIncludes(submodule.linkage_stmts().include_stmt());
+
+        return new SubmoduleDependencyInfo(name, latestRevision, belongsTo, imports, includes);
+    }
+
+    private static ImmutableSet<ModuleImport> getIncludes(List<Include_stmtContext> importStatements) {
+        ImmutableSet.Builder<ModuleImport> builder = ImmutableSet.builder();
+        for (Include_stmtContext importStmt : importStatements) {
+            String moduleName = getArgumentString(importStmt);
+            Date revision = getRevision(importStmt.revision_date_stmt());
+            builder.add(new ModuleImportImpl(moduleName, revision));
+        }
+        return builder.build();
+    }
+
+    private static Date getRevision(Revision_date_stmtContext revision_date_stmt) {
+        if (revision_date_stmt == null) {
+            return null;
+        }
+        String formatedDate = getArgumentString(revision_date_stmt);
+        return QName.parseRevision(formatedDate);
+    }
+
+    public static final class ModuleDependencyInfo extends YangModelDependencyInfo {
+
+        private ModuleDependencyInfo(String name, String latestRevision, String namespace,
+                ImmutableSet<ModuleImport> imports, ImmutableSet<ModuleImport> includes) {
+            super(name, latestRevision, imports, includes);
+        }
+
+        @Override
+        public String toString() {
+            return "Module [name=" + getName() + ", revision=" + getRevision()
+                    + ", dependencies=" + getDependencies() + "]";
+        }
+
+    }
+
+    public static final class SubmoduleDependencyInfo extends YangModelDependencyInfo {
+
+        private final String belongsTo;
+
+        public String getParentModule() {
+            return belongsTo;
+        }
+
+        private SubmoduleDependencyInfo(String name, String latestRevision, String belongsTo,
+                ImmutableSet<ModuleImport> imports, ImmutableSet<ModuleImport> includes) {
+            super(name, latestRevision, imports, includes);
+            this.belongsTo = belongsTo;
+        }
+        
+        @Override
+        public String toString() {
+            return "Submodule [name=" + getName() + ", revision=" + getRevision()
+                    + ", dependencies=" + getDependencies() + "]";
+        }
+
+    }
+
+    private static final class ModuleImportImpl implements ModuleImport {
+
+        private Date revision;
+        private String name;
+
+        public ModuleImportImpl(String moduleName, Date revision) {
+            this.name = moduleName;
+            this.revision = revision;
+        }
+
+        @Override
+        public String getModuleName() {
+            return this.name;
+        }
+
+        @Override
+        public Date getRevision() {
+            return this.revision;
+        }
+
+        @Override
+        public String getPrefix() {
+            return null;
+        }
+
+        @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;
+            ModuleImportImpl other = (ModuleImportImpl) 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 "ModuleImportImpl [name=" + name + ", revision=" + QName.formattedRevision(revision) + "]";
+        }
+        
+        
+    }
+}
diff --git a/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/impl/util/YangSourceContext.java b/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/impl/util/YangSourceContext.java
new file mode 100644 (file)
index 0000000..fb784d1
--- /dev/null
@@ -0,0 +1,254 @@
+package org.opendaylight.yangtools.yang.parser.impl.util;
+
+import java.io.InputStream;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.model.api.Module;
+import org.opendaylight.yangtools.yang.model.api.ModuleImport;
+import org.opendaylight.yangtools.yang.model.api.SchemaContext;
+import org.opendaylight.yangtools.yang.model.util.repo.SchemaSourceProvider;
+import org.opendaylight.yangtools.yang.model.util.repo.SourceIdentifier;
+import org.opendaylight.yangtools.yang.parser.impl.YangParserImpl;
+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.ImmutableList;
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.ImmutableMultimap;
+import com.google.common.collect.ImmutableSet;
+import com.google.common.collect.ImmutableSet.Builder;
+
+public class YangSourceContext implements SchemaSourceProvider<InputStream>,AutoCloseable {
+
+    private final ImmutableSet<SourceIdentifier> validSources;
+
+
+    private final ImmutableSet<SourceIdentifier> missingSources;
+    private final ImmutableMultimap<SourceIdentifier, ModuleImport> missingDependencies;
+    private SchemaSourceProvider<InputStream> sourceProvider;
+
+    private YangSourceContext(ImmutableSet<SourceIdentifier> validSourcesSet,
+            ImmutableSet<SourceIdentifier> missingSourcesSet,
+            ImmutableMultimap<SourceIdentifier, ModuleImport> missingDependenciesMap, SchemaSourceProvider<InputStream> sourceProvicer) {
+        validSources = validSourcesSet;
+        missingSources = missingSourcesSet;
+        missingDependencies = missingDependenciesMap;
+        sourceProvider = sourceProvicer;
+    }
+
+    public ImmutableSet<SourceIdentifier> getValidSources() {
+        return validSources;
+    }
+
+    public ImmutableSet<SourceIdentifier> getMissingSources() {
+        return missingSources;
+    }
+
+    public ImmutableMultimap<SourceIdentifier, ModuleImport> getMissingDependencies() {
+        return missingDependencies;
+    }
+    
+    @Override
+    public Optional<InputStream> getSchemaSource(String moduleName, Optional<String> revision) {
+        return getSchemaSource(SourceIdentifier.create(moduleName,revision));
+    }
+    
+    @Override
+    public Optional<InputStream> getSchemaSource(SourceIdentifier sourceIdentifier) {
+        if(validSources.contains(sourceIdentifier)) {
+            return getDelegateChecked().getSchemaSource(sourceIdentifier);
+        }
+        return Optional.absent();
+    }
+    
+    private SchemaSourceProvider<InputStream> getDelegateChecked() {
+        Preconditions.checkState(sourceProvider != null,"Instance is already closed.");
+        return sourceProvider;
+    }
+
+    @Override
+    public void close() {
+        if(sourceProvider != null) {
+            sourceProvider = null;
+        }
+    }
+    
+    public static final YangSourceContext createFrom(Iterable<QName> capabilities,
+            SchemaSourceProvider<InputStream> schemaSourceProvider) {
+        YangSourceContextResolver resolver = new YangSourceFromCapabilitiesResolver(capabilities, schemaSourceProvider);
+        return resolver.resolveContext();
+    }
+    
+    public static final SchemaContext toSchemaContext(YangSourceContext context) {
+        List<InputStream> inputStreams =  getValidInputStreams(context);
+        YangParserImpl parser = new YangParserImpl();
+        Set<Module> models = parser.parseYangModelsFromStreams(inputStreams);
+        return parser.resolveSchemaContext(models);
+    }
+    
+    public static List<InputStream> getValidInputStreams(YangSourceContext context) {
+        return getValidInputStreams(context, context.sourceProvider);
+    }
+    
+    public static List<InputStream> getValidInputStreams(YangSourceContext context, SchemaSourceProvider<InputStream> provider) {
+        // TODO Auto-generated method stub
+        final HashSet<SourceIdentifier> sourcesToLoad = new HashSet<>();
+        sourcesToLoad.addAll(context.getValidSources());
+        for(SourceIdentifier source : context.getValidSources()) {
+            if(source.getRevision() != null) {
+                SourceIdentifier sourceWithoutRevision = SourceIdentifier.create(source.getName(), Optional.<String>absent());
+                sourcesToLoad.removeAll(Collections.singleton(sourceWithoutRevision));
+            }
+        }
+        
+        ImmutableList.Builder<InputStream> ret = ImmutableList.<InputStream>builder();
+        for(SourceIdentifier sourceIdentifier : sourcesToLoad) {
+            Optional<InputStream> source = provider.getSchemaSource(sourceIdentifier);
+            ret.add(source.get());
+        }
+        return ret.build();
+    }
+
+
+    public static abstract class YangSourceContextResolver {
+        
+        private static final Logger LOG = LoggerFactory.getLogger(YangSourceContextResolver.class);
+
+        private SchemaSourceProvider<InputStream> sourceProvicer;
+
+        private HashMap<SourceIdentifier, ResolutionState> alreadyProcessed = new HashMap<>();
+
+        private ImmutableSet.Builder<SourceIdentifier> missingSources = ImmutableSet.builder();
+
+        private ImmutableMultimap.Builder<SourceIdentifier, ModuleImport> missingDependencies = ImmutableMultimap
+                .builder();
+
+        private ImmutableSet.Builder<SourceIdentifier> validSources = ImmutableSet.builder();
+
+        public YangSourceContextResolver(SchemaSourceProvider<InputStream> schemaSourceProvider) {
+            sourceProvicer = schemaSourceProvider;
+        }
+
+        public abstract YangSourceContext resolveContext();
+
+        public ResolutionState resolveSource(String name, Optional<String> formattedRevision) {
+            return resolveSource(new SourceIdentifier(name, formattedRevision));
+        }
+
+        private ResolutionState resolveSource(SourceIdentifier identifier) {
+            
+            if (alreadyProcessed.containsKey(identifier)) {
+                return alreadyProcessed.get(identifier);
+            }
+            LOG.info("Resolving source: {}",identifier);
+            ResolutionState potentialState = ResolutionState.EVERYTHING_OK;
+            try {
+                Optional<InputStream> source = getSchemaSource(identifier);
+                if (source.isPresent()) {
+
+                    YangModelDependencyInfo info = YangModelDependencyInfo.fromInputStream(source.get());
+
+                    checkValidSource(identifier,info);
+
+                    for (ModuleImport dependency : info.getDependencies()) {
+                        LOG.debug("Source: {} Resolving dependency: {}",identifier,dependency);
+                        ResolutionState dependencyState = resolveDependency(dependency);
+                        if (dependencyState == ResolutionState.MISSING_SOURCE) {
+                            potentialState = ResolutionState.MISSING_DEPENDENCY;
+                            missingDependencies.put(identifier, dependency);
+                        }
+                    }
+                } else {
+                    missingSources.add(identifier);
+                    return ResolutionState.MISSING_SOURCE;
+                } 
+            } catch (Exception e) {
+                potentialState = ResolutionState.OTHER_ERROR;
+            }
+            updateResolutionState(identifier, potentialState);
+            return potentialState;
+        }
+
+        private boolean checkValidSource(SourceIdentifier identifier, YangModelDependencyInfo info) {
+            if(!identifier.getName().equals(info.getName())) {
+                LOG.warn("Incorrect model returned. Identifier name was: {}, source contained: {}", identifier.getName(),info.getName());
+                throw new IllegalStateException("Incorrect source was returned");
+            }
+            return true;
+        }
+
+        private void updateResolutionState(SourceIdentifier identifier, ResolutionState potentialState) {
+            alreadyProcessed.put(identifier, potentialState);
+            switch (potentialState) {
+            case MISSING_SOURCE:
+                missingSources.add(identifier);
+                break;
+            case EVERYTHING_OK:
+                validSources.add(identifier);
+                break;
+           default:
+                break;
+            }
+        }
+
+        private ResolutionState resolveDependency(ModuleImport dependency) {
+            String name = dependency.getModuleName();
+            Optional<String> formattedRevision = Optional
+                    .fromNullable(QName.formattedRevision(dependency.getRevision()));
+            return resolveSource(new SourceIdentifier(name, formattedRevision));
+        }
+
+        private Optional<InputStream> getSchemaSource(SourceIdentifier identifier) {
+            return sourceProvicer
+                    .getSchemaSource(identifier.getName(), Optional.fromNullable(identifier.getRevision()));
+        }
+
+        protected YangSourceContext createSourceContext() {
+            
+            ImmutableSet<SourceIdentifier> missingSourcesSet = missingSources.build();
+            ImmutableMultimap<SourceIdentifier, ModuleImport> missingDependenciesMap = missingDependencies.build();
+            ImmutableSet<SourceIdentifier> validSourcesSet = validSources.build();
+            
+            
+            return new YangSourceContext(validSourcesSet,missingSourcesSet,missingDependenciesMap,sourceProvicer);
+            
+        }
+    }
+
+    private enum ResolutionState {
+        MISSING_SOURCE, MISSING_DEPENDENCY, OTHER_ERROR, EVERYTHING_OK
+    }
+
+    public static final class YangSourceFromCapabilitiesResolver extends YangSourceContextResolver {
+
+        private Iterable<QName> capabilities;
+
+        public YangSourceFromCapabilitiesResolver(Iterable<QName> capabilities,
+                SchemaSourceProvider<InputStream> schemaSourceProvider) {
+            super(schemaSourceProvider);
+            this.capabilities = capabilities;
+        }
+
+        @Override
+        public YangSourceContext resolveContext() {
+            for (QName capability : capabilities) {
+                resolveCapability(capability);
+            }
+            return createSourceContext();
+        }
+
+        private void resolveCapability(QName capability) {
+            super.resolveSource(capability.getLocalName(), Optional.fromNullable(capability.getFormattedRevision()));
+        }
+    }
+
+
+}
index 153ac29b18850039ae98f1d868421a2e5c2ebcdf..3cee12eb103ad01ce82c15a32070dc7e9be9df86 100644 (file)
@@ -122,7 +122,7 @@ public final class CopyUtils {
         copy.setReference(old.getReference());
         copy.setStatus(old.getStatus());
         copy.setAugmenting(old.isAugmenting());
-        for (DataSchemaNodeBuilder childNode : old.getChildNodes()) {
+        for (DataSchemaNodeBuilder childNode : old.getChildNodeBuilders()) {
             copy.addChildNode(copy(childNode, copy, updateQName));
         }
         copy.getGroupings().addAll(old.getGroupings());
@@ -132,7 +132,7 @@ public final class CopyUtils {
         for (TypeDefinitionBuilder tdb : old.getTypeDefinitionBuilders()) {
             copy.addTypedef(copy(tdb, copy, updateQName));
         }
-        for (UsesNodeBuilder oldUses : old.getUsesNodes()) {
+        for (UsesNodeBuilder oldUses : old.getUsesNodeBuilders()) {
             copy.addUsesNode(copyUses(oldUses, copy));
         }
         for (UnknownSchemaNodeBuilder un : old.getUnknownNodes()) {
@@ -159,7 +159,7 @@ public final class CopyUtils {
         copy.setAugmenting(old.isAugmenting());
         copy.setAddedByUses(old.isAddedByUses());
         copy.setConfiguration(old.isConfiguration());
-        for (DataSchemaNodeBuilder childNode : old.getChildNodes()) {
+        for (DataSchemaNodeBuilder childNode : old.getChildNodeBuilders()) {
             copy.addChildNode(copy(childNode, copy, updateQName));
         }
         copy.getGroupings().addAll(old.getGroupings());
@@ -169,7 +169,7 @@ public final class CopyUtils {
         for (TypeDefinitionBuilder tdb : old.getTypeDefinitionBuilders()) {
             copy.addTypedef(copy(tdb, copy, updateQName));
         }
-        for (UsesNodeBuilder oldUses : old.getUsesNodes()) {
+        for (UsesNodeBuilder oldUses : old.getUsesNodeBuilders()) {
             copy.addUsesNode(copyUses(oldUses, copy));
         }
         for (AugmentationSchemaBuilder augment : old.getAugmentationBuilders()) {
@@ -258,7 +258,7 @@ public final class CopyUtils {
         copy.setAugmenting(old.isAugmenting());
         copy.setAddedByUses(old.isAddedByUses());
         copy.setConfiguration(old.isConfiguration());
-        for (DataSchemaNodeBuilder childNode : old.getChildNodes()) {
+        for (DataSchemaNodeBuilder childNode : old.getChildNodeBuilders()) {
             copy.addChildNode(copy(childNode, copy, updateQName));
         }
         copy.getGroupings().addAll(old.getGroupings());
@@ -268,7 +268,7 @@ public final class CopyUtils {
         for (TypeDefinitionBuilder tdb : old.getTypeDefinitionBuilders()) {
             copy.addTypedef(copy(tdb, copy, updateQName));
         }
-        for (UsesNodeBuilder oldUses : old.getUsesNodes()) {
+        for (UsesNodeBuilder oldUses : old.getUsesNodeBuilders()) {
             copy.addUsesNode(copyUses(oldUses, copy));
         }
         for (AugmentationSchemaBuilder augment : old.getAugmentationBuilders()) {
@@ -295,7 +295,7 @@ public final class CopyUtils {
         copy.setReference(old.getReference());
         copy.setStatus(old.getStatus());
         copy.setAddedByUses(old.isAddedByUses());
-        for (DataSchemaNodeBuilder childNode : old.getChildNodes()) {
+        for (DataSchemaNodeBuilder childNode : old.getChildNodeBuilders()) {
             copy.addChildNode(copy(childNode, copy, updateQName));
         }
         copy.getGroupings().addAll(old.getGroupings());
@@ -305,7 +305,7 @@ public final class CopyUtils {
         for (TypeDefinitionBuilder tdb : old.getTypeDefinitionBuilders()) {
             copy.addTypedef(copy(tdb, copy, updateQName));
         }
-        for (UsesNodeBuilder oldUses : old.getUsesNodes()) {
+        for (UsesNodeBuilder oldUses : old.getUsesNodeBuilders()) {
             copy.addUsesNode(copyUses(oldUses, copy));
         }
         for (UnknownSchemaNodeBuilder un : old.getUnknownNodes()) {
@@ -397,10 +397,10 @@ public final class CopyUtils {
         copy.setStatus(old.getStatus());
         copy.addWhenCondition(old.getWhenCondition());
         copy.setTargetNodeSchemaPath(old.getTargetNodeSchemaPath());
-        for (DataSchemaNodeBuilder childNode : old.getChildNodes()) {
+        for (DataSchemaNodeBuilder childNode : old.getChildNodeBuilders()) {
             copy.addChildNode(copy(childNode, copy, false));
         }
-        for (UsesNodeBuilder oldUses : old.getUsesNodes()) {
+        for (UsesNodeBuilder oldUses : old.getUsesNodeBuilders()) {
             copy.addUsesNode(copyUses(oldUses, copy));
         }
         for (UnknownSchemaNodeBuilder un : old.getUnknownNodes()) {
index 86a062f753ecea7f9f484db95e06dfcfd35f5a31..580c6deca1de2c132c369d6ccd38b7539dc1f36a 100644 (file)
@@ -122,7 +122,7 @@ public class GroupingSort {
      */
     public static Set<UsesNodeBuilder> getAllUsesNodes(DataNodeContainerBuilder container) {
         Set<UsesNodeBuilder> ret = new HashSet<>();
-        Set<UsesNodeBuilder> usesNodes = container.getUsesNodes();
+        Set<UsesNodeBuilder> usesNodes = container.getUsesNodeBuilders();
         ret.addAll(usesNodes);
 
         for (UsesNodeBuilder usesNode : usesNodes) {
@@ -134,7 +134,7 @@ public class GroupingSort {
         for (GroupingBuilder groupingDefinition : groupings) {
             ret.addAll(getAllUsesNodes(groupingDefinition));
         }
-        Set<DataSchemaNodeBuilder> childNodes = container.getChildNodes();
+        Set<DataSchemaNodeBuilder> childNodes = container.getChildNodeBuilders();
         for (DataSchemaNodeBuilder childNode : childNodes) {
             if (childNode instanceof DataNodeContainerBuilder) {
                 ret.addAll(getAllUsesNodes((DataNodeContainerBuilder) childNode));
index d3e44832fbaccfc62658f85c67b4f4fd2b22c6e0..2b37a2ce70f88e732465a071b72adfec89bc28e2 100644 (file)
@@ -62,6 +62,9 @@ public final class GroupingUtils {
         }
 
         ModuleBuilder dependentModule;
+        if(groupingPrefix == null) {
+            dependentModule = module;
+        }
         if (groupingPrefix.equals(module.getPrefix())) {
             dependentModule = module;
         } else {
index ff96d95d8294ed59d96218b65bb922fda2c3bada..3b3423030cef6fe2a9a2f7416285d3220f635f88 100644 (file)
@@ -7,6 +7,8 @@
  */
 package org.opendaylight.yangtools.yang.parser.util;
 
+import static com.google.common.base.Preconditions.checkState;
+
 import java.math.BigDecimal;
 import java.net.URI;
 import java.util.ArrayList;
@@ -15,8 +17,10 @@ import java.util.Date;
 import java.util.List;
 import java.util.Stack;
 
+import org.antlr.v4.runtime.ParserRuleContext;
 import org.antlr.v4.runtime.tree.ParseTree;
 import org.antlr.v4.runtime.tree.TerminalNode;
+import org.omg.CORBA.CTX_RESTRICT_SCOPE;
 import org.opendaylight.yangtools.antlrv4.code.gen.*;
 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Argument_stmtContext;
 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Base_stmtContext;
@@ -121,6 +125,8 @@ import org.opendaylight.yangtools.yang.parser.builder.impl.UnionTypeBuilder;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
+import com.google.common.base.Optional;
+
 public final class ParserListenerUtils {
     private static final Logger LOG = LoggerFactory.getLogger(ParserListenerUtils.class);
 
@@ -140,7 +146,7 @@ public final class ParserListenerUtils {
             if (treeNode.getChild(i) instanceof StringContext) {
                 final StringContext context = (StringContext) treeNode.getChild(i);
                 if (context != null) {
-                    return stringFromStringContext(context,treeNode);
+                    return stringFromStringContext(context);
                     
                 }
             }
@@ -148,14 +154,14 @@ public final class ParserListenerUtils {
         return result;
     }
 
-    private static String stringFromStringContext(StringContext context, ParseTree treeNode) {
+    public static String stringFromStringContext(StringContext context) {
         StringBuilder str = new StringBuilder();
         for (TerminalNode stringNode : context.STRING()) {
             String result = stringNode.getText();
             if(!result.contains("\"")){
                 str.append(result);
             } else if (!(result.startsWith("\"")) && result.endsWith("\"")) {
-                LOG.error("Syntax error in module {} at line {}: missing '\"'.", getParentModule(treeNode),
+                LOG.error("Syntax error in module {} at line {}: missing '\"'.", getParentModule(context),
                         context.getStart().getLine());
             } else {
                 str.append(result.replace("\"", ""));
@@ -1671,4 +1677,18 @@ public final class ParserListenerUtils {
         return refine;
     }
 
+    public static String getArgumentString(org.antlr.v4.runtime.ParserRuleContext ctx) {
+        List<StringContext> potentialValues = ctx.getRuleContexts(StringContext.class);
+        checkState(!potentialValues.isEmpty());
+        return ParserListenerUtils.stringFromStringContext(potentialValues.get(0));
+    }
+    
+    public static <T extends ParserRuleContext> Optional<T> getFirstContext(ParserRuleContext context,Class<T> contextType) {
+        List<T> potential = context.getRuleContexts(contextType);
+        if(potential.isEmpty()) {
+            return Optional.absent();
+        }
+        return Optional.of(potential.get(0));
+    }
+
 }
index 16b740b77b3023263cadc14981f8122a8dfa6418..861778590e816e05ebc655caf393afcd34f1b33e 100644 (file)
@@ -59,6 +59,7 @@ import org.opendaylight.yangtools.yang.parser.builder.api.TypeDefinitionBuilder
 import org.opendaylight.yangtools.yang.parser.builder.impl.UnknownSchemaNodeBuilder
 import org.opendaylight.yangtools.yang.model.api.UnknownSchemaNode
 import org.opendaylight.yangtools.yang.model.api.DataNodeContainer
+import com.google.common.base.Preconditions
 
 public final class ParserUtils {
 
@@ -115,7 +116,9 @@ public final class ParserUtils {
         var ModuleBuilder dependentModule = null;
         var Date dependentModuleRevision = null;
 
-        if (prefix.equals(module.getPrefix())) {
+        if(prefix == null) {
+            dependentModule = module;
+        } else if (prefix.equals(module.getPrefix())) {
             dependentModule = module;
         } else {
             val ModuleImport dependentModuleImport = getModuleImport(module, prefix);
@@ -223,7 +226,7 @@ public final class ParserUtils {
      *            augmentation target node
      */
     public static def dispatch fillAugmentTarget(AugmentationSchemaBuilder augment, DataNodeContainerBuilder target) {
-        for (DataSchemaNodeBuilder child : augment.getChildNodes()) {
+        for (DataSchemaNodeBuilder child : augment.getChildNodeBuilders()) {
             val childCopy = CopyUtils.copy(child, target, false);
             if (augment.parent instanceof UsesNodeBuilder) {
                 setNodeAddedByUses(childCopy);
@@ -249,7 +252,7 @@ public final class ParserUtils {
      *            augmentation target choice node
      */
     public static def dispatch fillAugmentTarget(AugmentationSchemaBuilder augment, ChoiceBuilder target) {
-        for (DataSchemaNodeBuilder builder : augment.getChildNodes()) {
+        for (DataSchemaNodeBuilder builder : augment.getChildNodeBuilders()) {
             val childCopy = CopyUtils.copy(builder, target, false);
             if (augment.parent instanceof UsesNodeBuilder) {
                 setNodeAddedByUses(childCopy);
@@ -257,7 +260,7 @@ public final class ParserUtils {
             setNodeAugmenting(childCopy)
             target.addCase(childCopy);
         }
-        for (UsesNodeBuilder usesNode : augment.getUsesNodes()) {
+        for (UsesNodeBuilder usesNode : augment.getUsesNodeBuilders()) {
             if (usesNode !== null) {
                 throw new YangParseException(augment.getModuleName(), augment.getLine(),
                     "Error in augment parsing: cannot augment choice with nodes from grouping");
@@ -272,7 +275,7 @@ public final class ParserUtils {
         child.setAugmenting(true);
         if (child instanceof DataNodeContainerBuilder) {
             val DataNodeContainerBuilder dataNodeChild = child as DataNodeContainerBuilder;
-            for (inner : dataNodeChild.getChildNodes()) {
+            for (inner : dataNodeChild.getChildNodeBuilders()) {
                 setNodeAugmenting(inner);
             }
         } else if (child instanceof ChoiceBuilder) {
@@ -290,7 +293,7 @@ public final class ParserUtils {
         child.setAddedByUses(true);
         if (child instanceof DataNodeContainerBuilder) {
             val DataNodeContainerBuilder dataNodeChild = child as DataNodeContainerBuilder;
-            for (inner : dataNodeChild.getChildNodes()) {
+            for (inner : dataNodeChild.getChildNodeBuilders()) {
                 setNodeAddedByUses(inner);
             }
         } else if (child instanceof ChoiceBuilder) {
@@ -338,7 +341,7 @@ public final class ParserUtils {
 
         var SchemaNodeBuilder node = module.getDataChildByName(first.localName)
         if (node == null) {
-            val notifications = module.notifications
+            val notifications = module.getAddedNotifications
             for (notification : notifications) {
                 if (notification.QName.localName.equals(first.localName)) {
                     node = notification
@@ -346,7 +349,7 @@ public final class ParserUtils {
             }
         }
         if (node == null) {
-            val rpcs = module.rpcs
+            val rpcs = module.getAddedRpcs
             for (rpc : rpcs) {
                 if (rpc.QName.localName.equals(first.localName)) {
                     node = rpc
@@ -408,10 +411,10 @@ public final class ParserUtils {
             val name = splittedBase.get(1);
             val dependentModule = findModuleFromBuilders(modules, module, prefix, line);
             if (dependentModule !== null) {
-                result = findIdentity(dependentModule.identities, name);
+                result = findIdentity(dependentModule.getAddedIdentities, name);
             }
         } else {
-            result = findIdentity(module.identities, baseString);
+            result = findIdentity(module.getAddedIdentities, baseString);
         }
         return result;
     }
@@ -467,7 +470,12 @@ public final class ParserUtils {
         while (!(parent instanceof ModuleBuilder)) {
             parent = parent.getParent();
         }
-        return parent as ModuleBuilder;
+        Preconditions.checkState(parent instanceof ModuleBuilder)
+        var parentModule = parent as ModuleBuilder
+        if(parentModule.submodule) {
+           parentModule = parentModule.parent; 
+        }
+        return parentModule;
     }
 
     public static def Set<DataSchemaNodeBuilder> wrapChildNodes(String moduleName, int line, Set<DataSchemaNode> nodes,
index bb2fea413b75cdd096ec4b56d5830fa7cf713e79..e29cc9a07eab3b6905789182fb575a42790da4f0 100644 (file)
@@ -44,6 +44,8 @@ import org.opendaylight.yangtools.yang.model.util.Uint32;
 import org.opendaylight.yangtools.yang.model.util.UnionType;
 
 public class YangParserTest {
+    public static final String FS = File.separator;
+
     private final URI fooNS = URI.create("urn:opendaylight.foo");
     private final URI barNS = URI.create("urn:opendaylight.bar");
     private final URI bazNS = URI.create("urn:opendaylight.baz");
@@ -910,4 +912,28 @@ public class YangParserTest {
         }
     }
 
+    @Test
+    public void testSubmodules() {
+        String yangFilePath = getClass().getResource(FS + "submodule-test" + FS + "subfoo.yang").getPath();
+        String directoryPath = getClass().getResource(FS + "model").getPath();
+
+        File directory = new File(directoryPath);
+        File yangFile = new File(yangFilePath);
+
+        Set<Module> modules = new YangParserImpl().parseYangModels(yangFile, directory);
+        assertEquals(3, modules.size());
+
+        Module foo = TestUtils.findModule(modules, "foo");
+
+        DataSchemaNode id = foo.getDataChildByName("id");
+        assertNotNull(id);
+        DataSchemaNode subExt = foo.getDataChildByName("sub-ext");
+        assertNotNull(subExt);
+        DataSchemaNode subTransfer = foo.getDataChildByName("sub-transfer");
+        assertNotNull(subTransfer);
+
+        assertEquals(2, foo.getExtensionSchemaNodes().size());
+        assertEquals(2, foo.getAugmentations().size());
+    }
+
 }
diff --git a/yang/yang-parser-impl/src/test/resources/submodule-test/subfoo.yang b/yang/yang-parser-impl/src/test/resources/submodule-test/subfoo.yang
new file mode 100644 (file)
index 0000000..1fe00c0
--- /dev/null
@@ -0,0 +1,67 @@
+submodule subfoo {
+    yang-version 1;
+
+    belongs-to foo {
+        prefix f;
+    } 
+
+    import bar {
+        prefix "br";
+        revision-date 2013-07-03;
+    }
+
+    import baz {
+        prefix "bz";
+        revision-date 2013-02-27;
+    }
+
+    revision "2013-02-27" {
+    }
+
+    leaf id {
+        type br:int32-ext2 {
+            range "12..max";
+        }
+    }
+
+    container sub-ext {
+        bz:c-define "MY_INTERFACES";
+    }
+
+
+    container sub-transfer {
+        choice how {
+            default interval;
+            container input {
+            }
+            list output {
+                leaf id {
+                    type string;
+                }
+            }
+            case manual {
+                leaf manual {
+                    type empty;
+                }
+            }
+        }
+    }
+
+    anyxml sub-datas {
+        status obsolete;
+    }
+
+    augment "/br:interfaces/br:ifEntry/bz:augment-holder" {
+        when "if:ifType='ds0'";
+        leaf subleaf {
+            type string;
+        }
+    }
+
+    extension sub-mountpoint {
+        argument "name" {
+            yin-element "true";
+        }
+    }
+
+}