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