2 * Copyright (c) 2015 Cisco Systems, Inc. and others. All rights reserved.
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
8 package org.opendaylight.yangtools.yang.parser.spi.meta;
10 import static com.google.common.base.Preconditions.checkArgument;
11 import static com.google.common.base.Preconditions.checkState;
12 import static java.util.Objects.requireNonNull;
14 import com.google.common.collect.HashBasedTable;
15 import com.google.common.collect.ImmutableMap;
16 import com.google.common.collect.ImmutableSet;
17 import com.google.common.collect.ImmutableTable;
18 import com.google.common.collect.Table;
19 import java.util.HashMap;
22 import org.eclipse.jdt.annotation.NonNull;
23 import org.opendaylight.yangtools.concepts.Immutable;
24 import org.opendaylight.yangtools.concepts.Mutable;
25 import org.opendaylight.yangtools.yang.common.QName;
26 import org.opendaylight.yangtools.yang.common.YangVersion;
27 import org.slf4j.Logger;
28 import org.slf4j.LoggerFactory;
30 public final class StatementSupportBundle implements Immutable, NamespaceBehaviour.Registry {
32 private static final StatementSupportBundle EMPTY = new StatementSupportBundle(null, null, ImmutableMap.of(),
33 ImmutableMap.of(), ImmutableTable.of());
35 private final StatementSupportBundle parent;
36 private final ImmutableMap<QName, StatementSupport<?, ?, ?>> commonDefinitions;
37 private final ImmutableTable<YangVersion, QName, StatementSupport<?, ?, ?>> versionSpecificDefinitions;
38 private final ImmutableMap<Class<?>, NamespaceBehaviour<?, ?, ?>> namespaceDefinitions;
39 private final ImmutableSet<YangVersion> supportedVersions;
41 private StatementSupportBundle(final StatementSupportBundle parent,
42 final ImmutableSet<YangVersion> supportedVersions,
43 final ImmutableMap<QName, StatementSupport<?, ?, ?>> commonStatements,
44 final ImmutableMap<Class<?>, NamespaceBehaviour<?, ?, ?>> namespaces,
45 final ImmutableTable<YangVersion, QName, StatementSupport<?, ?, ?>> versionSpecificStatements) {
47 this.supportedVersions = supportedVersions;
48 commonDefinitions = commonStatements;
49 namespaceDefinitions = namespaces;
50 versionSpecificDefinitions = versionSpecificStatements;
54 * Returns statement definitions common for all versions.
56 * @return map of common statement definitions
58 public ImmutableMap<QName, StatementSupport<?, ?, ?>> getCommonDefinitions() {
59 return commonDefinitions;
63 * Returns statement definitions specific for requested version. Result of this method does nit include common
64 * statement definitions.
68 * @return map of statement definitions specific for requested version, it
69 * doesn't include common statement definitions.
71 public ImmutableMap<QName, StatementSupport<?, ?, ?>> getDefinitionsSpecificForVersion(final YangVersion version) {
72 return versionSpecificDefinitions.row(version);
76 * Returns all version specific statement definitions. Result of this method does not include common statement
79 * @return table of all version specific statement definitions, it doesn't
80 * include common statement definitions.
82 public ImmutableTable<YangVersion, QName, StatementSupport<?, ?, ?>> getAllVersionSpecificDefinitions() {
83 return versionSpecificDefinitions;
86 public ImmutableMap<Class<?>, NamespaceBehaviour<?, ?, ?>> getNamespaceDefinitions() {
87 return namespaceDefinitions;
90 public static Builder builder(final Set<YangVersion> supportedVersions) {
91 return new Builder(supportedVersions, EMPTY);
94 public static Builder derivedFrom(final StatementSupportBundle parent) {
95 return new Builder(parent.getSupportedVersions(), parent);
98 public Set<YangVersion> getSupportedVersions() {
99 return supportedVersions;
103 @SuppressWarnings("unchecked")
104 public <K, V, N extends ParserNamespace<K, V>> NamespaceBehaviour<K, V, N> getNamespaceBehaviour(
105 final Class<N> namespace) {
106 final NamespaceBehaviour<?, ?, ?> potential = namespaceDefinitions.get(namespace);
107 if (potential != null) {
108 checkState(namespace.equals(potential.getIdentifier()));
110 // Safe cast, previous checkState checks equivalence of key from which type argument are derived
111 return (NamespaceBehaviour<K, V, N>) potential;
113 if (parent != null) {
114 return parent.getNamespaceBehaviour(namespace);
119 public <K, V, N extends ParserNamespace<K, V>> boolean hasNamespaceBehaviour(final Class<N> namespace) {
120 if (namespaceDefinitions.containsKey(namespace)) {
123 if (parent != null) {
124 return parent.hasNamespaceBehaviour(namespace);
129 public StatementSupport<?, ?, ?> getStatementDefinition(final YangVersion version, final QName stmtName) {
130 StatementSupport<?, ?, ?> result = getVersionSpecificStatementDefinition(version, stmtName);
131 if (result == null) {
132 result = getCommonStatementDefinition(stmtName);
138 private StatementSupport<?, ?, ?> getCommonStatementDefinition(final QName stmtName) {
139 final StatementSupport<?, ?, ?> potential = commonDefinitions.get(stmtName);
140 if (potential != null) {
143 if (parent != null) {
144 return parent.getCommonStatementDefinition(stmtName);
149 private StatementSupport<?, ?, ?> getVersionSpecificStatementDefinition(final YangVersion version,
150 final QName stmtName) {
151 final StatementSupport<?, ?, ?> potential = versionSpecificDefinitions.get(version, stmtName);
152 if (potential != null) {
156 if (parent != null) {
157 return parent.getVersionSpecificStatementDefinition(version, stmtName);
162 public static final class Builder implements Mutable {
163 private static final Logger LOG = LoggerFactory.getLogger(Builder.class);
165 private final Map<QName, StatementSupport<?, ?, ?>> commonStatements = new HashMap<>();
166 private final Table<YangVersion, QName, StatementSupport<?, ?, ?>> versionSpecificStatements =
167 HashBasedTable.create();
168 private final Map<Class<?>, NamespaceBehaviour<?, ?, ?>> namespaces = new HashMap<>();
170 private final ImmutableSet<YangVersion> supportedVersions;
171 private StatementSupportBundle parent;
173 Builder(final Set<YangVersion> supportedVersions, final StatementSupportBundle parent) {
174 this.parent = requireNonNull(parent);
175 this.supportedVersions = ImmutableSet.copyOf(supportedVersions);
178 public @NonNull Builder addSupport(final StatementSupport<?, ?, ?> support) {
179 final QName identifier = support.getStatementName();
180 checkNoParentDefinition(identifier);
182 checkState(!commonStatements.containsKey(identifier),
183 "Statement %s already defined in common statement bundle.", identifier);
184 commonStatements.put(identifier, support);
188 public <K, V, N extends ParserNamespace<K, V>> @NonNull Builder addSupport(
189 final NamespaceBehaviour<K, V, N> namespaceSupport) {
190 final Class<N> identifier = namespaceSupport.getIdentifier();
191 checkState(!namespaces.containsKey(identifier));
192 checkState(!parent.hasNamespaceBehaviour(identifier));
193 namespaces.put(identifier, namespaceSupport);
197 public @NonNull Builder addVersionSpecificSupport(final YangVersion version,
198 final StatementSupport<?, ?, ?> definition) {
199 checkArgument(supportedVersions.contains(requireNonNull(version)));
201 final QName identifier = definition.getStatementName();
202 checkState(!commonStatements.containsKey(identifier),
203 "Statement %s already defined in common statement bundle.", identifier);
204 checkState(!versionSpecificStatements.contains(version, identifier),
205 "Statement %s already defined for version %s.", identifier, version);
206 checkNoParentDefinition(identifier);
207 checkState(parent.getVersionSpecificStatementDefinition(version, identifier) == null,
208 "Statement %s already defined for version %s in parent's statement bundle.", identifier, version);
209 versionSpecificStatements.put(version, identifier, definition);
213 public Set<YangVersion> getSupportedVersions() {
214 return supportedVersions;
217 public @NonNull Builder setParent(final StatementSupportBundle parent) {
218 this.parent = parent;
222 public @NonNull Builder overrideSupport(final StatementSupport<?, ?, ?> support) {
223 final QName identifier = support.getStatementName();
224 checkNoParentDefinition(identifier);
226 final StatementSupport<?, ?, ?> previousSupport = commonStatements.replace(identifier, support);
227 checkState(previousSupport != null, "Statement %s was not previously defined", identifier);
228 LOG.debug("Changed statement {} support from {} to {}", identifier, previousSupport, support);
233 * Create a {@link StatementSupportBundle} from the contents of this builder.
235 * @return A StatementSupportBundle
236 * @throws IllegalStateException if parent has not been set
238 public @NonNull StatementSupportBundle build() {
239 checkState(parent != null, "Parent must not be null");
240 return new StatementSupportBundle(parent, supportedVersions, ImmutableMap.copyOf(commonStatements),
241 ImmutableMap.copyOf(namespaces), ImmutableTable.copyOf(versionSpecificStatements));
244 private void checkNoParentDefinition(final QName identifier) {
245 checkState(parent.getCommonStatementDefinition(identifier) == null,
246 "Statement %s is defined in parent's common statement bundle", identifier);