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

name.remal.collections.ObservableCollections Maven / Gradle / Ivy

package name.remal.collections;

import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

import java.io.InvalidObjectException;
import java.io.ObjectInputValidation;
import java.io.Serializable;
import java.util.*;

import static java.util.Objects.requireNonNull;
import static name.remal.SneakyThrow.sneakyThrow;

public class ObservableCollections {

    @SuppressFBWarnings({"SE_TRANSIENT_FIELD_NOT_RESTORED", "NFF_NON_FUNCTIONAL_FIELD", "NP_STORE_INTO_NONNULL_FIELD"})
    private static abstract class BaseWrappedObservableCollection> implements ObservableCollection, Serializable, ObjectInputValidation {

        private static final long serialVersionUID = 1;

        @NotNull
        protected final C delegate;

        protected BaseWrappedObservableCollection(@NotNull C delegate) {
            this.delegate = requireNonNull(delegate, "delegate can't be null");
        }

        /*
         * For deserialization
         */
        @SuppressWarnings("ConstantConditions")
        protected BaseWrappedObservableCollection() {
            delegate = null;
        }

        @SuppressWarnings("ConstantConditions")
        @Override
        public void validateObject() throws InvalidObjectException {
            if (delegate == null) {
                throw new InvalidObjectException("delegate can't be null");
            }
        }


        @NotNull
        private transient final List> elementAddedHandlers = new ArrayList<>();

        @Override
        @NotNull
        public HandlerRegistration registerElementAddedHandler(@NotNull ElementAddedHandler handler) {
            elementAddedHandlers.add(handler);
            return () -> elementAddedHandlers.removeIf(it -> it == handler);
        }

        protected void invokeElementAddedHandlers(@Nullable E element) {
            if (element != null) {
                try {
                    for (ElementAddedHandler handler : elementAddedHandlers) {
                        handler.onElementAdded(element);
                    }
                } catch (Throwable throwable) {
                    throw sneakyThrow(throwable);
                }
            }
        }


        @NotNull
        private transient final List> elementRemovedHandlers = new ArrayList<>();

        @Override
        @NotNull
        public HandlerRegistration registerElementRemovedHandler(@NotNull ElementRemovedHandler handler) {
            elementRemovedHandlers.add(handler);
            return () -> elementRemovedHandlers.removeIf(it -> it == handler);
        }

        protected void invokeElementRemovedHandlers(@Nullable E element) {
            if (element != null) {
                try {
                    for (ElementRemovedHandler handler : elementRemovedHandlers) {
                        handler.onElementRemoved(element);
                    }
                } catch (Throwable throwable) {
                    throw sneakyThrow(throwable);
                }
            }
        }


        @Override
        public boolean add(E e) {
            boolean result = delegate.add(e);
            if (result) {
                invokeElementAddedHandlers(e);
            }
            return result;
        }

        @SuppressWarnings("unchecked")
        @Override
        public boolean remove(Object o) {
            boolean result = delegate.remove(o);
            if (result) {
                invokeElementRemovedHandlers((E) o);
            }
            return result;
        }

        @NotNull
        @Override
        public Iterator iterator() {
            return new Iterator() {

                private final Iterator delegateIterator = delegate.iterator();

                @Nullable
                private E lastReturned;

                @Override
                public boolean hasNext() {
                    return delegateIterator.hasNext();
                }

                @Override
                public E next() {
                    return lastReturned = delegateIterator.next();
                }

                @Override
                public void remove() {
                    delegateIterator.remove();
                    invokeElementRemovedHandlers(lastReturned);
                    lastReturned = null;
                }

            };
        }


        @Override
        public boolean addAll(@NotNull Collection c) {
            boolean result = false;
            for (E e : c) {
                result |= add(e);
            }
            return result;
        }

        @Override
        public boolean removeAll(@NotNull Collection c) {
            boolean result = false;
            for (Object e : c) {
                result |= remove(e);
            }
            return result;
        }

        @SuppressWarnings("unchecked")
        @Override
        public void clear() {
            Object[] elements = toArray();
            delegate.clear();
            for (Object element : elements) {
                invokeElementRemovedHandlers((E) element);
            }
        }

        @Override
        public boolean retainAll(@NotNull Collection c) {
            boolean result = false;
            Iterator iterator = iterator();
            while (iterator.hasNext()) {
                E element = iterator.next();
                if (!c.contains(element)) {
                    iterator.remove();
                    result = true;
                }
            }
            return result;
        }


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

