BUG 1131: Introduced sealing of builder, initial clean up of ModuleBuilder. 98/7898/11
authorTomas Olvecky <tolvecky@cisco.com>
Tue, 24 Jun 2014 11:09:12 +0000 (13:09 +0200)
committerMartin Vitez <mvitez@cisco.com>
Mon, 30 Jun 2014 09:39:29 +0000 (09:39 +0000)
Introduced sealing of builders, which makes sure builder is not
modified once the product of build was created.

Logic in parser prevented this already, but it was external
check to builders, not internal.

Sealing of builders is critical for implementing safe
instantiation since once you create copy of builder
(eg.instantiation of grouping) you do NOT want
to have grouping definition accidentally change.

This should prevent introducing regressions as described above.

Change-Id: Iad2dfc8036d27f3538e48315eb1fc17a5481f67b
Signed-off-by: Tony Tkacik <ttkacik@cisco.com>
Signed-off-by: Tomas Olvecky <tolvecky@cisco.com>
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 [new file with mode: 0644]
yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/builder/impl/RefineUtils.java
yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/builder/util/AbstractBuilder.java
yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/builder/util/AbstractDocumentedDataNodeContainerBuilder.java
yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/builder/util/AbstractDocumentedNode.java
yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/impl/YangParserImpl.java

index 020d7594bf95d9ce0c912d3f64c48146e1961483..628d7a244e3c31f8c656b401515b19cf9c14180a 100644 (file)
@@ -45,13 +45,10 @@ 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.UnknownSchemaNodeBuilder;
 import org.opendaylight.yangtools.yang.parser.builder.api.UsesNodeBuilder;
-import org.opendaylight.yangtools.yang.parser.builder.util.AbstractDocumentedDataNodeContainer;
 import org.opendaylight.yangtools.yang.parser.builder.util.AbstractDocumentedDataNodeContainerBuilder;
 import org.opendaylight.yangtools.yang.parser.builder.util.Comparators;
 import org.opendaylight.yangtools.yang.parser.util.YangParseException;
 
-import com.google.common.collect.ImmutableSet;
-
 /**
  * Builder of Module object. If this module is dependent on external
  * module/modules, these dependencies must be resolved before module is built,
@@ -71,11 +68,10 @@ public class ModuleBuilder extends AbstractDocumentedDataNodeContainerBuilder im
     private String belongsTo;
     private ModuleBuilder parent;
 
-
     private final Deque<Builder> actualPath = new LinkedList<>();
     private final Set<TypeAwareBuilder> dirtyNodes = new HashSet<>();
 
-    private final Set<ModuleImport> imports = new HashSet<ModuleImport>();
+    final Set<ModuleImport> imports = new HashSet<ModuleImport>();
 
     private final Set<AugmentationSchema> augments = new LinkedHashSet<>();
     private final List<AugmentationSchemaBuilder> augmentBuilders = new ArrayList<>();
@@ -107,7 +103,7 @@ public class ModuleBuilder extends AbstractDocumentedDataNodeContainerBuilder im
 
     private final List<ListSchemaNodeBuilder> allLists = new ArrayList<>();
 
-    private String source;
+    String source;
     private String yangVersion;
     private String organization;
     private String contact;
@@ -116,11 +112,6 @@ public class ModuleBuilder extends AbstractDocumentedDataNodeContainerBuilder im
         this(name, false, sourcePath);
     }
 
-    @Override
-    protected String getStatementName() {
-        return "module";
-    }
-
     public ModuleBuilder(final String name, final boolean submodule, final String sourcePath) {
         super(name, 0, null);
         this.name = name;
@@ -156,65 +147,66 @@ public class ModuleBuilder extends AbstractDocumentedDataNodeContainerBuilder im
         unknownNodes.addAll(base.getUnknownSchemaNodes());
     }
 
+    @Override
+    protected String getStatementName() {
+        return "module";
+    }
+
     /**
      * Build new Module object based on this builder.
      */
     @Override
     public Module build() {
+        if(instance != null) {
+            return instance;
+        }
+
         buildChildren();
-        instance = new ModuleImpl(name, sourcePath, this);
+
         // FEATURES
         for (FeatureBuilder fb : addedFeatures) {
             features.add(fb.build());
         }
-        instance.setFeatures(features);
 
         // NOTIFICATIONS
         for (NotificationBuilder entry : addedNotifications) {
             notifications.add(entry.build());
         }
-        instance.setNotifications(notifications);
 
         // AUGMENTATIONS
         for (AugmentationSchemaBuilder builder : augmentBuilders) {
             augments.add(builder.build());
         }
-        instance.setAugmentations(augments);
 
         // RPCs
         for (RpcDefinitionBuilder rpc : addedRpcs) {
             rpcs.add(rpc.build());
         }
-        instance.setRpcs(rpcs);
 
         // DEVIATIONS
         for (DeviationBuilder entry : deviationBuilders) {
             deviations.add(entry.build());
         }
-        instance.setDeviations(deviations);
 
         // EXTENSIONS
         for (ExtensionBuilder eb : addedExtensions) {
             extensions.add(eb.build());
         }
         Collections.sort(extensions, Comparators.SCHEMA_NODE_COMP);
-        instance.setExtensionSchemaNodes(extensions);
+
 
         // IDENTITIES
         for (IdentitySchemaNodeBuilder id : addedIdentities) {
             identities.add(id.build());
         }
-        instance.setIdentities(identities);
 
         // UNKNOWN NODES
         for (UnknownSchemaNodeBuilder unb : addedUnknownNodes) {
             unknownNodes.add(unb.build());
         }
         Collections.sort(unknownNodes, Comparators.SCHEMA_NODE_COMP);
-        instance.setUnknownSchemaNodes(unknownNodes);
-
-        instance.setSource(source);
 
+        instance = new ModuleImpl(name, sourcePath, this);
         return instance;
     }
 
