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
1 /*
2  * Copyright (c) 2015 Cisco Systems, Inc. and others.  All rights reserved.
3  *
4  * This program and the accompanying materials are made available under the
5  * terms of the Eclipse Public License v1.0 which accompanies this distribution,
6  * and is available at http://www.eclipse.org/legal/epl-v10.html
7  */
8 package org.opendaylight.yangtools.yang.parser.spi.meta;
9
10 import com.google.common.base.Preconditions;
11 import com.google.common.collect.HashBasedTable;
12 import com.google.common.collect.ImmutableMap;
13 import com.google.common.collect.ImmutableSet;
14 import com.google.common.collect.ImmutableTable;
15 import com.google.common.collect.Table;
16 import java.util.HashMap;
17 import java.util.Map;
18 import java.util.Set;
19 import org.opendaylight.yangtools.concepts.Immutable;
20 import org.opendaylight.yangtools.yang.common.QName;
21 import org.opendaylight.yangtools.yang.common.YangVersion;
22 import org.opendaylight.yangtools.yang.model.api.meta.IdentifierNamespace;
23
24 public final class StatementSupportBundle implements Immutable, NamespaceBehaviour.Registry {
25
26     private static final StatementSupportBundle EMPTY = new StatementSupportBundle(null, null, ImmutableMap.of(),
27             ImmutableMap.of(), ImmutableTable.of());
28
29     private final StatementSupportBundle parent;
30     private final ImmutableMap<QName, StatementSupport<?, ?, ?>> commonDefinitions;
31     private final ImmutableTable<YangVersion, QName, StatementSupport<?, ?, ?>> versionSpecificDefinitions;
32     private final ImmutableMap<Class<?>, NamespaceBehaviour<?, ?, ?>> namespaceDefinitions;
33     private final Set<YangVersion> supportedVersions;
34
35     private StatementSupportBundle(final StatementSupportBundle parent,
36             final Set<YangVersion> supportedVersions,
37             final ImmutableMap<QName, StatementSupport<?, ?, ?>> commonStatements,
38             final ImmutableMap<Class<?>, NamespaceBehaviour<?, ?, ?>> namespaces,
39             final ImmutableTable<YangVersion, QName, StatementSupport<?, ?, ?>> versionSpecificStatements) {
40         this.parent = parent;
41         this.supportedVersions = supportedVersions;
42         this.commonDefinitions = commonStatements;
43         this.namespaceDefinitions = namespaces;
44         this.versionSpecificDefinitions = versionSpecificStatements;
45     }
46
47     /**
48      * Returns statement definitions common for all versions
49      *
50      * @return map of common statement definitions
51      */
52     public ImmutableMap<QName, StatementSupport<?, ?, ?>> getCommonDefinitions() {
53         return commonDefinitions;
54     }
55
56     /**
57      * Returns statement definitions specific for requested version. Result of
58      * this method doesn't include common statement definitions.
59      *
60      * @param version
61      *            requested version
62      * @return map of statement definitions specific for requested version, it
63      *         doesn't include common statement definitions.
64      */
65     public ImmutableMap<QName, StatementSupport<?, ?, ?>> getDefinitionsSpecificForVersion(final YangVersion version) {
66         return versionSpecificDefinitions.row(version);
67     }
68
69     /**
70      * Returns all version specific statement definitions. Result of this method
71      * doesn't include common statement definitions.
72      *
73      * @return table of all version specific statement definitions, it doesn't
74      *         include common statement definitions.
75      */
76     public ImmutableTable<YangVersion, QName, StatementSupport<?, ?, ?>> getAllVersionSpecificDefinitions() {
77         return versionSpecificDefinitions;
78     }
79
80     public ImmutableMap<Class<?>, NamespaceBehaviour<?, ?, ?>> getNamespaceDefinitions() {
81         return namespaceDefinitions;
82     }
83
84     public static Builder builder(final Set<YangVersion> supportedVersions) {
85         return new Builder(supportedVersions, EMPTY);
86     }
87
88     public static Builder derivedFrom(final StatementSupportBundle parent) {
89         Preconditions.checkNotNull(parent);
90         return new Builder(parent.getSupportedVersions(), parent);
91     }
92
93     public Set<YangVersion> getSupportedVersions() {
94         return supportedVersions;
95     }
96
97     @Override
98     public <K, V, N extends IdentifierNamespace<K, V>> NamespaceBehaviour<K, V, N> getNamespaceBehaviour(
99             final Class<N> namespace) throws NamespaceNotAvailableException {
100         final NamespaceBehaviour<?, ?, ?> potential = namespaceDefinitions.get(namespace);
101         if (potential != null) {
102             Preconditions.checkState(namespace.equals(potential.getIdentifier()));
103
104             /*
105              * Safe cast, previous checkState checks equivalence of key from
106              * which type argument are derived
107              */
108             return (NamespaceBehaviour<K, V, N>) potential;
109         }
110         if (parent != null) {
111             return parent.getNamespaceBehaviour(namespace);
112         }
113         return null;
114     }
115
116     public <K, V, N extends IdentifierNamespace<K, V>> boolean hasNamespaceBehaviour(final Class<N> namespace) {
117         if (namespaceDefinitions.containsKey(namespace)) {
118             return true;
119         }
120         if (parent != null) {
121             return parent.hasNamespaceBehaviour(namespace);
122         }
123         return false;
124     }
125
126     public StatementSupport<?, ?, ?> getStatementDefinition(final YangVersion version, final QName stmtName) {
127         StatementSupport<?, ?, ?> result = getVersionSpecificStatementDefinition(version, stmtName);
128         if (result == null) {
129             result = getCommonStatementDefinition(stmtName);
130         }
131
132         return result;
133     }
134
135     private StatementSupport<?, ?, ?> getCommonStatementDefinition(final QName stmtName) {
136         final StatementSupport<?, ?, ?> potential = commonDefinitions.get(stmtName);
137         if (potential != null) {
138             return potential;
139         }
140         if (parent != null) {
141             return parent.getCommonStatementDefinition(stmtName);
142         }
143         return null;
144     }
145
146     private StatementSupport<?, ?, ?> getVersionSpecificStatementDefinition(final YangVersion version,
147             final QName stmtName) {
148         final StatementSupport<?, ?, ?> potential = versionSpecificDefinitions.get(version, stmtName);
149         if (potential != null) {
150             return potential;
151         }
152
153         if (parent != null) {
154             return parent.getVersionSpecificStatementDefinition(version, stmtName);
155         }
156         return null;
157     }
158
159     public static class Builder implements org.opendaylight.yangtools.concepts.Builder<StatementSupportBundle> {
160         private final Map<QName, StatementSupport<?, ?, ?>> commonStatements = new HashMap<>();
161         private final Table<YangVersion, QName, StatementSupport<?, ?, ?>> versionSpecificStatements = HashBasedTable
162                 .create();
163         private final Map<Class<?>, NamespaceBehaviour<?, ?, ?>> namespaces = new HashMap<>();
164
165         private final Set<YangVersion> supportedVersions;
166         private StatementSupportBundle parent;
167
168         Builder(final Set<YangVersion> supportedVersions, final StatementSupportBundle parent) {
169             this.parent = Preconditions.checkNotNull(parent);
170             this.supportedVersions = ImmutableSet.copyOf(supportedVersions);
171         }
172
173         public Builder addSupport(final StatementSupport<?, ?, ?> definition) {
174             final QName identifier = definition.getStatementName();
175             Preconditions.checkState(!commonStatements.containsKey(identifier),
176                     "Statement %s already defined in common statement bundle.", identifier);
177             Preconditions.checkState(parent.getCommonStatementDefinition(identifier) == null,
178                     "Statement %s already defined.", identifier);
179             commonStatements.put(identifier, definition);
180             return this;
181         }
182
183         public Builder addVersionSpecificSupport(final YangVersion version,
184                 final StatementSupport<?, ?, ?> definition) {
185             Preconditions.checkNotNull(version);
186             Preconditions.checkNotNull(definition);
187             Preconditions.checkArgument(supportedVersions.contains(version));
188
189             final QName identifier = definition.getStatementName();
190             Preconditions.checkState(!commonStatements.containsKey(identifier),
191                     "Statement %s already defined in common statement bundle.", identifier);
192             Preconditions.checkState(!versionSpecificStatements.contains(version, identifier),
193                     "Statement %s already defined for version %s.", identifier, version);
194             Preconditions.checkState(parent.getCommonStatementDefinition(identifier) == null,
195                     "Statement %s already defined in parent's common statement bundle.", identifier);
196             Preconditions.checkState(parent.getVersionSpecificStatementDefinition(version, identifier) == null,
197                     "Statement %s already defined for version %s in parent's statement bundle.", identifier, version);
198             versionSpecificStatements.put(version, identifier, definition);
199             return this;
200         }
201
202         public <K, V, N extends IdentifierNamespace<K, V>> Builder addSupport(
203                 final NamespaceBehaviour<K, V, N> namespaceSupport) {
204             final Class<N> identifier = namespaceSupport.getIdentifier();
205             Preconditions.checkState(!namespaces.containsKey(identifier));
206             Preconditions.checkState(!parent.hasNamespaceBehaviour(identifier));
207             namespaces.put(identifier, namespaceSupport);
208             return this;
209         }
210
211         public Set<YangVersion> getSupportedVersions() {
212             return supportedVersions;
213         }
214
215         public Builder setParent(final StatementSupportBundle parent) {
216             this.parent = parent;
217             return this;
218         }
219
220         @Override
221         public StatementSupportBundle build() {
222             Preconditions.checkState(parent != null, "Parent must not be null");
223             return new StatementSupportBundle(parent, supportedVersions, ImmutableMap.copyOf(commonStatements),
224                     ImmutableMap.copyOf(namespaces), ImmutableTable.copyOf(versionSpecificStatements));
225         }
226     }
227 }