Re: Optimal way to call methods of dynamcic loaded calls (from Jars)
and vice versa.
On 1/12/2015 6:30 AM, diamantis.kiriakakis@gmail.com wrote:
Dear Javaworld,
I need to create a java application that will use a plugin system to enable extra features. The plugins will be actually .JAR files. The process is well understandable, but in case i need to call a method of main application from the dynamically loaded .JAR, what are the best practices to do it? I managed to do it using Callbacks but im not sure if this is the best way to achieve it.
If the main application methods called by the plugin are static
methods, call them the same way you'd call Math.sqrt():
class Plugin {
...
Thing thing = MainApplication.thingInstance(42);
...
}
If the plugin calls instance methods of a main application object,
you need to decide how to communicate the main application instance to
the plugin. One way (if the main application exists before the plugin
is constructed) is to pass the instance to the plugin constructor:
class MainApplication {
...
Plugin plugin = new Plugin(this);
...
plugin.doYourThing();
...
Thing getThing(int count) { ... }
}
class Plugin {
private final MainApplication mainApp;
public Plugin(MainApplication mainApp) {
this.mainApp = mainApp;
...
}
...
Thing thing = mainApp.getThing(42);
...
}
Another possibility would be to construct the plugin independently
of the main application, but to pass the instance on invocation:
class MainApplication {
...
Plugin plugin = new Plugin();
...
plugin.doYourThing(this);
...
Thing getThing(int count) { ... }
}
class Plugin {
public Plugin() { ... }
...
public void doYourThing(MainApplication mainApp) {
Thing thing = mainApp.getThing(42);
...
}
}
Still another possibility: Construct the plugin independently, call
an initialization method to pass it the main application instance, and
then invoke its working methods:
class MainApplication {
...
Plugin plugin = new Plugin();
...
plugin.initialize(this);
...
plugin.doYourThing();
...
Thing getThing(int count) { ... }
}
class Plugin {
private MainApplication mainApp;
public Plugin() { ... }
...
public void initialize(MainApplication mainApp) {
if (this.mainApp != null)
throw new IllegalStateException("already init'ed");
this.mainApp = mainApp;
}
...
public void doYourThing() {
if (mainApp == null)
throw new IllegalStateException("not init'ed");
Thing thing = mainApp.getThing(42);
...
}
}
Or you could use interfaces rather than class names:
interface MainInterface {
Thing getThing(int);
}
class MainApplication implements MainInterface {
...
Plugin plugin = new Plugin(this);
...
plugin.doYourThing();
...
@Override
Thing getThing(int count) { ... }
}
class Plugin {
private final MainInterface mainApp;
public Plugin(MainInterface mainApp) {
this.mainApp = mainApp;
...
}
...
Thing thing = mainApp.getThing(42);
...
}
... and on and on and on it goes. Choose an approach (one of these
or something else entirely) that best fits the problem at hand. There
is no such thing as one way that is "optimal" for every situation.
--
esosman@comcast-dot-net.invalid
"Don't be afraid of work. Make work afraid of you." -- TLM