BUG-1270: improve QNameModule reuse
[yangtools.git] / yang / yang-parser-impl / src / main / java / org / opendaylight / yangtools / yang / parser / builder / impl / ModuleBuilder.java
index e351f6c5df3d0f4413ca0558652b3312c2a85017..db1babd6dc08ef8242c4aa37c81232224ebbc8e8 100644 (file)
@@ -6,24 +6,28 @@
  */
 package org.opendaylight.yangtools.yang.parser.builder.impl;
 
+import com.google.common.base.Preconditions;
 import com.google.common.io.ByteSource;
+
 import java.io.IOException;
 import java.io.InputStream;
 import java.net.URI;
 import java.util.ArrayList;
-import java.util.Collection;
 import java.util.Collections;
 import java.util.Date;
 import java.util.Deque;
+import java.util.HashMap;
 import java.util.HashSet;
 import java.util.LinkedHashSet;
 import java.util.LinkedList;
 import java.util.List;
+import java.util.Map;
 import java.util.Set;
 import java.util.TreeSet;
 
 import org.apache.commons.io.IOUtils;
 import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.common.QNameModule;
 import org.opendaylight.yangtools.yang.model.api.AugmentationSchema;
 import org.opendaylight.yangtools.yang.model.api.Deviation;
 import org.opendaylight.yangtools.yang.model.api.ExtensionDefinition;
@@ -64,9 +68,8 @@ public class ModuleBuilder extends AbstractDocumentedDataNodeContainerBuilder im
     private final String name;
     private final String sourcePath;
     private static final SchemaPath SCHEMA_PATH = SchemaPath.create(Collections.<QName> emptyList(), true);
-    private URI namespace;
     private String prefix;
-    private Date revision;
+    private QNameModule qnameModule = QNameModule.create(null, null);
 
     private final boolean submodule;
     private String belongsTo;
@@ -75,7 +78,8 @@ public class ModuleBuilder extends AbstractDocumentedDataNodeContainerBuilder im
     private final Deque<Builder> actualPath = new LinkedList<>();
     private final Set<TypeAwareBuilder> dirtyNodes = new HashSet<>();
 
-    final Set<ModuleImport> imports = new HashSet<ModuleImport>();
+    final Map<String, ModuleImport> imports = new HashMap<>();
+    final Map<String, ModuleBuilder> importedModules = new HashMap<>();
 
     private final Set<AugmentationSchema> augments = new LinkedHashSet<>();
     private final List<AugmentationSchemaBuilder> augmentBuilders = new ArrayList<>();
