From a78d63942d3bfdb9e5679e9a800b0e9b959e7a62 Mon Sep 17 00:00:00 2001 From: Fabienne Ducroquet Date: Fri, 1 Sep 2017 15:14:30 +0200 Subject: [PATCH] Snapshot: Define getAddsObservable/getRemovesObservable Replace all reimplementations of toObservable() with reimplementations of getAddsObservable and getRemovesObservable. --- gs-api/pom.xml | 25 +++- .../org/genericsystem/api/core/Snapshot.java | 61 +++++++++- .../src/main/resources/logback.xml | 0 .../genericsystem/common/AbstractCache.java | 2 + .../org/genericsystem/common/Container.java | 20 ++-- .../genericsystem/common/Differential.java | 40 ++----- gs-defaults/pom.xml | 23 ---- .../DefaultCompositesInheritance.java | 97 +++++++--------- .../defaults/DefaultDependencies.java | 29 +++-- .../defaults/tools/InheritanceComputer.java | 104 ++++++++++++++--- .../tools/ObservableInheritanceComputer.java | 67 ----------- .../defaults/tools/RxJavaHelpers.java | 108 ++++++++++++++++++ .../org/genericsystem/cache/UpdateTest.java | 3 +- 13 files changed, 364 insertions(+), 215 deletions(-) rename {gs-defaults => gs-api}/src/main/resources/logback.xml (100%) delete mode 100644 gs-defaults/src/main/java/org/genericsystem/defaults/tools/ObservableInheritanceComputer.java create mode 100644 gs-defaults/src/main/java/org/genericsystem/defaults/tools/RxJavaHelpers.java diff --git a/gs-api/pom.xml b/gs-api/pom.xml index 89ab3c548..9dc125d24 100644 --- a/gs-api/pom.xml +++ b/gs-api/pom.xml @@ -11,6 +11,29 @@ Generic System API jar + + + io.reactivex.rxjava2 + rxjavafx + 2.1.1 + + + io.reactivex.rxjava2 + rxjava + 2.1.3 + + + org.slf4j + slf4j-api + ${slf4j.version} + + + ch.qos.logback + logback-classic + ${logback.version} + + + ${project.artifactId} @@ -19,7 +42,7 @@ maven-javadoc-plugin ${maven-javadoc-plugin.version} - + diff --git a/gs-api/src/main/java/org/genericsystem/api/core/Snapshot.java b/gs-api/src/main/java/org/genericsystem/api/core/Snapshot.java index b486dddb4..2d1248668 100644 --- a/gs-api/src/main/java/org/genericsystem/api/core/Snapshot.java +++ b/gs-api/src/main/java/org/genericsystem/api/core/Snapshot.java @@ -1,5 +1,6 @@ package org.genericsystem.api.core; +import java.lang.invoke.MethodHandles; import java.util.Collection; import java.util.Iterator; import java.util.LinkedList; @@ -8,6 +9,10 @@ import java.util.stream.Collectors; import java.util.stream.Stream; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import io.reactivex.Observable; import javafx.collections.FXCollections; import javafx.collections.ObservableList; @@ -152,6 +157,17 @@ public Stream unfilteredStream() { return Snapshot.this.stream().filter(predicate); } + @Override + public Observable getAddsObservable() { + return getParent().getAddsObservable().filter(g -> predicate.test(g)); + } + + @Override + public Observable getRemovesObservable() { + return getParent().getRemovesObservable().filter(g -> predicate.test(g)); + } + + @Override public T get(Object o) { T result = Snapshot.this.get(o); @@ -172,6 +188,16 @@ public IndexFilter getFilter() { return filter; } + @Override + public Observable getAddsObservable() { + return getParent().getAddsObservable().filter(g -> filter.test((IGeneric) g)); + } + + @Override + public Observable getRemovesObservable() { + return getParent().getRemovesObservable().filter(g -> filter.test((IGeneric) g)); + } + @Override public Stream unfilteredStream() { throw new UnsupportedOperationException("unfilteredStream() should be called only on unfiltered snapshots."); @@ -187,6 +213,17 @@ public Stream unfilteredStream() { return Snapshot.this.stream().filter(g -> filters.stream().allMatch(filter -> filter.test((IGeneric) g))); } + @Override + public Observable getAddsObservable() { + return Snapshot.this.getAddsObservable().filter(g -> filters.stream().allMatch(filter -> filter.test((IGeneric) g))); + } + + @Override + public Observable getRemovesObservable() { + return Snapshot.this.getRemovesObservable().filter(g -> filters.stream().allMatch(filter -> filter.test((IGeneric) g))); + } + + @Override public T get(Object o) { T result = Snapshot.this.get(o); @@ -199,9 +236,27 @@ default List toList() { return stream().collect(Collectors.toList()); } + default Observable getAddsObservable() { + return Observable.never(); + } + + default Observable getRemovesObservable() { + return Observable.never(); + } + default ObservableList toObservableList() { - if (getParent() != null) - return getParent().toObservableList().filtered(g -> getFilter().test((IGeneric) g)); - return FXCollections.observableArrayList(toList()); + Logger logger = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass()); + ObservableList result = FXCollections.observableArrayList(toList()); + getAddsObservable().subscribe(g -> { + if (!result.contains(g)) { + logger.debug("Snapshot {}, generic added, {}", System.identityHashCode(this), g); + result.add(g); + } + }, e -> logger.error("Exception while computing observable list.", e)); + getRemovesObservable().subscribe(g -> { + logger.debug("Snapshot {}, generic removed, {}", System.identityHashCode(this), g); + result.remove(g); + }, e -> logger.error("Exception while computing observable list.", e)); + return result; } } diff --git a/gs-defaults/src/main/resources/logback.xml b/gs-api/src/main/resources/logback.xml similarity index 100% rename from gs-defaults/src/main/resources/logback.xml rename to gs-api/src/main/resources/logback.xml diff --git a/gs-common/src/main/java/org/genericsystem/common/AbstractCache.java b/gs-common/src/main/java/org/genericsystem/common/AbstractCache.java index 5b42edc1b..394c46803 100644 --- a/gs-common/src/main/java/org/genericsystem/common/AbstractCache.java +++ b/gs-common/src/main/java/org/genericsystem/common/AbstractCache.java @@ -354,11 +354,13 @@ public final ObservableValue> getObservable(Generic gener @Override public Observable getAddsObservable(Generic generic) { + // TODO return Observable.never(); } @Override public Observable getRemovesObservable(Generic generic) { + // TODO return Observable.never(); } } diff --git a/gs-common/src/main/java/org/genericsystem/common/Container.java b/gs-common/src/main/java/org/genericsystem/common/Container.java index dfcba39ba..e43cd8507 100644 --- a/gs-common/src/main/java/org/genericsystem/common/Container.java +++ b/gs-common/src/main/java/org/genericsystem/common/Container.java @@ -3,10 +3,10 @@ import java.util.stream.Stream; import org.genericsystem.api.core.Snapshot; +import org.genericsystem.defaults.tools.RxJavaHelpers; +import io.reactivex.Observable; import javafx.collections.FXCollections; -import javafx.collections.MapChangeListener; -import javafx.collections.ObservableList; import javafx.collections.ObservableMap; /** @@ -31,14 +31,12 @@ public Stream unfilteredStream() { } @Override - public ObservableList toObservableList() { - ObservableList result = FXCollections.observableArrayList(); - container.addListener((MapChangeListener) c -> { - if (c.wasAdded() && !c.wasRemoved()) - result.add(c.getKey()); - if (c.wasRemoved() && !c.wasAdded()) - result.remove(c.getKey()); - }); - return result; + public Observable getAddsObservable() { + return RxJavaHelpers.additionsOf(container).map(entry -> entry.getKey()); + } + + @Override + public Observable getRemovesObservable() { + return RxJavaHelpers.removalsOf(container).map(entry -> entry.getKey()); } } \ No newline at end of file diff --git a/gs-common/src/main/java/org/genericsystem/common/Differential.java b/gs-common/src/main/java/org/genericsystem/common/Differential.java index ee5bb1b27..bc57c7b96 100644 --- a/gs-common/src/main/java/org/genericsystem/common/Differential.java +++ b/gs-common/src/main/java/org/genericsystem/common/Differential.java @@ -20,7 +20,6 @@ import javafx.beans.property.IntegerProperty; import javafx.beans.property.SimpleIntegerProperty; import javafx.beans.value.ObservableValue; -import javafx.collections.FXCollections; import javafx.collections.ObservableList; /** @@ -107,40 +106,21 @@ public Stream unfilteredStream() { return Stream.concat(adds.contains(generic) ? Stream.empty() : subDifferential.getDependencies(generic).filter(new IndexFilter(FiltersBuilder.NOT_CONTAINED_IN_PARAM, new ArrayList<>(removes.toList()))).stream(), adds.filter(new IndexFilter(FiltersBuilder.IS_DIRECT_DEPENDENCY_OF, generic)).stream()); } - @Override public Snapshot filter(List filters) { - return new Snapshot() { - - @Override - public Stream unfilteredStream() { - List filters_ = new ArrayList<>(filters); - filters_.add(new IndexFilter(FiltersBuilder.NOT_CONTAINED_IN_PARAM, new ArrayList<>(removes.toList()))); - return Stream.concat(adds.contains(generic) ? Stream.empty() : subDifferential.getDependencies(generic).filter(filters_).stream(), adds.filter(filters).stream().filter(x -> generic.isDirectAncestorOf(x))); - } - }; + List filters_ = new ArrayList<>(filters); + filters_.add(new IndexFilter(FiltersBuilder.NOT_CONTAINED_IN_PARAM, new ArrayList<>(removes.toList()))); + return Snapshot.super.filter(filters_); + } + + @Override + public Observable getAddsObservable() { + return getDifferentialObservable().flatMap(diff -> diff.getAddsObservable(generic)); } @Override - public ObservableList toObservableList() { - ObservableList result = getDependenciesAsOservableListCacheMap().get(generic); - if (result == null) { - final ObservableList result_ = FXCollections.observableArrayList(getDifferentialProperty().getValue().getDependencies(generic).toList()); - Observable differentialObs = getDifferentialObservable(); - Observable adds = differentialObs.flatMap(diff -> diff.getAddsObservable(generic)); - Observable removes = differentialObs.flatMap(diff -> diff.getRemovesObservable(generic)); - adds.subscribe(g -> { - logger.debug("Generic added, {}", g); - result_.add(g); - }, e -> logger.error("Exception while computing observable list.", e)); - removes.subscribe(g -> { - logger.debug("Generic removed, {}", g); - result_.remove(g); - }, e -> logger.error("Exception while computing observable list.", e)); - result = result_; - getDependenciesAsOservableListCacheMap().put(generic, result); - } - return result; + public Observable getRemovesObservable() { + return getDifferentialObservable().flatMap(diff -> diff.getRemovesObservable(generic)); } }; } diff --git a/gs-defaults/pom.xml b/gs-defaults/pom.xml index 282c26a95..5c96ed5c9 100644 --- a/gs-defaults/pom.xml +++ b/gs-defaults/pom.xml @@ -17,28 +17,5 @@ gs-api 4.0-SNAPSHOT - - - org.slf4j - slf4j-api - ${slf4j.version} - - - - ch.qos.logback - logback-classic - ${logback.version} - - - - io.reactivex.rxjava2 - rxjavafx - 2.1.1 - - - io.reactivex.rxjava2 - rxjava - 2.1.3 - \ No newline at end of file diff --git a/gs-defaults/src/main/java/org/genericsystem/defaults/DefaultCompositesInheritance.java b/gs-defaults/src/main/java/org/genericsystem/defaults/DefaultCompositesInheritance.java index 8c349db92..1a8234ff9 100644 --- a/gs-defaults/src/main/java/org/genericsystem/defaults/DefaultCompositesInheritance.java +++ b/gs-defaults/src/main/java/org/genericsystem/defaults/DefaultCompositesInheritance.java @@ -4,7 +4,6 @@ import java.util.ArrayList; import java.util.List; import java.util.function.Predicate; -import java.util.stream.Collectors; import java.util.stream.Stream; import org.genericsystem.api.core.ApiStatics; @@ -13,15 +12,11 @@ import org.genericsystem.api.core.IndexFilter; import org.genericsystem.api.core.Snapshot; import org.genericsystem.defaults.DefaultConfig.NonHeritableProperty; -import org.genericsystem.defaults.tools.BindingsTools; import org.genericsystem.defaults.tools.InheritanceComputer; -import org.genericsystem.defaults.tools.ObservableInheritanceComputer; +import io.reactivex.Observable; import javafx.beans.binding.Bindings; -import javafx.beans.binding.ListBinding; import javafx.beans.value.ObservableValue; -import javafx.collections.FXCollections; -import javafx.collections.ObservableList; /** * @author Nicolas Feybesse @@ -82,17 +77,21 @@ default Snapshot getAttributes(T attribute) { if (nonHeritableProperty == null || attribute.inheritsFrom(nonHeritableProperty) || attribute.isInheritanceEnabled()) return new Snapshot() { + InheritanceComputer inheritanceComputer = new InheritanceComputer<>((T) DefaultCompositesInheritance.this, attribute, ApiStatics.STRUCTURAL); + @Override public Stream unfilteredStream() { - return new InheritanceComputer<>((T) DefaultCompositesInheritance.this, attribute, ApiStatics.STRUCTURAL).inheritanceStream(); + return inheritanceComputer.inheritanceStream(); } @Override - public ObservableList toObservableList() { - T nonHeritableProperty = getKey(NonHeritableProperty.class, ApiStatics.NO_POSITION); - if (nonHeritableProperty == null || attribute.inheritsFrom(nonHeritableProperty) || attribute.isInheritanceEnabled()) - return BindingsTools.createMinimalUnitaryChangesBinding(new ObservableInheritanceComputer<>((T) DefaultCompositesInheritance.this, attribute, ApiStatics.STRUCTURAL)); - return getComposites().toObservableList().filtered(holder -> holder.isSpecializationOf(attribute) && holder.getLevel() == ApiStatics.STRUCTURAL); + public Observable getAddsObservable() { + return inheritanceComputer.getAddsObservable(); + } + + @Override + public Observable getRemovesObservable() { + return inheritanceComputer.getRemovesObservable(); } }; return getComposites().filter(new IndexFilter(FiltersBuilder.IS_SPECIALIZATION_OF, attribute)).filter(new IndexFilter(FiltersBuilder.HAS_LEVEL, ApiStatics.STRUCTURAL)); @@ -144,17 +143,21 @@ default Snapshot getHolders(T attribute) { if (nonHeritableProperty == null || attribute.inheritsFrom(nonHeritableProperty) || attribute.isInheritanceEnabled()) return new Snapshot() { + InheritanceComputer inheritanceComputer = new InheritanceComputer<>((T) DefaultCompositesInheritance.this, attribute, ApiStatics.CONCRETE); + @Override public Stream unfilteredStream() { - return new InheritanceComputer<>((T) DefaultCompositesInheritance.this, attribute, ApiStatics.CONCRETE).inheritanceStream(); + return inheritanceComputer.inheritanceStream(); } @Override - public ObservableList toObservableList() { - T nonHeritableProperty = getKey(NonHeritableProperty.class, ApiStatics.NO_POSITION); - if (nonHeritableProperty == null || attribute.inheritsFrom(nonHeritableProperty) || attribute.isInheritanceEnabled()) - return BindingsTools.createMinimalUnitaryChangesBinding(new ObservableInheritanceComputer<>((T) DefaultCompositesInheritance.this, attribute, ApiStatics.CONCRETE)); - return getComposites().toObservableList().filtered(holder -> holder.isSpecializationOf(attribute) && holder.getLevel() == ApiStatics.CONCRETE); + public Observable getAddsObservable() { + return inheritanceComputer.getAddsObservable(); + } + + @Override + public Observable getRemovesObservable() { + return inheritanceComputer.getRemovesObservable(); } }; return DefaultCompositesInheritance.this.getComposites().filter(new IndexFilter(FiltersBuilder.IS_SPECIALIZATION_OF, attribute)).filter(new IndexFilter(FiltersBuilder.HAS_LEVEL, ApiStatics.CONCRETE)); @@ -292,18 +295,13 @@ public Stream unfilteredStream() { } @Override - public ObservableList toObservableList() { - return new ListBinding() { - private final ObservableList links = getLinks(attribute, value, targets).toObservableList(); - { - bind(links); - } - - @Override - protected ObservableList computeValue() { - return FXCollections.unmodifiableObservableList(FXCollections.observableList(links.stream().map(x -> x.getValue()).collect(Collectors.toList()))); - } - }; + public Observable getAddsObservable() { + return getLinks(attribute, value, targets).getAddsObservable().map(h -> h.getValue()); + } + + @Override + public Observable getRemovesObservable() { + return getLinks(attribute, value, targets).getRemovesObservable().map(h -> h.getValue()); } }; } @@ -319,18 +317,13 @@ public Stream unfilteredStream() { } @Override - public ObservableList toObservableList() { - return new ListBinding() { - private final ObservableList links = getLinks(attribute, targets).toObservableList(); - { - bind(links); - } - - @Override - protected ObservableList computeValue() { - return FXCollections.unmodifiableObservableList(FXCollections.observableList(links.stream().map(x -> x.getValue()).collect(Collectors.toList()))); - } - }; + public Observable getAddsObservable() { + return getLinks(attribute, targets).getAddsObservable().map(h -> h.getValue()); + } + + @Override + public Observable getRemovesObservable() { + return getLinks(attribute, targets).getRemovesObservable().map(h -> h.getValue()); } }; } @@ -345,19 +338,13 @@ public Stream unfilteredStream() { } @Override - public ObservableList toObservableList() { - return new ListBinding() { - private final ObservableList holders = getHolders(attribute, pos).toObservableList(); - { - bind(holders); - } - - @Override - protected ObservableList computeValue() { - return FXCollections.unmodifiableObservableList(FXCollections.observableList(holders.stream().map(x -> x.getValue()).collect(Collectors.toList()))); - - } - }; + public Observable getAddsObservable() { + return getHolders(attribute, pos).getAddsObservable().map(h -> h.getValue()); + } + + @Override + public Observable getRemovesObservable() { + return getHolders(attribute, pos).getRemovesObservable().map(h -> h.getValue()); } }; } diff --git a/gs-defaults/src/main/java/org/genericsystem/defaults/DefaultDependencies.java b/gs-defaults/src/main/java/org/genericsystem/defaults/DefaultDependencies.java index 0c56d03bf..6309702bf 100644 --- a/gs-defaults/src/main/java/org/genericsystem/defaults/DefaultDependencies.java +++ b/gs-defaults/src/main/java/org/genericsystem/defaults/DefaultDependencies.java @@ -13,10 +13,9 @@ import org.genericsystem.api.core.IGeneric; import org.genericsystem.api.core.IndexFilter; import org.genericsystem.api.core.Snapshot; -import org.genericsystem.defaults.tools.BindingsTools; +import org.genericsystem.defaults.tools.RxJavaHelpers; -import javafx.beans.Observable; -import javafx.collections.ObservableList; +import io.reactivex.Observable; /** * @author Nicolas Feybesse @@ -124,8 +123,17 @@ public Stream unfilteredStream() { } @Override - public ObservableList toObservableList() { - return BindingsTools.createMinimalUnitaryChangesBinding(getInheritings().toObservableList(), () -> getSubInheritings().toList(), g -> new Observable[] { g.getSubInheritings().toObservableList() }); + public Observable getAddsObservable() { + return Observable.merge(getInheritings().getAddsObservable(), + Observable.fromIterable(getInheritings()).flatMap(g -> g.getSubInheritings().getAddsObservable()), + RxJavaHelpers.additionsOf(getInheritings().toObservableList()).flatMap(g -> g.getSubInheritings().getAddsObservable())).distinct(); + } + + @Override + public Observable getRemovesObservable() { + return Observable.merge(getInheritings().getRemovesObservable(), + Observable.fromIterable(getInheritings()).flatMap(g -> g.getSubInheritings().getRemovesObservable()), + RxJavaHelpers.additionsOf(getInheritings().toObservableList()).flatMap(g -> g.getSubInheritings().getRemovesObservable())).distinct(); } }; } @@ -140,8 +148,15 @@ public Stream unfilteredStream() { } @Override - public ObservableList toObservableList() { - return BindingsTools.createMinimalUnitaryChangesBinding(getSubInheritings().toObservableList(), () -> getSubInstances().toList(), g -> new Observable[] { g.getInstances().toObservableList() }); + public Observable getAddsObservable() { + return Observable.merge(Observable.fromIterable(getSubInheritings()).flatMap(g -> g.getInstances().getAddsObservable()), + RxJavaHelpers.additionsOf(getSubInheritings().toObservableList()).flatMap(g -> g.getInstances().getAddsObservable())); + } + + @Override + public Observable getRemovesObservable() { + return Observable.merge(Observable.fromIterable(getSubInheritings()).flatMap(g -> g.getInstances().getRemovesObservable()), + RxJavaHelpers.additionsOf(getSubInheritings().toObservableList()).flatMap(g -> g.getInstances().getRemovesObservable())); } }; } diff --git a/gs-defaults/src/main/java/org/genericsystem/defaults/tools/InheritanceComputer.java b/gs-defaults/src/main/java/org/genericsystem/defaults/tools/InheritanceComputer.java index 78fa2e3b1..1bee91877 100644 --- a/gs-defaults/src/main/java/org/genericsystem/defaults/tools/InheritanceComputer.java +++ b/gs-defaults/src/main/java/org/genericsystem/defaults/tools/InheritanceComputer.java @@ -6,13 +6,17 @@ import java.util.HashSet; import java.util.Map; import java.util.Set; +import java.util.function.Predicate; import java.util.stream.Collectors; import java.util.stream.Stream; import org.genericsystem.api.core.FiltersBuilder; import org.genericsystem.api.core.IndexFilter; +import org.genericsystem.api.core.Snapshot; import org.genericsystem.defaults.DefaultGeneric; +import io.reactivex.Observable; + /** * @author Nicolas Feybesse * @@ -21,28 +25,54 @@ public class InheritanceComputer> { private final Map> inheritingsCache = new HashMap<>(); + private final Map> addsCache = new HashMap<>(); + private final Map> removesCache = new HashMap<>(); private final Set overridden = new HashSet<>(); private final T base; private final T origin; private final int level; + private final Predicate inheritingsFilter; public InheritanceComputer(T base, T origin, int level) { this.base = base; this.origin = origin; this.level = level; + inheritingsFilter = holder -> !overridden.contains(holder) && !holder.equals(origin) && holder.getLevel() == level; } public Stream inheritanceStream() { - return getInheringsStream(base).filter(holder -> !overridden.contains(holder) && !holder.equals(origin) && holder.getLevel() == level); + return getInheritingsStream(base).filter(holder -> inheritingsFilter.test(holder)); + } + + public Observable getAddsObservable() { + return getAddsObservable(base).filter(holder -> inheritingsFilter.test(holder)); + } + + public Observable getRemovesObservable() { + return getRemovesObservable(base).filter(holder -> inheritingsFilter.test(holder)); } - private Stream getInheringsStream(T superVertex) { + private Stream getInheritingsStream(T superVertex) { Collection result = inheritingsCache.get(superVertex); if (result == null) inheritingsCache.put(superVertex, result = buildInheritings(superVertex).inheritanceStream().collect(Collectors.toList())); return result.stream(); - // return new Inheritings(superVertex).inheritanceStream(); + // return new Inheritings(superVertex).inheritanceStream(); + } + + private Observable getAddsObservable(T superVertex) { + Observable result = addsCache.get(superVertex); + if (result == null) + addsCache.put(superVertex, result = buildInheritings(superVertex).inheritanceStreamAdds()); + return result; + } + + private Observable getRemovesObservable(T superVertex) { + Observable result = removesCache.get(superVertex); + if (result == null) + removesCache.put(superVertex, result = buildInheritings(superVertex).inheritanceStreamRemoves()); + return result; } protected Inheritings buildInheritings(T superVertex) { @@ -57,10 +87,6 @@ protected Inheritings(T localBase) { this.localBase = localBase; } - private Stream inheritanceStream() { - return fromAboveStream().flatMap(holder -> getStream(holder)).distinct(); - } - private boolean hasIntermediateSuperOrIsMeta() { return localBase.isMeta() || localBase.getSupers().stream().filter(next -> localBase.getMeta().equals(next.getMeta())).count() != 0; } @@ -69,25 +95,71 @@ private Stream metaAndSupersStream() { return Stream.concat(hasIntermediateSuperOrIsMeta() ? Stream.empty() : Stream.of(localBase.getMeta()), localBase.getSupers().stream()).distinct(); } + private Stream inheritanceStream() { + return fromAboveStream().flatMap(holder -> getStream(holder)).distinct(); + } + + private Observable inheritanceStreamAdds() { + return Observable.merge(fromAboveAdds().flatMap(holder -> getObservable(getStream(holder))).distinct(), + Observable.merge(fromAboveAdds(), getObservable(fromAboveStream())).flatMap(holder -> getStreamAdds(holder)).distinct()).distinct(); + } + + private Observable inheritanceStreamRemoves() { + return Observable.merge(Observable.merge(fromAboveAdds(), getObservable(fromAboveStream())).flatMap(holder -> getStreamRemoves(holder)).distinct(), + fromAboveRemoves().flatMap(holder -> getObservable(getStream(holder))).distinct()).distinct(); + } + private Stream fromAboveStream() { - return localBase.isRoot() ? Stream.of(origin) : metaAndSupersStream().flatMap(InheritanceComputer.this::getInheringsStream).distinct(); + return localBase.isRoot() ? Stream.of(origin) : metaAndSupersStream().flatMap(InheritanceComputer.this::getInheritingsStream).distinct(); + } + + private Observable fromAboveAdds() { + return localBase.isRoot() ? Observable.never() : getObservable(metaAndSupersStream()).flatMap(InheritanceComputer.this::getAddsObservable).distinct(); + } + + private Observable fromAboveRemoves() { + return localBase.isRoot() ? Observable.never() : getObservable(metaAndSupersStream()).flatMap(InheritanceComputer.this::getRemovesObservable).distinct(); + } + + private Stream getIndexStream(T holder) { + return Stream.concat(holder.getLevel() < level ? compositesByMeta(holder).stream() : Stream.empty(), compositesBySuper(holder).stream()); + } + + private Observable getIndexStreamAdds(T holder) { + return Observable.merge(holder.getLevel() < level ? compositesByMeta(holder).getAddsObservable() : Observable.never(), compositesBySuper(holder).getAddsObservable()); + } + + private Observable getIndexStreamRemoves(T holder) { + return Observable.merge(holder.getLevel() < level ? compositesByMeta(holder).getRemovesObservable() : Observable.never(), compositesBySuper(holder).getRemovesObservable()); } private Stream getStream(final T holder) { - if (compositesBySuper(holder).count() != 0) + if (compositesBySuper(holder).stream().count() != 0) overridden.add(holder); - Stream indexStream = Stream.concat(holder.getLevel() < level ? compositesByMeta(holder) : Stream.empty(), compositesBySuper(holder)); - return Stream.concat(Stream.of(holder), indexStream.flatMap(x -> getStream(x)).distinct()); + return Stream.concat(Stream.of(holder), getIndexStream(holder).flatMap(x -> getStream(x)).distinct()); } - protected Stream compositesByMeta(T holder) { - return localBase.getDependencies().filter(Arrays.asList(new IndexFilter(FiltersBuilder.COMPOSITES, localBase), new IndexFilter(FiltersBuilder.HAS_META, holder))).stream(); + private Observable getStreamAdds(T holder) { + Observable indexAdds = getIndexStreamAdds(holder); + return Observable.merge(Observable.merge(getObservable(getIndexStream(holder)), indexAdds).flatMap(x -> getStreamAdds(x)).distinct(), + indexAdds.flatMap(x -> getObservable(getStream(x))).distinct()).distinct(); } - protected Stream compositesBySuper(T holder) { - return localBase.getDependencies().filter(Arrays.asList(new IndexFilter(FiltersBuilder.COMPOSITES, localBase), new IndexFilter(FiltersBuilder.HAS_SUPER, holder))).stream(); + private Observable getStreamRemoves(T holder) { + return Observable.merge(getIndexStreamRemoves(holder).flatMap(x -> getObservable(getStream(x))).distinct(), + Observable.merge(getObservable(getIndexStream(holder)), getIndexStreamAdds(holder)).flatMap(x -> getStreamRemoves(x)).distinct()).distinct(); } - } + private Snapshot compositesByMeta(T holder) { + return localBase.getDependencies().filter(Arrays.asList(new IndexFilter(FiltersBuilder.COMPOSITES, localBase), new IndexFilter(FiltersBuilder.HAS_META, holder))); + } + private Snapshot compositesBySuper(T holder) { + return localBase.getDependencies().filter(Arrays.asList(new IndexFilter(FiltersBuilder.COMPOSITES, localBase), new IndexFilter(FiltersBuilder.HAS_SUPER, holder))); + } + + private Observable getObservable(Stream stream) { + return Observable.fromIterable(stream.collect(Collectors.toList())); + } + } } diff --git a/gs-defaults/src/main/java/org/genericsystem/defaults/tools/ObservableInheritanceComputer.java b/gs-defaults/src/main/java/org/genericsystem/defaults/tools/ObservableInheritanceComputer.java deleted file mode 100644 index eb5a012a1..000000000 --- a/gs-defaults/src/main/java/org/genericsystem/defaults/tools/ObservableInheritanceComputer.java +++ /dev/null @@ -1,67 +0,0 @@ -package org.genericsystem.defaults.tools; - -import java.util.ArrayList; -import java.util.List; -import java.util.stream.Collectors; -import java.util.stream.Stream; - -import org.genericsystem.api.core.FiltersBuilder; -import org.genericsystem.api.core.IndexFilter; -import org.genericsystem.defaults.DefaultGeneric; - -import javafx.beans.Observable; -import javafx.beans.binding.ListBinding; -import javafx.collections.FXCollections; -import javafx.collections.ObservableList; - -/** - * @author Nicolas Feybesse - * - * @param - */ -public class ObservableInheritanceComputer> extends ListBinding { - - List invalidators = new ArrayList<>(); - - private final T base; - private final T origin; - private final int level; - - public ObservableInheritanceComputer(T base, T origin, int level) { - this.base = base; - this.origin = origin; - this.level = level; - } - - @Override - protected ObservableList computeValue() { - invalidators.forEach(ObservableInheritanceComputer.this::unbind); - List newInvalidators = new ArrayList<>(); - List internal = new InheritanceComputer(base, origin, level) { - - @Override - protected Inheritings buildInheritings(T superVertex) { - return new Inheritings(superVertex) { - @Override - protected Stream compositesByMeta(T holder) { - ObservableList filtered = localBase.getComposites().filter(new IndexFilter(FiltersBuilder.HAS_META, holder)).toObservableList(); - newInvalidators.add(filtered); - bind(filtered); - return super.compositesByMeta(holder); - } - - @Override - protected Stream compositesBySuper(T holder) { - ObservableList filtered = localBase.getComposites().filter(new IndexFilter(FiltersBuilder.HAS_SUPER, holder)).toObservableList(); - newInvalidators.add(filtered); - bind(filtered); - return super.compositesBySuper(holder); - } - }; - - }; - }.inheritanceStream().collect(Collectors.toList()); - invalidators = newInvalidators; - return FXCollections.observableList(internal); - } -} diff --git a/gs-defaults/src/main/java/org/genericsystem/defaults/tools/RxJavaHelpers.java b/gs-defaults/src/main/java/org/genericsystem/defaults/tools/RxJavaHelpers.java new file mode 100644 index 000000000..cda0efe05 --- /dev/null +++ b/gs-defaults/src/main/java/org/genericsystem/defaults/tools/RxJavaHelpers.java @@ -0,0 +1,108 @@ +package org.genericsystem.defaults.tools; + +import java.util.AbstractMap.SimpleEntry; +import java.util.Map; +import java.util.Map.Entry; + +import io.reactivex.Observable; +import io.reactivex.ObservableOnSubscribe; +import io.reactivex.rxjavafx.subscriptions.JavaFxSubscriptions; +import javafx.collections.ListChangeListener; +import javafx.collections.MapChangeListener; +import javafx.collections.ObservableList; +import javafx.collections.ObservableMap; + +public class RxJavaHelpers { + /** + * Creates an observable that emits all additions to an ObservableList. + * + * @param source The source ObservableList for the item add events. + * @return An Observable emitting items added to the ObservableList. + */ + public static Observable additionsOf(final ObservableList source) { + return fromObservableListAdds(source); + } + + /** + * Creates an observable that emits all removals from an ObservableList. + * + * @param source The source ObservableList for the item removal events. + * @return An Observable emitting items removed from the ObservableList. + */ + public static Observable removalsOf(final ObservableList source) { + return fromObservableListRemovals(source); + } + + /** + * Creates an observable that emits all additions to an ObservableMap. + * + * @param source The source ObservableMap for the item add events. + * @return An Observable emitting Entry items added to the ObservableMap. + */ + public static Observable> additionsOf(final ObservableMap source) { + return fromObservableMapAdds(source); + } + + /** + * Creates an observable that emits all removals from an ObservableMap. + * + * @param source The source ObservableMap for the item removal events. + * @return An Observable emitting Entry items removed from the ObservableMap. + */ + public static Observable> removalsOf(final ObservableMap source) { + return fromObservableMapRemovals(source); + } + + public static Observable fromObservableListAdds(final ObservableList source) { + + return Observable.create((ObservableOnSubscribe) subscriber -> { + + ListChangeListener listener = c -> { + while (c.next()) + if (c.wasAdded()) + c.getAddedSubList().forEach(subscriber::onNext); + }; + source.addListener(listener); + subscriber.setDisposable(JavaFxSubscriptions.unsubscribeInEventDispatchThread(() -> source.removeListener(listener))); + }); + } + + public static Observable fromObservableListRemovals(final ObservableList source) { + + return Observable.create((ObservableOnSubscribe) subscriber -> { + ListChangeListener listener = c -> { + while (c.next()) + if (c.wasRemoved()) + c.getRemoved().forEach(subscriber::onNext); + }; + source.addListener(listener); + subscriber.setDisposable(JavaFxSubscriptions.unsubscribeInEventDispatchThread(() -> source.removeListener(listener))); + }); + } + + public static Observable> fromObservableMapAdds(final ObservableMap source) { + + return Observable.create((ObservableOnSubscribe>) subscriber -> { + + MapChangeListener listener = c -> { + if (c.wasAdded()) + subscriber.onNext(new SimpleEntry(c.getKey(),c.getValueAdded())); + }; + source.addListener(listener); + subscriber.setDisposable(JavaFxSubscriptions.unsubscribeInEventDispatchThread(() -> source.removeListener(listener))); + }); + } + + public static Observable> fromObservableMapRemovals(final ObservableMap source) { + + return Observable.create((ObservableOnSubscribe>) subscriber -> { + + MapChangeListener listener = c -> { + if (c.wasRemoved()) + subscriber.onNext(new SimpleEntry(c.getKey(),c.getValueRemoved())); + }; + source.addListener(listener); + subscriber.setDisposable(JavaFxSubscriptions.unsubscribeInEventDispatchThread(() -> source.removeListener(listener))); + }); + } +} \ No newline at end of file diff --git a/gs-kernel/src/test/java/org/genericsystem/cache/UpdateTest.java b/gs-kernel/src/test/java/org/genericsystem/cache/UpdateTest.java index 45ef90966..8e3b0562d 100644 --- a/gs-kernel/src/test/java/org/genericsystem/cache/UpdateTest.java +++ b/gs-kernel/src/test/java/org/genericsystem/cache/UpdateTest.java @@ -3,7 +3,6 @@ import org.genericsystem.api.core.ApiStatics; import org.genericsystem.api.core.exceptions.MetaRuleConstraintViolationException; import org.genericsystem.common.Generic; -import org.genericsystem.defaults.tools.ObservableInheritanceComputer; import org.genericsystem.kernel.Engine; import org.testng.annotations.Test; @@ -145,7 +144,7 @@ public void testInverseObservation() { Generic red = color.addInstance("Red"); Generic green = color.addInstance("Green"); Generic audiRed = audi.addLink(carColor, "audiRed", red); - ObservableList greenCars = new ObservableInheritanceComputer<>(green, carColor, ApiStatics.CONCRETE); + ObservableList greenCars = green.getHolders(carColor).toObservableList(); assert greenCars.isEmpty(); System.gc(); // Generic audiGreen = audiRed.updateComponent(green, ApiStatics.TARGET_POSITION);