Java pluginable application how does consumer load interface? - java

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.

Related

How to access the Utilities of Selenium Java Framework in various different projects?

I have created a Selenium Java Framework with a proper folder structure. Basically my framework consists of few common utilities(page objects, reporting configurations and, driver initialization settings, etc.). This framework was developed to automate and validate web applications. We have a bunch of web applications in our organization that are common in nature and behavior. The Java framework that I have developed has some generic methods and page objects that can be utilized in all the web applications.
Now, I have pushed my framework to the Github. And, I want other teams in my organization also to use my framework. So, in my organization for each project, we create a new repo. Therefore, I wanted to know if by any chance my framework can be accessed by other teams of my organization in their projects.
I don't want anyone to clone my framework repo, add their tests, and push it back. As each project in my organization will have their own repo. Therefore, I simply want them to add my framework as a dependency in their project repo. And, when they clone their repo and do a maven build, they should be able to access the utilities of my framework. Please let me know if this is possible by any chance. Thanks! in advance.
You have multiple options.
Option 1:
Give read-only access to the outside your project users, so that they can extract and re-use the items from the framework without impact your code. Other teams can tailor the framework according to their needs (you can consider it as adv/ disadv)
Option 2:
Convert your framework into a jar and then share it with other teams. Ask them to use the jar. No Edits in framework possible.
We are exactly doing the same thing (we are using option-2 as below). Other teams need to use it as a dependency in their pom.xml. Two ways to use the dependency in maven:
If your company has maven artifactory management system, you can publish your framework jar into that and ask the other teams to use it as a dependency in their pom.xml directly
Else,
2. You need to prepare a jar file, and the other teams need to use it as a dependency using system scope level as below:
<!-- Framework -->
<dependency>
<groupId>com.test.group></groupId>
<artifactId>automation-framework</artifactId>
<version>0.0.1-SNAPSHOT</version>
<scope>system</scope>
<systemPath>${jar.location}</systemPath>
</dependency>
groupId, artifactId, and version are the details of your framework project.
Other teams can create a folder called "libs" in in their project, and store your framework's jar in there. That location will go here: ${jar.location}
Every time you make changes to your framework and build new jar, they need to update the jar file under "libs" folder.
In this way, they can use all your utilities, but can't modify or publish any tests into your project.
You need to keep utils package and create all utils classes into that package and use it
In every projects you need to keep package for separate keeping utils classes

What's the purpose: api.jar + impl.jar + bundle.jar?

I see many Java packages have api, impl and bundle jars (name-api.jar, name-impl.jar, name-bundle.jar). Could someone explain what those mean? Are all three needed by the app?
The idea is that you can separate the dependencies of the application; in an attempt to make applications more portable. The idea is that you can make the application dependent on the api.jar when compiling. Then when you want to run the program you can then switch in the appropriate implementation jar (impl.jar) and the appropriate resource bundle jar (bundle.jar).
As an example suppose the library does some database interaction. You write your code so that it references the api.jar. Now suppose you need it to work with a specific type of database e.g. MySQL - you would then add the impl.jar that is specific to MySQL databases to the classpath to get it to work (if you need a different database later - you only need to switch that jar in the classpath).
The bundle.jar is a bit more obscure and not as common. This could be used to supply configuration setting for the library. For example it could be used to supply language specific settings, or some more specific config. In the case of the database library it might be that the implementation is designed for all versions of MySQL, and the resource bundle jar provides config files that allow it to work for a specific MySQL version.
Often :
name-api.jar contains only the interface of the API.
name-impl.jar provides an implementation of all interfaces in the name-api.jar
name-bundle.jar bundles everything with all the needed classes to run a Java application.
api.jar contains API interfaces. These are interfaces as a contract that the implementation of the API should follow.
impl.jar is the implementation of the api.jar. You can't just have the impl.jar without the api.jar.
bundle.jar is the resources (if I'm not mistaken). Those are resources needed for the implementation code necessary to run.
I've never seen such an arrangement.
If the designer packaged the app into three JARs, then I'd say all three are needed.
But you should recognize that it's just a choice made by the designer. It's possible that s/he could have just created a single JAR with everything in it and you'd be none the wiser.
I'm guessing now, but if you were to open those JARs you'd see only interfaces in the API JAR, implementations of those interfaces in the impl JAR, and resource bundles and other .properties files in the bundle JAR. Try it and see. You'll learn something.

Best way for sharing of domain objects across Eclipse plugins?

I am making a set of Eclipse Plugins for the Eclipse Workbench.
I want these Eclipse Plugins to communicate with each other through some shared
data structures/managers.
Is there some bootstrapping or other initialization process wherein I
can pass the shared domain objects through the constructor for the plugins(depepndency injection)?
What is the standard and best practice for achieving sharing of data across plugins?
Eclipse is OSGi based using the equinox runtime. OSGi manages all of the runtime dependencies you need.
The simplest way is to deploy your common code as a bundle (plugin). Export all of the packages you need to other plugins. (Export-Package header in manifest.mf)
In the plugins you need the package, declare them as imported packages (Import-Package in the manifest.mf file)
If you want to go the extra mile, expose the managers you need as services, and add service consumers in the plugins you need.
Here's a simple tutorial to using services:
http://www.knopflerfish.org/osgi_service_tutorial.html

Best Practice For Referencing an External Module In a Java Project

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.

Implementing dynamic plugins in Java

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.

Categories

Resources