7fe7eb0b23bcc60ae5fa6b7256c2e8bc6da6f9bf
[yangtools.git] / yang / yang-parser-spi / 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 this method does nit include common
58      * 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 does not include common statement
71      * 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             // Safe cast, previous checkState checks equivalence of key from which type argument are derived
105             return (NamespaceBehaviour<K, V, N>) potential;
106         }
107         if (parent != null) {
108             return parent.getNamespaceBehaviour(namespace);
109         }
110         return null;
111     }
112
113     public <K, V, N extends IdentifierNamespace<K, V>> boolean hasNamespaceBehaviour(final Class<N> namespace) {
114         if (namespaceDefinitions.containsKey(namespace)) {
115             return true;
116         }
117         if (parent != null) {
118             return parent.hasNamespaceBehaviour(namespace);
119         }
120         return false;
121     }
122
123     public StatementSupport<?, ?, ?> getStatementDefinition(final YangVersion version, final QName stmtName) {
124         StatementSupport<?, ?, ?> result = getVersionSpecificStatementDefinition(version, stmtName);
125         if (result == null) {
126             result = getCommonStatementDefinition(stmtName);
127         }
128
129         return result;
130     }
131
132     private StatementSupport<?, ?, ?> getCommonStatementDefinition(final QName stmtName) {
133         final StatementSupport<?, ?, ?> potential = commonDefinitions.get(stmtName);
134         if (potential != null) {
135             return potential;
136         }
137         if (parent != null) {
138             return parent.getCommonStatementDefinition(stmtName);
139         }
140         return null;
141     }
142
143     private StatementSupport<?, ?, ?> getVersionSpecificStatementDefinition(final YangVersion version,
144             final QName stmtName) {
145         final StatementSupport<?, ?, ?> potential = versionSpecificDefinitions.get(version, stmtName);
146         if (potential != null) {
147             return potential;
148         }
149
150         if (parent != null) {
151             return parent.getVersionSpecificStatementDefinition(version, stmtName);
152         }
153         return null;
154     }
155
156     public static class Builder implements org.opendaylight.yangtools.concepts.Builder<StatementSupportBundle> {
157         private final Map<QName, StatementSupport<?, ?, ?>> commonStatements = new HashMap<>();
158         private final Table<YangVersion, QName, StatementSupport<?, ?, ?>> versionSpecificStatements = HashBasedTable
159                 .create();
160         private final Map<Class<?>, NamespaceBehaviour<?, ?, ?>> namespaces = new HashMap<>();
161
162         private final Set<YangVersion> supportedVersions;
163         private StatementSupportBundle parent;
164
165         Builder(final Set<YangVersion> supportedVersions, final StatementSupportBundle parent) {
166             this.parent = Preconditions.checkNotNull(parent);
167             this.supportedVersions = ImmutableSet.copyOf(supportedVersions);
168         }
169
170         public Builder addSupport(final StatementSupport<?, ?, ?> definition) {
171             final QName identifier = definition.getStatementName();
172             Preconditions.checkState(!commonStatements.containsKey(identifier),
173                     "Statement %s already defined in common statement bundle.", identifier);
174             Preconditions.checkState(parent.getCommonStatementDefinition(identifier) == null,
175                     "Statement %s already defined.", identifier);
176             commonStatements.put(identifier, definition);
177             return this;
178         }
179
180         public <K, V, N extends IdentifierNamespace<K, V>> Builder addSupport(
181                 final NamespaceBehaviour<K, V, N> namespaceSupport) {
182             final Class<N> identifier = namespaceSupport.getIdentifier();
183             Preconditions.checkState(!namespaces.containsKey(identifier));
184             Preconditions.checkState(!parent.hasNamespaceBehaviour(identifier));
185             namespaces.put(identifier, namespaceSupport);
186             return this;
187         }
188
189         public Builder addVersionSpecificSupport(final YangVersion version,
190                 final StatementSupport<?, ?, ?> definition) {
191             Preconditions.checkNotNull(version);
192             Preconditions.checkNotNull(definition);
193             Preconditions.checkArgument(supportedVersions.contains(version));
194
195             final QName identifier = definition.getStatementName();
196             Preconditions.checkState(!commonStatements.containsKey(identifier),
197                     "Statement %s already defined in common statement bundle.", identifier);
198             Preconditions.checkState(!versionSpecificStatements.contains(version, identifier),
199                     "Statement %s already defined for version %s.", identifier, version);
200             Preconditions.checkState(parent.getCommonStatementDefinition(identifier) == null,
201                     "Statement %s already defined in parent's common statement bundle.", identifier);
202             Preconditions.checkState(parent.getVersionSpecificStatementDefinition(version, identifier) == null,
203                     "Statement %s already defined for version %s in parent's statement bundle.", identifier, version);
204             versionSpecificStatements.put(version, identifier, definition);
205             return this;
206         }
207
208         public Set<YangVersion> getSupportedVersions() {
209             return supportedVersions;
210         }
211
212         public Builder setParent(final StatementSupportBundle parent) {
213             this.parent = parent;
214             return this;
215         }
216
217         @Override
218         public StatementSupportBundle build() {
219             Preconditions.checkState(parent != null, "Parent must not be null");
220             return new StatementSupportBundle(parent, supportedVersions, ImmutableMap.copyOf(commonStatements),
221                     ImmutableMap.copyOf(namespaces), ImmutableTable.copyOf(versionSpecificStatements));
222         }
223     }
224 }