/** * */ package net.frontlinesms; import java.util.Collections; import java.util.HashSet; import java.util.Set; import org.apache.log4j.Logger; import org.springframework.context.ApplicationContext; import net.frontlinesms.plugins.PluginController; import net.frontlinesms.plugins.PluginInitialisationException; import net.frontlinesms.plugins.PluginProperties; /** * This class controls which plugins are currently enabled, and also provides convenience methods for performing actions on plugins. * TODO work out the PRECISE responsibilities of this class, and document properly. * @author Alex */ public class PluginManager { //> STATIC CONSTANTS //> INSTANCE PROPERTIES /** Logging object */ private final Logger log = FrontlineUtils.getLogger(this.getClass()); /** The application context */ private final ApplicationContext applicationContext; /** FrontlineSMS instance */ private final FrontlineSMS frontlineController; /** Plugin controllers available for this. */ private final Set<PluginController> pluginControllers = new HashSet<PluginController>(); // TODO this should be moved to a plugin controller manager class //> CONSTRUCTORS /** * Create a new {@link PluginManager} for a given {@link FrontlineSMS} instance * @param frontlineController * @param applicationContext */ PluginManager(FrontlineSMS frontlineController, ApplicationContext applicationContext) { this.frontlineController = frontlineController; this.applicationContext = applicationContext; this.loadPluginControllers(); } //> ACCESSORS /** @return {@link #pluginControllers} */ public Set<PluginController> getPluginControllers() { return Collections.unmodifiableSet(this.pluginControllers); } /** * Loads a plugin controller of the requested class name. * @param pluginClassName * @return The newly-loaded {@link PluginController} */ @SuppressWarnings("unchecked") public PluginController loadPluginController(String pluginClassName) { try { log.info("Loading plugin of class: " + pluginClassName); Class<? extends PluginController> controllerClass = (Class<? extends PluginController>) Class.forName(pluginClassName); return loadPluginController(controllerClass); } catch(Exception ex) { log.warn("Problem loading plugin controller for class: " + pluginClassName, ex); return null; } } /** * Loads a plugin controller of the requested class. * @param pluginClass * @return The newly-loaded {@link PluginController} * @throws IllegalAccessException * @throws InstantiationException */ public PluginController loadPluginController(Class<? extends PluginController> pluginClass) { try { PluginController newInstance = pluginClass.newInstance(); this.pluginControllers.add(newInstance); return newInstance; } catch(Exception ex) { log.warn("Problem loading plugin controller for class: " + pluginClass.getName(), ex); return null; } } /** * <p>Load the plugin controllers that will be used. N.B. these will not have {@link PluginController#init(FrontlineSMS, ApplicationContext)} called * until {@link #initPluginControllers()} is called.</p> * <p>This method should only be called from the constructor {@link #PluginManager(FrontlineSMS, ApplicationContext)}.</p> */ private void loadPluginControllers() { log.info("Loading plugin controllers...."); PluginProperties pluginProperties = PluginProperties.getInstance(); for(Class<? extends PluginController> pluginClass : pluginProperties.getPluginClasses()) { boolean loadClass = pluginProperties.isPluginEnabled(pluginClass); if(loadClass) { this.loadPluginController(pluginClass); } else { log.info("Not loading plugin of class: " + pluginClass.getName()); } } log.info("Plugin controllers loaded."); } /** * Discards a plugin controller in {@link #pluginControllers}. * @param pluginController */ public void unloadPluginController(PluginController pluginController) { this.pluginControllers.remove(pluginController); } /** * Initialise {@link #pluginControllers}. * This method should only be called from the constructor {@link FrontlineSMS#startServices()}. */ public void initPluginControllers() { log.info("Initialising plugin controllers..."); // Enable plugins for(PluginController controller : this.pluginControllers.toArray(new PluginController[0])) { boolean initSuccessful = false; try { initPluginController(controller); initSuccessful = true; } catch(Throwable t) { // There was a problem loading the plugin controller. Not much we can do, so log it and carry on. log.warn("There was a problem initialising the plugin controller: '" + controller + "'. Plugin will not be loaded.", t); } if(!initSuccessful) { this.pluginControllers.remove(controller); } } log.info("Plugin controllers initialised. Count: " + this.pluginControllers.size()); } /** * Attempt to initialise a {@link PluginController}. * @param controller * @throws PluginInitialisationException */ public void initPluginController(PluginController controller) throws PluginInitialisationException { controller.init(this.frontlineController, applicationContext); } //> INSTANCE HELPER METHODS //> STATIC FACTORIES //> STATIC HELPER METHODS }