com.codelanx.codelanxlib.listener.ListenerManager.java Source code

Java tutorial

Introduction

Here is the source code for com.codelanx.codelanxlib.listener.ListenerManager.java

Source

/*
 * Copyright (C) 2015 CodeLanx , All Rights Reserved
 *
 * This work is licensed under a Creative Commons
 * Attribution-NonCommercial-NoDerivs 3.0 Unported License.
 *
 * This program is protected software: You are free to distrubute your
 * own use of this software under the terms of the Creative Commons BY-NC-ND
 * license as published by Creative Commons in the year 2015 or as published
 * by a later date. You may not provide the source files or provide a means
 * of running the software outside of those licensed to use it.
 * 
 * This program 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.
 * 
 * You should have received a copy of the Creative Commons BY-NC-ND license
 * along with this program. If not, see <https://creativecommons.org/licenses/>.
 */
package com.codelanx.codelanxlib.listener;

import com.codelanx.codelanxlib.CodelanxLib;
import com.codelanx.codelanxlib.logging.Logging;
import com.codelanx.codelanxlib.util.exception.Exceptions;
import com.codelanx.codelanxlib.util.exception.IllegalPluginAccessException;
import com.codelanx.codelanxlib.util.Reflections;
import java.util.HashMap;
import java.util.Map;
import java.util.logging.Level;
import org.apache.commons.lang.Validate;
import org.bukkit.event.HandlerList;
import org.bukkit.event.Listener;
import org.bukkit.plugin.Plugin;

/**
 * Centrally holds references to different Listener classes to allow for
 * retrieval of {@link SubListener} references
 *
 * @since 0.0.1
 * @author 1Rogue
 * @version 0.1.0
 */
public final class ListenerManager {

    /**
     * Private constructor to prevent instantiation
     *
     * @since 0.1.0
     * @version 0.1.0
     */
    private ListenerManager() {
    }

    /**
     * Maps {@link SubListener} class types to a {@link SubListener} instance
     *
     * @since 0.1.0
     * @version 0.1.0
     */
    @SuppressWarnings("rawtypes")
    private static final Map<Class<? extends SubListener>, SubListener<?>> listeners = new HashMap<>();

    /**
     * Gets a listener by its string name. Returns null if the listener is
     * disabled or not registered.
     *
     * @since 0.0.1
     * @version 0.1.0
     *
     * @param <S> The {@link SubListener} type
     * @param listener An instance of the class type to retrieve
     * @return The listener class, null if disabled or not registered
     * @throws IllegalArgumentException If the listener isn't registered
     */
    public static <S extends SubListener<? extends Plugin>> S getListener(Class<S> listener) {
        Validate.isTrue(ListenerManager.isRegistered(listener), "Class is not registered with listener manager");
        return (S) ListenerManager.listeners.get(listener);
    }

    /**
     * Returns the {@link Plugin} relevant to the passed {@link SubListener}
     * class
     *
     * @since 0.1.0
     * @version 0.1.0
     *
     * @param <P> The {@link Plugin} type
     * @param <S> The {@link SubListener} type
     * @param listener The {@link SubListener} class that was registered
     * @return The {@link Plugin} that registered the {@link SubListener}
     * @throws IllegalArgumentException If the listener isn't registered
     */
    public static <P extends Plugin, S extends SubListener<P>> P getRegisteringPlugin(Class<S> listener) {
        return ListenerManager.getListener(listener).getPlugin();
    }

    /**
     * Returns whether or not a listener is registered under the relevant
     * listener key
     *
     * @since 0.0.1
     * @version 0.1.0
     *
     * @param <T> The {@link SubListener} class to get
     * @param listener The listener class to look for
     * @return {@code true} if registered, {@code false} otherwise
     */
    public static <T extends SubListener<?>> boolean isRegistered(Class<T> listener) {
        return ListenerManager.listeners.containsKey(listener);
    }

    /**
     * Returns {@code true} if the passed {@link Listener} has another Listener
     * of the same class type already registered for bukkit. This should not be
     * used with any listeners that are from an anonymous class, as this will
     * return {@code true} for any other anonymous classes as well
     * 
     * @since 0.1.0
     * @version 0.1.0
     * 
     * @param p The {@link Plugin} that registers this {@link Listener}
     * @param l The {@link Listener} to check
     * @return {@code true} if registered to bukkit
     */
    public static boolean isRegisteredToBukkit(Plugin p, Listener l) {
        if (l.getClass().isAnonymousClass()) {
            StackTraceElement t = Reflections.getCaller();
            Logging.simple().here().print(Level.WARNING, "Passed an anonymous class from %s:%d",
                    t.getClass().getName(), t.getLineNumber());
        }
        return HandlerList.getRegisteredListeners(p).stream()
                .anyMatch(r -> r.getListener().getClass() == l.getClass());
    }

    /**
     * Registers a listener through Bukkit and {@link ListenerManager}
     *
     * @since 0.0.1
     * @version 0.1.0
     *
     * @param <S> The {@link SubListener} class to register
     * @param listener The listener to register
     * @throws IllegalArgumentException Attempted to register a Listener twice
     * @return The listener that was registered
     */
    public static <S extends SubListener<?>> S registerListener(S listener) {
        Validate.isTrue(!ListenerManager.isRegistered(listener.getClass()),
                "Listener Map already contains key: " + listener.getClass().getName());
        ListenerManager.listeners.put(listener.getClass(), listener);
        if (!ListenerManager.isRegisteredToBukkit(listener.getPlugin(), listener)) {
            listener.getPlugin().getServer().getPluginManager().registerEvents(listener, listener.getPlugin());
        }
        return listener;
    }

    /**
     * Calls {@link ListenerManager#registerListener(SubListener)} for every
     * passed listener. Any exception thrown will be re-thrown after all
     * listeners are registered
     *
     * @since 0.0.1
     * @version 0.1.0
     *
     * @param <T> The {@link SubListener} class to register
     * @param listeners The listeners to register
     * @throws IllegalArgumentException Attempted to register a Listener twice
     */
    public static <T extends SubListener<?>> void registerListeners(T... listeners) {
        IllegalArgumentException ex = null;
        for (T listener : listeners) {
            try {
                ListenerManager.registerListener(listener);
            } catch (IllegalArgumentException e) {
                if (ex != null) {
                    ex = e;
                }
            }
        }
        if (ex != null) {
            throw ex;
        }
    }

    /**
     * Unregisters a specific {@link SubListener} from both CodelanxLib and
     * Bukkit
     *
     * @since 0.1.0
     * @version 0.1.0
     *
     * @param listener The {@link SubListener} class to unregister
     */
    public static void unregisterListener(Class<? extends SubListener<?>> listener) {
        if (ListenerManager.isRegistered(listener)) {
            HandlerList.unregisterAll(ListenerManager.listeners.remove(listener));
        }
    }

    /**
     * Unregisters all the listeners attached to this {@link ListenerManager}.
     * Can only be called from {@link CodelanxLib}
     *
     * @since 0.0.1
     * @version 0.1.0
     *
     * @throws IllegalPluginAccessException Only {@link CodelanxLib} can use
     */
    public static void release() {
        Exceptions.illegalPluginAccess(Reflections.accessedFrom(CodelanxLib.class),
                "ListenerManager#release may only be called by CodelanxLib");
        ListenerManager.listeners.values().forEach((l) -> {
            l.onDisable();
            HandlerList.unregisterAll(l);
        });
        ListenerManager.listeners.clear();
    }

}