@@ -341,6 +333,14 @@ public class ModuleBuilder extends AbstractDocumentedDataNodeContainerBuilder im
         return revision;
     }
 
+    protected Set<ModuleImport> getImports() {
+        return imports;
+    }
+
+    protected String getSource() {
+        return source;
+    }
+
     public boolean isSubmodule() {
         return submodule;
     }
@@ -379,6 +379,7 @@ public class ModuleBuilder extends AbstractDocumentedDataNodeContainerBuilder im
     }
 
     public boolean addModuleImport(final String moduleName, final Date revision, final String prefix) {
+        checkNotSealed();
         final ModuleImport moduleImport = createModuleImport(moduleName, revision, prefix);
         return imports.add(moduleImport);
     }
@@ -388,6 +389,7 @@ public class ModuleBuilder extends AbstractDocumentedDataNodeContainerBuilder im
     }
 
     public ExtensionBuilder addExtension(final QName qname, final int line, final SchemaPath path) {
+        checkNotSealed();
         Builder parent = getActualNode();
         if (!(parent.equals(this))) {
             throw new YangParseException(name, line, "extension can be defined only in module or submodule");
@@ -406,6 +408,7 @@ public class ModuleBuilder extends AbstractDocumentedDataNodeContainerBuilder im
     }
 
     public ContainerSchemaNodeBuilder addContainerNode(final int line, final QName qname, final SchemaPath schemaPath) {
+        checkNotSealed();
         final ContainerSchemaNodeBuilder builder = new ContainerSchemaNodeBuilder(name, line, qname, schemaPath);
 
         Builder parent = getActualNode();
@@ -416,6 +419,7 @@ public class ModuleBuilder extends AbstractDocumentedDataNodeContainerBuilder im
     }
 
     public ListSchemaNodeBuilder addListNode(final int line, final QName qname, final SchemaPath schemaPath) {
+        checkNotSealed();
         final ListSchemaNodeBuilder builder = new ListSchemaNodeBuilder(name, line, qname, schemaPath);
 
         Builder parent = getActualNode();
@@ -427,6 +431,7 @@ public class ModuleBuilder extends AbstractDocumentedDataNodeContainerBuilder im
     }
 
     public LeafSchemaNodeBuilder addLeafNode(final int line, final QName qname, final SchemaPath schemaPath) {
+        checkNotSealed();
         final LeafSchemaNodeBuilder builder = new LeafSchemaNodeBuilder(name, line, qname, schemaPath);
 
         Builder parent = getActualNode();
@@ -437,6 +442,7 @@ public class ModuleBuilder extends AbstractDocumentedDataNodeContainerBuilder im
     }
 
     public LeafListSchemaNodeBuilder addLeafListNode(final int line, final QName qname, final SchemaPath schemaPath) {
+        checkNotSealed();
         final LeafListSchemaNodeBuilder builder = new LeafListSchemaNodeBuilder(name, line, qname, schemaPath);
 
         Builder parent = getActualNode();
@@ -447,6 +453,7 @@ public class ModuleBuilder extends AbstractDocumentedDataNodeContainerBuilder im
     }
 
     public GroupingBuilder addGrouping(final int line, final QName qname, final SchemaPath path) {
+        checkNotSealed();
         final GroupingBuilder builder = new GroupingBuilderImpl(name, line, qname, path);
 
         Builder parent = getActualNode();
@@ -487,6 +494,7 @@ public class ModuleBuilder extends AbstractDocumentedDataNodeContainerBuilder im
     }
 
     public AugmentationSchemaBuilder addAugment(final int line, final String augmentTargetStr, final int order) {
+        checkNotSealed();
         final AugmentationSchemaBuilder builder = new AugmentationSchemaBuilderImpl(name, line, augmentTargetStr, order);
 
         Builder parent = getActualNode();
@@ -520,6 +528,7 @@ public class ModuleBuilder extends AbstractDocumentedDataNodeContainerBuilder im
     }
 
     public UsesNodeBuilder addUsesNode(final int line, final String groupingPathStr) {
+        checkNotSealed();
         final UsesNodeBuilder usesBuilder = new UsesNodeBuilderImpl(name, line, groupingPathStr);
 
         Builder parent = getActualNode();
@@ -542,6 +551,7 @@ public class ModuleBuilder extends AbstractDocumentedDataNodeContainerBuilder im
     }
 
     public void addRefine(final RefineHolderImpl refine) {
+        checkNotSealed();
         final Builder parent = getActualNode();
         if (!(parent instanceof UsesNodeBuilder)) {
             throw new YangParseException(name, refine.getLine(), "refine can be defined only in uses statement");
@@ -551,6 +561,7 @@ public class ModuleBuilder extends AbstractDocumentedDataNodeContainerBuilder im
     }
 
     public RpcDefinitionBuilder addRpc(final int line, final QName qname, final SchemaPath path) {
+        checkNotSealed();
         Builder parent = getActualNode();
         if (!(parent.equals(this))) {
             throw new YangParseException(name, line, "rpc can be defined only in module or submodule");
@@ -584,6 +595,7 @@ public class ModuleBuilder extends AbstractDocumentedDataNodeContainerBuilder im
     }
 
     public ContainerSchemaNodeBuilder addRpcInput(final int line, final QName qname, final SchemaPath schemaPath) {
+        checkNotSealed();
         final Builder parent = getActualNode();
         if (!(parent instanceof RpcDefinitionBuilder)) {
             throw new YangParseException(name, line, "input can be defined only in rpc statement");
@@ -598,6 +610,7 @@ public class ModuleBuilder extends AbstractDocumentedDataNodeContainerBuilder im
     }
 
     public ContainerSchemaNodeBuilder addRpcOutput(final SchemaPath schemaPath, final QName qname, final int line) {
+        checkNotSealed();
         final Builder parent = getActualNode();
         if (!(parent instanceof RpcDefinitionBuilder)) {
             throw new YangParseException(name, line, "output can be defined only in rpc statement");
@@ -612,10 +625,12 @@ public class ModuleBuilder extends AbstractDocumentedDataNodeContainerBuilder im
     }
 
     public void addNotification(final NotificationDefinition notification) {
+        checkNotSealed();
         notifications.add(notification);
     }
 
     public NotificationBuilder addNotification(final int line, final QName qname, final SchemaPath path) {
+        checkNotSealed();
         final Builder parent = getActualNode();
         if (!(parent.equals(this))) {
             throw new YangParseException(name, line, "notification can be defined only in module or submodule");
@@ -690,9 +705,6 @@ public class ModuleBuilder extends AbstractDocumentedDataNodeContainerBuilder im
         return builder;
     }
 
-
-
-
     @Override
     public void addTypedef(final TypeDefinitionBuilder typedefBuilder) {
         String nodeName = typedefBuilder.getQName().getLocalName();
@@ -864,249 +876,6 @@ public class ModuleBuilder extends AbstractDocumentedDataNodeContainerBuilder im
         this.source = source;
     }
 
-    public static final class ModuleImpl extends AbstractDocumentedDataNodeContainer implements Module {
-        private final URI namespace;
-        private final String name;
-        private final String sourcePath;
-        private final Date revision;
-        private final String prefix;
-        private final String yangVersion;
-        private final String organization;
-        private final String contact;
-        private final Set<ModuleImport> imports;
-        private final Set<FeatureDefinition> features = new TreeSet<>(Comparators.SCHEMA_NODE_COMP);
-        private final Set<NotificationDefinition> notifications = new TreeSet<>(Comparators.SCHEMA_NODE_COMP);
-        private final Set<AugmentationSchema> augmentations = new HashSet<>();
-        private final Set<RpcDefinition> rpcs = new TreeSet<>(Comparators.SCHEMA_NODE_COMP);
-        private final Set<Deviation> deviations = new HashSet<>();
-        private final List<ExtensionDefinition> extensionNodes = new ArrayList<>();
-        private final Set<IdentitySchemaNode> identities = new TreeSet<>(Comparators.SCHEMA_NODE_COMP);
-        private final List<UnknownSchemaNode> unknownNodes = new ArrayList<>();
-        private String source;
-
-        private ModuleImpl(final String name, final String sourcePath, final ModuleBuilder builder) {
-            super(builder);
-            this.name = name;
-            this.sourcePath = sourcePath;
-            this.imports = ImmutableSet.<ModuleImport>copyOf(builder.imports);
-            this.namespace = builder.getNamespace();
-            this.prefix = builder.getPrefix();
-            this.revision = builder.getRevision();
-            this.yangVersion = builder.getYangVersion();
-            this.organization = builder.getOrganization();
-            this.contact = builder.getContact();
-        }
-
-        @Override
-        public String getModuleSourcePath() {
-            return sourcePath;
-        }
-
-        @Override
-        public URI getNamespace() {
-            return namespace;
-        }
-
-        @Override
-        public String getName() {
-            return name;
-        }
-
-        @Override
-        public Date getRevision() {
-            return revision;
-        }
-
-        @Override
-        public String getPrefix() {
-            return prefix;
-        }
-
-        @Override
-        public String getYangVersion() {
-            return yangVersion;
-        }
-
-        @Override
-        public String getOrganization() {
-            return organization;
-        }
-
-        @Override
-        public String getContact() {
-            return contact;
-        }
-
-        @Override
-        public Set<ModuleImport> getImports() {
-            return imports;
-        }
-
-        @Override
-        public Set<FeatureDefinition> getFeatures() {
-            return features;
-        }
-
-        private void setFeatures(final Set<FeatureDefinition> features) {
-            if (features != null) {
-                this.features.addAll(features);
-            }
-        }
-
-        @Override
-        public Set<NotificationDefinition> getNotifications() {
-            return notifications;
-        }
-
-        private void setNotifications(final Set<NotificationDefinition> notifications) {
-            if (notifications != null) {
-                this.notifications.addAll(notifications);
-            }
-        }
-
-        @Override
-        public Set<AugmentationSchema> getAugmentations() {
-            return augmentations;
-        }
-
-        private void setAugmentations(final Set<AugmentationSchema> augmentations) {
-            if (augmentations != null) {
-                this.augmentations.addAll(augmentations);
-            }
-        }
-
-        @Override
-        public Set<RpcDefinition> getRpcs() {
-            return rpcs;
-        }
-
-        private void setRpcs(final Set<RpcDefinition> rpcs) {
-            if (rpcs != null) {
-                this.rpcs.addAll(rpcs);
-            }
-        }
-
-        @Override
-        public Set<Deviation> getDeviations() {
-            return deviations;
-        }
-
-        private void setDeviations(final Set<Deviation> deviations) {
-            if (deviations != null) {
-                this.deviations.addAll(deviations);
-            }
-        }
-
-        @Override
-        public List<ExtensionDefinition> getExtensionSchemaNodes() {
-            Collections.sort(extensionNodes, Comparators.SCHEMA_NODE_COMP);
-            return extensionNodes;
-        }
-
-        private void setExtensionSchemaNodes(final List<ExtensionDefinition> extensionNodes) {
-            if (extensionNodes != null) {
-                this.extensionNodes.addAll(extensionNodes);
-            }
-        }
-
-        @Override
-        public Set<IdentitySchemaNode> getIdentities() {
-            return identities;
-        }
-
-        private void setIdentities(final Set<IdentitySchemaNode> identities) {
-            if (identities != null) {
-                this.identities.addAll(identities);
-            }
-        }
-
-        @Override
-        public List<UnknownSchemaNode> getUnknownSchemaNodes() {
-            return unknownNodes;
-        }
-
-        private void setUnknownSchemaNodes(final List<UnknownSchemaNode> unknownNodes) {
-            if (unknownNodes != null) {
-                this.unknownNodes.addAll(unknownNodes);
-            }
-        }
-
-        void setSource(final String source) {
-            this.source = source;
-        }
-
-        public String getSource() {
-            return source;
-        }
-
-        @Override
-        public int hashCode() {
-            final int prime = 31;
-            int result = 1;
-            result = prime * result + ((namespace == null) ? 0 : namespace.hashCode());
-            result = prime * result + ((name == null) ? 0 : name.hashCode());
-            result = prime * result + ((revision == null) ? 0 : revision.hashCode());
-            result = prime * result + ((yangVersion == null) ? 0 : yangVersion.hashCode());
-            return result;
-        }
-
-        @Override
-        public boolean equals(final Object obj) {
-            if (this == obj) {
-                return true;
-            }
-            if (obj == null) {
-                return false;
-            }
-            if (getClass() != obj.getClass()) {
-                return false;
-            }
-            ModuleImpl other = (ModuleImpl) obj;
-            if (namespace == null) {
-                if (other.namespace != null) {
-                    return false;
-                }
-            } else if (!namespace.equals(other.namespace)) {
-                return false;
-            }
-            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;
-            }
-            if (yangVersion == null) {
-                if (other.yangVersion != null) {
-                    return false;
-                }
-            } else if (!yangVersion.equals(other.yangVersion)) {
-                return false;
-            }
-            return true;
-        }
-
-        @Override
-        public String toString() {
-            StringBuilder sb = new StringBuilder(ModuleImpl.class.getSimpleName());
-            sb.append("[");
-            sb.append("name=" + name);
-            sb.append(", namespace=" + namespace);
-            sb.append(", revision=" + revision);
-            sb.append(", prefix=" + prefix);
-            sb.append(", yangVersion=" + yangVersion);
-            sb.append("]");
-            return sb.toString();
-        }
-    }
-
     /**
      * Add child to parent. Method checks for duplicates and add given child
      * node to parent. If node with same name is found, throws exception. If
@@ -1293,4 +1062,8 @@ public class ModuleBuilder extends AbstractDocumentedDataNodeContainerBuilder im
         }
         return true;
     }
+
+    public List<UnknownSchemaNode> getExtensionInstances() {
+        return unknownNodes;
+    }
 }
diff --git a/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/builder/impl/ModuleImpl.java b/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/builder/impl/ModuleImpl.java
new file mode 100644 (file)
index 0000000..7adca41
--- /dev/null
@@ -0,0 +1,247 @@
+package org.opendaylight.yangtools.yang.parser.builder.impl;
+
+import com.google.common.base.Optional;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableSet;
+import java.net.URI;
+import java.util.Collections;
+import java.util.Date;
+import java.util.List;
+import java.util.Set;
+import java.util.TreeSet;
+import org.opendaylight.yangtools.concepts.Immutable;
+import org.opendaylight.yangtools.yang.model.api.AugmentationSchema;
+import org.opendaylight.yangtools.yang.model.api.Deviation;
+import org.opendaylight.yangtools.yang.model.api.ExtensionDefinition;
+import org.opendaylight.yangtools.yang.model.api.FeatureDefinition;
+import org.opendaylight.yangtools.yang.model.api.IdentitySchemaNode;
+import org.opendaylight.yangtools.yang.model.api.Module;
+import org.opendaylight.yangtools.yang.model.api.ModuleImport;
+import org.opendaylight.yangtools.yang.model.api.NotificationDefinition;
+import org.opendaylight.yangtools.yang.model.api.RpcDefinition;
+import org.opendaylight.yangtools.yang.model.api.SchemaNode;
+import org.opendaylight.yangtools.yang.model.api.UnknownSchemaNode;
+import org.opendaylight.yangtools.yang.parser.builder.util.AbstractDocumentedDataNodeContainer;
+import org.opendaylight.yangtools.yang.parser.builder.util.Comparators;
+
+public final class ModuleImpl extends AbstractDocumentedDataNodeContainer implements Module, Immutable {
+
+    private final URI namespace;
+    private final String name;
+    private final String sourcePath;
+    private final Optional<Date> revision;
+    private final String prefix;
+    private final String yangVersion;
+    private final String organization;
+    private final String contact;
+    private final Set<ModuleImport> imports;
+    private final Set<FeatureDefinition> features;
+    private final Set<NotificationDefinition> notifications;
+    private final Set<AugmentationSchema> augmentations;
+    private final Set<RpcDefinition> rpcs;
+    private final Set<Deviation> deviations;
+    private final List<ExtensionDefinition> extensionNodes;
+    private final Set<IdentitySchemaNode> identities;
+    private final List<UnknownSchemaNode> unknownNodes;
+    private final String source;
+
+    /**
+     *
+     *
+     * <b>Note</b>Constructor has intentionality limited visibility to package, since
+     * this class should be only instantied via builders.
+     *
+     * @param name
+     * @param sourcePath
+     * @param builder
+     */
+    ModuleImpl(final String name, final String sourcePath, final ModuleBuilder builder) {
+        super(builder);
+        this.name = name;
+        this.sourcePath = sourcePath;
+        this.imports = ImmutableSet.<ModuleImport> copyOf(builder.imports);
+        this.namespace = builder.getNamespace();
+        this.prefix = builder.getPrefix();
+        this.revision = builder.getRevision() == null ? Optional.<Date>absent():
+                Optional.of(new Date(builder.getRevision().getTime()));
+        this.yangVersion = builder.getYangVersion();
+        this.organization = builder.getOrganization();
+        this.contact = builder.getContact();
+        this.features = toImmutableSortedSet(builder.getFeatures());
+        this.notifications = toImmutableSortedSet(builder.getNotifications());
+        this.augmentations = ImmutableSet.copyOf(builder.getAugments());
+        this.rpcs = toImmutableSortedSet(builder.getRpcs());
+        this.deviations = ImmutableSet.copyOf(builder.getDeviations());
+        this.extensionNodes = ImmutableList.copyOf(builder.getExtensions());
+        this.identities = ImmutableSet.copyOf(builder.getIdentities());
+        this.unknownNodes = ImmutableList.copyOf(builder.getExtensionInstances());
+        this.source = builder.source;
+
+    }
+
+    @Override
+    public String getModuleSourcePath() {
+        return sourcePath;
+    }
+
+    @Override
+    public URI getNamespace() {
+        return namespace;
+    }
+
+    @Override
+    public String getName() {
+        return name;
+    }
+
+    @Override
+    public Date getRevision() {
+        if (revision.isPresent()) {
+            return new Date(revision.get().getTime());
+        } else {
+            return null;
+        }
+    }
+
+    @Override
+    public String getPrefix() {
+        return prefix;
+    }
+
+    @Override
+    public String getYangVersion() {
+        return yangVersion;
+    }
+
+    @Override
+    public String getOrganization() {
+        return organization;
+    }
+
+    @Override
+    public String getContact() {
+        return contact;
+    }
+
+    @Override
+    public Set<ModuleImport> getImports() {
+        return imports;
+    }
+
+    @Override
+    public Set<FeatureDefinition> getFeatures() {
+        return features;
+    }
+
+    @Override
+    public Set<NotificationDefinition> getNotifications() {
+        return notifications;
+    }
+
+    @Override
+    public Set<AugmentationSchema> getAugmentations() {
+        return augmentations;
+    }
+
+    @Override
+    public Set<RpcDefinition> getRpcs() {
+        return rpcs;
+    }
+
+    @Override
+    public Set<Deviation> getDeviations() {
+        return deviations;
+    }
+
+    @Override
+    public List<ExtensionDefinition> getExtensionSchemaNodes() {
+        return extensionNodes;
+    }
+
+    @Override
+    public Set<IdentitySchemaNode> getIdentities() {
+        return identities;
+    }
+
+    @Override
+    public List<UnknownSchemaNode> getUnknownSchemaNodes() {
+        return unknownNodes;
+    }
+
+    public String getSource() {
+        return source;
+    }
+
+    @Override
+    public int hashCode() {
+        final int prime = 31;
+        int result = 1;
+        result = prime * result + ((namespace == null) ? 0 : namespace.hashCode());
+        result = prime * result + ((name == null) ? 0 : name.hashCode());
+        result = prime * result + ((revision == null) ? 0 : revision.hashCode());
+        result = prime * result + ((yangVersion == null) ? 0 : yangVersion.hashCode());
+        return result;
+    }
+
+    @Override
+    public boolean equals(final Object obj) {
+        if (this == obj) {
+            return true;
+        }
+        if (obj == null) {
+            return false;
+        }
+        if (getClass() != obj.getClass()) {
+            return false;
+        }
+        ModuleImpl other = (ModuleImpl) obj;
+        if (namespace == null) {
+            if (other.namespace != null) {
+                return false;
+            }
+        } else if (!namespace.equals(other.namespace)) {
+            return false;
+        }
+        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;
+        }
+        if (yangVersion == null) {
+            if (other.yangVersion != null) {
+                return false;
+            }
+        } else if (!yangVersion.equals(other.yangVersion)) {
+            return false;
+        }
+        return true;
+    }
+
+    private static <T extends SchemaNode> Set<T> toImmutableSortedSet(final Set<T> original) {
+        TreeSet<T> sorted = new TreeSet<>(Comparators.SCHEMA_NODE_COMP);
+        sorted.addAll(original);
+        return Collections.unmodifiableSet(sorted);
+    }
+
+    @Override
+    public String toString() {
+        StringBuilder sb = new StringBuilder(ModuleImpl.class.getSimpleName());
+        sb.append("[");
+        sb.append("name=" + name);
+        sb.append(", namespace=" + namespace);
+        sb.append(", revision=" + revision);
+        sb.append(", prefix=" + prefix);
+        sb.append(", yangVersion=" + yangVersion);
+        sb.append("]");
+        return sb.toString();
+    }
+}
\ No newline at end of file
index b24d77326666e23db4c26f6b365fe87837debccd..c5071762f15dd81b9acc048c8825f83e224a7295 100644 (file)
@@ -7,11 +7,12 @@
  */
 package org.opendaylight.yangtools.yang.parser.builder.impl;
 
-import java.lang.reflect.Method;
 import java.util.List;
 
 import org.opendaylight.yangtools.yang.model.api.MustDefinition;
 import org.opendaylight.yangtools.yang.parser.builder.api.Builder;
+import org.opendaylight.yangtools.yang.parser.builder.api.DataSchemaNodeBuilder;
+import org.opendaylight.yangtools.yang.parser.builder.api.DocumentedNodeBuilder;
 import org.opendaylight.yangtools.yang.parser.builder.api.GroupingBuilder;
 import org.opendaylight.yangtools.yang.parser.builder.api.RefineBuilder;
 import org.opendaylight.yangtools.yang.parser.builder.api.SchemaNodeBuilder;
@@ -260,33 +261,41 @@ public final class RefineUtils {
         final int line = refine.getLine();
         Class<? extends Builder> cls = node.getClass();
 
+
+        final DocumentedNodeBuilder documentedNode;
+        if(node instanceof DocumentedNodeBuilder) {
+            documentedNode = ((DocumentedNodeBuilder) node);
+        } else {
+            documentedNode = null;
+        }
+
         String description = refine.getDescription();
+
+
         if (description != null) {
-            try {
-                Method method = cls.getMethod("setDescription", String.class);
-                method.invoke(node, description);
-            } catch (Exception e) {
-                throw new YangParseException(moduleName, line, "Cannot refine description in " + cls.getName(), e);
+            if(documentedNode != null) {
+                documentedNode.setDescription(description);
+            } else {
+                throw new YangParseException(moduleName, line, String.format("Cannot refine description in of target %s",refine.getTargetPathString()));
             }
+
         }
 
         String reference = refine.getReference();
         if (reference != null) {
-            try {
-                Method method = cls.getMethod("setReference", String.class);
-                method.invoke(node, reference);
-            } catch (Exception e) {
-                throw new YangParseException(moduleName, line, "Cannot refine reference in " + cls.getName(), e);
+            if(documentedNode != null) {
+                documentedNode.setReference(reference);
+            } else {
+                throw new YangParseException(moduleName, line, String.format("Cannot refine reference in of target %s",refine.getTargetPathString()));
             }
         }
 
         Boolean config = refine.isConfiguration();
         if (config != null) {
-            try {
-                Method method = cls.getMethod("setConfiguration", Boolean.TYPE);
-                method.invoke(node, config);
-            } catch (Exception e) {
-                throw new YangParseException(moduleName, line, "Cannot refine config in " + cls.getName(), e);
+            if(node instanceof DataSchemaNodeBuilder) {
+                ((DataSchemaNodeBuilder) node).setConfiguration(config);
+            } else {
+                throw new YangParseException(moduleName, line, String.format("Cannot refine config of target %s ",refine.getTargetPathString()));
             }
         }
     }
index 35b869be6bf9f9f13827a8db6b8e067f1a798a97..5063b7f49a1a05888df56c19a00a71d7941ddde8 100644 (file)
@@ -27,6 +27,7 @@ public abstract class AbstractBuilder implements Builder {
 
     protected final List<UnknownSchemaNode> unknownNodes = new ArrayList<>();
     protected final List<UnknownSchemaNodeBuilder> addedUnknownNodes = new ArrayList<UnknownSchemaNodeBuilder>();
+    private boolean sealed;
 
     protected AbstractBuilder(final String moduleName, final int line) {
         this.moduleName = Preconditions.checkNotNull(moduleName,"moduleName must not be null");
@@ -56,6 +57,7 @@ public abstract class AbstractBuilder implements Builder {
 
     @Override
     public void setParent(final Builder parentBuilder) {
+        checkNotSealed();
         this.parentBuilder = parentBuilder;
     }
 
@@ -69,4 +71,17 @@ public abstract class AbstractBuilder implements Builder {
         addedUnknownNodes.add(unknownNode);
     }
 
+    protected void seal() {
+        checkNotSealed();
+        sealed  = true;
+    }
+
+    protected final void checkNotSealed() {
+        Preconditions.checkState(!sealed, "Builder is sealed. No further modifications allowed");
+    }
+
+    protected boolean isSealed() {
+        return sealed;
+    }
+
 }
index 72468cfe255058a04bca9a0c36aadfaab31a9db7..1c5022368a9e065a1cbea68c0aec2c4e1bd4f320 100644 (file)
@@ -116,6 +116,7 @@ public abstract class AbstractDocumentedDataNodeContainerBuilder extends Abstrac
 
     @Override
     public final void addChildNode(final DataSchemaNode child) {
+        checkNotSealed();
         QName childName = child.getQName();
         for (DataSchemaNode childNode : childNodes.values()) {
             if (childNode.getQName().equals(childName)) {
@@ -139,6 +140,7 @@ public abstract class AbstractDocumentedDataNodeContainerBuilder extends Abstrac
 
     @Override
     public final void addGrouping(final GroupingBuilder grouping) {
+        checkNotSealed();
         QName groupingName = grouping.getQName();
         for (GroupingBuilder addedGrouping : addedGroupings) {
             if (addedGrouping.getQName().equals(groupingName)) {
@@ -166,6 +168,7 @@ public abstract class AbstractDocumentedDataNodeContainerBuilder extends Abstrac
 
     @Override
     public final void addUsesNode(final UsesNodeBuilder usesNode) {
+        checkNotSealed();
         addedUsesNodes.add(usesNode);
     }
 
@@ -177,6 +180,7 @@ public abstract class AbstractDocumentedDataNodeContainerBuilder extends Abstrac
 
     @Override
     public void addTypedef(final TypeDefinitionBuilder type) {
+        checkNotSealed();
         String typeName = type.getQName().getLocalName();
         for (TypeDefinitionBuilder addedTypedef : addedTypedefs) {
             if (addedTypedef.getQName().getLocalName().equals(typeName)) {
@@ -190,6 +194,9 @@ public abstract class AbstractDocumentedDataNodeContainerBuilder extends Abstrac
     protected abstract String getStatementName();
 
     protected void buildChildren() {
+        checkNotSealed();
+        seal();
+
         for (DataSchemaNodeBuilder node : addedChildNodes) {
             childNodes.put(node.getQName(), node.build());
         }
index f779e6006a9d3a791ac38f72cb539d026956c3b1..807b70037036ba1ab7b2a0991fb00366743932ac 100644 (file)
@@ -2,7 +2,8 @@ package org.opendaylight.yangtools.yang.parser.builder.util;
 
 import org.opendaylight.yangtools.yang.model.api.DocumentedNode;
 import org.opendaylight.yangtools.yang.model.api.Status;
-import org.opendaylight.yangtools.yang.parser.builder.api.DocumentedNodeBuilder;
+
+import com.google.common.base.Preconditions;
 
 public abstract class AbstractDocumentedNode implements DocumentedNode {
 
@@ -10,7 +11,8 @@ public abstract class AbstractDocumentedNode implements DocumentedNode {
     private final String reference;
     private final Status status;
 
-    protected AbstractDocumentedNode(final DocumentedNodeBuilder builder) {
+    protected AbstractDocumentedNode(final AbstractDocumentedNodeBuilder builder) {
+        Preconditions.checkArgument(builder.isSealed(), "Builder must be sealed.");
         this.description = builder.getDescription();
         this.reference = builder.getReference();
         this.status = builder.getStatus();
index 2f8dcf64fc4113e297a67100de615accacb7cd46..ee8ef76994885b6ef19dedc1fd8d160e9848b327 100644 (file)
@@ -83,7 +83,7 @@ import org.opendaylight.yangtools.yang.parser.builder.impl.GroupingUtils;
 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.ModuleBuilder.ModuleImpl;
+import org.opendaylight.yangtools.yang.parser.builder.impl.ModuleImpl;
 import org.opendaylight.yangtools.yang.parser.builder.impl.UnionTypeBuilder;
 import org.opendaylight.yangtools.yang.parser.builder.impl.UnknownSchemaNodeBuilderImpl;
 import org.opendaylight.yangtools.yang.parser.builder.util.Comparators;