Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Revert the "Remove Java Plugin Framework" commits in 0.49.0, to allow external plugins to be loaded in the usual manner #141

Merged
merged 3 commits into from
Dec 2, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions gradle.properties
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ dependencyVersionCommonsIo=2.15.0
# Should we be using Dbcp2?
dependencyVersionCommonsDbcp=1.4
dependencyVersionGuava=32.1.3-jre
dependencyVersionJpf=1.5
# JUnit 5 is available, some re-write required
dependencyVersionJunit=4.13.2
dependencyVersionMySql=8.0.33
Expand Down
35 changes: 35 additions & 0 deletions osmosis-core/build.gradle
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
dependencies {
implementation group: 'net.sf.jpf', name: 'jpf', version: dependencyVersionJpf
}

/*
* Define a custom task to automatically generate the OsmosisConstants file
* and update the java compilation task to depend on it.
Expand Down Expand Up @@ -28,3 +32,34 @@ task generateJavaSources {
// Define task dependency to ensure constants file is always up to date.
compileJava.dependsOn generateJavaSources
sourcesJar.dependsOn generateJavaSources


/*
* Define a custom task to automatically generate the plugin.xml file
* and update the copy resources task to depend on it.
*/
task generateResources {
description = 'Generates the plugin.xml file with the current version number.'

// Build file objects for our template file, and output java file.
def commonPathPrefix = "$projectDir/src/main/resources/org/openstreetmap/osmosis/core/plugin/plugin.xml"
def outputFile = new File(commonPathPrefix)
def inputFile = new File(commonPathPrefix + ".template")

/*
* Declare inputs and outputs of the task to allow gradle to determine if
* it is up to date.
*/
inputs.file inputFile
outputs.file outputFile

doLast {
// Insert the version string into the constants file.
def fileContent = inputFile.getText()
fileContent = fileContent.replace("no-version-specified", version)
outputFile.write(fileContent)
}
}
// Define task dependency to ensure constants file is always up to date.
processResources.dependsOn generateResources
sourcesJar.dependsOn generateResources
Original file line number Diff line number Diff line change
Expand Up @@ -2,17 +2,31 @@
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.lang.reflect.InvocationTargetException;
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;
Expand Down Expand Up @@ -46,7 +60,7 @@ public TaskRegistrar() {

/**
* Returns the configured task manager factory register configured.
*
*
* @return The task manager factory register.
*/
public TaskManagerFactoryRegister getFactoryRegister() {
Expand All @@ -57,7 +71,7 @@ public TaskManagerFactoryRegister getFactoryRegister() {
/**
* 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.
*/
Expand All @@ -69,11 +83,14 @@ public void initialize(List<String> plugins) {
for (String plugin : plugins) {
loadPlugin(plugin);
}

// Register the plugins loaded via JPF.
loadJPFPlugins();
}

/**
* Loads a plugin manually.
*
*
* @param pluginLoader The pluginLoader that you wish to load.
*/
public void loadPlugin(final PluginLoader pluginLoader) {
Expand All @@ -88,39 +105,38 @@ public void loadPlugin(final PluginLoader pluginLoader) {

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
Expand All @@ -129,9 +145,165 @@ private void loadBuiltInPlugins() {
}


/**
* 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.
*/
Expand All @@ -149,7 +321,7 @@ private void loadPlugin(final String plugin) {

/**
* Load the given plugin, old API or new JPF.
*
*
* @param pluginClassName
* the name of the class to instantiate
* @param classLoader
Expand All @@ -175,13 +347,7 @@ private void loadPluginClass(final String pluginClassName, final ClassLoader cla

// Instantiate the plugin loader.
try {
pluginLoader = pluginClass.getDeclaredConstructor().newInstance();
} catch (InvocationTargetException e) {
throw new IllegalArgumentException("Unable to instantiate plugin class (" + pluginClassName + ").", e);
} catch (SecurityException e) {
throw new IllegalArgumentException("Unable to instantiate plugin class (" + pluginClassName + ").", e);
} catch (NoSuchMethodException e) {
throw new IllegalArgumentException("Unable to instantiate plugin class (" + pluginClassName + ").", e);
pluginLoader = pluginClass.newInstance();
} catch (InstantiationException e) {
throw new IllegalArgumentException("Unable to instantiate plugin class (" + pluginClassName + ").", e);
} catch (IllegalAccessException e) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
// This software is released into the Public Domain. See copying.txt for details.
package org.openstreetmap.osmosis.core.plugin;

import org.java.plugin.Plugin;


/**
* The core plugin entry point.
*
* @author Marcus Wolschon
*/
public class CorePlugin extends Plugin {

/**
* {@inheritDoc}
*/
@Override
protected void doStart() throws Exception {
// ignored
}


/**
* {@inheritDoc}
*/
@Override
protected void doStop() throws Exception {
// ignored
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
<?xml version="1.0" encoding="utf-8" ?>
<!DOCTYPE plugin PUBLIC "-//JPF//Java Plug-in Manifest 1.0" "http://jpf.sourceforge.net/plugin_1_0.dtd">
<plugin id="org.openstreetmap.osmosis.core.plugin.Core" version="no-version-specified"
class="org.openstreetmap.osmosis.core.plugin.CorePlugin">
<extension-point id="Task">
<parameter-def id="class" />
<parameter-def id="name" />
</extension-point>
</plugin>
Loading