Merge "BUG-1589 Exclude xml* prefixes from RandomPrefix"
authorRobert Varga <rovarga@cisco.com>
Mon, 25 Aug 2014 19:17:01 +0000 (19:17 +0000)
committerGerrit Code Review <gerrit@opendaylight.org>
Mon, 25 Aug 2014 19:17:01 +0000 (19:17 +0000)
29 files changed:
code-generator/binding-generator-impl/src/main/java/org/opendaylight/yangtools/sal/binding/generator/impl/BindingGeneratorImpl.java
code-generator/binding-generator-impl/src/main/java/org/opendaylight/yangtools/sal/binding/generator/impl/RuntimeGeneratedMappingServiceImpl.java
code-generator/binding-generator-impl/src/main/java/org/opendaylight/yangtools/sal/binding/generator/impl/YangTemplate.xtend
code-generator/binding-generator-impl/src/main/java/org/opendaylight/yangtools/sal/binding/generator/util/BindingRuntimeContext.java
code-generator/binding-java-api-generator/src/main/java/org/opendaylight/yangtools/sal/java/api/generator/YangModuleInfoTemplate.xtend
code-generator/maven-sal-api-gen-plugin/src/main/java/org/opendaylight/yangtools/maven/sal/api/gen/plugin/CodeGeneratorImpl.java
code-generator/maven-sal-api-gen-plugin/src/test/java/org/opendaylight/yangtools/yang/unified/doc/generator/maven/YangModuleInfoCompilationTest.java [new file with mode: 0644]
code-generator/maven-sal-api-gen-plugin/src/test/resources/yang-module-info/import-module.yang [new file with mode: 0644]
code-generator/maven-sal-api-gen-plugin/src/test/resources/yang-module-info/main-module.yang [new file with mode: 0644]
code-generator/maven-sal-api-gen-plugin/src/test/resources/yang-module-info/submodule1.yang [new file with mode: 0644]
code-generator/maven-sal-api-gen-plugin/src/test/resources/yang-module-info/submodule2.yang [new file with mode: 0644]
code-generator/maven-sal-api-gen-plugin/src/test/resources/yang-module-info/submodule3.yang [new file with mode: 0644]
yang/yang-data-codec-gson/src/test/java/org/opendaylight/yangtools/yang/data/codec/gson/StreamToNormalizedNodeTest.java
yang/yang-model-api/src/main/java/org/opendaylight/yangtools/yang/model/api/Module.java
yang/yang-parser-impl/src/main/antlr/YangParser.g4
yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/builder/api/AugmentationSchemaBuilder.java
yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/builder/api/ConstraintsBuilder.java
yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/builder/api/RefineBuilder.java
yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/builder/api/TypeDefinitionBuilder.java
yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/builder/api/UnknownSchemaNodeBuilder.java
yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/builder/impl/BuilderUtils.java
yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/builder/impl/ModuleBuilder.java
yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/builder/impl/ModuleImpl.java
yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/impl/ParserListenerUtils.java
yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/impl/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/URLSchemaContextResolver.java
yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/repo/URLSchemaContextResolver.java
yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/util/ModuleDependencySort.java

index 9c66f8d6a6bcb91f04d25ffb95fe59d5dc17428a..befe3e88e02c494e48b287d8089cf2f05eb8fd08 100644 (file)
@@ -30,6 +30,7 @@ import static org.opendaylight.yangtools.yang.model.util.SchemaContextUtil.findP
 import com.google.common.base.Splitter;
 import com.google.common.collect.Iterables;
 import com.google.common.collect.Sets;
+
 import java.util.ArrayList;
 import java.util.Collection;
 import java.util.Collections;
@@ -38,6 +39,7 @@ import java.util.Iterator;
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
+
 import org.opendaylight.yangtools.binding.generator.util.BindingGeneratorUtil;
 import org.opendaylight.yangtools.binding.generator.util.BindingTypes;
 import org.opendaylight.yangtools.binding.generator.util.ReferencedTypeImpl;