        @Override
        public boolean isEmpty() {
            return delegate.isEmpty();
        }

        @Override
        public boolean contains(Object o) {
            return delegate.contains(o);
        }

        @NotNull
        @Override
        public Object[] toArray() {
            return delegate.toArray();
        }

        @SuppressWarnings("SuspiciousToArrayCall")
        @NotNull
        @Override
        public  T[] toArray(@NotNull T[] a) {
            return delegate.toArray(a);
        }

        @Override
        public boolean containsAll(@NotNull Collection c) {
            return delegate.containsAll(c);
        }


        @Override
        public String toString() {
            return delegate.toString();
        }

        @Override
        public boolean equals(Object o) {
            if (this == o) return true;
            if (!(o instanceof BaseWrappedObservableCollection)) return false;
            BaseWrappedObservableCollection that = (BaseWrappedObservableCollection) o;
            return Objects.equals(delegate, that.delegate);
        }

        @Override
        public int hashCode() {
            return delegate.hashCode();
        }

    }


    private static class WrappedObservableCollection extends BaseWrappedObservableCollection> {

        private static final long serialVersionUID = 1;

        private WrappedObservableCollection(@NotNull Collection delegate) {
            super(delegate);
        }

        /*
         * For deserialization
         */
        @SuppressWarnings("unused")
        private WrappedObservableCollection() {
        }

    }

    @NotNull
    public static  ObservableCollection observableCollection(@NotNull Collection collection) {
        return new WrappedObservableCollection<>(collection);
    }


    private static class WrappedObservableList extends BaseWrappedObservableCollection> implements ObservableList {

        private static final long serialVersionUID = 1;

        private WrappedObservableList(@NotNull List delegate) {
            super(delegate);
        }

        /*
         * For deserialization
         */
        @SuppressWarnings("unused")
        private WrappedObservableList() {
        }

        @Override
        public E set(int index, E element) {
            E prev = delegate.set(index, element);
            if (!Objects.equals(prev, element)) {
                invokeElementRemovedHandlers(prev);
                invokeElementAddedHandlers(element);
            }
            return prev;
        }

        @Override
        public void add(int index, E element) {
            delegate.add(index, element);
            invokeElementAddedHandlers(element);
        }

        @Override
        public boolean addAll(int index, @NotNull Collection c) {
            boolean result = delegate.addAll(index, c);
            if (result) {
                for (E e : c) {
                    invokeElementAddedHandlers(e);
                }
            }
            return result;
        }

        @Override
        public E remove(int index) {
            E prev = delegate.remove(index);
            invokeElementRemovedHandlers(prev);
            return prev;
        }


        @NotNull
        @Override
        public ListIterator listIterator(int index) {
            return new ListIterator() {

                private final ListIterator delegateIterator = delegate.listIterator(index);

                @Nullable
                private E lastReturned;

                @Override
                public boolean hasNext() {
                    return delegateIterator.hasNext();
                }

                @Override
                public E next() {
                    return lastReturned = delegateIterator.next();
                }

                @Override
                public boolean hasPrevious() {
                    return delegateIterator.hasPrevious();
                }

                @Override
                public E previous() {
                    return lastReturned = delegateIterator.previous();
                }

                @Override
                public int nextIndex() {
                    return delegateIterator.nextIndex();
                }

                @Override
                public int previousIndex() {
                    return delegateIterator.previousIndex();
                }

                @Override
                public void remove() {
                    delegateIterator.remove();
                    invokeElementRemovedHandlers(lastReturned);
                    lastReturned = null;
                }

                @Override
                public void set(E e) {
                    E prev = get(nextIndex() - 1);
                    delegateIterator.set(e);
                    if (!Objects.equals(prev, e)) {
                        invokeElementRemovedHandlers(prev);
                        invokeElementAddedHandlers(e);
                    }
                }

                @Override
                public void add(E e) {
                    delegateIterator.add(e);
                    invokeElementAddedHandlers(e);
                }

            };
        }

        @NotNull
        @Override
        public ListIterator listIterator() {
            return listIterator(0);
        }


        @Override
        public E get(int index) {
            return delegate.get(index);
        }

        @Override
        public int indexOf(Object o) {
            return delegate.indexOf(o);
        }

