diff options
-rw-r--r-- | store/src/main/java/tools/refinery/store/query/RelationalScope.java | 14 | ||||
-rw-r--r-- | store/src/main/java/tools/refinery/store/query/internal/ModelUpdateListener.java | 112 | ||||
-rw-r--r-- | store/src/main/java/tools/refinery/store/query/internal/RelationUpdateListener.java | 52 | ||||
-rw-r--r-- | store/src/main/java/tools/refinery/store/query/internal/RelationalEngineContext.java | 2 | ||||
-rw-r--r-- | store/src/main/java/tools/refinery/store/query/internal/RelationalRuntimeContext.java | 14 | ||||
-rw-r--r-- | store/src/main/java/tools/refinery/store/query/internal/ViewUpdate.java | 4 | ||||
-rw-r--r-- | store/src/main/java/tools/refinery/store/query/internal/ViewUpdateBuffer.java | 46 | ||||
-rw-r--r-- | store/src/main/java/tools/refinery/store/query/internal/ViewUpdateTranslator.java (renamed from store/src/main/java/tools/refinery/store/query/internal/RelationUpdateListenerEntry.java) | 27 |
8 files changed, 187 insertions, 84 deletions
diff --git a/store/src/main/java/tools/refinery/store/query/RelationalScope.java b/store/src/main/java/tools/refinery/store/query/RelationalScope.java index 5fe8083a..e37fdb95 100644 --- a/store/src/main/java/tools/refinery/store/query/RelationalScope.java +++ b/store/src/main/java/tools/refinery/store/query/RelationalScope.java | |||
@@ -9,23 +9,23 @@ import org.eclipse.viatra.query.runtime.api.scope.IIndexingErrorListener; | |||
9 | import org.eclipse.viatra.query.runtime.api.scope.QueryScope; | 9 | import org.eclipse.viatra.query.runtime.api.scope.QueryScope; |
10 | 10 | ||
11 | import tools.refinery.store.model.Model; | 11 | import tools.refinery.store.model.Model; |
12 | import tools.refinery.store.model.Tuple; | 12 | import tools.refinery.store.query.internal.ModelUpdateListener; |
13 | import tools.refinery.store.query.internal.RelationUpdateListener; | ||
14 | import tools.refinery.store.query.internal.RelationalEngineContext; | 13 | import tools.refinery.store.query.internal.RelationalEngineContext; |
15 | import tools.refinery.store.query.view.RelationView; | 14 | import tools.refinery.store.query.view.RelationView; |
16 | 15 | ||
17 | public class RelationalScope extends QueryScope{ | 16 | public class RelationalScope extends QueryScope{ |
18 | private final Model model; | 17 | private final Model model; |
19 | private final RelationUpdateListener updateListener; | 18 | private final ModelUpdateListener updateListener; |
20 | 19 | ||
21 | public RelationalScope(Model model, Set<RelationView<?>> relationViews) { | 20 | public RelationalScope(Model model, Set<RelationView<?>> relationViews) { |
22 | this.model = model; | 21 | this.model = model; |
23 | updateListener = new RelationUpdateListener(relationViews); | 22 | this.updateListener = new ModelUpdateListener(relationViews); |
23 | //this.changeListener = new | ||
24 | } | 24 | } |
25 | 25 | ||
26 | public <D> void processUpdate(RelationView<D> relationView, Tuple key, D oldValue, D newValue) { | 26 | // public <D> void processUpdate(RelationView<D> relationView, Tuple key, D oldValue, D newValue) { |
27 | updateListener.processChange(relationView, key, oldValue, newValue); | 27 | // updateListener.processChange(relationView, key, oldValue, newValue); |
28 | } | 28 | // } |
29 | 29 | ||
30 | @Override | 30 | @Override |
31 | protected IEngineContext createEngineContext(ViatraQueryEngine engine, IIndexingErrorListener errorListener, | 31 | protected IEngineContext createEngineContext(ViatraQueryEngine engine, IIndexingErrorListener errorListener, |
diff --git a/store/src/main/java/tools/refinery/store/query/internal/ModelUpdateListener.java b/store/src/main/java/tools/refinery/store/query/internal/ModelUpdateListener.java new file mode 100644 index 00000000..425ae8f7 --- /dev/null +++ b/store/src/main/java/tools/refinery/store/query/internal/ModelUpdateListener.java | |||
@@ -0,0 +1,112 @@ | |||
1 | package tools.refinery.store.query.internal; | ||
2 | |||
3 | import java.util.HashMap; | ||
4 | import java.util.HashSet; | ||
5 | import java.util.Map; | ||
6 | import java.util.Set; | ||
7 | |||
8 | import org.eclipse.viatra.query.runtime.matchers.context.IQueryRuntimeContextListener; | ||
9 | import org.eclipse.viatra.query.runtime.matchers.tuple.ITuple; | ||
10 | |||
11 | import tools.refinery.store.model.Tuple; | ||
12 | import tools.refinery.store.model.representation.Relation; | ||
13 | import tools.refinery.store.query.view.RelationView; | ||
14 | |||
15 | public class ModelUpdateListener { | ||
16 | /** | ||
17 | * Collections of Relations and their Views. | ||
18 | */ | ||
19 | private final Map<Relation<?>, Set<RelationView<?>>> relation2View; | ||
20 | /** | ||
21 | * Collection of Views and their buffers. | ||
22 | */ | ||
23 | private final Map<RelationView<?>, Set<ViewUpdateBuffer<?>>> view2Buffers; | ||
24 | |||
25 | public ModelUpdateListener(Set<RelationView<?>> relationViews) { | ||
26 | this.relation2View = new HashMap<>(); | ||
27 | this.view2Buffers = new HashMap<>(); | ||
28 | |||
29 | for (RelationView<?> relationView : relationViews) { | ||
30 | registerView(relationView); | ||
31 | } | ||
32 | } | ||
33 | |||
34 | private void registerView(RelationView<?> view) { | ||
35 | Relation<?> relation = view.getRepresentation(); | ||
36 | |||
37 | // 1. register views to relations, if necessary | ||
38 | var views = relation2View.get(relation); | ||
39 | if (views == null) { | ||
40 | views = new HashSet<>(); | ||
41 | relation2View.put(relation, views); | ||
42 | } | ||
43 | views.add(view); | ||
44 | |||
45 | // 2. register notifier map to views, if necessary | ||
46 | if (!view2Buffers.containsKey(view)) { | ||
47 | view2Buffers.put(view, new HashSet<>()); | ||
48 | } | ||
49 | } | ||
50 | |||
51 | boolean containsRelationalView(RelationView<?> relationalKey) { | ||
52 | return view2Buffers.containsKey(relationalKey); | ||
53 | } | ||
54 | |||
55 | <D> void addListener(RelationView<D> relationView, ITuple seed, IQueryRuntimeContextListener listener) { | ||
56 | if (view2Buffers.containsKey(relationView)) { | ||
57 | ViewUpdateTranslator<D> updateListener = new ViewUpdateTranslator<>(relationView, seed, listener); | ||
58 | ViewUpdateBuffer<D> updateBuffer = new ViewUpdateBuffer<>(updateListener); | ||
59 | view2Buffers.get(relationView).add(updateBuffer); | ||
60 | } else | ||
61 | throw new IllegalArgumentException(); | ||
62 | } | ||
63 | |||
64 | void removeListener(RelationView<?> relationView, ITuple seed, IQueryRuntimeContextListener listener) { | ||
65 | if (view2Buffers.containsKey(relationView)) { | ||
66 | Set<ViewUpdateBuffer<?>> buffers = this.view2Buffers.get(relationView); | ||
67 | for(var buffer : buffers) { | ||
68 | if(buffer.getUpdateListener().key == seed && buffer.getUpdateListener().listener == listener) { | ||
69 | // remove buffer and terminate immediately, or it will break iterator. | ||
70 | buffers.remove(buffer); | ||
71 | return; | ||
72 | } | ||
73 | } | ||
74 | } else | ||
75 | throw new IllegalArgumentException(); | ||
76 | } | ||
77 | |||
78 | public <D> void addUpdate(Relation<D> relation, Tuple key, D oldValue, D newValue) { | ||
79 | var views = this.relation2View.get(relation); | ||
80 | if (views != null) { | ||
81 | for (var view : views) { | ||
82 | var buffers = this.view2Buffers.get(view); | ||
83 | for (var buffer : buffers) { | ||
84 | @SuppressWarnings("unchecked") | ||
85 | var typedBuffer = (ViewUpdateBuffer<D>) buffer; | ||
86 | typedBuffer.addChange(key, oldValue, newValue); | ||
87 | } | ||
88 | } | ||
89 | } else { | ||
90 | throw new IllegalArgumentException( | ||
91 | "Relation " + relation.getName() + " is not in the scope of the update listener."); | ||
92 | } | ||
93 | } | ||
94 | |||
95 | public boolean hasChange() { | ||
96 | for (var bufferCollection : this.view2Buffers.values()) { | ||
97 | for (ViewUpdateBuffer<?> buffer : bufferCollection) { | ||
98 | if (buffer.hasChange()) | ||
99 | return true; | ||
100 | } | ||
101 | } | ||
102 | return false; | ||
103 | } | ||
104 | |||
105 | public void flush() { | ||
106 | for (var bufferCollection : this.view2Buffers.values()) { | ||
107 | for (ViewUpdateBuffer<?> buffer : bufferCollection) { | ||
108 | buffer.flush(); | ||
109 | } | ||
110 | } | ||
111 | } | ||
112 | } | ||
diff --git a/store/src/main/java/tools/refinery/store/query/internal/RelationUpdateListener.java b/store/src/main/java/tools/refinery/store/query/internal/RelationUpdateListener.java deleted file mode 100644 index cf5260f6..00000000 --- a/store/src/main/java/tools/refinery/store/query/internal/RelationUpdateListener.java +++ /dev/null | |||
@@ -1,52 +0,0 @@ | |||
1 | package tools.refinery.store.query.internal; | ||
2 | |||
3 | import java.util.HashMap; | ||
4 | import java.util.HashSet; | ||
5 | import java.util.Map; | ||
6 | import java.util.Set; | ||
7 | |||
8 | import org.eclipse.viatra.query.runtime.matchers.context.IQueryRuntimeContextListener; | ||
9 | import org.eclipse.viatra.query.runtime.matchers.tuple.ITuple; | ||
10 | |||
11 | import tools.refinery.store.model.Tuple; | ||
12 | import tools.refinery.store.query.view.RelationView; | ||
13 | |||
14 | public class RelationUpdateListener { | ||
15 | private final Map<RelationView<?>,Set<RelationUpdateListenerEntry<?>>> view2Listeners; | ||
16 | |||
17 | public RelationUpdateListener(Set<RelationView<?>> relationViews) { | ||
18 | view2Listeners = new HashMap<>(); | ||
19 | for(RelationView<?> relationView : relationViews) { | ||
20 | view2Listeners.put(relationView, new HashSet<>()); | ||
21 | } | ||
22 | } | ||
23 | public boolean containsRelationalView(RelationView<?> relationalKey) { | ||
24 | RelationView<?> relationView = relationalKey.getWrappedKey(); | ||
25 | return view2Listeners.containsKey(relationView); | ||
26 | } | ||
27 | public void addListener(RelationView<?> relationalKey, ITuple seed, IQueryRuntimeContextListener listener) { | ||
28 | RelationView<?> relationView = relationalKey.getWrappedKey(); | ||
29 | if(view2Listeners.containsKey(relationView)) { | ||
30 | RelationUpdateListenerEntry<?> entry = new RelationUpdateListenerEntry<>(relationalKey, seed, listener); | ||
31 | view2Listeners.get(relationView).add(entry); | ||
32 | } else throw new IllegalArgumentException(); | ||
33 | } | ||
34 | public void removeListener(RelationView<?> relationalKey, ITuple seed, IQueryRuntimeContextListener listener) { | ||
35 | RelationView<?> relationView = relationalKey.getWrappedKey(); | ||
36 | if(view2Listeners.containsKey(relationView)) { | ||
37 | RelationUpdateListenerEntry<?> entry = new RelationUpdateListenerEntry<>(relationalKey, seed, listener); | ||
38 | view2Listeners.get(relationView).remove(entry); | ||
39 | } else throw new IllegalArgumentException(); | ||
40 | } | ||
41 | |||
42 | public <D> void processChange(RelationView<D> relationView, Tuple tuple, D oldValue, D newValue) { | ||
43 | Set<RelationUpdateListenerEntry<?>> listeners = view2Listeners.get(relationView); | ||
44 | if(listeners != null) { | ||
45 | for(RelationUpdateListenerEntry<?> listener : listeners) { | ||
46 | @SuppressWarnings("unchecked") | ||
47 | RelationUpdateListenerEntry<D> typeCorrectListener = (RelationUpdateListenerEntry<D>) listener; | ||
48 | typeCorrectListener.processChange(tuple, oldValue, newValue); | ||
49 | } | ||
50 | } else throw new IllegalArgumentException("View was not indexed in constructor "+relationView); | ||
51 | } | ||
52 | } | ||
diff --git a/store/src/main/java/tools/refinery/store/query/internal/RelationalEngineContext.java b/store/src/main/java/tools/refinery/store/query/internal/RelationalEngineContext.java index 691baf81..dfbd8545 100644 --- a/store/src/main/java/tools/refinery/store/query/internal/RelationalEngineContext.java +++ b/store/src/main/java/tools/refinery/store/query/internal/RelationalEngineContext.java | |||
@@ -11,7 +11,7 @@ public class RelationalEngineContext implements IEngineContext{ | |||
11 | private final RelationalRuntimeContext runtimeContext; | 11 | private final RelationalRuntimeContext runtimeContext; |
12 | 12 | ||
13 | 13 | ||
14 | public RelationalEngineContext(Model model, RelationUpdateListener updateListener) { | 14 | public RelationalEngineContext(Model model, ModelUpdateListener updateListener) { |
15 | runtimeContext = new RelationalRuntimeContext(model, updateListener); | 15 | runtimeContext = new RelationalRuntimeContext(model, updateListener); |
16 | } | 16 | } |
17 | 17 | ||
diff --git a/store/src/main/java/tools/refinery/store/query/internal/RelationalRuntimeContext.java b/store/src/main/java/tools/refinery/store/query/internal/RelationalRuntimeContext.java index da118f26..d5112128 100644 --- a/store/src/main/java/tools/refinery/store/query/internal/RelationalRuntimeContext.java +++ b/store/src/main/java/tools/refinery/store/query/internal/RelationalRuntimeContext.java | |||
@@ -25,12 +25,12 @@ import tools.refinery.store.query.view.RelationView; | |||
25 | 25 | ||
26 | public class RelationalRuntimeContext implements IQueryRuntimeContext { | 26 | public class RelationalRuntimeContext implements IQueryRuntimeContext { |
27 | private final RelationalQueryMetaContext metaContext = new RelationalQueryMetaContext(); | 27 | private final RelationalQueryMetaContext metaContext = new RelationalQueryMetaContext(); |
28 | private final RelationUpdateListener relationUpdateListener; | 28 | private final ModelUpdateListener modelUpdateListener; |
29 | private final Model model; | 29 | private final Model model; |
30 | 30 | ||
31 | public RelationalRuntimeContext(Model model, RelationUpdateListener relationUpdateListener) { | 31 | public RelationalRuntimeContext(Model model, ModelUpdateListener relationUpdateListener) { |
32 | this.model = model; | 32 | this.model = model; |
33 | this.relationUpdateListener = relationUpdateListener; | 33 | this.modelUpdateListener = relationUpdateListener; |
34 | } | 34 | } |
35 | 35 | ||
36 | @Override | 36 | @Override |
@@ -58,7 +58,7 @@ public class RelationalRuntimeContext implements IQueryRuntimeContext { | |||
58 | @Override | 58 | @Override |
59 | public boolean isIndexed(IInputKey key, IndexingService service) { | 59 | public boolean isIndexed(IInputKey key, IndexingService service) { |
60 | if(key instanceof RelationView<?> relationalKey) { | 60 | if(key instanceof RelationView<?> relationalKey) { |
61 | return this.relationUpdateListener.containsRelationalView(relationalKey); | 61 | return this.modelUpdateListener.containsRelationalView(relationalKey); |
62 | } else { | 62 | } else { |
63 | return false; | 63 | return false; |
64 | } | 64 | } |
@@ -74,7 +74,7 @@ public class RelationalRuntimeContext implements IQueryRuntimeContext { | |||
74 | RelationView<?> checkKey(IInputKey key) { | 74 | RelationView<?> checkKey(IInputKey key) { |
75 | if(key instanceof RelationView) { | 75 | if(key instanceof RelationView) { |
76 | RelationView<?> relationViewKey = (RelationView<?>) key; | 76 | RelationView<?> relationViewKey = (RelationView<?>) key; |
77 | if(relationUpdateListener.containsRelationalView(relationViewKey)) { | 77 | if(modelUpdateListener.containsRelationalView(relationViewKey)) { |
78 | return relationViewKey; | 78 | return relationViewKey; |
79 | } else { | 79 | } else { |
80 | throw new IllegalStateException("Query is asking for non-indexed key"); | 80 | throw new IllegalStateException("Query is asking for non-indexed key"); |
@@ -144,14 +144,14 @@ public class RelationalRuntimeContext implements IQueryRuntimeContext { | |||
144 | @Override | 144 | @Override |
145 | public void addUpdateListener(IInputKey key, Tuple seed, IQueryRuntimeContextListener listener) { | 145 | public void addUpdateListener(IInputKey key, Tuple seed, IQueryRuntimeContextListener listener) { |
146 | RelationView<?> relationalKey = checkKey(key); | 146 | RelationView<?> relationalKey = checkKey(key); |
147 | this.relationUpdateListener.addListener(relationalKey, seed, listener); | 147 | this.modelUpdateListener.addListener(relationalKey, seed, listener); |
148 | 148 | ||
149 | } | 149 | } |
150 | 150 | ||
151 | @Override | 151 | @Override |
152 | public void removeUpdateListener(IInputKey key, Tuple seed, IQueryRuntimeContextListener listener) { | 152 | public void removeUpdateListener(IInputKey key, Tuple seed, IQueryRuntimeContextListener listener) { |
153 | RelationView<?> relationalKey = checkKey(key); | 153 | RelationView<?> relationalKey = checkKey(key); |
154 | this.relationUpdateListener.removeListener(relationalKey, seed, listener); | 154 | this.modelUpdateListener.removeListener(relationalKey, seed, listener); |
155 | } | 155 | } |
156 | 156 | ||
157 | @Override | 157 | @Override |
diff --git a/store/src/main/java/tools/refinery/store/query/internal/ViewUpdate.java b/store/src/main/java/tools/refinery/store/query/internal/ViewUpdate.java new file mode 100644 index 00000000..d4a295f8 --- /dev/null +++ b/store/src/main/java/tools/refinery/store/query/internal/ViewUpdate.java | |||
@@ -0,0 +1,4 @@ | |||
1 | package tools.refinery.store.query.internal; | ||
2 | |||
3 | record ViewUpdate (Object[] tuple, boolean isInsertion) { | ||
4 | } | ||
diff --git a/store/src/main/java/tools/refinery/store/query/internal/ViewUpdateBuffer.java b/store/src/main/java/tools/refinery/store/query/internal/ViewUpdateBuffer.java new file mode 100644 index 00000000..6bc4c96a --- /dev/null +++ b/store/src/main/java/tools/refinery/store/query/internal/ViewUpdateBuffer.java | |||
@@ -0,0 +1,46 @@ | |||
1 | package tools.refinery.store.query.internal; | ||
2 | |||
3 | import java.util.ArrayList; | ||
4 | import java.util.Arrays; | ||
5 | import java.util.List; | ||
6 | |||
7 | import tools.refinery.store.model.Tuple; | ||
8 | |||
9 | public class ViewUpdateBuffer<D> { | ||
10 | protected final ViewUpdateTranslator<D> updateListener; | ||
11 | protected final List<ViewUpdate> buffer = new ArrayList<>(); | ||
12 | |||
13 | public ViewUpdateBuffer(ViewUpdateTranslator<D> updateListener) { | ||
14 | this.updateListener = updateListener; | ||
15 | } | ||
16 | |||
17 | public ViewUpdateTranslator<D> getUpdateListener() { | ||
18 | return updateListener; | ||
19 | } | ||
20 | |||
21 | public boolean hasChange() { | ||
22 | return ! buffer.isEmpty(); | ||
23 | } | ||
24 | |||
25 | public void addChange(Tuple tuple, D oldValue, D newValue) { | ||
26 | if(oldValue != newValue) { | ||
27 | Object[] oldTuple = updateListener.isMatching(tuple, oldValue); | ||
28 | Object[] newTuple = updateListener.isMatching(tuple, newValue); | ||
29 | if(!Arrays.equals(oldTuple, newTuple)) { | ||
30 | if(oldTuple != null) { | ||
31 | buffer.add(new ViewUpdate(oldTuple, false)); | ||
32 | } | ||
33 | if(newTuple != null) { | ||
34 | buffer.add(new ViewUpdate(newTuple, true)); | ||
35 | } | ||
36 | } | ||
37 | } | ||
38 | } | ||
39 | |||
40 | public void flush() { | ||
41 | for (ViewUpdate viewChange : buffer) { | ||
42 | updateListener.processChange(viewChange); | ||
43 | } | ||
44 | buffer.clear(); | ||
45 | } | ||
46 | } | ||
diff --git a/store/src/main/java/tools/refinery/store/query/internal/RelationUpdateListenerEntry.java b/store/src/main/java/tools/refinery/store/query/internal/ViewUpdateTranslator.java index 860a80b7..4596b9c1 100644 --- a/store/src/main/java/tools/refinery/store/query/internal/RelationUpdateListenerEntry.java +++ b/store/src/main/java/tools/refinery/store/query/internal/ViewUpdateTranslator.java | |||
@@ -1,6 +1,5 @@ | |||
1 | package tools.refinery.store.query.internal; | 1 | package tools.refinery.store.query.internal; |
2 | 2 | ||
3 | import java.util.Arrays; | ||
4 | import java.util.Objects; | 3 | import java.util.Objects; |
5 | 4 | ||
6 | import org.eclipse.viatra.query.runtime.matchers.context.IQueryRuntimeContextListener; | 5 | import org.eclipse.viatra.query.runtime.matchers.context.IQueryRuntimeContextListener; |
@@ -10,30 +9,24 @@ import org.eclipse.viatra.query.runtime.matchers.tuple.Tuples; | |||
10 | import tools.refinery.store.model.Tuple; | 9 | import tools.refinery.store.model.Tuple; |
11 | import tools.refinery.store.query.view.RelationView; | 10 | import tools.refinery.store.query.view.RelationView; |
12 | 11 | ||
13 | public class RelationUpdateListenerEntry<D> { | 12 | public class ViewUpdateTranslator<D> { |
14 | final RelationView<D> key; | 13 | final RelationView<D> key; |
15 | final ITuple filter; | 14 | final ITuple filter; |
16 | final IQueryRuntimeContextListener listener; | 15 | final IQueryRuntimeContextListener listener; |
17 | 16 | ||
18 | public RelationUpdateListenerEntry(RelationView<D> key, ITuple filter, IQueryRuntimeContextListener listener) { | 17 | public ViewUpdateTranslator(RelationView<D> key, ITuple filter, IQueryRuntimeContextListener listener) { |
19 | super(); | 18 | super(); |
20 | this.key = key; | 19 | this.key = key; |
21 | this.filter = filter; | 20 | this.filter = filter; |
22 | this.listener = listener; | 21 | this.listener = listener; |
23 | } | 22 | } |
24 | 23 | ||
25 | public void processChange(Tuple tuple, D oldValue, D newValue) { | 24 | public void processChange(ViewUpdate change) { |
26 | Object[] oldTuple = isMatching(key.getWrappedKey().transform(tuple, oldValue), filter); | 25 | listener.update(key, Tuples.flatTupleOf(change.tuple()), change.isInsertion()); |
27 | Object[] newTuple = isMatching(key.getWrappedKey().transform(tuple, newValue), filter); | 26 | } |
28 | 27 | ||
29 | if(!Arrays.equals(oldTuple, newTuple)) { | 28 | public Object[] isMatching(Tuple tuple, D value){ |
30 | if(oldTuple != null) { | 29 | return isMatching(key.getWrappedKey().transform(tuple, value), filter); |
31 | listener.update(key, Tuples.flatTupleOf(oldTuple), false); | ||
32 | } | ||
33 | if(newTuple != null) { | ||
34 | listener.update(key, Tuples.flatTupleOf(newTuple), true); | ||
35 | } | ||
36 | } | ||
37 | } | 30 | } |
38 | 31 | ||
39 | private Object[] isMatching(Object[] tuple, ITuple filter) { | 32 | private Object[] isMatching(Object[] tuple, ITuple filter) { |
@@ -55,9 +48,9 @@ public class RelationUpdateListenerEntry<D> { | |||
55 | public boolean equals(Object obj) { | 48 | public boolean equals(Object obj) { |
56 | if (this == obj) | 49 | if (this == obj) |
57 | return true; | 50 | return true; |
58 | if (!(obj instanceof RelationUpdateListenerEntry)) | 51 | if (!(obj instanceof ViewUpdateTranslator)) |
59 | return false; | 52 | return false; |
60 | RelationUpdateListenerEntry<?> other = (RelationUpdateListenerEntry<?>) obj; | 53 | ViewUpdateTranslator<?> other = (ViewUpdateTranslator<?>) obj; |
61 | return Objects.equals(filter, other.filter) && Objects.equals(key, other.key) | 54 | return Objects.equals(filter, other.filter) && Objects.equals(key, other.key) |
62 | && Objects.equals(listener, other.listener); | 55 | && Objects.equals(listener, other.listener); |
63 | } | 56 | } |