@@ -105,9 +107,28 @@ import org.slf4j.LoggerFactory;
 
 public class BindingGeneratorImpl implements BindingGenerator {
     private static final Logger LOG = LoggerFactory.getLogger(BindingGeneratorImpl.class);
+    private static final Splitter COLON_SPLITTER = Splitter.on(':');
+    private static final Splitter BSDOT_SPLITTER = Splitter.on("\\.");
+    private static final char NEW_LINE = '\n';
+
+    /**
+     * Constant with the concrete name of identifier.
+     */
+    private static final String AUGMENT_IDENTIFIER_NAME = "augment-identifier";
+
+    /**
+     * Constant with the concrete name of namespace.
+     */
+    private static final String YANG_EXT_NAMESPACE = "urn:opendaylight:yang:extension:yang-ext";
 
     private final Map<Module, ModuleContext> genCtx = new HashMap<>();
 
+    /**
+     * When set to true, generated classes will include javadoc comments which
+     * are useful for users.
+     */
+    private final boolean verboseClassComments;
+
     /**
      * Outer key represents the package name. Outer value represents map of all
      * builders in the same package. Inner key represents the schema node name
@@ -128,18 +149,23 @@ public class BindingGeneratorImpl implements BindingGenerator {
     private SchemaContext schemaContext;
 
     /**
-     * Constant with the concrete name of namespace.
+     * Create a new binding generator with verboe comments.
+     *
+     * @deprecated Use {@link #BindingGeneratorImpl(boolean)} instead.
      */
-    private final static String YANG_EXT_NAMESPACE = "urn:opendaylight:yang:extension:yang-ext";
+    @Deprecated
+    public BindingGeneratorImpl() {
+        this(true);
+    }
 
     /**
-     * Constant with the concrete name of identifier.
+     * Create a new binding generator.
+     *
+     * @param verboseClassComments generate verbose comments
      */
-    private final static String AUGMENT_IDENTIFIER_NAME = "augment-identifier";
-
-    private final char NEW_LINE = '\n';
-
-    private final char TAB = '\t';
+    public BindingGeneratorImpl(final boolean verboseClassComments) {
+        this.verboseClassComments = verboseClassComments;
+    }
 
     /**
      * Resolves generated types from <code>context</code> schema nodes of all
@@ -617,7 +643,6 @@ public class BindingGeneratorImpl implements BindingGenerator {
         newType.setDescription(createDescription(identity, newType.getFullyQualifiedName()));
         newType.setReference(identity.getReference());
         newType.setModuleName(module.getName());
-        SchemaPath path = identity.getPath();
         newType.setSchemaPath(identity.getPath().getPathFromRoot());
 
         final QName qname = identity.getQName();
@@ -1368,7 +1393,7 @@ public class BindingGeneratorImpl implements BindingGenerator {
                 final String nodeParam = node.getNodeParameter();
                 IdentitySchemaNode identity = null;
                 String basePackageName = null;
-                final Iterable<String> splittedElement = Splitter.on(':').split(nodeParam);
+                final Iterable<String> splittedElement = COLON_SPLITTER.split(nodeParam);
                 final Iterator<String> iterator = splittedElement.iterator();
                 final int length = Iterables.size(splittedElement);
                 if (length == 1) {
@@ -1965,15 +1990,13 @@ public class BindingGeneratorImpl implements BindingGenerator {
 
     private String createDescription(final Set<? extends SchemaNode> schemaNodes, final String moduleName, final String moduleSourcePath) {
         final StringBuilder sb = new StringBuilder();
-        final String yangSnipet = YangTemplate.generateYangSnipet(schemaNodes);
 
         if (!isNullOrEmpty(schemaNodes)) {
             final SchemaNode node = schemaNodes.iterator().next();
 
             if (node instanceof RpcDefinition) {
                 sb.append("Interface for implementing the following YANG RPCs defined in module <b>" + moduleName + "</b>");
-            }
-            else if (node instanceof NotificationDefinition) {
+            } else if (node instanceof NotificationDefinition) {
                 sb.append("Interface for receiving the following YANG notifications defined in module <b>" + moduleName + "</b>");
             }
         }
@@ -1982,72 +2005,77 @@ public class BindingGeneratorImpl implements BindingGenerator {
         sb.append(moduleSourcePath);
         sb.append("</i>):");
         sb.append(NEW_LINE);
-        sb.append("<pre>");
-        sb.append(NEW_LINE);
-        sb.append(yangSnipet);
-        sb.append("</pre>");
-        sb.append(NEW_LINE);
+
+        if (verboseClassComments) {
+            sb.append("<pre>");
+            sb.append(NEW_LINE);
+            sb.append(YangTemplate.generateYangSnipet(schemaNodes));
+            sb.append("</pre>");
+            sb.append(NEW_LINE);
+        }
 
         return sb.toString();
     }
 
     private String createDescription(final SchemaNode schemaNode, final String fullyQualifiedName) {
         final StringBuilder sb = new StringBuilder();
-        final Module module = findParentModule(schemaContext, schemaNode);
-        final String yangSnipet = YangTemplate.generateYangSnipet(schemaNode);
         final String formattedDescription = YangTemplate.formatToParagraph(schemaNode.getDescription(), 0);
-        final StringBuilder linkToBuilderClass = new StringBuilder();
-        final StringBuilder linkToKeyClass = new StringBuilder();
-        final Splitter splitter = Splitter.on("\\.");
-        final String[] namespace = Iterables.toArray(splitter.split(fullyQualifiedName), String.class);
-        String className = namespace[namespace.length - 1];
-
-        if (hasBuilderClass(schemaNode)) {
-            linkToBuilderClass.append(className);
-            linkToBuilderClass.append("Builder");
-
-            if (schemaNode instanceof ListSchemaNode) {
-                linkToKeyClass.append(className);
-                linkToKeyClass.append("Key");
-            }
-        }
 
         if (!isNullOrEmpty(formattedDescription)) {
             sb.append(formattedDescription);
             sb.append(NEW_LINE);
         }
-        sb.append("<p>");
-        sb.append("This class represents the following YANG schema fragment defined in module <b>");
-        sb.append(module.getName());
-        sb.append("</b>");
-        sb.append(NEW_LINE);
-        sb.append("<br />(Source path: <i>");
-        sb.append(module.getModuleSourcePath());
-        sb.append("</i>):");
-        sb.append(NEW_LINE);
-        sb.append("<pre>");
-        sb.append(NEW_LINE);
-        sb.append(yangSnipet);
-        sb.append("</pre>");
-        sb.append(NEW_LINE);
-        sb.append("The schema path to identify an instance is");
-        sb.append(NEW_LINE);
-        sb.append("<i>");
-        sb.append(YangTemplate.formatSchemaPath(module.getName(), schemaNode.getPath().getPathFromRoot()));
-        sb.append("</i>");
-        sb.append(NEW_LINE);
 
-        if (hasBuilderClass(schemaNode)) {
+        if (verboseClassComments) {
+            final Module module = findParentModule(schemaContext, schemaNode);
+            final StringBuilder linkToBuilderClass = new StringBuilder();
+            final StringBuilder linkToKeyClass = new StringBuilder();
+            final String[] namespace = Iterables.toArray(BSDOT_SPLITTER.split(fullyQualifiedName), String.class);
+            String className = namespace[namespace.length - 1];
+
+            if (hasBuilderClass(schemaNode)) {
+                linkToBuilderClass.append(className);
+                linkToBuilderClass.append("Builder");
+
+                if (schemaNode instanceof ListSchemaNode) {
+                    linkToKeyClass.append(className);
+                    linkToKeyClass.append("Key");
+                }
+            }
+
+            sb.append("<p>");
+            sb.append("This class represents the following YANG schema fragment defined in module <b>");
+            sb.append(module.getName());
+            sb.append("</b>");
+            sb.append(NEW_LINE);
+            sb.append("<br />(Source path: <i>");
+            sb.append(module.getModuleSourcePath());
+            sb.append("</i>):");
             sb.append(NEW_LINE);
-            sb.append("<p>To create instances of this class use " + "{@link " + linkToBuilderClass + "}.");
+            sb.append("<pre>");
             sb.append(NEW_LINE);
-            sb.append("@see ");
-            sb.append(linkToBuilderClass);
-            if (schemaNode instanceof ListSchemaNode) {
+            sb.append(YangTemplate.generateYangSnipet(schemaNode));
+            sb.append("</pre>");
+            sb.append(NEW_LINE);
+            sb.append("The schema path to identify an instance is");
+            sb.append(NEW_LINE);
+            sb.append("<i>");
+            sb.append(YangTemplate.formatSchemaPath(module.getName(), schemaNode.getPath().getPathFromRoot()));
+            sb.append("</i>");
+            sb.append(NEW_LINE);
+
+            if (hasBuilderClass(schemaNode)) {
+                sb.append(NEW_LINE);
+                sb.append("<p>To create instances of this class use " + "{@link " + linkToBuilderClass + "}.");
+                sb.append(NEW_LINE);
                 sb.append("@see ");
-                sb.append(linkToKeyClass);
+                sb.append(linkToBuilderClass);
+                if (schemaNode instanceof ListSchemaNode) {
+                    sb.append("@see ");
+                    sb.append(linkToKeyClass);
+                }
+                sb.append(NEW_LINE);
             }
-            sb.append(NEW_LINE);
         }
 
         return sb.toString();
@@ -2067,26 +2095,28 @@ public class BindingGeneratorImpl implements BindingGenerator {
 
     private String createDescription(final Module module) {
         final StringBuilder sb = new StringBuilder();
-        final String yangSnipet = YangTemplate.generateYangSnipet(module);
         final String formattedDescription = YangTemplate.formatToParagraph(module.getDescription(), 0);
 
         if (!isNullOrEmpty(formattedDescription)) {
             sb.append(formattedDescription);
             sb.append(NEW_LINE);
         }
-        sb.append("<p>");
-        sb.append("This class represents the following YANG schema fragment defined in module <b>");
-        sb.append(module.getName());
-        sb.append("</b>");
-        sb.append(NEW_LINE);
-        sb.append("<br />Source path: <i>");
-        sb.append(module.getModuleSourcePath());
-        sb.append("</i>):");
-        sb.append(NEW_LINE);
-        sb.append("<pre>");
-        sb.append(NEW_LINE);
-        sb.append(yangSnipet);
-        sb.append("</pre>");
+
+        if (verboseClassComments) {
+            sb.append("<p>");
+            sb.append("This class represents the following YANG schema fragment defined in module <b>");
+            sb.append(module.getName());
+            sb.append("</b>");
+            sb.append(NEW_LINE);
+            sb.append("<br />Source path: <i>");
+            sb.append(module.getModuleSourcePath());
+            sb.append("</i>):");
+            sb.append(NEW_LINE);
+            sb.append("<pre>");
+            sb.append(NEW_LINE);
+            sb.append(YangTemplate.generateYangSnipet(module));
+            sb.append("</pre>");
+        }
 
         return sb.toString();
     }
index da757095d6a5d984bbaa2465f772cf86aa5adf33..29a532228dd54bfc6421c34035af5f91f923cafb 100644 (file)
@@ -13,6 +13,7 @@ import com.google.common.collect.HashMultimap;
 import com.google.common.collect.Multimap;
 import com.google.common.util.concurrent.ListenableFuture;
 import com.google.common.util.concurrent.SettableFuture;
+
 import java.net.URI;
 import java.util.AbstractMap.SimpleEntry;
 import java.util.ArrayList;
@@ -27,8 +28,11 @@ import java.util.Set;
 import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.ConcurrentMap;
 import java.util.concurrent.ExecutionException;
+
 import javassist.ClassPool;
+
 import javax.annotation.concurrent.GuardedBy;
+
 import org.opendaylight.yangtools.binding.generator.util.BindingGeneratorUtil;
 import org.opendaylight.yangtools.binding.generator.util.ReferencedTypeImpl;
 import org.opendaylight.yangtools.binding.generator.util.Types;
@@ -134,7 +138,7 @@ SchemaLock, AutoCloseable, SchemaContextHolder, TypeResolver {
 
     @GuardedBy("this")
     private void recreateBindingContext(final SchemaContext schemaContext) {
-        BindingGeneratorImpl newBinding = new BindingGeneratorImpl();
+        BindingGeneratorImpl newBinding = new BindingGeneratorImpl(false);
         newBinding.generateTypes(schemaContext);
 
         for (Map.Entry<Module, ModuleContext> entry : newBinding.getModuleContexts().entrySet()) {
index 98d7ef1d9e120bc4540bf7fa7e8d910ac58cf125..d0ad08c36b950c07a0945204b5bd37cb71f60406 100644 (file)
@@ -7,7 +7,6 @@
  */
 package org.opendaylight.yangtools.sal.binding.generator.impl
 
-import java.text.SimpleDateFormat
 import java.util.Collection
 import java.util.Date
 import java.util.List
@@ -40,11 +39,16 @@ import org.opendaylight.yangtools.yang.model.api.UnknownSchemaNode
 import org.opendaylight.yangtools.yang.model.api.UsesNode
 import org.opendaylight.yangtools.yang.model.api.type.EnumTypeDefinition
 import org.opendaylight.yangtools.yang.model.api.type.EnumTypeDefinition.EnumPair
+import org.opendaylight.yangtools.yang.common.SimpleDateFormatUtil
+import com.google.common.base.CharMatcher
 
 class YangTemplate {
 
+    // FIXME: this is not thread-safe and seems to be unused!
     private static var Module module = null
 
+    private static val CharMatcher NEWLINE_OR_TAB = CharMatcher.anyOf("\n\t")
+
     def static String generateYangSnipet(SchemaNode schemaNode) {
         if (schemaNode == null)
             return ''
@@ -121,16 +125,11 @@ class YangTemplate {
         '''
     }
 
-    def static formatDate(Date moduleRevision) {
-        val SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-mm-dd")
-        return dateFormat.format(moduleRevision)
-    }
-
     def static writeRevision(Date moduleRevision, String moduleDescription) {
         val revisionIndent = 12
 
         '''
-            revision Â«formatDate(moduleRevision)» {
+            revision Â«SimpleDateFormatUtil.getRevisionFormat.format(moduleRevision)» {
                 description "«formatToParagraph(moduleDescription, revisionIndent)»";
             }
         '''
@@ -736,8 +735,7 @@ class YangTemplate {
         val lineIndent = computeNextLineIndent(nextLineIndent);
 
         formattedText = formattedText.replace("*/", "&#42;&#47;");
-        formattedText = formattedText.replace("\n", "");
-        formattedText = formattedText.replace("\t", "");
+        formattedText = NEWLINE_OR_TAB.removeFrom(formattedText);
         formattedText = formattedText.replaceAll(" +", " ");
 
         val StringTokenizer tokenizer = new StringTokenizer(formattedText, " ", true);
@@ -785,8 +783,7 @@ class YangTemplate {
             val ns = pathElement.namespace
             val localName = pathElement.localName
 
-            sb.append("\\")
-            sb.append('(')
+            sb.append("\\(")
             sb.append(ns)
             sb.append(')')
             sb.append(localName)
index 1b40b8895c57d82eadd8fe32f843e5eab5a8bbda..a69e30ea1f437067035f5ffc459a637ad3c1e958 100644 (file)
@@ -77,7 +77,7 @@ public class BindingRuntimeContext implements Immutable {
         this.strategy = strategy;
         this.schemaContext = schema;
 
-        BindingGeneratorImpl generator = new BindingGeneratorImpl();
+        BindingGeneratorImpl generator = new BindingGeneratorImpl(false);
         generator.generateTypes(schema);
         Map<Module, ModuleContext> modules = generator.getModuleContexts();
 
index 4feee7dbc0766bf47c25a0aed3e5e5a227a15515..08f19bdd70d45d42a1f30168437ec47fed887cf3 100644 (file)
@@ -33,6 +33,7 @@ import com.google.common.collect.ImmutableSet
 import static org.opendaylight.yangtools.yang.binding.BindingMapping.*
 import org.opendaylight.yangtools.yang.binding.YangModelBindingProvider
 import com.google.common.base.Preconditions
+import org.opendaylight.yangtools.yang.binding.BindingMapping
 
 class YangModuleInfoTemplate {
 
@@ -72,7 +73,7 @@ class YangModuleInfoTemplate {
                     return INSTANCE;
                 }
 
-                Â«module.classBody»
+                Â«classBody(module, MODULE_INFO_CLASS_NAME)»
             }
         '''
         return '''
@@ -96,10 +97,12 @@ class YangModuleInfoTemplate {
 
     }
 
-    private def CharSequence classBody(Module m) '''
-        private Â«MODULE_INFO_CLASS_NAME»() {
-            Â«IF m.imports.size != 0»
+    private def CharSequence classBody(Module m, String className) '''
+        private Â«className»() {
+            Â«IF !m.imports.empty || !m.submodules.empty»
                 Â«Set.importedName»<«YangModuleInfo.importedName»> set = new Â«HashSet.importedName»<>();
+            Â«ENDIF»
+            Â«IF !m.imports.empty»
                 Â«FOR imp : m.imports»
                     Â«val name = imp.moduleName»
                     Â«val rev = imp.revision»
@@ -116,10 +119,18 @@ class YangModuleInfoTemplate {
                         set.add(«BindingGeneratorUtil.moduleNamespaceToPackageName(ctx.findModuleByName(name, rev))».«MODULE_INFO_CLASS_NAME».getInstance());
                     Â«ENDIF»
                 Â«ENDFOR»
-                importedModules = Â«ImmutableSet.importedName».copyOf(set);
-            Â«ELSE»
+            Â«ENDIF»
+            Â«IF !m.submodules.empty»
+                Â«FOR submodule : m.submodules»
+                    set.add(«BindingMapping.getClassName(submodule.name)»Info.getInstance());
+                Â«ENDFOR»
+            Â«ENDIF»
+            Â«IF m.imports.empty && m.submodules.empty»
                 importedModules = Â«Collections.importedName».emptySet();
+            Â«ELSE»
+                importedModules = Â«ImmutableSet.importedName».copyOf(set);
             Â«ENDIF»
+
             Â«InputStream.importedName» stream = Â«MODULE_INFO_CLASS_NAME».class.getResourceAsStream(resourcePath);
             if (stream == null) {
                 throw new IllegalStateException("Resource '" + resourcePath + "' is missing");
@@ -172,6 +183,9 @@ class YangModuleInfoTemplate {
             sb.append("]");
             return sb.toString();
         }
+
+        Â«generateSubInfo(m)»
+
     '''
 
     def getSourcePath() {
@@ -286,4 +300,27 @@ class YangModuleInfoTemplate {
         return builder.toString();
     }
 
+    private def generateSubInfo(Module module) '''
+        Â«FOR submodule : module.submodules»
+            private static final class Â«BindingMapping.getClassName(submodule.name)»Info implements Â«YangModuleInfo.importedName» {
+
+                private static final Â«YangModuleInfo.importedName» INSTANCE = new Â«BindingMapping.getClassName(submodule.name)»Info();
+
+                private final Â«String.importedName» name = "«submodule.name»";
+                private final Â«String.importedName» namespace = "«submodule.namespace.toString»";
+                Â«val DateFormat df = new SimpleDateFormat("yyyy-MM-dd")»
+                private final Â«String.importedName» revision = "«df.format(submodule.revision)»";
+                private final Â«String.importedName» resourcePath = "/«submodule.moduleSourcePath.replace(java.io.File.separatorChar, '/')»";
+
+                private final Â«Set.importedName»<YangModuleInfo> importedModules;
+
+                public static Â«YangModuleInfo.importedName» getInstance() {
+                    return INSTANCE;
+                }
+
+                Â«classBody(submodule, BindingMapping.getClassName(submodule.name + "Info"))»
+            }
+        Â«ENDFOR»
+    '''
+
 }
index a2b60e89d3454151f4388e8a2c3d73f9893d22f6..99f426dcc68c888492f3f730cbab95e8e7e9469d 100644 (file)
@@ -11,6 +11,18 @@ import com.google.common.base.Joiner;
 import com.google.common.base.Preconditions;
 import com.google.common.collect.ImmutableSet;
 import com.google.common.collect.ImmutableSet.Builder;
+
+import java.io.BufferedWriter;
+import java.io.File;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.io.OutputStreamWriter;
+import java.io.Writer;
+import java.util.Collection;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
 import org.apache.maven.plugin.logging.Log;
 import org.apache.maven.project.MavenProject;
 import org.opendaylight.yangtools.binding.generator.util.BindingGeneratorUtil;
@@ -29,17 +41,6 @@ import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.sonatype.plexus.build.incremental.BuildContext;
 
-import java.io.BufferedWriter;
-import java.io.File;
-import java.io.IOException;
-import java.io.OutputStream;
-import java.io.OutputStreamWriter;
-import java.io.Writer;
-import java.util.Collection;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-
 public final class CodeGeneratorImpl implements CodeGenerator, BuildContextAware {
     private static final String FS = File.separator;
     private BuildContext buildContext;
@@ -57,7 +58,7 @@ public final class CodeGeneratorImpl implements CodeGenerator, BuildContextAware
 
         outputBaseDir = outputDir == null ? getDefaultOutputBaseDir() : outputDir;
 
-        final BindingGenerator bindingGenerator = new BindingGeneratorImpl();
+        final BindingGenerator bindingGenerator = new BindingGeneratorImpl(true);
         final List<Type> types = bindingGenerator.generateTypes(context, yangModules);
         final GeneratorJavaFile generator = new GeneratorJavaFile(buildContext, types);
 
@@ -78,8 +79,8 @@ public final class CodeGeneratorImpl implements CodeGenerator, BuildContextAware
         return result;
     }
 
-    private Collection<? extends File> generateModuleInfos(File outputBaseDir, Set<Module> yangModules,
-                                                           SchemaContext context) {
+    private Collection<? extends File> generateModuleInfos(final File outputBaseDir, final Set<Module> yangModules,
+                                                           final SchemaContext context) {
         Builder<File> result = ImmutableSet.builder();
         Builder<String> bindingProviders = ImmutableSet.builder();
         for (Module module : yangModules) {
@@ -96,8 +97,8 @@ public final class CodeGeneratorImpl implements CodeGenerator, BuildContextAware
         return result.build();
     }
 
-    private File writeMetaInfServices(File outputBaseDir, Class<YangModelBindingProvider> serviceClass,
-            ImmutableSet<String> services) {
+    private File writeMetaInfServices(final File outputBaseDir, final Class<YangModelBindingProvider> serviceClass,
+            final ImmutableSet<String> services) {
         File metainfServicesFolder = new File(outputBaseDir, "META-INF" + File.separator + "services");
         metainfServicesFolder.mkdirs();
         File serviceFile = new File(metainfServicesFolder, serviceClass.getName());
@@ -118,38 +119,38 @@ public final class CodeGeneratorImpl implements CodeGenerator, BuildContextAware
         return outputBaseDir;
     }
 
-    private static void setOutputBaseDirAsSourceFolder(File outputBaseDir, MavenProject mavenProject) {
+    private static void setOutputBaseDirAsSourceFolder(final File outputBaseDir, final MavenProject mavenProject) {
         Preconditions.checkNotNull(mavenProject, "Maven project needs to be set in this phase");
         mavenProject.addCompileSourceRoot(outputBaseDir.getPath());
     }
 
     @Override
-    public void setLog(Log log) {
+    public void setLog(final Log log) {
     }
 
     @Override
-    public void setAdditionalConfig(Map<String, String> additionalConfiguration) {
+    public void setAdditionalConfig(final Map<String, String> additionalConfiguration) {
         this.additionalConfig = additionalConfiguration;
     }
 
     @Override
-    public void setResourceBaseDir(File resourceBaseDir) {
+    public void setResourceBaseDir(final File resourceBaseDir) {
         this.resourceBaseDir = resourceBaseDir;
     }
 
     @Override
-    public void setMavenProject(MavenProject project) {
+    public void setMavenProject(final MavenProject project) {
         this.mavenProject = project;
         this.projectBaseDir = project.getBasedir();
     }
 
     @Override
-    public void setBuildContext(BuildContext buildContext) {
+    public void setBuildContext(final BuildContext buildContext) {
         this.buildContext = Preconditions.checkNotNull(buildContext);
     }
 
-    private Set<File> generateYangModuleInfo(File outputBaseDir, Module module, SchemaContext ctx,
-            Builder<String> providerSourceSet) {
+    private Set<File> generateYangModuleInfo(final File outputBaseDir, final Module module, final SchemaContext ctx,
+            final Builder<String> providerSourceSet) {
         Builder<File> generatedFiles = ImmutableSet.<File> builder();
 
         final YangModuleInfoTemplate template = new YangModuleInfoTemplate(module, ctx);
@@ -171,7 +172,7 @@ public final class CodeGeneratorImpl implements CodeGenerator, BuildContextAware
 
     }
 
-    private File writeJavaSource(File packageDir, String className, String source) {
+    private File writeJavaSource(final File packageDir, final String className, final String source) {
         if (!packageDir.exists()) {
             packageDir.mkdirs();
         }
@@ -180,7 +181,7 @@ public final class CodeGeneratorImpl implements CodeGenerator, BuildContextAware
         return file;
     }
 
-    private File writeFile(File file, String source) {
+    private File writeFile(final File file, final String source) {
         try (final OutputStream stream = buildContext.newFileOutputStream(file)) {
             try (final Writer fw = new OutputStreamWriter(stream)) {
                 try (final BufferedWriter bw = new BufferedWriter(fw)) {
diff --git a/code-generator/maven-sal-api-gen-plugin/src/test/java/org/opendaylight/yangtools/yang/unified/doc/generator/maven/YangModuleInfoCompilationTest.java b/code-generator/maven-sal-api-gen-plugin/src/test/java/org/opendaylight/yangtools/yang/unified/doc/generator/maven/YangModuleInfoCompilationTest.java
new file mode 100644 (file)
index 0000000..1208f19
--- /dev/null
@@ -0,0 +1,225 @@
+/*
+ * Copyright (c) 2013 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.yangtools.yang.unified.doc.generator.maven;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.lang.reflect.Method;
+import java.net.URI;
+import java.net.URL;
+import java.net.URLClassLoader;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Set;
+import javax.tools.JavaCompiler;
+import javax.tools.JavaFileObject;
+import javax.tools.StandardJavaFileManager;
+import javax.tools.ToolProvider;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.opendaylight.yangtools.maven.sal.api.gen.plugin.CodeGeneratorImpl;
+import org.opendaylight.yangtools.yang.binding.YangModuleInfo;
+import org.opendaylight.yangtools.yang.model.api.SchemaContext;
+import org.opendaylight.yangtools.yang.model.parser.api.YangContextParser;
+import org.opendaylight.yangtools.yang.parser.impl.YangParserImpl;
+import org.sonatype.plexus.build.incremental.DefaultBuildContext;
+
+/**
+ * Test correct generation of YangModuleInfo class.
+ *
+ */
+// TODO: most of private static methods are copied from
+// binding-java-api-generator project - reorganize compilation tests
+public class YangModuleInfoCompilationTest {
+    public static final String FS = File.separator;
+    private static final String BASE_PKG = "org.opendaylight.yang.gen.v1";
+
+    private static final String TEST_PATH = "target" + FS + "test";
+    private static final File TEST_DIR = new File(TEST_PATH);
+
+    private static final String GENERATOR_OUTPUT_PATH = TEST_PATH + FS + "src";
+    private static final File GENERATOR_OUTPUT_DIR = new File(GENERATOR_OUTPUT_PATH);
+    private static final String COMPILER_OUTPUT_PATH = TEST_PATH + FS + "bin";
+    private static final File COMPILER_OUTPUT_DIR = new File(COMPILER_OUTPUT_PATH);
+
+    @BeforeClass
+    public static void createTestDirs() {
+        if (TEST_DIR.exists()) {
+            deleteTestDir(TEST_DIR);
+        }
+        assertTrue(GENERATOR_OUTPUT_DIR.mkdirs());
+        assertTrue(COMPILER_OUTPUT_DIR.mkdirs());
+    }
+
+    @Test
+    public void compilationTest() throws Exception {
+        final File sourcesOutputDir = new File(GENERATOR_OUTPUT_PATH + FS + "yang");
+        assertTrue("Failed to create test file '" + sourcesOutputDir + "'", sourcesOutputDir.mkdirs());
+        final File compiledOutputDir = new File(COMPILER_OUTPUT_PATH + FS + "yang");
+        assertTrue("Failed to create test file '" + compiledOutputDir + "'", compiledOutputDir.mkdirs());
+
+        generateTestSources("/yang-module-info", sourcesOutputDir);
+
+        // Test if $YangModuleInfoImpl.java file is generated
+        final String BASE_PATH = "org" + FS + "opendaylight" + FS + "yang" + FS + "gen" + FS + "v1";
+        final String NS_TEST = BASE_PATH + FS + "yang" + FS + "test" + FS + "main" + FS + "rev140630";
+        File parent = new File(sourcesOutputDir, NS_TEST);
+        File keyArgs = new File(parent, "$YangModuleInfoImpl.java");
+        assertTrue(keyArgs.exists());
+
+        // Test if sources are compilable
+        testCompilation(sourcesOutputDir, compiledOutputDir);
+
+        // Create URLClassLoader
+        File[] roots = File.listRoots();
+        URL[] urls = new URL[roots.length + 1];
+        for (int i = 0; i < roots.length; i++) {
+            urls[i] = roots[i].toURI().toURL();
+
+        }
+        urls[roots.length] = compiledOutputDir.toURI().toURL();
+        ClassLoader loader = new URLClassLoader(urls);
+
+        // Load class
+        Class<?> yangModuleInfoClass = Class.forName(BASE_PKG + ".yang.test.main.rev140630.$YangModuleInfoImpl", true,
+                loader);
+
+        // Test generated $YangModuleInfoImpl class
+        assertFalse(yangModuleInfoClass.isInterface());
+        Method getInstance = assertContainsMethod(yangModuleInfoClass, YangModuleInfo.class, "getInstance");
+        Object yangModuleInfo = getInstance.invoke(null);
+
+        // Test getImportedModules method
+        Method getImportedModules = assertContainsMethod(yangModuleInfoClass, Set.class, "getImportedModules");
+        Object importedModules = getImportedModules.invoke(yangModuleInfo);
+        assertTrue(importedModules instanceof Set);
+
+        YangModuleInfo infoImport = null;
+        YangModuleInfo infoSub1 = null;
+        YangModuleInfo infoSub2 = null;
+        YangModuleInfo infoSub3 = null;
+        for (Object importedModule : (Set<?>) importedModules) {
+            assertTrue(importedModule instanceof YangModuleInfo);
+            YangModuleInfo ymi = (YangModuleInfo) importedModule;
+            String name = ymi.getName();
+
+            switch (name) {
+            case "import-module":
+                infoImport = ymi;
+                break;
+            case "submodule1":
+                infoSub1 = ymi;
+                break;
+            case "submodule2":
+                infoSub2 = ymi;
+                break;
+            case "submodule3":
+                infoSub3 = ymi;
+            }
+        }
+        assertNotNull(infoImport);
+        assertNotNull(infoSub1);
+        assertNotNull(infoSub2);
+        assertNotNull(infoSub3);
+
+        cleanUp(sourcesOutputDir, compiledOutputDir);
+    }
+
+    private void generateTestSources(String resourceDirPath, File sourcesOutputDir) throws Exception {
+        final List<File> sourceFiles = getSourceFiles(resourceDirPath);
+        YangContextParser parser = new YangParserImpl();
+        final SchemaContext context = parser.parseFiles(sourceFiles);
+        CodeGeneratorImpl codegen = new CodeGeneratorImpl();
+        codegen.setBuildContext(new DefaultBuildContext());
+        codegen.generateSources(context, sourcesOutputDir, context.getModules());
+    }
+
+    private static void testCompilation(File sourcesOutputDir, File compiledOutputDir) {
+        JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
+        StandardJavaFileManager fileManager = compiler.getStandardFileManager(null, null, null);
+        List<File> filesList = getJavaFiles(sourcesOutputDir);
+        Iterable<? extends JavaFileObject> compilationUnits = fileManager.getJavaFileObjectsFromFiles(filesList);
+        Iterable<String> options = Arrays.asList("-d", compiledOutputDir.getAbsolutePath());
+        boolean compiled = compiler.getTask(null, null, null, options, null, compilationUnits).call();
+        assertTrue(compiled);
+    }
+
+    private static List<File> getJavaFiles(File directory) {
+        List<File> result = new ArrayList<>();
+        File[] filesToRead = directory.listFiles();
+        if (filesToRead != null) {
+            for (File file : filesToRead) {
+                if (file.isDirectory()) {
+                    result.addAll(getJavaFiles(file));
+                } else {
+                    String absPath = file.getAbsolutePath();
+                    if (absPath.endsWith(".java")) {
+                        result.add(file);
+                    }
+                }
+            }
+        }
+        return result;
+    }
+
+    private static List<File> getSourceFiles(String path) throws Exception {
+        final URI resPath = YangModuleInfoCompilationTest.class.getResource(path).toURI();
+        final File sourcesDir = new File(resPath);
+        if (sourcesDir.exists()) {
+            final List<File> sourceFiles = new ArrayList<>();
+            final File[] fileArray = sourcesDir.listFiles();
+            if (fileArray == null) {
+                throw new IllegalArgumentException("Unable to locate files in " + sourcesDir);
+            }
+            sourceFiles.addAll(Arrays.asList(fileArray));
+            return sourceFiles;
+        } else {
+            throw new FileNotFoundException("Testing files were not found(" + sourcesDir.getName() + ")");
+        }
+    }
+
+    private static void deleteTestDir(File file) {
+        if (file.isDirectory()) {
+            File[] filesToDelete = file.listFiles();
+            if (filesToDelete != null) {
+                for (File f : filesToDelete) {
+                    deleteTestDir(f);
+                }
+            }
+        }
+        if (!file.delete()) {
+            throw new RuntimeException("Failed to clean up after test");
+        }
+    }
+
+    private static Method assertContainsMethod(Class<?> clazz, Class<?> returnType, String name, Class<?>... args) {
+        try {
+            Method m = clazz.getDeclaredMethod(name, args);
+            assertEquals(returnType, m.getReturnType());
+            return m;
+        } catch (NoSuchMethodException e) {
+            throw new AssertionError("Method " + name + " with args " + Arrays.toString(args)
+                    + " does not exists in class " + clazz.getSimpleName());
+        }
+    }
+
+    private static void cleanUp(File... resourceDirs) {
+        for (File resourceDir : resourceDirs) {
+            if (resourceDir.exists()) {
+                deleteTestDir(resourceDir);
+            }
+        }
+    }
+
+}
diff --git a/code-generator/maven-sal-api-gen-plugin/src/test/resources/yang-module-info/import-module.yang b/code-generator/maven-sal-api-gen-plugin/src/test/resources/yang-module-info/import-module.yang
new file mode 100644 (file)
index 0000000..4c29dcb
--- /dev/null
@@ -0,0 +1,12 @@
+module import-module {
+    yang-version 1;
+    namespace "yang:test:import";
+    prefix "i";
+
+    revision "2013-11-19" {
+    }
+
+
+    container imp-cont {}
+
+}
diff --git a/code-generator/maven-sal-api-gen-plugin/src/test/resources/yang-module-info/main-module.yang b/code-generator/maven-sal-api-gen-plugin/src/test/resources/yang-module-info/main-module.yang
new file mode 100644 (file)
index 0000000..c20b20f
--- /dev/null
@@ -0,0 +1,25 @@
+module main-module {
+
+    namespace "yang:test:main";
+    prefix m;
+
+    include submodule1 {
+        revision-date 2014-04-02;
+    }
+
+    include submodule2 {
+        revision-date 2014-06-30;
+    }
+
+    include submodule3 {
+        revision-date 2014-06-30;
+    }
+
+    import import-module {
+        prefix n;
+    }
+
+    revision 2014-06-30 {
+    }
+
+}
diff --git a/code-generator/maven-sal-api-gen-plugin/src/test/resources/yang-module-info/submodule1.yang b/code-generator/maven-sal-api-gen-plugin/src/test/resources/yang-module-info/submodule1.yang
new file mode 100644 (file)
index 0000000..02e1478
--- /dev/null
@@ -0,0 +1,17 @@
+submodule submodule1 {
+
+    belongs-to main-module {
+        prefix m;
+    }
+
+    revision 2014-04-02 {
+    }
+
+
+    typedef sub1-type {
+        type string;
+    }
+
+    container sub1-cont {}
+
+}
diff --git a/code-generator/maven-sal-api-gen-plugin/src/test/resources/yang-module-info/submodule2.yang b/code-generator/maven-sal-api-gen-plugin/src/test/resources/yang-module-info/submodule2.yang
new file mode 100644 (file)
index 0000000..fcdf5e1
--- /dev/null
@@ -0,0 +1,21 @@
+submodule submodule2 {
+
+    belongs-to main-module {
+        prefix m;
+    }
+
+    include submodule1 {
+        revision-date 2014-04-02;
+    }
+
+    revision 2014-06-30 {
+    }
+
+
+    grouping sub2-gr {
+        leaf sub2-leaf {
+            type string;
+        }
+    }
+
+}
diff --git a/code-generator/maven-sal-api-gen-plugin/src/test/resources/yang-module-info/submodule3.yang b/code-generator/maven-sal-api-gen-plugin/src/test/resources/yang-module-info/submodule3.yang
new file mode 100644 (file)
index 0000000..2602814
--- /dev/null
@@ -0,0 +1,13 @@
+submodule submodule3 {
+
+    belongs-to main-module {
+        prefix m;
+    }
+
+    revision 2014-06-30 {
+    }
+
+
+    container sub3-cont {}
+
+}
index 1010989bc890300f56ea7ad540d80c384688351e..e38c63bbf5ce375a175d5eaa667fbcbc3d49d9dc 100644 (file)
@@ -8,7 +8,6 @@
 package org.opendaylight.yangtools.yang.data.codec.gson;
 
 import com.google.gson.stream.JsonReader;
-
 import java.io.BufferedReader;
 import java.io.File;
 import java.io.FileNotFoundException;
@@ -16,9 +15,9 @@ import java.io.FileReader;
 import java.io.IOException;
 import java.io.StringReader;
 import java.io.StringWriter;
+import java.net.URISyntaxException;
 import java.util.ArrayList;
 import java.util.List;
-
 import org.junit.BeforeClass;
 import org.junit.Test;
 import org.opendaylight.yangtools.yang.common.QName;
@@ -45,10 +44,10 @@ public class StreamToNormalizedNodeTest {
     private static String streamAsString;
 
     @BeforeClass
-    public static void initialization() throws IOException {
+    public static void initialization() throws IOException, URISyntaxException {
         schemaContext = loadModules("/complexjson/yang");
-        streamAsString = loadTextFile(StreamToNormalizedNodeTest.class.getResource("/complexjson/complex-json.json")
-                .getPath());
+        streamAsString = loadTextFile(new File(StreamToNormalizedNodeTest.class.getResource(
+                "/complexjson/complex-json.json").toURI()));
     }
 
     /**
@@ -138,8 +137,8 @@ public class StreamToNormalizedNodeTest {
         return parser.parseFiles(testFiles);
     }
 
-    private static String loadTextFile(final String filePath) throws IOException {
-        FileReader fileReader = new FileReader(filePath);
+    private static String loadTextFile(final File file) throws IOException {
+        FileReader fileReader = new FileReader(file);
         BufferedReader bufReader = new BufferedReader(fileReader);
 
         String line = null;
index 23eb68ef1de1cdc268cc06da40b57d2c47a0ab6f..9a28d8fe633a247c75724c767a1a5e702d295473 100644 (file)
@@ -9,7 +9,6 @@ package org.opendaylight.yangtools.yang.model.api;
 
 import java.util.List;
 import java.util.Set;
-
 import javax.annotation.concurrent.Immutable;
 
 /**
@@ -128,6 +127,8 @@ public interface Module extends DataNodeContainer, SourceStreamAware, ModuleIden
      */
     Set<ModuleImport> getImports();
 
+    Set<Module> getSubmodules();
+
     /**
      * Returns <code>FeatureDefinition</code> instances which contain data from
      * <b>feature</b> statements defined in the module.
index eea920abc01891933f2ac273662e88aa780adfec..c1b004dfd289baf1dbb6839b733cfe3a65ed23bd 100644 (file)
@@ -46,8 +46,8 @@ input_stmt : INPUT_KEYWORD LEFT_BRACE (identifier_stmt |typedef_stmt | grouping_
 rpc_stmt : RPC_KEYWORD string (SEMICOLON | (LEFT_BRACE (identifier_stmt |if_feature_stmt  | status_stmt | description_stmt | reference_stmt | typedef_stmt | grouping_stmt | input_stmt | output_stmt )* RIGHT_BRACE));
 when_stmt : WHEN_KEYWORD string (SEMICOLON | (LEFT_BRACE (identifier_stmt |description_stmt | reference_stmt )* RIGHT_BRACE));
 
-augment_stmt : AUGMENT_KEYWORD string LEFT_BRACE  (identifier_stmt |when_stmt | if_feature_stmt | status_stmt | description_stmt | reference_stmt | data_def_stmt | case_stmt)+ RIGHT_BRACE;
-uses_augment_stmt : AUGMENT_KEYWORD string LEFT_BRACE  (identifier_stmt |when_stmt | if_feature_stmt | status_stmt | description_stmt | reference_stmt | data_def_stmt | case_stmt)+ RIGHT_BRACE;
+augment_stmt : AUGMENT_KEYWORD string LEFT_BRACE  (identifier_stmt |when_stmt | if_feature_stmt | status_stmt | description_stmt | reference_stmt | data_def_stmt | case_stmt)* RIGHT_BRACE;
+uses_augment_stmt : AUGMENT_KEYWORD string LEFT_BRACE  (identifier_stmt |when_stmt | if_feature_stmt | status_stmt | description_stmt | reference_stmt | data_def_stmt | case_stmt)* RIGHT_BRACE;
 refine_anyxml_stmts : (identifier_stmt |must_stmt | config_stmt | mandatory_stmt | description_stmt | reference_stmt )*;
 refine_case_stmts : (identifier_stmt |description_stmt | reference_stmt )*;
 refine_choice_stmts : (identifier_stmt |default_stmt | config_stmt | mandatory_stmt | description_stmt | reference_stmt )*;
@@ -89,7 +89,7 @@ status_stmt : STATUS_KEYWORD status_arg stmtend;
 position_stmt : POSITION_KEYWORD string stmtend;
 bit_stmt : BIT_KEYWORD string (SEMICOLON | (LEFT_BRACE  (identifier_stmt |position_stmt | status_stmt | description_stmt | reference_stmt )* RIGHT_BRACE));
 bits_specification : bit_stmt (bit_stmt | identifier_stmt)*;
-union_specification : type_stmt (identifier_stmt | type_stmt )+;
+union_specification : type_stmt (identifier_stmt | type_stmt )*;
 identityref_specification : base_stmt  ;
 instance_identifier_specification : (require_instance_stmt )?;
 require_instance_arg :string; // TRUE_KEYWORD | FALSE_KEYWORD;
index 1699da75abf9d9516cf156d9bbe0fd8d33f934be..f7004791e2c1d21da4fd77970c28438bfdd5f588 100644 (file)
@@ -19,13 +19,11 @@ public interface AugmentationSchemaBuilder extends DataNodeContainerBuilder,Docu
      * Returns when condition
      *
      * If when condition is present node defined by the parent data definition
-     * statement is only valid when the returned XPath
-     * expression conceptually evaluates to "true"
-     * for a particular instance, then the node defined by the parent data
-     * definition statement is valid; otherwise, it is not.
-     *
+     * statement is only valid when the returned XPath expression conceptually
+     * evaluates to "true" for a particular instance, then the node defined by
+     * the parent data definition statement is valid; otherwise, it is not.
      *
-     * @return
+     * @return when condition as string
      */
     String getWhenCondition();
 
index 196b49deb25a4736bbafd5a09a286ba8025edff4..e122e5978fbec50546e5f57df7461c4ae21d65b2 100644 (file)
@@ -65,7 +65,7 @@ public interface ConstraintsBuilder extends Builder<ConstraintDefinition> {
      *
      * This constraint has meaning only if associated node is list or leaf-list.
      *
-     * @param minElements
+     * @param maxElements
      *            number of maximum required elements.
      */
     void setMaxElements(Integer maxElements);
@@ -119,7 +119,7 @@ public interface ConstraintsBuilder extends Builder<ConstraintDefinition> {
     /**
      * Build constraint definition
      *
-     * @return
+     * @return instance of ConstraintDefinition created from this builder
      */
     ConstraintDefinition toInstance();
 
index 183f9fd05c62d8a19ab451188576cdfee6f29bc0..89237986586239bd6339692db77c379f1645b2f9 100644 (file)
@@ -106,7 +106,7 @@ public interface RefineBuilder extends DocumentedNodeBuilder {
    *
    * This constraint has meaning only if associated node is list or leaf-list.
    *
-   * @param minElements number of maximum required elements.
+   * @param maxElements number of maximum required elements.
    */
    void setMaxElements(Integer maxElements);
 
index e547d440fa9cf8c90f6d0761006bae90fb100162..068130fbf80ddfd4363a59d2ce447f08cc4cd89f 100644 (file)
@@ -69,10 +69,10 @@ public interface TypeDefinitionBuilder extends TypeAwareBuilder, SchemaNodeBuild
     List<PatternConstraint> getPatterns();
 
     /**
-     * Set length restrictions for resulting type definition.
+     * Set pattern restrictions for resulting type definition.
      *
-     * @param lengths
-     *            Length restrictions of resulting type definition.
+     * @param patterns
+     *            patterns restrictions of resulting type definition.
      */
     void setPatterns(List<PatternConstraint> patterns);
 
@@ -86,11 +86,8 @@ public interface TypeDefinitionBuilder extends TypeAwareBuilder, SchemaNodeBuild
     Integer getFractionDigits();
 
     /**
-     *
-     * Sets fractions digits of resulting type if it is derived
-     * from <code>decimal</code> built-in type.
-     *
-     * @return fractions digits of resulting type
+     * Sets fractions digits of resulting type if it is derived from
+     * <code>decimal</code> built-in type.
      */
     void setFractionDigits(Integer fractionDigits);
 
index 3b0cb966cd0ba3873a5145166e390d2a1fad8209..433c0821c02f850fe0532269b0fa94699acd3d77 100644 (file)
@@ -72,7 +72,9 @@ public interface UnknownSchemaNodeBuilder extends SchemaNodeBuilder, DocumentedN
 
     /**
      * Sets extension builder, which declares this unknown node
-     * @param extensionBuilder extension definition, which declares this unknown node
+     *
+     * @param extension
+     *            extension builder, which declares this unknown node
      */
     void setExtensionBuilder(ExtensionBuilder extension);
 
index 4a61d7b0f6d0eef9458a16fbc1c3becd97d3976c..759e779eed26e29a079b7e37681515022e8a160a 100644 (file)
@@ -20,8 +20,6 @@ import java.io.FileNotFoundException;
 import java.io.IOException;
 import java.io.InputStream;
 import java.net.URI;
-import java.text.DateFormat;
-import java.text.SimpleDateFormat;
 import java.util.ArrayList;
 import java.util.Collection;
 import java.util.Date;
@@ -35,10 +33,13 @@ import java.util.Set;
 import java.util.TreeMap;
 import org.antlr.v4.runtime.tree.ParseTree;
 import org.apache.commons.io.IOUtils;
+import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Belongs_to_stmtContext;
 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Module_header_stmtsContext;
 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Module_stmtContext;
 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Namespace_stmtContext;
 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Revision_stmtsContext;
+import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Submodule_header_stmtsContext;
+import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Submodule_stmtContext;
 import org.opendaylight.yangtools.yang.common.QName;
 import org.opendaylight.yangtools.yang.model.api.AnyXmlSchemaNode;
 import org.opendaylight.yangtools.yang.model.api.ChoiceCaseNode;
@@ -78,9 +79,7 @@ import org.slf4j.LoggerFactory;
 
 public final class BuilderUtils {
 
-    private static final DateFormat SIMPLE_DATE_FORMAT = new SimpleDateFormat("yyyy-MM-dd");
     private static final Logger LOG = LoggerFactory.getLogger(BuilderUtils.class);
-    private static final Splitter SLASH_SPLITTER = Splitter.on('/').omitEmptyStrings();
     private static final Splitter COLON_SPLITTER = Splitter.on(':');
     private static final Date NULL_DATE = new Date(0L);
     private static final String INPUT = "input";
@@ -473,7 +472,7 @@ public final class BuilderUtils {
      *            Class to be checked
      * @param optional
      *            Original value
-     * @return
+     * @return Optional object with type argument casted as cls
      */
     private static <T> Optional<T> castOptional(final Class<T> cls, final Optional<?> optional) {
         if (optional.isPresent()) {
@@ -635,10 +634,9 @@ public final class BuilderUtils {
      * Find augment target node and perform augmentation.
      *
      * @param augment
+     *            augment builder to process
      * @param firstNodeParent
      *            parent of first node in path
-     * @param path
-     *            path to augment target
      * @return true if augmentation process succeed, false otherwise
      */
     public static boolean processAugmentation(final AugmentationSchemaBuilder augment,
@@ -822,11 +820,17 @@ public final class BuilderUtils {
 
     public static Map<String, TreeMap<Date, URI>> createYangNamespaceContext(
             final Collection<? extends ParseTree> modules, final Optional<SchemaContext> context) {
-        Map<String, TreeMap<Date, URI>> map = new HashMap<>();
+        Map<String, TreeMap<Date, URI>> namespaceContext = new HashMap<>();
+        Set<Submodule_stmtContext> submodules = new HashSet<>();
+        // first read ParseTree collection and separate modules and submodules
         for (ParseTree module : modules) {
             for (int i = 0; i < module.getChildCount(); i++) {
                 ParseTree moduleTree = module.getChild(i);
-                if (moduleTree instanceof Module_stmtContext) {
+                if (moduleTree instanceof Submodule_stmtContext) {
+                    // put submodule context to separate collection
+                    submodules.add((Submodule_stmtContext) moduleTree);
+                } else if (moduleTree instanceof Module_stmtContext) {
+                    // get name, revision and namespace from module
                     Module_stmtContext moduleCtx = (Module_stmtContext) moduleTree;
                     final String moduleName = ParserListenerUtils.stringFromNode(moduleCtx);
                     Date rev = null;
@@ -854,28 +858,56 @@ public final class BuilderUtils {
                             }
                         }
                     }
-                    TreeMap<Date, URI> revToNs = map.get(moduleName);
+                    // update namespaceContext
+                    TreeMap<Date, URI> revToNs = namespaceContext.get(moduleName);
                     if (revToNs == null) {
                         revToNs = new TreeMap<>();
                         revToNs.put(rev, namespace);
-                        map.put(moduleName, revToNs);
+                        namespaceContext.put(moduleName, revToNs);
                     }
                     revToNs.put(rev, namespace);
                 }
             }
         }
+        // after all ParseTree-s are parsed update namespaceContext with modules
+        // from SchemaContext
         if (context.isPresent()) {
             for (Module module : context.get().getModules()) {
-                TreeMap<Date, URI> revToNs = map.get(module.getName());
+                TreeMap<Date, URI> revToNs = namespaceContext.get(module.getName());
                 if (revToNs == null) {
                     revToNs = new TreeMap<>();
                     revToNs.put(module.getRevision(), module.getNamespace());
-                    map.put(module.getName(), revToNs);
+                    namespaceContext.put(module.getName(), revToNs);
                 }
                 revToNs.put(module.getRevision(), module.getNamespace());
             }
         }
-        return map;
+        // when all modules are processed, traverse submodules and update
+        // namespaceContext with mapping for submodules
+        for (Submodule_stmtContext submodule : submodules) {
+            final String moduleName = ParserListenerUtils.stringFromNode(submodule);
+            for (int i = 0; i < submodule.getChildCount(); i++) {
+                ParseTree subHeaderCtx = submodule.getChild(i);
+                if (subHeaderCtx instanceof Submodule_header_stmtsContext) {
+                    for (int j = 0; j < subHeaderCtx.getChildCount(); j++) {
+                        ParseTree belongsCtx = subHeaderCtx.getChild(j);
+                        if (belongsCtx instanceof Belongs_to_stmtContext) {
+                            final String belongsTo = ParserListenerUtils.stringFromNode(belongsCtx);
+                            TreeMap<Date, URI> ns = namespaceContext.get(belongsTo);
+                            if (ns == null) {
+                                throw new YangParseException(moduleName, submodule.getStart().getLine(), String.format(
+                                        "Unresolved belongs-to statement: %s", belongsTo));
+                            }
+                            // submodule get namespace and revision from module
+                            TreeMap<Date, URI> subNs = new TreeMap<>();
+                            subNs.put(ns.firstKey(), ns.firstEntry().getValue());
+                            namespaceContext.put(moduleName, subNs);
+                        }
+                    }
+                }
+            }
+        }
+        return namespaceContext;
     }
 
 }
index 3d43e0025f8c98de7ec0e604e646420fa83da5f8..5c4afe6ae17b49e99535784d7e4ab2a74c28f26a 100644 (file)
@@ -79,7 +79,9 @@ public class ModuleBuilder extends AbstractDocumentedDataNodeContainerBuilder im
     final Map<String, ModuleImport> imports = new HashMap<>();
     final Map<String, ModuleBuilder> importedModules = new HashMap<>();
 
-    private final Map<String, Date> includedModules = new HashMap<>();
+    final Set<ModuleBuilder> addedSubmodules = new HashSet<>();
+    final Set<Module> submodules = new HashSet<>();
+    final Map<String, Date> includedModules = new HashMap<>();
 
     private final Set<AugmentationSchema> augments = new LinkedHashSet<>();
     private final List<AugmentationSchemaBuilder> augmentBuilders = new ArrayList<>();
@@ -171,6 +173,11 @@ public class ModuleBuilder extends AbstractDocumentedDataNodeContainerBuilder im
 
         buildChildren();
 
+        // SUBMODULES
+        for (ModuleBuilder submodule : addedSubmodules) {
+            submodules.add(submodule.build());
+        }
+
         // FEATURES
         for (FeatureBuilder fb : addedFeatures) {
             features.add(fb.build());
@@ -374,6 +381,10 @@ public class ModuleBuilder extends AbstractDocumentedDataNodeContainerBuilder im
         includedModules.put(name, revision);
     }
 
+    public void addSubmodule(final ModuleBuilder submodule) {
+        addedSubmodules.add(submodule);
+    }
+
     protected String getSource() {
         return source;
     }
index d2c3729871227954435671f78d27bece1e06a8f9..00018b8dda1128e20704ac15f5b89d9fff0859e4 100644 (file)
@@ -36,6 +36,7 @@ public final class ModuleImpl extends AbstractDocumentedDataNodeContainer implem
     private final String organization;
     private final String contact;
     private final Set<ModuleImport> imports;
+    private final Set<Module> submodules;
     private final Set<FeatureDefinition> features;
     private final Set<NotificationDefinition> notifications;
     private final Set<AugmentationSchema> augmentations;
@@ -61,6 +62,7 @@ public final class ModuleImpl extends AbstractDocumentedDataNodeContainer implem
         this.name = checkNotNull(name, "Missing name");
         this.sourcePath = sourcePath; //TODO: can this be nullable?
         this.imports = ImmutableSet.<ModuleImport> copyOf(builder.imports.values());
+        this.submodules = ImmutableSet.<Module> copyOf(builder.submodules);
         this.prefix = builder.getPrefix();
 
         this.qnameModule = QNameModule.create(builder.getNamespace(),
@@ -125,6 +127,11 @@ public final class ModuleImpl extends AbstractDocumentedDataNodeContainer implem
         return imports;
     }
 
+    @Override
+    public Set<Module> getSubmodules() {
+        return submodules;
+    }
+
     @Override
     public Set<FeatureDefinition> getFeatures() {
         return features;
index 57f1cc963519ef230b14f53e429223329995e748..933ac6b6d4f17f489efb3fa878ea868bbf7bfb94 100644 (file)
@@ -1091,12 +1091,8 @@ public final class ParserListenerUtils {
      *            type body context
      * @param actualPath
      *            current path in schema
-     * @param namespace
-     *            current namespace
-     * @param revision
-     *            current revision
-     * @param prefix
-     *            current prefix
+     * @param moduleQName
+     *            current module qname
      * @param parent
      *            parent builder
      * @return TypeDefinition object based on parsed values.
index 1ed5986df5c75d4f53f162f2988ad2a4f844256a..38055d908df31608a5a3d100c8976fc69f0c182c 100644 (file)
@@ -503,6 +503,7 @@ public final class YangParserImpl implements YangContextParser {
     }
 
     private void addSubmoduleToModule(final ModuleBuilder submodule, final ModuleBuilder module) {
+        module.addSubmodule(submodule);
         submodule.setParent(module);
         module.getDirtyNodes().addAll(submodule.getDirtyNodes());
         module.getImports().putAll(submodule.getImports());
index ece9226253cb04bb012a19c0fa67b7fae1745619..9de7ce02b4fa5b077b642d1e5214db151b4c7f12 100644 (file)
@@ -127,14 +127,14 @@ public final class YangParserListenerImpl extends YangParserBaseListener {
      * Create a new instance.
      *
      * FIXME: the resulting type needs to be extracted, such that we can reuse
-     *        the "BaseListener" aspect, which need not be exposed to the user.
-     *        Maybe factor out a base class into repo.spi?
+     * the "BaseListener" aspect, which need not be exposed to the user. Maybe
+     * factor out a base class into repo.spi?
      *
      * @param namespaceContext
      * @param sourcePath
      * @param walker
      * @param tree
-     * @return
+     * @return new instance of YangParserListenerImpl
      */
     public static YangParserListenerImpl create(final Map<String, TreeMap<Date, URI>> namespaceContext,
             final String sourcePath, final ParseTreeWalker walker, final ParseTree tree) {
@@ -346,8 +346,7 @@ public final class YangParserListenerImpl extends YangParserBaseListener {
             final ParseTree treeNode = ctx.getChild(i);
             if (treeNode instanceof Prefix_stmtContext) {
                 importPrefix = stringFromNode(treeNode);
-            }
-            if (treeNode instanceof Revision_date_stmtContext) {
+            } else if (treeNode instanceof Revision_date_stmtContext) {
                 String importRevisionStr = stringFromNode(treeNode);
                 try {
                     importRevision = SIMPLE_DATE_FORMAT.parse(importRevisionStr);
index 34c81911321ac42a698252cfdeb02f6b45fbccae..252a782e1567eea80aad6ed7365df494decb9bd4 100644 (file)
@@ -13,6 +13,7 @@ import com.google.common.base.Optional;
 import com.google.common.collect.ImmutableMap;
 import com.google.common.collect.ImmutableMap.Builder;
 import com.google.common.io.ByteSource;
+
 import java.io.IOException;
 import java.io.InputStream;
 import java.net.URL;
@@ -20,8 +21,10 @@ import java.util.Collection;
 import java.util.Map.Entry;
 import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.ConcurrentMap;
+
 import javax.annotation.concurrent.GuardedBy;
 import javax.annotation.concurrent.ThreadSafe;
+
 import org.opendaylight.yangtools.concepts.AbstractObjectRegistration;
 import org.opendaylight.yangtools.concepts.Identifiable;
 import org.opendaylight.yangtools.concepts.ObjectRegistration;
@@ -32,6 +35,11 @@ import org.opendaylight.yangtools.yang.parser.impl.YangParserImpl;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
+/**
+ * @deprecated Use {@link org.opendaylight.yangtools.yang.parser.repo.URLSchemaContextResolver}
+ * instead.
+ */
+@Deprecated
 @ThreadSafe
 public class URLSchemaContextResolver implements AdvancedSchemaSourceProvider<InputStream> {
 
@@ -47,7 +55,7 @@ public class URLSchemaContextResolver implements AdvancedSchemaSourceProvider<In
     /**
      * Register new yang schema when it appears.
      */
-    public synchronized ObjectRegistration<URL> registerSource(URL source) {
+    public synchronized ObjectRegistration<URL> registerSource(final URL source) {
         checkArgument(source != null, "Supplied source must not be null");
         InputStream yangStream = getInputStream(source);
         YangModelDependencyInfo modelInfo = YangModelDependencyInfo.fromInputStream(yangStream);
@@ -63,7 +71,7 @@ public class URLSchemaContextResolver implements AdvancedSchemaSourceProvider<In
     }
 
     @Override
-    public synchronized Optional<InputStream> getSchemaSource(SourceIdentifier key) {
+    public synchronized Optional<InputStream> getSchemaSource(final SourceIdentifier key) {
         SourceContext ctx = availableSources.get(key);
         if (ctx != null) {
             InputStream stream = getInputStream(ctx.getInstance());
@@ -73,11 +81,11 @@ public class URLSchemaContextResolver implements AdvancedSchemaSourceProvider<In
     }
 
     @Override
-    public Optional<InputStream> getSchemaSource(String name, Optional<String> version) {
+    public Optional<InputStream> getSchemaSource(final String name, final Optional<String> version) {
         return getSchemaSource(SourceIdentifier.create(name, version));
     }
 
-    private static InputStream getInputStream(URL source) {
+    private static InputStream getInputStream(final URL source) {
         InputStream stream;
         try {
             stream = source.openStream();
@@ -93,7 +101,7 @@ public class URLSchemaContextResolver implements AdvancedSchemaSourceProvider<In
         final SourceIdentifier identifier;
         final YangModelDependencyInfo dependencyInfo;
 
-        public SourceContext(URL instance, SourceIdentifier identifier, YangModelDependencyInfo modelInfo) {
+        public SourceContext(final URL instance, final SourceIdentifier identifier, final YangModelDependencyInfo modelInfo) {
             super(instance);
             this.identifier = identifier;
             this.dependencyInfo = modelInfo;
@@ -114,7 +122,7 @@ public class URLSchemaContextResolver implements AdvancedSchemaSourceProvider<In
         }
     }
 
-    private synchronized void removeSource(SourceContext sourceContext) {
+    private synchronized void removeSource(final SourceContext sourceContext) {
         boolean removed = availableSources.remove(sourceContext.getIdentifier(), sourceContext);
         if (removed) {
             tryToUpdateSchemaContext();
index bbcd95e220eb34737f50374cadd359c7af17e749..02497a880921dc19edf213ea25e36d09d58fcead 100644 (file)
@@ -13,9 +13,9 @@ import com.google.common.annotations.Beta;
 import com.google.common.base.Objects.ToStringHelper;
 import com.google.common.base.Optional;
 import com.google.common.base.Preconditions;
-import com.google.common.cache.Cache;
-import com.google.common.cache.CacheBuilder;
-import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ArrayListMultimap;
+import com.google.common.collect.ImmutableSet;
+import com.google.common.collect.Multimap;
 import com.google.common.util.concurrent.CheckedFuture;
 import com.google.common.util.concurrent.Futures;
 
@@ -37,30 +37,41 @@ import org.opendaylight.yangtools.yang.model.repo.api.SchemaSourceFilter;
 import org.opendaylight.yangtools.yang.model.repo.api.SourceIdentifier;
 import org.opendaylight.yangtools.yang.model.repo.api.YangTextSchemaSource;
 import org.opendaylight.yangtools.yang.model.repo.spi.PotentialSchemaSource;
+import org.opendaylight.yangtools.yang.model.repo.spi.PotentialSchemaSource.Costs;
+import org.opendaylight.yangtools.yang.model.repo.spi.SchemaListenerRegistration;
 import org.opendaylight.yangtools.yang.model.repo.spi.SchemaSourceProvider;
 import org.opendaylight.yangtools.yang.model.repo.spi.SchemaSourceRegistration;
 import org.opendaylight.yangtools.yang.model.repo.spi.SchemaSourceRegistry;
+import org.opendaylight.yangtools.yang.model.repo.util.InMemorySchemaSourceCache;
 import org.opendaylight.yangtools.yang.parser.util.ASTSchemaSource;
 import org.opendaylight.yangtools.yang.parser.util.TextToASTTransformer;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 @Beta
-public class URLSchemaContextResolver implements SchemaSourceProvider<YangTextSchemaSource> {
+public class URLSchemaContextResolver implements AutoCloseable, SchemaSourceProvider<YangTextSchemaSource> {
     private static final Logger LOG = LoggerFactory.getLogger(URLSchemaContextResolver.class);
 
-    private final Cache<SourceIdentifier, YangTextSchemaSource> sources = CacheBuilder.newBuilder().build();
     private final Collection<SourceIdentifier> requiredSources = new ConcurrentLinkedDeque<>();
+    private final Multimap<SourceIdentifier, YangTextSchemaSource> texts = ArrayListMultimap.create();
     private final AtomicReference<Optional<SchemaContext>> currentSchemaContext =
             new AtomicReference<>(Optional.<SchemaContext>absent());
+    private final InMemorySchemaSourceCache<ASTSchemaSource> cache;
+    private final SchemaListenerRegistration transReg;
     private final SchemaSourceRegistry registry;
     private final SchemaRepository repository;
     private volatile Object version = new Object();
     private volatile Object contextVersion = version;
 
+
     private URLSchemaContextResolver(final SchemaRepository repository, final SchemaSourceRegistry registry) {
         this.repository = Preconditions.checkNotNull(repository);
         this.registry = Preconditions.checkNotNull(registry);
+
+        final TextToASTTransformer t = TextToASTTransformer.create(repository, registry);
+        transReg = registry.registerSchemaSourceListener(t);
+
+        cache = InMemorySchemaSourceCache.createSoftCache(registry, ASTSchemaSource.class);
     }
 
     public static URLSchemaContextResolver create(final String name) {
@@ -96,23 +107,31 @@ public class URLSchemaContextResolver implements SchemaSourceProvider<YangTextSc
         LOG.trace("Resolved URL {} to source {}", url, ast);
 
         final SourceIdentifier resolvedId = ast.getIdentifier();
-        final SchemaSourceRegistration<YangTextSchemaSource> reg = registry.registerSchemaSource(this,
-                PotentialSchemaSource.create(resolvedId, YangTextSchemaSource.class, 0));
-
-        requiredSources.add(resolvedId);
-        LOG.trace("Added source {} to schema context requirements", resolvedId);
-        version = new Object();
 
-        return new AbstractURLRegistration(text) {
-            @Override
-            protected void removeRegistration() {
-                requiredSources.remove(resolvedId);
-                LOG.trace("Removed source {} from schema context requirements", resolvedId);
-                version = new Object();
-                reg.close();
-                sources.invalidate(resolvedId);
-            }
-        };
+        synchronized (this) {
+            texts.put(resolvedId, text);
+            LOG.debug("Populated {} with text", resolvedId);
+
+            final SchemaSourceRegistration<YangTextSchemaSource> reg = registry.registerSchemaSource(this,
+                PotentialSchemaSource.create(resolvedId, YangTextSchemaSource.class, Costs.IMMEDIATE.getValue()));
+            requiredSources.add(resolvedId);
+            cache.schemaSourceEncountered(ast);
+            LOG.debug("Added source {} to schema context requirements", resolvedId);
+            version = new Object();
+
+            return new AbstractURLRegistration(text) {
+                @Override
+                protected void removeRegistration() {
+                    synchronized (URLSchemaContextResolver.this) {
+                        requiredSources.remove(resolvedId);
+                        LOG.trace("Removed source {} from schema context requirements", resolvedId);
+                        version = new Object();
+                        reg.close();
+                        texts.remove(resolvedId, text);
+                    }
+                }
+            };
+        }
     }
 
     /**
@@ -139,7 +158,7 @@ public class URLSchemaContextResolver implements SchemaSourceProvider<YangTextSc
             Collection<SourceIdentifier> sources;
             do {
                 v = version;
-                sources = ImmutableList.copyOf(requiredSources);
+                sources = ImmutableSet.copyOf(requiredSources);
             } while (v != version);
 
             while (true) {
@@ -148,11 +167,13 @@ public class URLSchemaContextResolver implements SchemaSourceProvider<YangTextSc
                     sc = Optional.of(f.checkedGet());
                     break;
                 } catch (SchemaResolutionException e) {
-                    LOG.info("Failed to fully assemble schema context for {}", sources, e);
+                    LOG.debug("Failed to fully assemble schema context for {}", sources, e);
                     sources = e.getResolvedSources();
                 }
             }
 
+            LOG.debug("Resolved schema context for {}", sources);
+
             synchronized (this) {
                 if (contextVersion == cv) {
                     currentSchemaContext.set(sc);
@@ -165,13 +186,20 @@ public class URLSchemaContextResolver implements SchemaSourceProvider<YangTextSc
     }
 
     @Override
-    public CheckedFuture<YangTextSchemaSource, SchemaSourceException> getSource(final SourceIdentifier sourceIdentifier) {
-        final YangTextSchemaSource ret = sources.getIfPresent(sourceIdentifier);
-        if (ret == null) {
+    public synchronized CheckedFuture<YangTextSchemaSource, SchemaSourceException> getSource(final SourceIdentifier sourceIdentifier) {
+        final Collection<YangTextSchemaSource> ret = texts.get(sourceIdentifier);
+
+        LOG.debug("Lookup {} result {}", sourceIdentifier, ret);
+        if (ret.isEmpty()) {
             return Futures.<YangTextSchemaSource, SchemaSourceException>immediateFailedCheckedFuture(
                     new MissingSchemaSourceException("URL for " + sourceIdentifier + " not registered", sourceIdentifier));
         }
 
-        return Futures.immediateCheckedFuture(ret);
+        return Futures.immediateCheckedFuture(ret.iterator().next());
+    }
+
+    @Override
+    public void close() {
+        transReg.close();
     }
 }
index 051dd4f72729a94bb9d76f3e3c117d5797f4c282..f7e270ea1d5badf84ef605c51a93da8422739e9d 100644 (file)
@@ -14,7 +14,6 @@ import com.google.common.base.Optional;
 import com.google.common.collect.Lists;
 import com.google.common.collect.Maps;
 import com.google.common.collect.Sets;
-
 import java.net.URI;
 import java.util.ArrayList;
 import java.util.Collection;
@@ -24,7 +23,6 @@ import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
-
 import org.opendaylight.yangtools.yang.common.SimpleDateFormatUtil;
 import org.opendaylight.yangtools.yang.model.api.Module;
 import org.opendaylight.yangtools.yang.model.api.ModuleImport;
@@ -148,7 +146,7 @@ public final class ModuleDependencySort {
      */
     private static void processDependencies(final Map<String, Map<Date, ModuleNodeImpl>> moduleGraph,
             final Iterable<ModuleOrModuleBuilder> mmbs) {
-        Map<URI, Object> allNS = new HashMap<>();
+        Map<URI, ModuleOrModuleBuilder> allNS = new HashMap<>();
 
         // Create edges in graph
         for (ModuleOrModuleBuilder mmb : mmbs) {
@@ -175,28 +173,15 @@ public final class ModuleDependencySort {
 
             // check for existence of module with same namespace
             if (allNS.containsKey(ns)) {
-                Object mod = allNS.get(ns);
+                ModuleOrModuleBuilder mod = allNS.get(ns);
                 String name = null;
                 Date revision = null;
-
-                if(mod instanceof ModuleOrModuleBuilder) {
-                    ModuleOrModuleBuilder modOrmodBuilder = ((ModuleOrModuleBuilder) mod);
-                    if(modOrmodBuilder.isModule()) {
-                        mod = ((ModuleOrModuleBuilder) mod).getModule();
-                    } else if (modOrmodBuilder.isModuleBuilder()) {
-                        mod = ((ModuleOrModuleBuilder) mod).getModuleBuilder();
-                    } else {
-                        LOGGER.warn("ModuleOrModuleBuilder is neither Module or ModuleBuilder");
-                    }
-                }
-                if (mod instanceof Module) {
-                    name = ((Module) mod).getName();
-                    revision = ((Module) mod).getRevision();
-                } else if (mod instanceof ModuleBuilder) {
-                    name = ((ModuleBuilder) mod).getName();
-                    revision = ((ModuleBuilder) mod).getRevision();
-                } else {
-                    LOGGER.warn("Module has no name: {}", mod);
+                if (mod.isModule()) {
+                    name = mod.getModule().getName();
+                    revision = mod.getModule().getRevision();
+                } else if (mod.isModuleBuilder()) {
+                    name = mod.getModuleBuilder().getName();
+                    revision = mod.getModuleBuilder().getRevision();
                 }
                 if (!(fromName.equals(name))) {
                     LOGGER.warn(