        @Override
        public int lastIndexOf(Object o) {
            return delegate.lastIndexOf(o);
        }

        @NotNull
        @Override
        public List subList(int fromIndex, int toIndex) {
            return delegate.subList(fromIndex, toIndex);
        }

    }

    @NotNull
    public static  ObservableList observableList(@NotNull List list) {
        return new WrappedObservableList<>(list);
    }


    private static class WrappedObservableSet extends BaseWrappedObservableCollection> implements ObservableSet {

        private static final long serialVersionUID = 1;

        private WrappedObservableSet(@NotNull Set delegate) {
            super(delegate);
        }

        /*
         * For deserialization
         */
        @SuppressWarnings("unused")
        private WrappedObservableSet() {
        }

    }

    @NotNull
    public static  ObservableSet observableSet(@NotNull Set set) {
        return new WrappedObservableSet<>(set);
    }


    @SuppressWarnings("NonSerializableFieldInSerializableClass")
    @SuppressFBWarnings({"SE_TRANSIENT_FIELD_NOT_RESTORED", "NFF_NON_FUNCTIONAL_FIELD", "NP_STORE_INTO_NONNULL_FIELD"})
    private static class WrappedObservableMap implements ObservableMap, Serializable, ObjectInputValidation {

        private static final long serialVersionUID = 1;

        @NotNull
        private final Map delegate;

        private WrappedObservableMap(@NotNull Map delegate) {
            this.delegate = requireNonNull(delegate, "delegate can't be null");
        }

        /*
         * For deserialization
         */
        @SuppressWarnings({"ConstantConditions", "unused"})
        private WrappedObservableMap() {
            delegate = null;
        }

        @SuppressWarnings("ConstantConditions")
        @Override
        public void validateObject() throws InvalidObjectException {
            if (delegate == null) {
                throw new InvalidObjectException("delegate can't be null");
            }
        }


        @NotNull
        private transient final List> entryAddedHandlers = new ArrayList<>();

        @Override
        @NotNull
        public HandlerRegistration registerEntryAddedHandler(@NotNull EntryAddedHandler handler) {
            entryAddedHandlers.add(handler);
            return () -> entryAddedHandlers.removeIf(it -> it == handler);
        }

        private void invokeEntryAddedHandlers(K key, V value) {
            try {
                for (EntryAddedHandler handler : entryAddedHandlers) {
                    handler.onEntryAdded(key, value);
                }
            } catch (Throwable throwable) {
                throw sneakyThrow(throwable);
            }
        }


        @NotNull
        private transient final List> entryRemovedHandlers = new ArrayList<>();

        @Override
        @NotNull
        public HandlerRegistration registerEntryRemovedHandler(@NotNull EntryRemovedHandler handler) {
            entryRemovedHandlers.add(handler);
            return () -> entryRemovedHandlers.removeIf(it -> it == handler);
        }

        private void invokeEntryRemovedHandlers(K key, V value) {
            try {
                for (EntryRemovedHandler handler : entryRemovedHandlers) {
                    handler.onEntryRemoved(key, value);
                }
            } catch (Throwable throwable) {
                throw sneakyThrow(throwable);
            }
        }


        @SuppressWarnings("ConstantConditions")
        @Nullable
        @Override
        public V put(K key, V value) {
            boolean containsKey = delegate.containsKey(key);
            V prev = delegate.put(key, value);
            if (!containsKey) {
                invokeEntryAddedHandlers(key, value);
            } else if (!Objects.equals(prev, value)) {
                invokeEntryRemovedHandlers(key, prev);
                invokeEntryAddedHandlers(key, value);
            }
            return prev;
        }

        @Override
        public void putAll(@NotNull Map m) {
            m.forEach(this::put);
        }

        @SuppressWarnings({"unchecked", "SuspiciousMethodCalls"})
        @Override
        public V remove(Object key) {
            boolean containsKey = delegate.containsKey(key);
            V prev = delegate.remove(key);
            if (containsKey) {
                invokeEntryRemovedHandlers((K) key, prev);
            }
            return prev;
        }

        @Override
        public void clear() {
            List> entries = new ArrayList<>(delegate.entrySet());
            delegate.clear();
            for (Entry entry : entries) {
                invokeEntryRemovedHandlers(entry.getKey(), entry.getValue());
            }
        }


