I'm trying to create a framework for plugin/apps, and I think I've settled on using a Service Provider Interface (SPI) in Java to achieve that. The ultimate vision is that people can download plugins (like an app store) and then just drop the jars into a folder, and they'll work with the existing program.
So I have a class PluginInterface that will be my SPI. I want all plugins to implement this class (it has basic methods like doesAccept, handle, etc.). Since 3rd parties will be creating the Service Providers, how can I let them reference this Java interface in their code (so they can implement it), without actually giving them the source code of the main application?
Create two JARs api and impl where you put your application in the impl and put whatever the code you need to share with third party developer in api.
Example: jaxb-api.jar and jaxb-impl.jar
Related
I'm creating a small hobby Java task/todo application. I want to be able to write plugins for it, which will be stored in a directory somewhere, probably in a plugins directory next to the myapplication.jar.
I have some idea on how to load these plugins, and I want to write interfaces which the plugin creator can use, like SomeActionInterface, when implemented allows the plugin to add functionality to SomeAction.
My question is, where does that SomeActionInterface go, and how would the plugin creator access said interface?
Does the interface go in the main myapplication.jar which the user should have loaded on their classpath, or does it go in a separate myapplication-plugininterfaces.jar?
Normally you would expose SPI and API that the plugin authors can use to implement their code. Normally these classes are packaged as a separate JAR, this allows to have a minimal dependency to build a plugin.
There are some good examples of plugin architecture that you can explore:
JDBC exposes java.sql.Connection and relate classes so the database projects can implement drivers for Java.
SLF4J handles new logger framework bindings as plugins. There are slf4-api and slf4j-ext dependencies that are used to implement a plugin.
Well it's actually not in the library itself, it's in a different library which depends on the annoration processor.
I have the roughly the following project structure.
Annotation Processor -> Android Library module -> Android App module
In the Android app I use annotations on some classes and the processor generates class that I'd like to use (and call its methods) in the library module. Is that even possible?
Right now I can only access it from the App module itself.
I actually feel like it all quite makes sense, just wonder if there is some way how to workaround that.
(When I pull the classes referencing generated code from the library module into app module itself, it works perfectly, I just want to have them in the library)
So far the only solution I was able to come up with was to not use the generated class itself, but rather define an interface, use that and let the code generator generate an implementation of it. Then provide the implementation from the app module back to the library module at runtime.
I want to develop a service that exposes a rest API to upload plugins and the plugins are locally executable, i.e. other classes from the server use them.
The plugins also:
The plugin should be a jar file that is submitted through the REST API and once is validated, is then made available through another API method to see the metadata and to execute.
Are not too complex (they should all contain at least a a class that extends of an abstract class or an interface implementation of an interface, the service) but could have their own dependencies.
The API allows to validate that the plugin is compliant with the service and that it declares some additional information on an XML or JSON file contained on the JAR.
Have some metadata that has to be exposed through the API (Version, who made it, is it usable, what data can it be handled) in Json form.
All implement an algorithm to perform some data crunch so they all have something like an execute() method. The result of executing this method is handled to another class, so is not totally important to expose it on the API.
Must be able to be uploaded and executed by the other server classes in runtime, so no restart is possible
The thing is that I am not sure where to start, since I had already developed some of the basic API on Spring-boot since it had all the things I needed to easily develop a REST API but the more I read about how to dynamically load modules (plugins) the more I see that Spring does not support this ind of thing and I am not sure a class loader or Service loader would work in that context.
I found out about OSGi framework but I honestly do not know it changing the whole technology stack will help me so I want to make sure it is the right answer, and if yes, then find some resources that point me in the right direction, e.g. some tutorial that implements something similar.
Thank you for any advice.
Checkout OSGi enRoute. It includes a model to developing RESTful services: http://enroute.osgi.org/services/osgi.enroute.rest.api.html.
OSGi sounds like the best match to what you try to do.
You can install everything as a bundle including your main application. Nowadays this is much less work than some years before but still not to be underestimated.
The other option is to start an embedded OSGi framework where you just install your plugins. This is less work but you need to know exactly how it works.
So for both cases I suggest to get help from an external OSGi expert as it speeds up the transition a lot and avoids many wrong paths you will choose as a beginner.
I have a Java project that expects external modules to be registered with it. These modules:
Implement a particular interface in the main project
Are packaged into a uni-jar (along with any dependencies)
Contain some human-readable meta-information (like the module name).
My main project needs to be able to load at runtime (e.g. using its own classloader) any of these external modules. My question is: what's the best way of registering these modules with the main project (I'd prefer to keep this vanilla Java, and not use any third-party frameworks/libraries for this isolated issue)?
My current solution is to keep a single .properties file in the main project with key=name, value=class |delimiter| human-readable-name (or coordinate two .properties files in order to avoid the delimiter parsing). At runtime, the main project loads in the .properties file and uses any entries it finds to drive the classloader.
This feels hokey to me. Is there a better way to this?
The standard approach in Java is to define a Service Provider.
Let all module express their metadata via a standard xml file. Call it "my-module-data.xml".
On your main container startup it looks for a classpath*:my-module-data.xml" (which can have a FrontController class) and delegates to the individual modules FrontController class to do whatever it wants :)
Also google for Spring-OSGI and their doco can be helpful here.
Expanding on #ZZ Coder...
The Service Provider pattern mentioned, and used internally within the JDK is now a little more formalized in JDK 6 with ServiceLoader. The concept is further expanded up by the Netbeans Lookup API.
The underlying infrastructure is identical. That is, both API use the same artifacts, the same way. The NetBeans version is just a more flexible and robust API (allowing alternative lookup services, for example, as well as the default one).
Of course, it would be remiss to not mention the dominant, more "heavyweight" standards of EJB, Spring, and OSGi.
I'd like to implement a dynamic plugin feature in a Java application. Ideally:
The application would define an interface Plugin with a method like getCapabilities().
A plugin would be a JAR pluginX.jar containing a class PluginXImpl implementing Plugin (and maybe some others).
The user would put pluginX.jar in a special directory or set a configuration parameter pointing to it. The user should not necessarily have to include pluginX.jar in their classpath.
The application would find PluginXImpl (maybe via the JAR manifest, maybe by reflection) and add it to a registry.
The client could get an instance of PluginXImpl, e.g., by invoking a method like getPluginWithCapabilities("X"). The user should not necessarily have to know the name of the plugin.
I've got a sense I should be able to do this with peaberry, but I can't make any sense of the documentation. I've invested some time in learning Guice, so my preferred answer would not be "use Spring Dynamic Modules."
Can anybody give me a simple idea of how to go about doing this using Guice/peaberry, OSGi, or just plain Java?
This is actually quite easy using plain Java means:
Since you don't want the user to configure the classpath before starting the application, I would first create a URLClassLoader with an array of URLs to the files in your plugin directory. Use File.listFiles to find all plugin jars and then File.toURI().toURL() to get a URL to each file. You should pass the system classloader (ClassLoader.getSystemClassLoader()) as a parent to your URLClassLoader.
If the plugin jars contain a configuration file in META-INF/services as described in the API documentation for java.util.ServiceLoader, you can now use ServiceLoader.load(Plugin.class, myUrlClassLoader) to obatin a service loader for your Plugin interface and call iterator() on it to get instances of all configured Plugin implementations.
You still have to provide your own wrapper around this to filter plugin capabilites, but that shouldn't be too much trouble, I suppose.
OSGI would be fine if you want to replace the plugins during runtime i.g. for bugfixes in a 24/7 environment. I played a while with OSGI but it took too much time, because it wasn't a requirement, and you need a plan b if you remove a bundle.
My humble solution then was, providing a properties files with the class names of plugin descriptor classes and let the server call them to register (including quering their capabilities).
This is obvious suboptimal but I can't wait to read the accepted answer.
Any chance you can leverage the Service Provider Interface?
The best way to implement plug-ins with Guice is with Multibindings. The linked page goes into detail on how to use multibindings to host plugins.
Apologize if you know this, but check out the forName method of Class. It is used at least in JDBC to dynamically load the DBMS-specific driver classes runtime by class name.
Then I guess it would not be difficult to enumerate all class/jar files in a directory, load each of them, and define an interface for a static method getCapabilities() (or any name you choose) that returns their capabilities/description in whatever terms and format that makes sense for your system.