aboutsummaryrefslogtreecommitdiffstats
path: root/subprojects/viatra-runtime-rete/src/main/java/tools/refinery/viatra/runtime/rete/index/SpecializedProjectionIndexer.java
diff options
context:
space:
mode:
Diffstat (limited to 'subprojects/viatra-runtime-rete/src/main/java/tools/refinery/viatra/runtime/rete/index/SpecializedProjectionIndexer.java')
-rw-r--r--subprojects/viatra-runtime-rete/src/main/java/tools/refinery/viatra/runtime/rete/index/SpecializedProjectionIndexer.java176
1 files changed, 176 insertions, 0 deletions
diff --git a/subprojects/viatra-runtime-rete/src/main/java/tools/refinery/viatra/runtime/rete/index/SpecializedProjectionIndexer.java b/subprojects/viatra-runtime-rete/src/main/java/tools/refinery/viatra/runtime/rete/index/SpecializedProjectionIndexer.java
new file mode 100644
index 00000000..9c647aa9
--- /dev/null
+++ b/subprojects/viatra-runtime-rete/src/main/java/tools/refinery/viatra/runtime/rete/index/SpecializedProjectionIndexer.java
@@ -0,0 +1,176 @@
1/*******************************************************************************
2 * Copyright (c) 2004-2012 Gabor Bergmann and Daniel Varro
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9
10package tools.refinery.viatra.runtime.rete.index;
11
12import java.util.ArrayList;
13import java.util.List;
14import java.util.Objects;
15
16import tools.refinery.viatra.runtime.matchers.tuple.Tuple;
17import tools.refinery.viatra.runtime.matchers.tuple.TupleMask;
18import tools.refinery.viatra.runtime.matchers.util.Direction;
19import tools.refinery.viatra.runtime.rete.network.Node;
20import tools.refinery.viatra.runtime.rete.network.ReteContainer;
21import tools.refinery.viatra.runtime.rete.network.Supplier;
22import tools.refinery.viatra.runtime.rete.network.communication.CommunicationTracker;
23import tools.refinery.viatra.runtime.rete.network.communication.Timestamp;
24
25/**
26 * A specialized projection indexer that can be memory-less (relying on an external source of information).
27 *
28 * <p>
29 * All specialized projection indexers of a single node will share the same listener list, so that notification order is
30 * maintained (see Bug 518434).
31 *
32 * @author Gabor Bergmann
33 * @noimplement Rely on the provided implementations
34 * @noreference Use only via standard Node and Indexer interfaces
35 * @noinstantiate This class is not intended to be instantiated by clients.
36 */
37public abstract class SpecializedProjectionIndexer extends StandardIndexer implements ProjectionIndexer {
38
39 protected Node activeNode;
40 protected List<ListenerSubscription> subscriptions;
41
42 /**
43 * @since 1.7
44 */
45 public SpecializedProjectionIndexer(final ReteContainer reteContainer, final TupleMask mask, final Supplier parent,
46 final Node activeNode, final List<ListenerSubscription> subscriptions) {
47 super(reteContainer, mask);
48 this.parent = parent;
49 this.activeNode = activeNode;
50 this.subscriptions = subscriptions;
51 }
52
53 public List<ListenerSubscription> getSubscriptions() {
54 return subscriptions;
55 }
56
57 @Override
58 public Node getActiveNode() {
59 return activeNode;
60 }
61
62 @Override
63 protected void propagate(final Direction direction, final Tuple updateElement, final Tuple signature,
64 final boolean change, final Timestamp timestamp) {
65 throw new UnsupportedOperationException();
66 }
67
68 @Override
69 public void attachListener(final IndexerListener listener) {
70 super.attachListener(listener);
71 final CommunicationTracker tracker = this.getCommunicationTracker();
72 final IndexerListener proxy = tracker.proxifyIndexerListener(this, listener);
73 final ListenerSubscription subscription = new ListenerSubscription(this, proxy);
74 tracker.registerDependency(this, proxy.getOwner());
75 // See Bug 518434
76 // Must add to the first position, so that the later listeners are notified earlier.
77 // Thus if the beta node added as listener is also an indirect descendant of the same indexer on its opposite
78 // slot,
79 // then the beta node is connected later than its ancestor's listener, therefore it will be notified earlier,
80 // eliminating duplicate insertions and lost deletions that would result from fall-through update propagation
81 subscriptions.add(0, subscription);
82 }
83
84 @Override
85 public void detachListener(final IndexerListener listener) {
86 final CommunicationTracker tracker = this.getCommunicationTracker();
87 // obtain the proxy before the super call would unregister the dependency
88 final IndexerListener proxy = tracker.proxifyIndexerListener(this, listener);
89 super.detachListener(listener);
90 final ListenerSubscription subscription = new ListenerSubscription(this, proxy);
91 final boolean wasContained = subscriptions.remove(subscription);
92 assert wasContained;
93 tracker.unregisterDependency(this, proxy.getOwner());
94 }
95
96 @Override
97 public void networkStructureChanged() {
98 super.networkStructureChanged();
99 final List<ListenerSubscription> oldSubscriptions = new ArrayList<ListenerSubscription>();
100 oldSubscriptions.addAll(subscriptions);
101 subscriptions.clear();
102 for (final ListenerSubscription oldSubscription : oldSubscriptions) {
103 // there is no need to unregister and re-register the dependency between indexer and listener
104 // because the owner of the listener is the same (even if it is proxified)
105 final CommunicationTracker tracker = this.getCommunicationTracker();
106 // the subscriptions are shared, so we MUST reuse the indexer of the subscription instead of simply 'this'
107 final IndexerListener proxy = tracker.proxifyIndexerListener(oldSubscription.indexer, oldSubscription.listener);
108 final ListenerSubscription newSubscription = new ListenerSubscription(oldSubscription.indexer, proxy);
109 subscriptions.add(newSubscription);
110 }
111 }
112
113 /**
114 * @since 2.4
115 */
116 public abstract void propagateToListener(IndexerListener listener, Direction direction, Tuple updateElement,
117 Timestamp timestamp);
118
119 /**
120 * Infrastructure to share subscriptions between specialized indexers of the same parent node.
121 *
122 * @author Gabor Bergmann
123 * @since 1.7
124 */
125 public static class ListenerSubscription {
126 protected SpecializedProjectionIndexer indexer;
127 protected IndexerListener listener;
128
129 public ListenerSubscription(SpecializedProjectionIndexer indexer, IndexerListener listener) {
130 super();
131 this.indexer = indexer;
132 this.listener = listener;
133 }
134
135 /**
136 * @since 2.4
137 */
138 public SpecializedProjectionIndexer getIndexer() {
139 return indexer;
140 }
141
142 /**
143 * @since 2.4
144 */
145 public IndexerListener getListener() {
146 return listener;
147 }
148
149 /**
150 * Call this from parent node.
151 * @since 2.4
152 */
153 public void propagate(Direction direction, Tuple updateElement, Timestamp timestamp) {
154 indexer.propagateToListener(listener, direction, updateElement, timestamp);
155 }
156
157 @Override
158 public int hashCode() {
159 return Objects.hash(indexer, listener);
160 }
161
162 @Override
163 public boolean equals(Object obj) {
164 if (this == obj)
165 return true;
166 if (obj == null)
167 return false;
168 if (getClass() != obj.getClass())
169 return false;
170 ListenerSubscription other = (ListenerSubscription) obj;
171 return Objects.equals(listener, other.listener) && Objects.equals(indexer, other.indexer);
172 }
173
174 }
175
176}