Reputation: 6624
I'm trying to make my Java app modular, so that there will be the core base module that a client will have to aqcuire, but he/ she will be able to add additional features/ plugins as they come up, or as her needs extend. Like how IDEs like NetBeans go about it.
I plan on having a sub-directory, called modules/ plugins, in the clients pc where any plugin applications will be included as .jar files. The main module will, when a user launches the application, include these other plugins in the final item, so that, for example, a Stage will have buttons from both the main module and plugin modules on the same scene.
I'm fluent with elgg, which uses views to do this. Borrowing from this, I could have a HBox, for example on the main module that gets populated with Buttons from the different plugins on launching the application.
How can I go about having core_base_module.jar below call all plugins in the plugins directory below. In other words, how can I go about having one .jar
file calling another .jar
file?
Sample directory structure:
main dir/---core_base_module.jar
/---plugins ---/chat.jar
/videoplayer.jar
/like.jar
/unlike.jar
/etc.jar
/etc_etc.jar
Upvotes: 3
Views: 1739
Reputation: 148890
If you really want to create a professional grade application, the ServiceLoader API suggested by @DavidRoussel is the way to go.
If you prefer something more lightweight, that you can do by hand, you can just use an API package containing only interfaces of abstract classes that you include in your application, and an implementation package containing actual classes that you provide as a separate jar. As you cannot create object only know by an interface through new
, you will have to use a factory pattern and reflection. You should also use Class.forName("package.to.class")
to test the existance of implementation at the beginning of your program.
Example assuming an interface Foo
optionally implemented by FooImpl
whose constructor takes a string argument the factory could be :
public class FooFactory {
public static final String CLASSNAME = "...FooImpl";
public static Foo createFoo(String key) {
try {
Class<?> fooclazz = Class.forName(CLASSNAME);
Foo foo = (Foo) fooclazz.getConstructor(String.class).newInstance(key);
return foo;
}
catch (Exception e) {
// eventually process some exceptions
}
return null;
}
}
You initially set a global boolean hasFoo
(static member of main class for example) with :
try {
Class.forName(FooFactory.CLASSNAME);
hasOpt = true;
}
catch (Exception e) {
hasOpt = false;
}
And you optionnaly use it :
if (MainClass.hasOpt) {
Foo foo = FooFactory.createFoo("bar");
// do something with foo
}
else {
// warning message : Option not present
}
With this method, it is enough to add the implementation jar in classpath and restart the application to use it.
Upvotes: 1
Reputation: 5916
You could do this manually by:
While you could do that all yourself, it might be easier to use the Service Loader API. This API is part of Java, and was created for this purpose. This is what spring uses to load plugins that can handle different XML tags in the spring XML config files. For instance look in spring-web.jar!/META-INF/services
Then you'll want your startup script to add all the JARs to your main class path like this:
java -cp plugins/* -jar app.jar
Or if you don't have a lauch script, you can do the same in java but creating a URLClassLoader passing it all the jar files that your want, then invoke your main class inside this new classloader.
More information:
Upvotes: 4