Dynamically loading plugins

S

Steve Sobol

Here's what I'd like to do:

I am creating an application whose functionality will be provided by
plugins. These plugins will be Java classes implementing an interface I am
creating. One of the methods that must be implemented is called
registerPlugin() (there will be other methods too, but that's the only one
that's important right now).

I will be scanning a directory, most likely right under the directory where
my app is installed, for jar files, each containing one plugin class, and
possibly several supporting classes in addition to the plugin class.

These jars are NOT going to be on the classpath.

Each jar containing a plugin will have a line like the following in its
manifest:

Plugin-Class: net.justthe.pluginImpl.myCoolPlugin

Basically, the process will be to check each jar and...

--find out which class to load by reading the Plugin-Class line from the
manifest

--load that class

--call registerPlugin()

Now, the reason that I'm writing is that my experience loading classes like
this is, well... nonexistent, and I'd like some advice on how to go about
doing it. I'm not asking anyone to write code for me. I just need a few
pointers.

Thanks in advance... **SJS

--
JustThe.net - Steve Sobol / (e-mail address removed) / PGP: 0xE3AE35ED
Coming to you from Southern California's High Desert, where the
temperatures are as high as the gas prices! / 888.480.4NET (4638)

"Life's like an hourglass glued to the table" --Anna Nalick, "Breathe"
 
S

Stefan Schulz

Now, the reason that I'm writing is that my experience loading classes like
this is, well... nonexistent, and I'd like some advice on how to go about
doing it. I'm not asking anyone to write code for me. I just need a few
pointers.

You need to implement a ClassLoader that knows your plugin path, and scans
the jar files for the requested classes. This way, the plugin classes and
their support classes can be loaded even though they are not on the
classpath.

Next up, at startup you iterate through all the jars in your plugin path,
and examine the Manifest for Plugin-Class entries. You will need to define
a constructor all plugins need to provide. Not very elegant, but necessary.

You then get the plugin class by using Class.forName(pluginName), retrieve
a constructor with the defined signature, and call newInstance one it with
the appropriate arguments (if it is nullary, you can just use the
newInstance() method in Class). After that, you have your plugin
instantiated, congratulations. Now just call registerPlugin, and do
whatever you want to do with the plugin.
 
S

Steve Sobol

Stefan said:
Next up, at startup you iterate through all the jars in your plugin path,
and examine the Manifest for Plugin-Class entries. You will need to define
a constructor all plugins need to provide. Not very elegant, but necessary.

That's cool - this shouldn't be hard to implement.

In this case, since I need to define a constructor... instead of creating an
interface, should I create an abstract class?

Thanks,
**SJS

--
JustThe.net - Steve Sobol / (e-mail address removed) / PGP: 0xE3AE35ED
Coming to you from Southern California's High Desert, where the
temperatures are as high as the gas prices! / 888.480.4NET (4638)

"Life's like an hourglass glued to the table" --Anna Nalick, "Breathe"
 
R

Raymond DeCampo

Steve said:
That's cool - this shouldn't be hard to implement.

In this case, since I need to define a constructor... instead of
creating an interface, should I create an abstract class?

No, I think that Stefan was promoting that you use an interface and
document that the implementations should support a constructor with a
particular signature. Usually this is a no-argument constructor.

Also, I would point out that an abstract class does not solve the
constructor problem. The constructors of an abstract class are not
inherited, so they do not force the subclasses to have a particular
constructor any more than an interface can force its implementations to.

If you are in doubt as to whether you need an interface or an abstract
class, you can always do both. That is, create an interface. Then
create an abstract class that implements the interface. Initial
implementations will extend the abstract class, but someday you may find
one for which that would not make sense. Then you are OK because you
coded to the interface instead of the abstract class.

Ray
 
S

Steve Sobol

Raymond said:
No, I think that Stefan was promoting that you use an interface and
document that the implementations should support a constructor with a
particular signature. Usually this is a no-argument constructor.

Also, I would point out that an abstract class does not solve the
constructor problem. The constructors of an abstract class are not
inherited, so they do not force the subclasses to have a particular
constructor any more than an interface can force its implementations to.

If you are in doubt as to whether you need an interface or an abstract
class, you can always do both.

Good info - thank you.

I think I'll stick with the interface, if creating a class won't provide any
extra benefit. Can always add one later.

--
JustThe.net - Steve Sobol / (e-mail address removed) / PGP: 0xE3AE35ED
Coming to you from Southern California's High Desert, where the
temperatures are as high as the gas prices! / 888.480.4NET (4638)

"Life's like an hourglass glued to the table" --Anna Nalick, "Breathe"
 
T

Thomas Weidenfeller

Steve said:
These jars are NOT going to be on the classpath.

Each jar containing a plugin will have a line like the following in its
manifest:

Plugin-Class: net.justthe.pluginImpl.myCoolPlugin

I would suggest

X-Plugin-Class: net.justthe.pluginImpl.myCoolPlugin

(note the "X-") to make it clear that this is not a standard Manifest entry.
Basically, the process will be to check each jar and...

--find out which class to load by reading the Plugin-Class line from
the manifest

Use java.io.File.listFiles() and the classes from java.util.jar to read
the Manifests from all the jar files.
--load that class

Create a java.net.URLClassLoader which "file:" URLs (e.g. as returned
from File.toURL()) pointing to all the jars. There is no need to
implement an own class loader. URLClassLoader can well load from files.

Only class loader for all your plugins is needed, not a class loader for
each plugin.
--call registerPlugin()

Use e.g. URLClassLoader.loadClass() to load the class. Then use
Class.newInstancer() to get an instance of the class (or reflection, if
you have constructors with arguments). Call your registerPlugin() method
on the instance.


/Thomas
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,994
Messages
2,570,223
Members
46,813
Latest member
lawrwtwinkle111

Latest Threads

Top