// This software is released into the Public Domain. See copying.txt for details. package org.openstreetmap.osmosis.core; import java.io.BufferedReader; import java.io.File; import java.io.FilenameFilter; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.net.MalformedURLException; import java.net.URL; import java.util.Collections; import java.util.Iterator; import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.Map.Entry; import java.util.logging.Logger; import org.java.plugin.JpfException; import org.java.plugin.ObjectFactory; import org.java.plugin.PluginLifecycleException; import org.java.plugin.PluginManager; import org.java.plugin.PluginManager.PluginLocation; import org.java.plugin.registry.Extension; import org.java.plugin.registry.ExtensionPoint; import org.java.plugin.registry.ManifestProcessingException; import org.java.plugin.registry.PluginDescriptor; import org.java.plugin.standard.StandardPluginLocation; import org.openstreetmap.osmosis.core.pipeline.common.TaskManagerFactory; import org.openstreetmap.osmosis.core.pipeline.common.TaskManagerFactoryRegister; import org.openstreetmap.osmosis.core.plugin.PluginLoader; /** * Provides the initialisation logic for registering all task factories. * * @author Brett Henderson */ public class TaskRegistrar { /** * Our logger for debug and error -output. */ private static final Logger LOG = Logger.getLogger(TaskRegistrar.class.getName()); /** * The register containing all known task manager factories. */ private TaskManagerFactoryRegister factoryRegister; /** * Creates a new instance. */ public TaskRegistrar() { factoryRegister = new TaskManagerFactoryRegister(); } /** * Returns the configured task manager factory register configured. * * @return The task manager factory register. */ public TaskManagerFactoryRegister getFactoryRegister() { return factoryRegister; } /** * Initialises factories for all tasks. Loads additionally specified plugins * as well as default tasks. * * @param plugins * The class names of all plugins to be loaded. */ public void initialize(List<String> plugins) { // Register the built-in plugins. loadBuiltInPlugins(); // Register the plugins specified on the command line. for (String plugin : plugins) { loadPlugin(plugin); } // Register the plugins loaded via JPF. loadJPFPlugins(); } private void loadBuiltInPlugins() { final String pluginResourceName = "osmosis-plugins.conf"; try { for (URL pluginConfigurationUrl : Collections.list(Thread.currentThread() .getContextClassLoader().getResources(pluginResourceName))) { BufferedReader pluginReader; LOG.finer("Loading plugin configuration file from url " + pluginConfigurationUrl + "."); try (InputStream pluginInputStream = pluginConfigurationUrl.openStream()) { if (pluginInputStream == null) { throw new OsmosisRuntimeException("Cannot open URL " + pluginConfigurationUrl + "."); } pluginReader = new BufferedReader(new InputStreamReader(pluginInputStream)); for (;;) { String plugin; plugin = pluginReader.readLine(); if (plugin == null) { break; } plugin = plugin.trim(); if (!plugin.isEmpty()) { LOG.finer("Loading plugin via loader " + plugin + "."); loadPlugin(plugin); } } } } } catch (IOException e) { throw new OsmosisRuntimeException( "Unable to load the plugins based on " + pluginResourceName + " resources."); } } /** * Loads the tasks implemented as plugins. * */ private void loadJPFPlugins() { PluginManager pluginManager; // Create a new JPF plugin manager. pluginManager = ObjectFactory.newInstance().createManager(); // Search known locations for plugin files. LOG.fine("Searching for JPF plugins."); List<PluginLocation> locations = gatherJpfPlugins(); // Register the core plugin. LOG.fine("Registering the core plugin."); registerCorePlugin(pluginManager); // Register all located plugins. LOG.fine("Registering the extension plugins."); if (locations.size() == 0) { // There are no plugins available so stop processing here. return; } registerJpfPlugins(pluginManager, locations); // Initialise all of the plugins that have been registered. LOG.fine("Activating the plugins."); // load plugins for the task-extension-point PluginDescriptor core = pluginManager.getRegistry() .getPluginDescriptor("org.openstreetmap.osmosis.core.plugin.Core"); ExtensionPoint point = pluginManager.getRegistry().getExtensionPoint(core.getId(), "Task"); for (Iterator<Extension> it = point.getConnectedExtensions().iterator(); it.hasNext();) { Extension ext = it.next(); PluginDescriptor descr = ext.getDeclaringPluginDescriptor(); try { pluginManager.enablePlugin(descr, true); pluginManager.activatePlugin(descr.getId()); ClassLoader classLoader = pluginManager.getPluginClassLoader(descr); loadPluginClass(ext.getParameter("class").valueAsString(), classLoader); } catch (PluginLifecycleException e) { throw new OsmosisRuntimeException("Cannot load JPF-plugin '" + ext.getId() + "' for extensionpoint '" + ext.getExtendedPointId() + "'", e); } } } /** * Register the core plugin from which other plugins will extend. * * @param pluginManager * The plugin manager to register the plugin with. */ private void registerCorePlugin(PluginManager pluginManager) { try { URL core; PluginDescriptor coreDescriptor; // Get the plugin configuration file. core = getClass().getResource("/org/openstreetmap/osmosis/core/plugin/plugin.xml"); LOG.finest("Plugin URL: " + core); // Register the core plugin in the plugin registry. pluginManager.getRegistry().register(new URL[] {core}); // Get the plugin descriptor from the registry. coreDescriptor = pluginManager.getRegistry().getPluginDescriptor( "org.openstreetmap.osmosis.core.plugin.Core"); // Enable the plugin. pluginManager.enablePlugin(coreDescriptor, true); pluginManager.activatePlugin("org.openstreetmap.osmosis.core.plugin.Core"); } catch (ManifestProcessingException e) { throw new OsmosisRuntimeException("Unable to register core plugin.", e); } catch (PluginLifecycleException e) { throw new OsmosisRuntimeException("Unable to enable core plugin.", e); } } /** * Register the given JPF-plugins with the {@link PluginManager}. * * @param locations * the plugins found */ private void registerJpfPlugins(PluginManager pluginManager, List<PluginLocation> locations) { if (locations == null) { throw new IllegalArgumentException("null plugin-list given"); } try { pluginManager.publishPlugins(locations.toArray(new PluginLocation[locations.size()])); } catch (JpfException e) { throw new OsmosisRuntimeException("Unable to publish plugins.", e); } } /** * @return a list of all JPF-plugins found. */ private List<PluginLocation> gatherJpfPlugins() { File[] pluginsDirs = new File[] { new File("plugins"), new File(System.getProperty("user.home") + "/.openstreetmap" + File.separator + "osmosis" + File.separator + "plugins"), new File(System.getenv("APPDATA") + File.separator + "openstreetmap" + File.separator + "osmosis" + File.separator + "plugins") }; FilenameFilter pluginFileNameFilter = new FilenameFilter() { /** * @param dir * the directory of the file * @param name * the unqualified name of the file * @return true if this may be a plugin-file */ public boolean accept(final File dir, final String name) { return name.toLowerCase().endsWith(".zip") || name.toLowerCase().endsWith(".jar"); } }; List<PluginLocation> locations = new LinkedList<PluginLocation>(); for (File pluginDir : pluginsDirs) { LOG.finer("Loading plugins in " + pluginDir.getAbsolutePath()); if (!pluginDir.exists()) { continue; } File[] plugins = pluginDir.listFiles(pluginFileNameFilter); try { for (int i = 0; i < plugins.length; i++) { LOG.finest("Found plugin " + plugins[i].getAbsolutePath()); PluginLocation location = StandardPluginLocation.create(plugins[i]); if (location != null) { locations.add(location); } else { LOG.warning("JPF Plugin " + plugins[i].getAbsolutePath() + " is malformed and cannot be loaded."); } } } catch (MalformedURLException e) { throw new OsmosisRuntimeException("Cannot create plugin location " + pluginDir.getAbsolutePath(), e); } } return locations; } /** * Loads the tasks associated with a plugin (old plugin-api). * * @param plugin * The plugin loader class name. */ private void loadPlugin(final String plugin) { ClassLoader classLoader; // Obtain the thread context class loader. This becomes important if run // within an application server environment where plugins might be // inaccessible to this class's classloader. classLoader = Thread.currentThread().getContextClassLoader(); loadPluginClass(plugin, classLoader); } /** * Load the given plugin, old API or new JPF. * * @param pluginClassName * the name of the class to instantiate * @param classLoader * the ClassLoader to use */ @SuppressWarnings("unchecked") private void loadPluginClass(final String pluginClassName, final ClassLoader classLoader) { Class<?> untypedPluginClass; PluginLoader pluginLoader; Map<String, TaskManagerFactory> pluginTasks; // Load the plugin class. try { untypedPluginClass = classLoader.loadClass(pluginClassName); } catch (ClassNotFoundException e) { throw new OsmosisRuntimeException("Unable to load plugin class (" + pluginClassName + ").", e); } // Verify that the plugin implements the plugin loader interface. if (!PluginLoader.class.isAssignableFrom(untypedPluginClass)) { throw new OsmosisRuntimeException("The class (" + pluginClassName + ") does not implement interface (" + PluginLoader.class.getName() + "). Maybe it's not a plugin?"); } Class<PluginLoader> pluginClass = (Class<PluginLoader>) untypedPluginClass; // Instantiate the plugin loader. try { pluginLoader = pluginClass.newInstance(); } catch (InstantiationException e) { throw new IllegalArgumentException("Unable to instantiate plugin class (" + pluginClassName + ").", e); } catch (IllegalAccessException e) { throw new IllegalArgumentException("Unable to instantiate plugin class (" + pluginClassName + ").", e); } // Obtain the plugin task factories with their names. pluginTasks = pluginLoader.loadTaskFactories(); // Register the plugin tasks. for (Entry<String, TaskManagerFactory> taskEntry : pluginTasks.entrySet()) { factoryRegister.register(taskEntry.getKey(), taskEntry.getValue()); } } }