Bug 6867: Extend yang statement parser to support different yang versions
[yangtools.git] / yang / yang-parser-impl / src / main / java / org / opendaylight / yangtools / yang / parser / spi / meta / StatementSupportBundle.java
index badd2b6bccd7b1f728748a2f236df79003d796cf..3d9c9375f92b03c265049ede136da8ecf30e2e3c 100644 (file)
@@ -8,48 +8,95 @@
 package org.opendaylight.yangtools.yang.parser.spi.meta;
 
 import com.google.common.base.Preconditions;
+import com.google.common.collect.HashBasedTable;
 import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.ImmutableSet;
+import com.google.common.collect.ImmutableTable;
+import com.google.common.collect.Table;
 import java.util.HashMap;
 import java.util.Map;
+import java.util.Set;
 import org.opendaylight.yangtools.concepts.Immutable;
 import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.common.YangVersion;
 import org.opendaylight.yangtools.yang.model.api.meta.IdentifierNamespace;
 
-public final class StatementSupportBundle implements Immutable,NamespaceBehaviour.Registry {
+public final class StatementSupportBundle implements Immutable, NamespaceBehaviour.Registry {
 
-    private static final StatementSupportBundle EMPTY = new StatementSupportBundle(null, ImmutableMap.of(), ImmutableMap.of());
+    private static final StatementSupportBundle EMPTY = new StatementSupportBundle(null, null, ImmutableMap.of(),
+            ImmutableMap.of(), ImmutableTable.of());
 
     private final StatementSupportBundle parent;
-    private final ImmutableMap<QName, StatementSupport<?,?,?>> definitions;
+    private final ImmutableMap<QName, StatementSupport<?, ?, ?>> commonDefinitions;
+    private final ImmutableTable<YangVersion, QName, StatementSupport<?, ?, ?>> versionSpecificDefinitions;
     private final ImmutableMap<Class<?>, NamespaceBehaviour<?, ?, ?>> namespaceDefinitions;
+    private final Set<YangVersion> supportedVersions;
 
     private StatementSupportBundle(final StatementSupportBundle parent,
-                                   final ImmutableMap<QName, StatementSupport<?, ?, ?>> statements,
-                                   final ImmutableMap<Class<?>, NamespaceBehaviour<?, ?, ?>> namespaces) {
+            final Set<YangVersion> supportedVersions,
+            final ImmutableMap<QName, StatementSupport<?, ?, ?>> commonStatements,
+            final ImmutableMap<Class<?>, NamespaceBehaviour<?, ?, ?>> namespaces,
+            final ImmutableTable<YangVersion, QName, StatementSupport<?, ?, ?>> versionSpecificStatements) {
         this.parent = parent;
-        this.definitions = statements;
+        this.supportedVersions = supportedVersions;
+        this.commonDefinitions = commonStatements;
         this.namespaceDefinitions = namespaces;
+        this.versionSpecificDefinitions = versionSpecificStatements;
     }
 
-    public ImmutableMap<QName, StatementSupport<?, ?, ?>> getDefinitions() {
-        return definitions;
+    /**
+     * Returns statement definitions common for all versions
+     *
+     * @return map of common statement definitions
+     */
+    public ImmutableMap<QName, StatementSupport<?, ?, ?>> getCommonDefinitions() {
+        return commonDefinitions;
+    }
+
+    /**
+     * Returns statement definitions specific for requested version. Result of
+     * this method doesn't include common statement definitions.
+     *
+     * @param version
+     *            requested version
+     * @return map of statement definitions specific for requested version, it
+     *         doesn't include common statement definitions.
+     */
+    public ImmutableMap<QName, StatementSupport<?, ?, ?>> getDefinitionsSpecificForVersion(final YangVersion version) {
+        return versionSpecificDefinitions.row(version);
+    }
+
+    /**
+     * Returns all version specific statement definitions. Result of this method
+     * doesn't include common statement definitions.
+     *
+     * @return table of all version specific statement definitions, it doesn't
+     *         include common statement definitions.
+     */
+    public ImmutableTable<YangVersion, QName, StatementSupport<?, ?, ?>> getAllVersionSpecificDefinitions() {
+        return versionSpecificDefinitions;
     }
 
     public ImmutableMap<Class<?>, NamespaceBehaviour<?, ?, ?>> getNamespaceDefinitions() {
         return namespaceDefinitions;
     }
 
-    public static Builder builder() {
-        return new Builder(EMPTY);
+    public static Builder builder(final Set<YangVersion> supportedVersions) {
+        return new Builder(supportedVersions, EMPTY);
     }
 
     public static Builder derivedFrom(final StatementSupportBundle parent) {
-        return new Builder(parent);
+        Preconditions.checkNotNull(parent);
+        return new Builder(parent.getSupportedVersions(), parent);
+    }
+
+    public Set<YangVersion> getSupportedVersions() {
+        return supportedVersions;
     }
 
     @Override
-    public <K, V, N extends IdentifierNamespace<K, V>> NamespaceBehaviour<K, V, N> getNamespaceBehaviour(final Class<N> namespace)
-            throws NamespaceNotAvailableException {
+    public <K, V, N extends IdentifierNamespace<K, V>> NamespaceBehaviour<K, V, N> getNamespaceBehaviour(
+            final Class<N> namespace) throws NamespaceNotAvailableException {
         final NamespaceBehaviour<?, ?, ?> potential = namespaceDefinitions.get(namespace);
         if (potential != null) {
             Preconditions.checkState(namespace.equals(potential.getIdentifier()));
@@ -76,33 +123,79 @@ public final class StatementSupportBundle implements Immutable,NamespaceBehaviou
         return false;
     }
 
-    public StatementSupport<?, ?,?> getStatementDefinition(final QName stmtName) {
-        final StatementSupport<?,?, ?> potential = definitions.get(stmtName);
+    public StatementSupport<?, ?, ?> getStatementDefinition(final YangVersion version, final QName stmtName) {
+        StatementSupport<?, ?, ?> result = getVersionSpecificStatementDefinition(version, stmtName);
+        if (result == null) {
+            result = getCommonStatementDefinition(stmtName);
+        }
+
+        return result;
+    }
+
+    private StatementSupport<?, ?, ?> getCommonStatementDefinition(final QName stmtName) {
+        final StatementSupport<?, ?, ?> potential = commonDefinitions.get(stmtName);
+        if (potential != null) {
+            return potential;
+        }
+        if (parent != null) {
+            return parent.getCommonStatementDefinition(stmtName);
+        }
+        return null;
+    }
+
+    private StatementSupport<?, ?, ?> getVersionSpecificStatementDefinition(final YangVersion version,
+            final QName stmtName) {
+        final StatementSupport<?, ?, ?> potential = versionSpecificDefinitions.get(version, stmtName);
         if (potential != null) {
             return potential;
         }
+
         if (parent != null) {
-            return parent.getStatementDefinition(stmtName);
+            return parent.getVersionSpecificStatementDefinition(version, stmtName);
         }
         return null;
     }
 
     public static class Builder implements org.opendaylight.yangtools.concepts.Builder<StatementSupportBundle> {
-        private final Map<QName, StatementSupport<?, ?, ?>> statements = new HashMap<>();
+        private final Map<QName, StatementSupport<?, ?, ?>> commonStatements = new HashMap<>();
+        private final Table<YangVersion, QName, StatementSupport<?, ?, ?>> versionSpecificStatements = HashBasedTable
+                .create();
         private final Map<Class<?>, NamespaceBehaviour<?, ?, ?>> namespaces = new HashMap<>();
 
+        private final Set<YangVersion> supportedVersions;
         private StatementSupportBundle parent;
 
-        Builder(final StatementSupportBundle parent) {
-            this.parent = parent;
+        Builder(final Set<YangVersion> supportedVersions, final StatementSupportBundle parent) {
+            this.parent = Preconditions.checkNotNull(parent);
+            this.supportedVersions = ImmutableSet.copyOf(supportedVersions);
         }
 
         public Builder addSupport(final StatementSupport<?, ?, ?> definition) {
             final QName identifier = definition.getStatementName();
-            Preconditions.checkState(!statements.containsKey(identifier), "Statement %s already defined.", identifier);
-            Preconditions.checkState(parent.getStatementDefinition(identifier) == null,
+            Preconditions.checkState(!commonStatements.containsKey(identifier),
+                    "Statement %s already defined in common statement bundle.", identifier);
+            Preconditions.checkState(parent.getCommonStatementDefinition(identifier) == null,
                     "Statement %s already defined.", identifier);
-            statements.put(identifier, definition);
+            commonStatements.put(identifier, definition);
+            return this;
+        }
+
+        public Builder addVersionSpecificSupport(final YangVersion version,
+                final StatementSupport<?, ?, ?> definition) {
+            Preconditions.checkNotNull(version);
+            Preconditions.checkNotNull(definition);
+            Preconditions.checkArgument(supportedVersions.contains(version));
+
+            final QName identifier = definition.getStatementName();
+            Preconditions.checkState(!commonStatements.containsKey(identifier),
+                    "Statement %s already defined in common statement bundle.", identifier);
+            Preconditions.checkState(!versionSpecificStatements.contains(version, identifier),
+                    "Statement %s already defined for version %s.", identifier, version);
+            Preconditions.checkState(parent.getCommonStatementDefinition(identifier) == null,
+                    "Statement %s already defined in parent's common statement bundle.", identifier);
+            Preconditions.checkState(parent.getVersionSpecificStatementDefinition(version, identifier) == null,
+                    "Statement %s already defined for version %s in parent's statement bundle.", identifier, version);
+            versionSpecificStatements.put(version, identifier, definition);
             return this;
         }
 
@@ -115,6 +208,10 @@ public final class StatementSupportBundle implements Immutable,NamespaceBehaviou
             return this;
         }
 
+        public Set<YangVersion> getSupportedVersions() {
+            return supportedVersions;
+        }
+
         public Builder setParent(final StatementSupportBundle parent) {
             this.parent = parent;
             return this;
@@ -122,8 +219,9 @@ public final class StatementSupportBundle implements Immutable,NamespaceBehaviou
 
         @Override
         public StatementSupportBundle build() {
-            return new StatementSupportBundle(parent, ImmutableMap.copyOf(statements), ImmutableMap.copyOf(namespaces));
+            Preconditions.checkState(parent != null, "Parent must not be null");
+            return new StatementSupportBundle(parent, supportedVersions, ImmutableMap.copyOf(commonStatements),
+                    ImmutableMap.copyOf(namespaces), ImmutableTable.copyOf(versionSpecificStatements));
         }
     }
-
 }