Developing application with plugin support in Java - java

I have been researching on how to develop an application that can load plugins.
So far, I've seen that this can be done by defining an Interface, and have the plugins implement it.
However, my current issue is on how to load the plugins when they're packed in Jars. Is there a "best" way to do it?
The current logic I'm thinking of is to get each plugin and inside their Jar look for the class that implements the Interface. But I don't know how to do such lookup. I think that this logic may not be a good one, but I couldn't find any useful information on this specific topic.
**Edit1: **
Adding more information:
The intended plugins would be Jar files contained inside a subdirectory where the main application's Jar would be located, like this:
Application's folder
|- Main_Application.jar
|- Plugins
|- Plugin1.jar
|- Plugin2.jar
|- Steve's_plugin.jar
And so on.
What I expect is that the Application will be able to load all plugins inside the folder at runtime. So in the code, it would only be aware that the plugin's folder should exist and there should be Jars inside such folder.
Let's say I have a plugin interface like this:
interface Plugin
{
public void run();
}
Plugins would be identified by a class that implements such interface, like so
class Plugin1 implements Plugin
{
//attributes and other methods
#override
public void run()
{
//something happens here
}
}
class Plugin2 implements Plugin
{
//attributes and other methods
#override
public void run()
{
//something happens here
}
}
The Application should be compiled only once, and be able to load any Plugins added to the folder when it is executed.
For the Application to be able to load any Plugin, do I need to establish rules on the contents of the Jar, like package name and the class that implements the interface? Or it is expected that the class implementing the plugin interface could be in any package within the Jar, and have any name?
This is the more generic approach to what I would like to do with such plugins. In short, I'm planning to build an Application that will have tabs, and each plugin will provide the Interface and Functionality of each tab. I'm trying this because I want to be able to maintain each tab separately, and don't want to recompile the whole application because of changes in only one component that don't affect the others at all.

Get the list of plugin jars:
File[] jars = new File("Plugins").listFiles();
Then, use the code from this answer about loading all classes from a JAR file, but run it once for each file in jars whose name ends in ".jar". At the bottom of the loop body, after
Class c = cl.loadClass(className);
continue with
if (Plugin.class.isAssignableFrom(c)) {
Plugin plugin = (Plugin) c.newInstance();
// And then, do something with the plugin here
}
I share #Mifeet's concerns about security - you might want to use a SecurityManager to limit what the plugin code is allowed to do.

Very old question, but still relevant if some one searches.. Adding to the accepted answer,
Use OSGI framework
Refer Apache Felix for a reference implementation
If you wanted to have a light version of OSGi, try to use apache connect - pojosr

Related

Atmosphere servlet classloading conflict with java

I am not sure how to title this question but I'll try to explain what the issue is.
I am currently testing out Atmosphere framework in a web application. I started by reading the documentation and then testing the chat-multiroom sample. I am running it in eclipse using tomcat 8.5. When the atmosphere servlet initializes it will scan a package for any classes that have certain annotations and if it finds the annothions it will add the class to a map using a path as the key. For this to work it must first scan its own packages looking for what annotations it should use and add them to a map of available annotations. This list has to be populated for the annotated classes to be initialised. The code for this looks like this:
public Class<? extends Processor> handleProcessor(Class<?> clazz) {
if (Processor.class.isAssignableFrom(clazz)) {
Class<Processor> p = (Class<Processor>) clazz;
if (logger.isTraceEnabled()) {
logger.trace("Processor {} associated with {}", p, p.getAnnotation(AtmosphereAnnotation.class).value());
}
annotations.put(p.getAnnotation(AtmosphereAnnotation.class).value(), p);
return p;
}
return null;
}
So it goes though every class it finds and checks if it implements Processor. Processeor is an interface provided by atmosphere imported with import org.atmosphere.annotation.Processor;
However when I debug this code it is instead compareing clazz with the jdk:s interface javax.annotation.processing.Processor instead of org.atmosphere.annotation.Processor. This is causing the map to be empty. This results in the endpoints are not loaded because there are no annotations to look for.
If I download the atmosphere code and copy it to my src folder it works correctly.
I am using Eclipse IDE at the moment and I am wondering if there is a way to configure the project or the tomcat server in some way to make it understand which interface it should use.
[EDIT]
After some more research the problem isn't due to the class comparision instead it is about how tomcat loads classes. Atmosphere relies on that the container loads the annotation classes and passes it into Atmosphere ServletContainerInitializer however tomcat will not pass the classes that exisit in the package jar files under the webapps lib folder. It will only pass in the classes that are in the webapps WEB-INF/classes folder and not the WEB-INF/lib folder. That is why it works if I add the Atmosphere src to the webapps src folder in eclipse.
[EDIT2]
It turns out I had disabled jar scanning in catalina.properties.
Enabling the jar scanning again solved the issue.

Extending xtext new project wizard

