BUG-4688: Fix BelongsToPrefixToModuleIdentifier namespace
[yangtools.git] / yang / yang-parser-impl / src / main / java / org / opendaylight / yangtools / yang / parser / stmt / reactor / NamespaceStorageSupport.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.stmt.reactor;
9
10 import com.google.common.collect.ImmutableMap;
11 import java.util.HashMap;
12 import java.util.Map;
13 import java.util.Map.Entry;
14 import java.util.Set;
15 import javax.annotation.Nonnull;
16 import org.opendaylight.yangtools.yang.common.SimpleDateFormatUtil;
17 import org.opendaylight.yangtools.yang.model.api.ModuleIdentifier;
18 import org.opendaylight.yangtools.yang.model.api.meta.IdentifierNamespace;
19 import org.opendaylight.yangtools.yang.parser.spi.meta.NamespaceBehaviour.NamespaceStorageNode;
20 import org.opendaylight.yangtools.yang.parser.spi.meta.NamespaceBehaviour.Registry;
21 import org.opendaylight.yangtools.yang.parser.spi.meta.NamespaceNotAvailableException;
22 import org.opendaylight.yangtools.yang.parser.spi.meta.StatementNamespace;
23 import org.opendaylight.yangtools.yang.parser.spi.meta.StmtContext;
24 import org.opendaylight.yangtools.yang.parser.spi.source.SourceException;
25
26 abstract class NamespaceStorageSupport implements NamespaceStorageNode {
27
28     private Map<Class<?>, Map<?,?>> namespaces = ImmutableMap.of();
29
30     @Override
31     public abstract NamespaceStorageNode getParentNamespaceStorage();
32
33     /**
34      * Return the registry of a source context.
35      *
36      * @return registry of source context
37      */
38     public abstract Registry getBehaviourRegistry();
39
40     protected void checkLocalNamespaceAllowed(final Class<? extends IdentifierNamespace<?, ?>> type) {
41         // NOOP
42     }
43
44     /**
45      * Occurs when an item is added to model namespace.
46      *
47      * @throws SourceException instance of SourceException
48      */
49     protected <K, V, N extends IdentifierNamespace<K, V>> void onNamespaceElementAdded(final Class<N> type, final K key,
50             final V value) {
51         // NOOP
52     }
53
54     @Nonnull
55     public final <K,V, KT extends K, N extends IdentifierNamespace<K, V>> V getFromNamespace(final Class<N> type,
56             final KT key) throws NamespaceNotAvailableException {
57         return getBehaviourRegistry().getNamespaceBehaviour(type).getFrom(this, key);
58     }
59
60     public final <K, V, N extends IdentifierNamespace<K, V>> Map<K, V> getAllFromNamespace(final Class<N> type) {
61         return getBehaviourRegistry().getNamespaceBehaviour(type).getAllFrom(this);
62     }
63
64     @SuppressWarnings("unchecked")
65     public final <K, V, N extends IdentifierNamespace<K, V>> Map<K, V> getAllFromCurrentStmtCtxNamespace(
66             final Class<N> type) {
67         return (Map<K, V>) namespaces.get(type);
68     }
69
70     public final <K,V, KT extends K, VT extends V,N extends IdentifierNamespace<K, V>> void addToNs(final Class<N> type,
71             final KT key, final VT value) throws NamespaceNotAvailableException {
72         getBehaviourRegistry().getNamespaceBehaviour(type).addTo(this,key,value);
73     }
74
75     @SuppressWarnings({ "unchecked", "rawtypes" })
76     public final <K, N extends StatementNamespace<K, ?,?>> void addContextToNamespace(final Class<N> type, final K key,
77             final StmtContext<?, ?, ?> value) throws NamespaceNotAvailableException {
78         getBehaviourRegistry().getNamespaceBehaviour((Class)type).addTo(this, key, value);
79     }
80
81     @SuppressWarnings("unchecked")
82     @Override
83     public <K, V, N extends IdentifierNamespace<K, V>> V getFromLocalStorage(final Class<N> type, final K key) {
84         final Map<K, V> localNamespace = (Map<K, V>) namespaces.get(type);
85
86         V potential = null;
87         if (localNamespace != null) {
88             potential = localNamespace.get(key);
89         }
90
91         if (potential == null && isModuleIdentifierWithoutSpecifiedRevision(key)) {
92             potential = getRegardlessOfRevision((ModuleIdentifier)key, (Map<ModuleIdentifier,V>)localNamespace);
93         }
94
95         return potential;
96     }
97
98     private static boolean isModuleIdentifierWithoutSpecifiedRevision(final Object obj) {
99         return obj instanceof ModuleIdentifier
100                 && ((ModuleIdentifier) obj).getRevision() == SimpleDateFormatUtil.DEFAULT_DATE_IMP;
101     }
102
103     private static <K, V, N extends IdentifierNamespace<K, V>> V getRegardlessOfRevision(final ModuleIdentifier key,
104             final Map<ModuleIdentifier, V> localNamespace) {
105
106         if (localNamespace == null) {
107             return null;
108         }
109
110         final Set<Entry<ModuleIdentifier, V>> entrySet = localNamespace.entrySet();
111         for (final Entry<ModuleIdentifier, V> entry : entrySet) {
112             final ModuleIdentifier moduleIdentifierInMap = entry.getKey();
113             if (moduleIdentifierInMap.getName().equals(key.getName())) {
114                 return entry.getValue();
115             }
116         }
117
118         return null;
119     }
120
121     @Override
122     public <K, V, N extends IdentifierNamespace<K, V>> Map<K, V> getAllFromLocalStorage(final Class<N> type) {
123         @SuppressWarnings("unchecked")
124         final Map<K, V> localNamespace = (Map<K, V>) namespaces.get(type);
125         return localNamespace;
126     }
127
128     private <K, V, N extends IdentifierNamespace<K, V>> Map<K, V> ensureLocalNamespace(final Class<N> type) {
129         @SuppressWarnings("unchecked")
130         Map<K, V> ret = (Map<K,V>) namespaces.get(type);
131         if (ret == null) {
132             checkLocalNamespaceAllowed(type);
133             ret = new HashMap<>(1);
134
135             if (namespaces.isEmpty()) {
136                 namespaces = new HashMap<>(1);
137             }
138             namespaces.put(type, ret);
139         }
140
141         return ret;
142     }
143
144     @Override
145     public <K, V, N extends IdentifierNamespace<K, V>> V putToLocalStorage(final Class<N> type, final K key,
146             final V value) {
147         final V ret = ensureLocalNamespace(type).put(key, value);
148         onNamespaceElementAdded(type, key, value);
149         return ret;
150     }
151
152     @Override
153     public <K, V, N extends IdentifierNamespace<K, V>> V putToLocalStorageIfAbsent(final Class<N> type, final K key,
154             final V value) {
155         final V ret = ensureLocalNamespace(type).putIfAbsent(key, value);
156         if (ret == null) {
157             onNamespaceElementAdded(type, key, value);
158         }
159         return ret;
160     }
161 }