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