Bug 6551: Support for third-party Yang extensions implementation
[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.ImmutableMap;
12 import java.util.HashMap;
13 import java.util.Map;
14 import org.opendaylight.yangtools.concepts.Immutable;
15 import org.opendaylight.yangtools.yang.common.QName;
16 import org.opendaylight.yangtools.yang.model.api.meta.IdentifierNamespace;
17
18 public final class StatementSupportBundle implements Immutable,NamespaceBehaviour.Registry {
19
20     private static final StatementSupportBundle EMPTY = new StatementSupportBundle(null, ImmutableMap.of(), ImmutableMap.of());
21
22     private final StatementSupportBundle parent;
23     private final ImmutableMap<QName, StatementSupport<?,?,?>> definitions;
24     private final ImmutableMap<Class<?>, NamespaceBehaviour<?, ?, ?>> namespaceDefinitions;
25
26     private StatementSupportBundle(final StatementSupportBundle parent,
27                                    final ImmutableMap<QName, StatementSupport<?, ?, ?>> statements,
28                                    final ImmutableMap<Class<?>, NamespaceBehaviour<?, ?, ?>> namespaces) {
29         this.parent = parent;
30         this.definitions = statements;
31         this.namespaceDefinitions = namespaces;
32     }
33
34     public ImmutableMap<QName, StatementSupport<?, ?, ?>> getDefinitions() {
35         return definitions;
36     }
37
38     public ImmutableMap<Class<?>, NamespaceBehaviour<?, ?, ?>> getNamespaceDefinitions() {
39         return namespaceDefinitions;
40     }
41
42     public static Builder builder() {
43         return new Builder(EMPTY);
44     }
45
46     public static Builder derivedFrom(final StatementSupportBundle parent) {
47         return new Builder(parent);
48     }
49
50     @Override
51     public <K, V, N extends IdentifierNamespace<K, V>> NamespaceBehaviour<K, V, N> getNamespaceBehaviour(final Class<N> namespace)
52             throws NamespaceNotAvailableException {
53         final NamespaceBehaviour<?, ?, ?> potential = namespaceDefinitions.get(namespace);
54         if (potential != null) {
55             Preconditions.checkState(namespace.equals(potential.getIdentifier()));
56
57             /*
58              * Safe cast, previous checkState checks equivalence of key from
59              * which type argument are derived
60              */
61             return (NamespaceBehaviour<K, V, N>) potential;
62         }
63         if (parent != null) {
64             return parent.getNamespaceBehaviour(namespace);
65         }
66         return null;
67     }
68
69     public <K, V, N extends IdentifierNamespace<K, V>> boolean hasNamespaceBehaviour(final Class<N> namespace) {
70         if (namespaceDefinitions.containsKey(namespace)) {
71             return true;
72         }
73         if (parent != null) {
74             return parent.hasNamespaceBehaviour(namespace);
75         }
76         return false;
77     }
78
79     public StatementSupport<?, ?,?> getStatementDefinition(final QName stmtName) {
80         final StatementSupport<?,?, ?> potential = definitions.get(stmtName);
81         if (potential != null) {
82             return potential;
83         }
84         if (parent != null) {
85             return parent.getStatementDefinition(stmtName);
86         }
87         return null;
88     }
89
90     public static class Builder implements org.opendaylight.yangtools.concepts.Builder<StatementSupportBundle> {
91
92         private StatementSupportBundle parent;
93         private final Map<QName, StatementSupport<?, ?, ?>> statements = new HashMap<>();
94         private final Map<Class<?>, NamespaceBehaviour<?, ?, ?>> namespaces = new HashMap<>();
95
96         Builder(final StatementSupportBundle parent) {
97             this.parent = parent;
98         }
99
100         public Builder addSupport(final StatementSupport<?, ?, ?> definition) {
101             final QName identifier = definition.getStatementName();
102             Preconditions.checkState(!statements.containsKey(identifier), "Statement %s already defined.", identifier);
103             Preconditions.checkState(parent.getStatementDefinition(identifier) == null,
104                     "Statement %s already defined.", identifier);
105             statements.put(identifier, definition);
106             return this;
107         }
108
109         public <K, V, N extends IdentifierNamespace<K, V>> Builder addSupport(
110                 final NamespaceBehaviour<K, V, N> namespaceSupport) {
111             final Class<N> identifier = namespaceSupport.getIdentifier();
112             Preconditions.checkState(!namespaces.containsKey(identifier));
113             Preconditions.checkState(!parent.hasNamespaceBehaviour(identifier));
114             namespaces.put(identifier, namespaceSupport);
115             return this;
116         }
117
118         public Builder setParent(final StatementSupportBundle parent) {
119             this.parent = parent;
120             return this;
121         }
122
123         @Override
124         public StatementSupportBundle build() {
125             return new StatementSupportBundle(parent, ImmutableMap.copyOf(statements), ImmutableMap.copyOf(namespaces));
126         }
127
128     }
129
130 }