package com.sijobe.spc.core; import com.sijobe.spc.util.DynamicClassLoader; import java.lang.reflect.Modifier; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; /** * This class provides methods to manage the Hooks that are available. * * @see IHook * @author simo_415 * @version 1.0 */ public class HookManager { /** * The master list that contains all of the registered hooks */ private List<IHook> master = new ArrayList<IHook>(); /** * The type separated list that has hooks grouped together by type, this is * used by the getHooks method * * @see HookManager#getHooks(Class) */ private Map<Class<? extends IHook>,List<IHook>> typemap = new HashMap<Class<? extends IHook>,List<IHook>>(); public HookManager() { master = new ArrayList<IHook>(); typemap = new HashMap<Class<? extends IHook>,List<IHook>>(); } /** * Registers the specified hook class with the manager. The instance is * initialised in this method using the default constructor. If the * master list contains this hook already then the hook isn't added to the * list since it already exists. If you want to overwrite the old instance * of the hook with a new instance use the remove(Hook) method first. * * @param hook - The hook to add to the manager. * @see HookManager#remove(IHook) */ public void register(Class<IHook> hook) { if (Modifier.isAbstract(hook.getModifiers())) { return; } try { register(hook.newInstance()); } catch (Exception e) { System.err.println("Could not load hook " + hook.getName() + ". " + "Check that the class has the default constructor visible."); e.printStackTrace(); } } /** * Registers the specified hook instance with the manager. If the * master list contains this hook already then the hook isn't added to the * list since it already exists. If you want to overwrite the old instance * of the hook with a new instance use the remove(Hook) method first. * * @param hook - The instance of the hook to add to the manager. * @see HookManager#remove(IHook) */ public void register(IHook hook) { // TODO: Should add to TYPES if (!master.contains(hook)) { master.add(hook); } else { return; } } /** * Removes the specified hook instance from the manager. * * @param hook - The hook to remove from the manager. */ public void remove(IHook hook) { if (master.contains(hook)) { master.remove(hook); } for (Class<? extends IHook> types : typemap.keySet()) { typemap.get(types).remove(hook); } } /** * Removes the specified class type from the manager * * @param type - The type of hook to remove */ public void remove(Class<IHook> type) { for (IHook hook : master) { if (type.isAssignableFrom(hook.getClass())) { master.remove(hook); } } for (Class<? extends IHook> types : typemap.keySet()) { for (IHook hook : typemap.get(types)) { if (type.isAssignableFrom(hook.getClass())) { typemap.get(types).remove(hook); } } if (typemap.get(types).size() == 0) { typemap.remove(typemap.get(types)); } } } /** * Gets hooks that are registered with this manager of the specified class * type. This allows for an easier management of hooking in hook implemented * classes. * <br><br> * Example Usage: * <pre>{@code * for (Hook hook : HookManager.getHooks(Hook.class) { * if (hook.isEnabled()) { * // Do stuff. * } * } * </pre> * * @param <H> - The class type that must extend Hook * @param type - The class type * @return A List of registered hooks with matching class types */ @SuppressWarnings("unchecked") public <H extends IHook> List<H> getHooks(Class<H> type) { if (typemap.containsKey(type)) { return (List<H>) typemap.get(type); } List<H> thisType = new ArrayList<H>(); for (IHook hook : master) { if (type.isAssignableFrom(hook.getClass())) { thisType.add((H) hook); } } typemap.put(type, (List<IHook>)thisType); return thisType; } /** * Method loads all Hooks that are currently available on the classpath. * * @param <H> - The type of hook to load * @param type - The type of class to load */ @SuppressWarnings("unchecked") public <H extends IHook> void loadHooks(Class<H> type) { SPCLoader.load(); List<Class<H>> hooks = DynamicClassLoader.getClasses(type); if (hooks != null) { for (Class<H> hook : hooks) { register((Class<IHook>)hook); } } } }