I'm using xtext 2.13/java8 to create a DSL with IDE as described in "Implementing Domain-Specific Languages with Xtext and XTend 2nd edition".
The IDE includes a new project wizard, and the DSL includes a code generator that produces java code. The generated java code depends on some helper classes in another support plugin that is provided as part of the DSL project.
I can export the update site and install into a fresh eclipse.
There, I can create a new DSL project that compiles the DSL file into java.
I would like to extend the new project wizard so that I can automatically add the dependency on my support plugin to the generated MANIFEST file in the new project. I can add it manually after the project is created (the plugin is present in the installed feature), but I don't want users to have to do that.
org.eclipse.xtext.ui.wizard.AbstractPluginProjectCreator has code that adds the dependencies on logging packages, but I don't see any way to extend or override that logic using any extension points. Is there a way to do this?
This turned out to be not too hard, though it took a half-day of experimenting to find it.
The xtext project defines a generated MyDSLProjectCreator class in the *.ui plugin under src-gen in the .ui.wizard package that defines the method we need to override:
#Override
protected List<String> getRequiredBundles() {
return Lists.newArrayList(DSL_PROJECT_NAME);
}
By default, this adds just the DSL project bundle to the dependencies of the new project. I need to add also the support plugins. I can't edit this generated file, but I can extend it, so I defined MyExtendedProjectCreator class in the src folder of the same .ui.wizard package that extends this class (java source):
public class MyExtendedProjectCreator extends MyDslProjectCreator {
#Override
protected List<String> getRequiredBundles() {
return Lists.newArrayList(DSL_PROJECT_NAME,
"my.plugin.id");
}
}
To invoke that project creator instead of the default, I had to override another method in the MyDslUiModule class. This can be found in the .ui package under src (xtend file):
#FinalFieldsConstructor
class MyDslUiModule extends AbstractMyDslUiModule {
public def override Class<? extends IProjectCreator> bindIProjectCreator() {
MyExtendedProjectCreator;
}
}

Java, create runnable jar file including ONLY used dependencies.

This question has been asked before, but have no satisfactory answer yet!
I have a Java Main.java class in a project full of other unrelated classes. I would like to export that Main.java into an executable jar file, containing only the dependencies it ACTUALLY uses.
Is this possible, if so how?
Both Eclipse( create runnable jar ) and Intellij ( create artifact ) will include all dependencies defined in the module containing the Main.java class.
You should really be using a dependency management system, instead of the ones provided by default in Eclipse and IDEA. Many Java developers (including me) use Maven. If you're working in Eclipse, it includes m2eclipse
You don't want to have all the dependencies in one project because it can get really bloated. However, if you have a Maven parent pom that uses the <dependencyManagement> tag, you can easily just reference this parent pom and then easily only make references to the dependencies you need in that sub project. This keeps everything separate that actually is separate, and provides an easy organization mechanism - the reason why people use Maven.
How to use <dependencyManagement> in Maven
Maven also has plugins that manage your jar creation for you, e.g. maven-assembly-plugin that allow you to construct your dependencies exactly how you want them in the jar and so forth.
You have to do this yourself somehow. What do you expect any IDE / dependency management system to do with the following code:
Test.java
public class Test {
public static void main(String... args) {
System.exit(0);
new Foo(null);
}
}
Foo.java
import com.google.common.base.Preconditions;
public class Foo {
public Foo(String s) {
Preconditions.checkNotNull(s);
}
}
The Guava dependency is not needed here... but you only know that in RUNTIME. If you include all the import statements of all the classes, then you include all the dependencies. If you don't, then you need to do runtime analysis. Your problem is akin to the Turing halting problem.

Added jar in BootStrap location is not reflecting in My Classes using Eclipse

Please help me to understand whats wrong with this.
I added a jar in a BootStrap location of
jdk(C:\Program Files\Java\jdk1.6.0_27\lib\ext) and in jre(C:\Program
Files\Java\jre1.6.0_22\lib\ext)
but jar class is not reflecting while try to invoke methods or classes added by jar in Eclipse.
Also help me to know where I can see the printed things by static block by Logs.......
Below I included the class I used to create the JAR.
package test.classloader;
public class BootStrapTest {
static
{
System.out.println("BootStrap Jar is Loaded....................");
}
public static String checkClassLoader()
{
return "This is BootStrap Class Check ClassLoader";
}
}
I am going to take a stab at the reason behind why you think you need to do this. Excuse me if I am incorrect but you provide vague information and it is unclear what your question is.
If you need missing Java EE libs (or other 3rd party libs) in Eclipse, add one of the sofware REPOs (to your Eclipse software manager) listed on this URL and then install the Java EE libs from it: http://download.eclipse.org/tools/orbit/downloads/
Or, use Maven as a build tool and add the appropriate dependency to download the lib that your project needs.

How to create a JAR with only the class files needed by a given class

I have a directory full of hundreds of class files that have been constructed by a previous compilation. Let's say I have a class which only depends upon a small subset of those generated class files. Is it possible to create a JAR which only has the dependencies for the given class?
EDIT: Please note that I am not speaking of the library level dependencies (i.e. JARs). When I refer to dependencies above, I am referring to the sort of dependency that results from class A calling class B. Perhaps an example would be good. Imagine I have the following classes in my project.
public class A {
B bField;
}
public class B {
C cField;
}
public class C {
B bField;
}
Now imagine I want to build a JAR with class B, then the JAR would also need to include the class file for C because the one depends upon the other. If I wanted to build a JAR from class A, then all three classes would be included. Is there a way to examine this dependency chain and build a JAR with the result?
Several products can do this, including ProGuard.
The danger is that without exhaustive run-time analysis, or a good understanding of your code and any frameworks it uses, some classes may be missed if they've instantiated via reflection. Plugin systems, dependency injection, scripting, and so on can all interfere with the accuracy of static analysis.
Yes it is possible. you can create a file with the list of classes that you do want to include and pass that file into the jar command. The details are documented here.

Categories

Resources