All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.aksw.commons.collection.observable.ObservableSetUnion Maven / Gradle / Ivy

There is a newer version: 0.9.9
Show newest version
package org.aksw.commons.collection.observable;

import java.beans.PropertyChangeListener;
import java.beans.VetoableChangeListener;
import java.util.AbstractSet;
import java.util.Collection;
import java.util.Collections;
import java.util.Iterator;
import java.util.LinkedHashSet;
import java.util.Set;

import com.google.common.collect.Sets;


public class ObservableSetUnion
    extends AbstractSet
    implements ObservableSet
{
    protected ObservableSet lhs;
    protected ObservableSet rhs;
    protected Set effectiveSet;

    public ObservableSetUnion(ObservableSet lhs, ObservableSet rhs) {
        super();
        this.lhs = lhs;
        this.rhs = rhs;
        this.effectiveSet = Sets.union(lhs, rhs);
    }

    @Override
    public boolean delta(Collection additions, Collection removals) {
        throw new UnsupportedOperationException();
    }

    @Override
    public Registration addPropertyChangeListener(PropertyChangeListener listener) {
        // FIXME Create a union event - i.e. cross check additions / deletions against the values
        // in the sets:
        // - suppress an added value if it was already present (in the other set)
        // - suppress a deleted value if it is present in the other set

        Registration a = lhs.addPropertyChangeListener(convertListener(this, rhs, listener));
        Registration b = rhs.addPropertyChangeListener(convertListener(this, lhs, listener));

        // Return a runnable that deregister both listeners
        // return () -> { a.run(); b.run(); };
        return Registration.from(
            () -> { listener.propertyChange(new CollectionChangedEventImpl(
                    this, this, this,
                    Collections.emptySet(), Collections.emptySet(), Collections.emptySet())); },
            () -> { a.remove(); b.remove(); }
        );
    }


    @Override
    public Runnable addVetoableChangeListener(VetoableChangeListener listener) {
        Runnable a = lhs.addVetoableChangeListener(convertListener(this, rhs, listener));
        Runnable b = rhs.addVetoableChangeListener(convertListener(this, lhs, listener));

        // Return a runnable that deregister both listeners
        return () -> { a.run(); b.run(); };
    }


    @SuppressWarnings("unchecked")
    public static  VetoableChangeListener convertListener(
            Object self, Set other,
            VetoableChangeListener listener) {

        return ev -> {
            CollectionChangedEvent newEv = convertEvent(self, (CollectionChangedEvent)ev, other);
            if (newEv.hasChanges()) {
                listener.vetoableChange(newEv);
            }
        };
    }


    @SuppressWarnings("unchecked")
    public static  PropertyChangeListener convertListener(
            Object self, Set other,
            PropertyChangeListener listener) {

        return ev -> {
            CollectionChangedEvent newEv = convertEvent(self, (CollectionChangedEvent)ev, other);
            if (newEv.hasChanges()) {
                listener.propertyChange(newEv);
            }
        };
    }


    protected static  Set nullSafeDifference(Set set, Set other) {
        return set == null ? Collections.emptySet() : Sets.difference((Set)set, other);
    }

    @SuppressWarnings("unchecked")
    public static  CollectionChangedEvent convertEvent(Object self,
            CollectionChangedEvent ev, Set other) {

        // Added items that already exist in the 'other' set are substracted
        Set effectiveAdditions = nullSafeDifference((Set)ev.getAdditions(), other);
        // Deletions that already exist in the other set are also substracted
        Set effectiveDeletions = nullSafeDifference((Set)ev.getDeletions(), other);

        return new CollectionChangedEventImpl(
            self, self,
            Sets.union(Sets.difference((Set)self, effectiveDeletions), effectiveAdditions),
            effectiveAdditions,
            effectiveDeletions,
            // Refreshes are just passed through
            nullSafeDifference((Set)ev.getRefreshes(), other));
    }


    @Override
    public Iterator iterator() {
        return effectiveSet.iterator();
    }

    @Override
    public int size() {
        return effectiveSet.size();
    }

    public static  ObservableSet create(ObservableSet a, ObservableSet b) {
        return new ObservableSetUnion<>(a, b);
    }

    public static void main(String[] args) {
        ObservableSet a = ObservableSetImpl.decorate(new LinkedHashSet<>());
        ObservableSet b = ObservableSetImpl.decorate(new LinkedHashSet<>());

        ObservableSet c = ObservableSetUnion.create(a, b);

        c.addPropertyChangeListener(ev -> System.out.println(ev));


        a.add("Hello"); // expect addition
        b.add("Hello"); // expect no event

        a.remove("Hello"); // expect no event
        b.remove("Hello"); // expect event

    }

}





© 2015 - 2025 Weber Informatics LLC | Privacy Policy