@@ -125,7 +129,7 @@ public class ModuleBuilder extends AbstractDocumentedDataNodeContainerBuilder im
     }
 
     public ModuleBuilder(final Module base) {
-        super(base.getName(), 0, new QName(base.getNamespace(), base.getRevision(), base.getPrefix(), base.getName()),
+        super(base.getName(), 0, QName.create(base.getQNameModule(), base.getPrefix(), base.getName()),
                 SCHEMA_PATH, base);
         this.name = base.getName();
         this.sourcePath = base.getModuleSourcePath();
@@ -133,9 +137,8 @@ public class ModuleBuilder extends AbstractDocumentedDataNodeContainerBuilder im
         submodule = false;
         yangVersion = base.getYangVersion();
         actualPath.push(this);//FIXME: this escapes constructor
-        namespace = base.getNamespace();
         prefix = base.getPrefix();
-        revision = base.getRevision();
+        qnameModule = base.getQNameModule();
 
         augments.addAll(base.getAugmentations());
         rpcs.addAll(base.getRpcs());
@@ -323,11 +326,19 @@ public class ModuleBuilder extends AbstractDocumentedDataNodeContainerBuilder im
     }
 
     public URI getNamespace() {
-        return namespace;
+        return qnameModule.getNamespace();
+    }
+
+    public QNameModule getQNameModule() {
+        return qnameModule;
+    }
+
+    public void setQNameModule(final QNameModule qnameModule) {
+        this.qnameModule = Preconditions.checkNotNull(qnameModule);
     }
 
     public void setNamespace(final URI namespace) {
-        this.namespace = namespace;
+        this.qnameModule = QNameModule.create(namespace, qnameModule.getRevision());
     }
 
     public String getPrefix() {
@@ -335,13 +346,26 @@ public class ModuleBuilder extends AbstractDocumentedDataNodeContainerBuilder im
     }
 
     public Date getRevision() {
-        return revision;
+        return qnameModule.getRevision();
     }
 
-    protected Set<ModuleImport> getImports() {
+    public ModuleImport getImport(final String prefix) {
+        return imports.get(prefix);
+    }
+
+    public Map<String, ModuleImport> getImports() {
         return imports;
     }
 
+    public ModuleBuilder getImportedModule(final String prefix) {
+        return importedModules.get(prefix);
+    }
+
+    public void addImportedModule(final String prefix, final ModuleBuilder module) {
+        checkPrefix(prefix);
+        importedModules.put(prefix, module);
+    }
+
     protected String getSource() {
         return source;
     }
@@ -364,7 +388,7 @@ public class ModuleBuilder extends AbstractDocumentedDataNodeContainerBuilder im
     }
 
     public void setRevision(final Date revision) {
-        this.revision = revision;
+        this.qnameModule = QNameModule.create(qnameModule.getNamespace(), revision);
     }
 
     public void setPrefix(final String prefix) {
@@ -383,14 +407,20 @@ public class ModuleBuilder extends AbstractDocumentedDataNodeContainerBuilder im
         this.contact = contact;
     }
 
-    public boolean addModuleImport(final String moduleName, final Date revision, final String prefix) {
+    public void addModuleImport(final String moduleName, final Date revision, final String prefix) {
+        checkPrefix(prefix);
         checkNotSealed();
         final ModuleImport moduleImport = createModuleImport(moduleName, revision, prefix);
-        return imports.add(moduleImport);
+        imports.put(prefix, moduleImport);
     }
 
-    public Set<ModuleImport> getModuleImports() {
-        return imports;
+    private void checkPrefix(final String prefix) {
+        if (prefix == null || prefix.isEmpty()) {
+            throw new IllegalArgumentException("Cannot add imported module with undefined prefix");
+        }
+        if (prefix.equals(this.prefix)) {
+            throw new IllegalArgumentException("Cannot add imported module with prefix equals to module prefix");
+        }
     }
 
     public ExtensionBuilder addExtension(final QName qname, final int line, final SchemaPath path) {
@@ -764,7 +794,7 @@ public class ModuleBuilder extends AbstractDocumentedDataNodeContainerBuilder im
         ((TypeAwareBuilder) parent).setType(type);
     }
 
-    public UnionTypeBuilder addUnionType(final int line, final URI namespace, final Date revision) {
+    public UnionTypeBuilder addUnionType(final int line, final QNameModule module) {
         final Builder parent = getActualNode();
         if (parent == null) {
             throw new YangParseException(name, line, "Unresolved parent of union type");
@@ -842,11 +872,11 @@ public class ModuleBuilder extends AbstractDocumentedDataNodeContainerBuilder im
             addedUnknownNodes.add(builder);
         } else {
             if (parent instanceof SchemaNodeBuilder) {
-                ((SchemaNodeBuilder) parent).addUnknownNodeBuilder(builder);
+                parent.addUnknownNodeBuilder(builder);
             } else if (parent instanceof DataNodeContainerBuilder) {
-                ((DataNodeContainerBuilder) parent).addUnknownNodeBuilder(builder);
+                parent.addUnknownNodeBuilder(builder);
             } else if (parent instanceof RefineHolderImpl) {
-                ((RefineHolderImpl) parent).addUnknownNodeBuilder(builder);
+                parent.addUnknownNodeBuilder(builder);
             } else {
                 throw new YangParseException(name, line, "Unresolved parent of unknown node '" + qname.getLocalName()
                         + "'");
@@ -877,7 +907,7 @@ public class ModuleBuilder extends AbstractDocumentedDataNodeContainerBuilder im
         return "module " + name;
     }
 
-    public void setSource(ByteSource byteSource) throws IOException {
+    public void setSource(final ByteSource byteSource) throws IOException {
         try (InputStream stream = byteSource.openStream()) {
             setSource(IOUtils.toString(stream));
         }
@@ -1000,8 +1030,7 @@ public class ModuleBuilder extends AbstractDocumentedDataNodeContainerBuilder im
     }
 
     private ModuleImport createModuleImport(final String moduleName, final Date revision, final String prefix) {
-        final ModuleImport moduleImport = new ModuleImportImpl(moduleName, revision, prefix);
-        return moduleImport;
+        return new ModuleImportImpl(moduleName, revision, prefix);
     }
 
     private void raiseYangParserException(final String cantAddType, final String type, final String name,
@@ -1024,8 +1053,7 @@ public class ModuleBuilder extends AbstractDocumentedDataNodeContainerBuilder im
         final int prime = 31;
         int result = 1;
         result = prime * result + ((name == null) ? 0 : name.hashCode());
-        result = prime * result + ((namespace == null) ? 0 : namespace.hashCode());
-        result = prime * result + ((revision == null) ? 0 : revision.hashCode());
+        result = prime * result + qnameModule.hashCode();
         result = prime * result + ((prefix == null) ? 0 : prefix.hashCode());
 
         return result;
@@ -1050,11 +1078,7 @@ public class ModuleBuilder extends AbstractDocumentedDataNodeContainerBuilder im
         } else if (!name.equals(other.name)) {
             return false;
         }
-        if (namespace == null) {
-            if (other.namespace != null) {
-                return false;
-            }
-        } else if (!namespace.equals(other.namespace)) {
+        if (!qnameModule.equals(other.qnameModule)) {
             return false;
         }
         if (prefix == null) {
@@ -1064,13 +1088,6 @@ public class ModuleBuilder extends AbstractDocumentedDataNodeContainerBuilder im
         } else if (!prefix.equals(other.prefix)) {
             return false;
         }
-        if (revision == null) {
-            if (other.revision != null) {
-                return false;
-            }
-        } else if (!revision.equals(other.revision)) {
-            return false;
-        }
         return true;
     }