com.ndemyanovskyi.observing.Listeners.java Source code

Java tutorial

Introduction

Here is the source code for com.ndemyanovskyi.observing.Listeners.java

Source

/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */

package com.ndemyanovskyi.observing;

import com.ndemyanovskyi.collection.set.DefaultSet;
import com.ndemyanovskyi.iterator.Iterators;
import com.ndemyanovskyi.observing.Listeners.SubListeners;
import com.ndemyanovskyi.observing.Observable.Listener;
import java.util.Collections;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.function.Consumer;
import static org.apache.commons.collections4.map.AbstractReferenceMap.ReferenceStrength.HARD;
import static org.apache.commons.collections4.map.AbstractReferenceMap.ReferenceStrength.SOFT;
import static org.apache.commons.collections4.map.AbstractReferenceMap.ReferenceStrength.WEAK;
import org.apache.commons.collections4.map.ReferenceMap;

public class Listeners<L extends Listener> implements DefaultSet<L> {

    private Set<L> hardSet;
    private Set<L> softSet;
    private Set<L> weakSet;
    private Map<Class<?>, SubListeners<?>> subs;

    private final Observable owner;

    public Listeners(Observable owner) {
        this.owner = Objects.requireNonNull(owner);
    }

    Set<L> hardSet() {
        if (hardSet == null) {
            hardSet = new HashSet<>();
        }
        return hardSet;
    }

    Set<L> softSet() {
        if (softSet == null) {
            softSet = Collections.newSetFromMap(new ReferenceMap<>(SOFT, HARD));
        }
        return softSet;
    }

    Set<L> weakSet() {
        if (weakSet == null) {
            weakSet = Collections.newSetFromMap(new ReferenceMap<>(WEAK, HARD));
        }
        return weakSet;
    }

    private Map<Class<?>, SubListeners<?>> subs() {
        if (subs == null) {
            subs = new ReferenceMap<>(HARD, SOFT);
        }
        return subs;
    }

    public void notifyChange() {
        if (!isEmpty()) {
            for (Listener l : this) {
                l.onChange(owner);
            }
        }
    }

    @Override
    public int size() {
        int size = 0;
        if (hardSet != null)
            size += hardSet.size();
        if (softSet != null)
            size += softSet.size();
        if (weakSet != null)
            size += weakSet.size();
        return size;
    }

    @Override
    public Iterator<L> iterator() {
        Iterator<L> empty = Iterators.empty();
        return Iterators.combined((hardSet != null) ? hardSet.iterator() : empty,
                (softSet != null) ? softSet.iterator() : empty, (weakSet != null) ? weakSet.iterator() : empty);
    }

    @Override
    public boolean add(L e) {
        return hardSet().add(e);
    }

    public boolean addSoft(L e) {
        return softSet().add(e);
    }

    public boolean addWeak(L e) {
        return weakSet().add(e);
    }

    @Override
    public boolean remove(Object o) {
        return (hardSet != null && hardSet.remove(o)) && (softSet != null && softSet.remove(o))
                && (weakSet != null && weakSet.remove(o));
    }

    public <T extends L> SubListeners<T> sub(Class<T> c) {
        SubListeners<T> sub = (SubListeners<T>) subs().get(c);
        if (sub == null) {
            sub = new SubListeners<>(this, c);
            subs().put(c, sub);
        }
        return sub;
    }

    public static class SubListeners<S extends Listener> extends Listeners<S> {

        private final Class<S> representClass;
        private final Listeners<? super S> base;

        public SubListeners(Listeners<? super S> base, Class<S> representClass) {
            super(base.owner);
            this.base = base;
            this.representClass = Objects.requireNonNull(representClass);
        }

        public Class<S> getRepresentClass() {
            return representClass;
        }

        @Override
        public boolean add(S e) {
            return base.add(e);
        }

        @Override
        public boolean addSoft(S e) {
            return base.addSoft(e);
        }

        @Override
        public boolean addWeak(S e) {
            return base.addWeak(e);
        }

        @Override
        public boolean remove(Object o) {
            return representClass.isInstance(o) && base.remove(o);
        }

        @Override
        public Iterator<S> iterator() {
            return Iterators.filtered((Iterator<S>) base.iterator(), representClass::isInstance);
        }

        @Override
        public <T extends S> SubListeners<T> sub(Class<T> c) {
            if (!c.isAssignableFrom(representClass)) {
                throw new IllegalArgumentException(c + " not assignable from " + representClass);
            }

            return base.sub((Class) c);
        }

        @Override
        public void notifyChange() {
            base.notifyChange();
        }

        public void notifyChange(Consumer<? super S> action) {
            if (!base.isEmpty()) {
                for (Listener l : base) {
                    l.onChange(base.owner);
                    if (representClass.isInstance(l)) {
                        action.accept((S) l);
                    }
                }
            }
        }

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

        @Override
        public boolean isEmpty() {
            return size() == 0;
        }

    }

}