/* * To change this template, choose Tools | Templates * and open the template in the editor. */ package org.pepsoft.worldpainter.plugins; import org.pepsoft.util.PluginManager; import java.io.File; import java.security.PublicKey; import java.util.*; import java.util.stream.Collectors; /** * A manager of WorldPainter {@link Plugin}s. * * @author pepijn */ public class WPPluginManager { private WPPluginManager(UUID uuid, ClassLoader classLoader) { allPlugins = PluginManager.findPlugins(Plugin.class, FILENAME, classLoader); Set<String> namesEncountered = new HashSet<>(); for (Iterator<Plugin> i = allPlugins.iterator(); i.hasNext(); ) { Plugin plugin = i.next(); if ((plugin.getUUIDs() != null) && (uuid != null) && (! plugin.getUUIDs().contains(uuid))) { logger.error(plugin.getName() + " plugin is not authorised for this installation; not loading it"); i.remove(); continue; } String name = plugin.getName(); if (namesEncountered.contains(name)) { throw new RuntimeException("Multiple plugins with the same name (" + name + ") detected!"); } else { namesEncountered.add(name); } logger.info("Loaded plugin: " + name + " (version " + plugin.getVersion() + ")"); } } /** * Get a list of all loaded WorldPainter plugins. * * @return A list of all loaded WorldPainter plugins. */ public List<Plugin> getAllPlugins() { return Collections.unmodifiableList(allPlugins); } /** * Get a list of all loaded WorldPainter plugins which implement a * particular type. * * @param type The type of plugin to return. * @param <T> The type of plugin to return. * @return A list of all loaded WorldPainter plugins which implement the * specified type */ @SuppressWarnings("unchecked") // Guaranteed by Java public <T extends Plugin> List<T> getPlugins(Class<T> type) { return allPlugins.stream() .filter(plugin -> type.isAssignableFrom(plugin.getClass())) .map(plugin -> (T) plugin) .collect(Collectors.toList()); } /** * Initialise the WorldPainter plugin manager for a particular WorldPainter * installation. This method or {@link #initialise(UUID, ClassLoader)} * should be invoked only once, before {@link #getInstance()} is invoked. * * <p><strong>Please note!</strong> If plugins should be loaded from plugin * jars, {@link PluginManager#loadPlugins(File, PublicKey)} must be invoked * <em>before</em> this method, to ensure the jars are discovered. * * @param uuid The unique identifier of the WorldPainter installation for * which to initialise the WorldPainter plugin manager. */ public static synchronized void initialise(UUID uuid) { initialise(uuid, ClassLoader.getSystemClassLoader()); } /** * Initialise the WorldPainter plugin manager for a particular WorldPainter * installation. This method or {@link #initialise(UUID)} should be invoked * only once, before {@link #getInstance()} is invoked. * * <p><strong>Please note!</strong> If plugins should be loaded from plugin * jars, {@link PluginManager#loadPlugins(File, PublicKey)} must be invoked * <em>before</em> this method, to ensure the jars are discovered. * * @param uuid The unique identifier of the WorldPainter installation for * which to initialise the WorldPainter plugin manager. * @param classLoader The class loader from which to discover the default/ * system plugins (those not loaded from plugin jars). */ public static synchronized void initialise(UUID uuid, ClassLoader classLoader) { if (instance != null) { throw new IllegalStateException("Already initialised"); } instance = new WPPluginManager(uuid, classLoader); } /** * Obtain the single instance of the WorldPainter plugin manager. Note that * the plugin manager must be initialised first by invoking * {@link #initialise(UUID)} or {@link #initialise(UUID, ClassLoader)}. * * @return The single instance of the WorldPainter plugin manager. */ public static synchronized WPPluginManager getInstance() { return instance; } private final List<Plugin> allPlugins; private static WPPluginManager instance; private static final String FILENAME = "org.pepsoft.worldpainter.plugins"; private static final org.slf4j.Logger logger = org.slf4j.LoggerFactory.getLogger(WPPluginManager.class); }