Fix InstanceIdentifier.toReference() return
[yangtools.git] / parser / yang-parser-reactor / src / main / java / org / opendaylight / yangtools / yang / parser / stmt / reactor / BehaviourNamespaceAccess.java
1 /*
2  * Copyright (c) 2023 PANTHEON.tech, s.r.o. 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 static java.util.Objects.requireNonNull;
11
12 import com.google.common.base.MoreObjects;
13 import com.google.common.collect.Multimap;
14 import com.google.common.collect.Multimaps;
15 import java.util.ArrayDeque;
16 import java.util.ArrayList;
17 import java.util.HashMap;
18 import java.util.List;
19 import java.util.Map;
20 import java.util.Map.Entry;
21 import org.eclipse.jdt.annotation.NonNull;
22 import org.opendaylight.yangtools.yang.parser.spi.meta.NamespaceBehaviour;
23 import org.opendaylight.yangtools.yang.parser.spi.meta.NamespaceKeyCriterion;
24 import org.opendaylight.yangtools.yang.parser.spi.meta.NamespaceStorage;
25 import org.opendaylight.yangtools.yang.parser.spi.meta.NamespaceStorage.GlobalStorage;
26 import org.opendaylight.yangtools.yang.parser.spi.meta.ParserNamespace;
27
28 /**
29  * A {@link NamespaceAccess} backed by a {@link NamespaceBehaviour}. Also holds reference to {@link BuildGlobalContext}.
30  */
31 final class BehaviourNamespaceAccess<K, V> extends NamespaceAccess<K, V> {
32     private final @NonNull NamespaceBehaviour<K, V> behaviour;
33     private final @NonNull GlobalStorage globalStorage;
34
35     private Multimap<K, KeyedValueAddedListener<K, V>> keyListeners;
36     private List<PredicateValueAddedListener<K, V>> predicateListeners;
37
38     BehaviourNamespaceAccess(final GlobalStorage globalStorage, final NamespaceBehaviour<K, V> behaviour) {
39         this.globalStorage = requireNonNull(globalStorage);
40         this.behaviour = requireNonNull(behaviour);
41     }
42
43     @Override
44     ParserNamespace<K, V> namespace() {
45         return behaviour.namespace();
46     }
47
48     @Override
49     V valueFrom(final NamespaceStorage storage, final K key) {
50         return behaviour.getFrom(globalStorage, storage, key);
51     }
52
53     @Override
54     void valueTo(final NamespaceStorage storage, final K key, final V value) {
55         behaviour.addTo(globalStorage, storage, key, value);
56
57         if (keyListeners != null) {
58             final var listeners = keyListeners.get(key);
59             if (!listeners.isEmpty()) {
60                 final var toNotify = new ArrayList<KeyedValueAddedListener<K, V>>();
61                 final var it = listeners.iterator();
62                 while (it.hasNext()) {
63                     final var listener = it.next();
64                     if (listener.isRequestedValue(this, storage, key, value)) {
65                         it.remove();
66                         toNotify.add(listener);
67                     }
68                 }
69                 for (var listener : toNotify) {
70                     listener.onValueAdded(key, value);
71                 }
72
73                 if (keyListeners.isEmpty()) {
74                     keyListeners = null;
75                 }
76             }
77         }
78
79         if (predicateListeners != null) {
80             final var it = predicateListeners.iterator();
81             while (it.hasNext()) {
82                 if (it.next().onValueAdded(key, value)) {
83                     it.remove();
84                 }
85             }
86             if (predicateListeners != null && predicateListeners.isEmpty()) {
87                 predicateListeners = null;
88             }
89         }
90     }
91
92     @Override
93     Map<K, V> allFrom(final NamespaceStorage storage) {
94         return behaviour.getAllFrom(globalStorage, storage);
95     }
96
97     @Override
98     Entry<K, V> entryFrom(final NamespaceStorage storage, final NamespaceKeyCriterion<K> criterion) {
99         return behaviour.getFrom(globalStorage, storage, criterion);
100     }
101
102     @Override
103     void addListener(final K key, final KeyedValueAddedListener<K, V> listener) {
104         final var k = requireNonNull(key);
105         final var l = requireNonNull(listener);
106         if (keyListeners == null) {
107             keyListeners = Multimaps.newMultimap(new HashMap<>(), ArrayDeque::new);
108         }
109         keyListeners.put(k, l);
110     }
111
112     @Override
113     void addListener(final PredicateValueAddedListener<K, V> listener) {
114         if (predicateListeners == null) {
115             predicateListeners = new ArrayList<>();
116         }
117         predicateListeners.add(listener);
118     }
119
120     @Override
121     public String toString() {
122         return MoreObjects.toStringHelper(this).add("behaviour", behaviour).toString();
123     }
124 }