        @NotNull
        @Override
        public Set keySet() {
            return new AbstractSet() {

                private final Set delegateKeySet = delegate.keySet();

                @SuppressWarnings({"SuspiciousMethodCalls", "unchecked"})
                @Override
                public boolean remove(Object o) {
                    boolean contains = delegate.containsKey(o);
                    V prev = delegate.remove(o);
                    if (contains) {
                        invokeEntryRemovedHandlers((K) o, prev);
                    }
                    return contains;
                }

                @NotNull
                @Override
                public Iterator iterator() {
                    return new Iterator() {

                        private final Iterator> delegateIterator = entrySet().iterator();

                        @Override
                        public boolean hasNext() {
                            return delegateIterator.hasNext();
                        }

                        @Override
                        public K next() {
                            return delegateIterator.next().getKey();
                        }

                        @Override
                        public void remove() {
                            delegateIterator.remove();
                        }

                    };
                }

                @Override
                public void clear() {
                    WrappedObservableMap.this.clear();
                }

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

                @Override
                public boolean contains(Object o) {
                    return delegateKeySet.contains(o);
                }

            };
        }

        @NotNull
        @Override
        public Collection values() {
            return new AbstractCollection() {

                private final Collection delegateValues = delegate.values();

                @Override
                public boolean remove(Object o) {
                    for (Entry entry : delegate.entrySet()) {
                        if (Objects.equals(o, entry.getValue())) {
                            WrappedObservableMap.this.remove(entry.getKey());
                            return true;
                        }
                    }
                    return false;
                }

                @NotNull
                @Override
                public Iterator iterator() {
                    return new Iterator() {

                        private final Iterator> delegateIterator = entrySet().iterator();

                        @Override
                        public boolean hasNext() {
                            return delegateIterator.hasNext();
                        }

                        @Override
                        public V next() {
                            return delegateIterator.next().getValue();
                        }

                        @Override
                        public void remove() {
                            delegateIterator.remove();
                        }

                    };
                }

                @Override
                public void clear() {
                    WrappedObservableMap.this.clear();
                }

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

                @Override
                public boolean contains(Object o) {
                    return delegateValues.contains(o);
                }

            };
        }

        @NotNull
        @Override
        public Set> entrySet() {
            return new AbstractSet>() {

                private final Set> delegateEntrySet = delegate.entrySet();

                @NotNull
                @Override
                public Iterator> iterator() {
                    return new Iterator>() {

                        private final Iterator> delegateIterator = delegateEntrySet.iterator();

                        @Nullable
                        private Entry lastReturned;

                        @Override
                        public boolean hasNext() {
                            return delegateIterator.hasNext();
                        }

                        @Override
                        public Entry next() {
                            return lastReturned = delegateIterator.next();
                        }

                        @Override
                        public void remove() {
                            delegateIterator.remove();
                            if (lastReturned != null) {
                                invokeEntryRemovedHandlers(lastReturned.getKey(), lastReturned.getValue());
                            }
                            lastReturned = null;
                        }

                    };
                }

                @SuppressWarnings("unchecked")
                @Override
                public boolean remove(Object o) {
                    boolean result = delegateEntrySet.remove(o);
                    if (result) {
                        invokeEntryRemovedHandlers(((Entry) o).getKey(), ((Entry) o).getValue());
                    }
                    return result;
                }

                @Override
                public void clear() {
                    WrappedObservableMap.this.clear();
                }

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

                @Override
                public boolean contains(Object o) {
                    return delegateEntrySet.contains(o);
                }

            };
        }


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

        @Override
        public boolean isEmpty() {
            return delegate.isEmpty();
        }

        @Override
        public boolean containsKey(Object key) {
            return delegate.containsKey(key);
        }

        @Override
        public boolean containsValue(Object value) {
            return delegate.containsValue(value);
        }

        @Override
        public V get(Object key) {
            return delegate.get(key);
        }


        @Override
        public String toString() {
            return delegate.toString();
        }

        @Override
        public boolean equals(Object o) {
            if (this == o) return true;
            if (!(o instanceof WrappedObservableMap)) return false;
            WrappedObservableMap that = (WrappedObservableMap) o;
            return Objects.equals(delegate, that.delegate);
        }

        @Override
        public int hashCode() {
            return delegate.hashCode();
        }

    }

    @NotNull
    public static  ObservableMap observableMap(@NotNull Map map) {
        return new WrappedObservableMap<>(map);
    }

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy