cz.cuni.mff.ms.brodecva.botnicek.ide.utils.events.DefaultEventManager.java Source code

Java tutorial

Introduction

Here is the source code for cz.cuni.mff.ms.brodecva.botnicek.ide.utils.events.DefaultEventManager.java

Source

/**
 * Copyright Vclav Brodec 2014.
 * 
 * This file is part of Botn?ek.
 * 
 * Botn?ek is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 * 
 * Botn?ek is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with Botn?ek.  If not, see <http://www.gnu.org/licenses/>.
 */
package cz.cuni.mff.ms.brodecva.botnicek.ide.utils.events;

import java.io.Serializable;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import java.util.WeakHashMap;

import com.google.common.base.Preconditions;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Sets;

import cz.cuni.mff.ms.brodecva.botnicek.ide.utils.data.Presence;

/**
 * <p>
 * Vchoz implementace sprvce udlost.
 * </p>
 * <p>
 * Krom toho, e realizuje odesln zprv o udlosti tak, aby klient nemusel
 * rozliovat, jak typ odesl, tak dovoluje v ppad poteby neodebrat
 * poslucha?, ani by dochzelo k unikn pamti.
 * </p>
 * <p>
 * Pestoe jsou instance tto tdy serializovateln, nelze toto garantovat pro
 * vloen objekty.
 * </p>
 * 
 * @author Vclav Brodec
 * @version 1.0
 */
public final class DefaultEventManager implements EventManager, Serializable {

    /**
     * <p>
     * Nvtvnk pro rozlien typu udlosti pi vypravovn poslucha?m.
     * </p>
     * <p>
     * Dky nmu je udlost podle svho typu rozeslna sprvnm poslucha?m.
     * </p>
     * <p>
     * Pi prchodu poslucha?i bere v potaz vlastnosti {@link WeakHashMap} pi
     * iteraci pes ?leny.
     * </p>
     */
    private final class MappedEventVisitor implements Visitor {

        @Override
        public <L> void visit(final Event<L> event) {
            visitCommon(event);
        }

        @Override
        public <K, L> void visit(final MappedEvent<K, L> event) {
            visitMapped(event);
            visitCommon(event);
        }

        private <L> void visitCommon(final Event<L> event) {
            @SuppressWarnings("unchecked")
            final Set<L> listeners = (Set<L>) DefaultEventManager.this.eventsToListeners.get(event.getClass());
            if (Presence.isAbsent(listeners)) {
                return;
            }

            final Set<L> listenersSnapshot = ImmutableSet.copyOf(listeners);
            for (final L listener : listenersSnapshot) {
                event.dispatchTo(listener);
            }
        }

        private <K, L> void visitMapped(final MappedEvent<K, L> event) {
            @SuppressWarnings("unchecked")
            final Map<K, Set<?>> keysTolisteners = (Map<K, Set<?>>) DefaultEventManager.this.eventsAndKeysToListeners
                    .get(event.getClass());
            if (Presence.isAbsent(keysTolisteners)) {
                return;
            }

            @SuppressWarnings("unchecked")
            final Set<L> mappedListeners = (Set<L>) keysTolisteners.get(event.getKey());
            if (Presence.isAbsent(mappedListeners)) {
                return;
            }

            final Set<L> listenersSnapshot = ImmutableSet.copyOf(mappedListeners);
            for (final L listener : listenersSnapshot) {
                event.dispatchTo(listener);
            }
        }
    }

    private static final long serialVersionUID = 1L;

    /**
     * Vytvo manaer udlost.
     * 
     * @return manaer
     */
    public static DefaultEventManager create() {
        return new DefaultEventManager();
    }

    private final Map<Class<? extends MappedEvent<?, ?>>, Map<?, Set<?>>> eventsAndKeysToListeners = new HashMap<>();

    private final Map<Class<? extends Event<?>>, Set<?>> eventsToListeners = new HashMap<>();

    private DefaultEventManager() {
    }

    /*
     * (non-Javadoc)
     * 
     * @see cz.cuni.mff.ms.brodecva.botnicek.ide.utils.events.EventRegister#
     * addEventListener(java.lang.Class, java.lang.Object)
     */
    @Override
    public <L> void addListener(final Class<? extends Event<L>> type, final L listener) {
        Preconditions.checkNotNull(type);
        Preconditions.checkNotNull(listener);

        @SuppressWarnings("unchecked")
        final Set<L> listeners = (Set<L>) this.eventsToListeners.get(type);
        final Set<L> usedListeners;
        if (Presence.isAbsent(listeners)) {
            usedListeners = Sets.newSetFromMap(new WeakHashMap<L, Boolean>());
            this.eventsToListeners.put(type, usedListeners);
        } else {
            usedListeners = listeners;
        }

        final boolean fresh = usedListeners.add(listener);
        Preconditions.checkArgument(fresh);
    }

    /*
     * (non-Javadoc)
     * 
     * @see
     * cz.cuni.mff.ms.brodecva.botnicek.ide.utils.EventRegister#addEventListener
     * (java.lang.Class, java.lang.Object)
     */
    @Override
    public <K, L> void addListener(final Class<? extends MappedEvent<K, L>> type, final K key, final L listener) {
        Preconditions.checkNotNull(type);
        Preconditions.checkNotNull(key);
        Preconditions.checkNotNull(listener);

        @SuppressWarnings("unchecked")
        final Map<K, Set<?>> keysTolisteners = (Map<K, Set<?>>) this.eventsAndKeysToListeners.get(type);
        final Map<K, Set<?>> usedKeysToListeners;
        if (Presence.isAbsent(keysTolisteners)) {
            usedKeysToListeners = new WeakHashMap<>();
            this.eventsAndKeysToListeners.put(type, usedKeysToListeners);
        } else {
            usedKeysToListeners = keysTolisteners;
        }

        @SuppressWarnings("unchecked")
        final Set<L> listeners = (Set<L>) usedKeysToListeners.get(key);
        final Set<L> usedListeners;
        if (Presence.isAbsent(listeners)) {
            usedListeners = Collections.newSetFromMap(new WeakHashMap<L, Boolean>());
            usedKeysToListeners.put(key, usedListeners);
        } else {
            usedListeners = listeners;
        }

        final boolean fresh = usedListeners.add(listener);
        Preconditions.checkArgument(fresh);
    }

    /*
     * (non-Javadoc)
     * 
     * @see
     * cz.cuni.mff.ms.brodecva.botnicek.ide.utils.events.Dispatcher#fire(cz.
     * cuni.mff.ms.brodecva.botnicek.ide.utils.events.SimpleEvent)
     */
    @Override
    public <L> void fire(final Event<L> event) {
        Preconditions.checkNotNull(event);

        event.accept(new MappedEventVisitor());
    }

    /*
     * (non-Javadoc)
     * 
     * @see cz.cuni.mff.ms.brodecva.botnicek.ide.utils.events.EventRegister#
     * removeAllListeners(java.lang.Class)
     */
    @Override
    public <K, L> void removeAllListeners(final Class<? extends Event<L>> type) {
        Preconditions.checkNotNull(type);

        Preconditions.checkNotNull(type);

        this.eventsToListeners.remove(type);
    }

    /*
     * (non-Javadoc)
     * 
     * @see cz.cuni.mff.ms.brodecva.botnicek.ide.utils.events.EventRegister#
     * removeAllListeners(java.lang.Class, java.lang.Object)
     */
    @Override
    public <K, L> void removeAllListeners(final Class<? extends MappedEvent<K, L>> type, final K key) {
        Preconditions.checkNotNull(type);
        Preconditions.checkNotNull(key);

        Preconditions.checkNotNull(type);
        Preconditions.checkNotNull(key);

        @SuppressWarnings("unchecked")
        final Map<K, Set<?>> keysTolisteners = (Map<K, Set<?>>) this.eventsAndKeysToListeners.get(type);
        Preconditions.checkArgument(Presence.isPresent(keysTolisteners));

        keysTolisteners.remove(key);

        if (keysTolisteners.isEmpty()) {
            this.eventsAndKeysToListeners.remove(type);
        }
    }

    /*
     * (non-Javadoc)
     * 
     * @see cz.cuni.mff.ms.brodecva.botnicek.ide.utils.events.EventRegister#
     * removeEventListener(java.lang.Class, java.lang.Object)
     */
    @Override
    public <L> void removeListener(final Class<? extends Event<L>> type, final L listener) {
        Preconditions.checkNotNull(type);
        Preconditions.checkNotNull(listener);

        @SuppressWarnings("unchecked")
        final Set<L> listeners = (Set<L>) this.eventsToListeners.get(type);
        Preconditions.checkArgument(Presence.isPresent(listeners));

        final boolean contained = listeners.remove(listener);
        Preconditions.checkArgument(contained);

        if (listeners.isEmpty()) {
            this.eventsToListeners.remove(listeners);
        }
    }

    /*
     * (non-Javadoc)
     * 
     * @see
     * cz.cuni.mff.ms.brodecva.botnicek.ide.utils.EventRegister#removeEventListener
     * (java.lang.Class, java.lang.Object)
     */
    @Override
    public <K, L> void removeListener(final Class<? extends MappedEvent<K, L>> type, final K key,
            final L listener) {
        Preconditions.checkNotNull(type);
        Preconditions.checkNotNull(key);
        Preconditions.checkNotNull(listener);

        @SuppressWarnings("unchecked")
        final Map<K, Set<?>> keysTolisteners = (Map<K, Set<?>>) this.eventsAndKeysToListeners.get(type);
        Preconditions.checkArgument(Presence.isPresent(keysTolisteners));

        @SuppressWarnings("unchecked")
        final Set<L> listeners = (Set<L>) keysTolisteners.get(key);
        Preconditions.checkArgument(Presence.isPresent(listeners));

        final boolean contained = listeners.remove(listener);
        Preconditions.checkArgument(contained);

        if (listeners.isEmpty()) {
            keysTolisteners.remove(key);
        }
        if (keysTolisteners.isEmpty()) {
            this.eventsAndKeysToListeners.remove(type);
        }
    }
}