Design question

I have a classloader that loads classes from a plugins folder. These classes must extend a certain parent class. Now I want to be able to get a 'name' and 'version' from the class, and do it without having to construct the plugin itself. I don't want to construct the plugin, because I have the potential of running out of memory when I load a lot of plugins, let's say 100 plugins. This is especially useful when I want to list all plugins and just select 2 to use. Only 2 would get constructed instead of all 100.

So I ask, which design is better:

A) Make each subclass have a static getName and getVersion method, giving an error at runtime if they have failed to do this.

B) Use protected methods, which forces the user to have the method in order to compile. It's cleaner, and the proper way to do it.

They both have advantages and disadvantages. By making them static, I have to use reflection to get the actual value of getName, otherwise I get the parent class' version of getName. Using protected methods forces me to construct all 100 classes just to get the names and versions.

Opinions?

[1143 byte] By [robtafta] at [2007-11-27 11:45:24]
# 1

Well methods A and B will force you to load the classes anyway. They wont solve any

memory issues only thing your avoiding with A is making an instance, which may not be

as big as the class itself

I wouldnt use a class loader if I am not loading from the network. Heres what I would

ideally do. Keep the jars in ext directory or some where in your class path. Use a

properties file to store the plugin name and version.

The properties file could be something like

plugin.version.name=fully qualified class name

However you must find a way to register the plugin with the properties file this is one

method. Provide an interface to register a JAR file with the system, and load the classes

just once, and get all the info you need to store in the properties file then copy the jar into

the classpath.

WirajRa at 2007-7-29 18:01:32 > top of Java-index,Java Essentials,Java Programming...
# 2

Have you considered some sort of Factory pattern?

Like

public interface PluginFactory{

public String getName();

public String getVersion();

public Plugin loadPlugin(Something something);

}

public interface Plugin{

// your other stuff

}

cotton.ma at 2007-7-29 18:01:32 > top of Java-index,Java Essentials,Java Programming...
# 3

> Well methods A and B will force you to load the

> classes anyway. They wont solve any

> memory issues only thing your avoiding with A is

> making an instance, which may not be

> as big as the class itself

> I wouldnt use a class loader if I am not loading

> from the network. Heres what I would

> ideally do. Keep the jars in ext directory or some

> where in your class path. Use a

> properties file to store the plugin name and

> version.

> The properties file could be something like

>

> plugin.version.name=fully qualified class name

>

> However you must find a way to register the plugin

> with the properties file this is one

> method. Provide an interface to register a JAR file

> with the system, and load the classes

> just once, and get all the info you need to store in

> the properties file then copy the jar into

> the classpath.

I don't want to risk having a class file and no properties file, or vice versa, or having them somehow get mixed up. I do allow for multiple classes to have the same name, as long as they are in jars, and I can load them both and use them both. I also have a getAuthor method, and what makes the different versions unique is having either a different name, version, or author. If all 3 are the same, I consider them duplicates. I allow this so that in cases where comparing version 1 to version 2 is needed.

I don't think loading a class and constructing a class are in any way similar in memory consumption. For example, class Temp loads a 100MB database file into memory in its constructor. Method A would not load the 100MB, whereas method B would.

robtafta at 2007-7-29 18:01:32 > top of Java-index,Java Essentials,Java Programming...
# 4

@cotton.m

I think I like this idea. I was thinking of having the Plugin return a PluginInfo class, but I would really still be stuck in the same situation, having to make the method to get the info static, and having to use reflection to properly get the Plugins information.

The only downside, although nothing I care a lot about, is that the plugin will have 2 classes, instead of 1. I suppose requiring they all be jarred is acceptable enough.

Thanks.

robtafta at 2007-7-29 18:01:32 > top of Java-index,Java Essentials,Java Programming...
# 5

I'd go with the reflection approach. Your plugin loader should be self-contained, so other than taking up space in the permgen, loading classes shouldn't be a problem.

If you are worried about invalid plugins getting into the process, you could always use a dedicated classloader in the inspection phase: load classes into it, query them, keep track of the classes/jars you want, then discard the loader and reload the classes using a new classloader. A little more cumbersome, and probably somewhat slower, but I suspect that the initial inspection will take most of the time anyway.

I'm a bit confused about with your comment about a "parent class." I'm assuming that you're simply examining all plugins in the particular folder, in which case there shouldn't be a "parent class" involved.

kdgregorya at 2007-7-29 18:01:32 > top of Java-index,Java Essentials,Java Programming...
# 6

When I say parent class, I mean the abstract class or interface that the child classes inherit from. My biggest worry is constructing multiple plugins at the same time that use a lot of memory. In most cases, only 2 are loaded at a time (unless I ahve to load them all), but a list is generated with information about each plugin (using reflection and static methods). The problem with reflection, is that I have to use it from another class, and I can never just use the methods directly.

If I have a static String getName() in Plugin, and I have the same getName() in MyPluginwhich extends Plugin.

if I have this:

Plugin plugin = PluginLoader.getPlugin(0); //lets say it returns the first plugin it finds and constructs it

System.out.println(plugin.getName()); //this returns Plugin's name, even though it is really MyPlugin.

I cannot get the name from plugin directly. Even if you have a nonstatic method in Plugin that just calls the static one, it still returns Plugin's static name. This forces me to get the name, version, author from PluginLoader, which will call the reflection on whatever Plugin I pass it. I thought about using reflection in a static method inside Plugin, but I would ahve to pass in the instance...I suppose that could work...calling plugin.getName(plugin) although it looks silly.

cotton.m's example will force me to keep the PluginFactory and the Plugin paired together if I ever want to get the information on the Plugin. I could take the information in the factory and store it in Plugin after it is constructed, then I don't have to carry both objects around together. It would also allow me to just call plugin.getName() and get the name, and it would be the same as the values in PluginFactory. I'm still liking this best.

robtafta at 2007-7-29 18:01:32 > top of Java-index,Java Essentials,Java Programming...
# 7

Ive had this problem and in one case I used a rather simple

solution. However in the case of classes I dont think it works

that great - so im really just mentioning this for posterity.

Sometimes when I serialize huge or cumbersome objects and want

to find info about them without loading the entire thing what I do

is write 2 objects to the same file. The first is a tiny info class.

This way I can call readObject() and get the info and I only have to

load the huge object if i need to.

The classloader loads bytes not files. So you can load the info data

first and then load the class bytes if you need to. In this situation this

solution isnt really great though cause its basically reinventing the

JAR file. Plus you wont be able to use the file as a normal .class

anymore.

TuringPesta at 2007-7-29 18:01:32 > top of Java-index,Java Essentials,Java Programming...
# 8

I must be misunderstanding how you're dealing with plugins, then.

My understanding is that you (1) have a directory/jar/whatever full of plugin classes, and (2) have a PluginLoader class that only wants to load valid plugins.

The first problem, of course, is identifying the plugin classes. I think you mentioned a properties file above, but I think that's a relatively brittle solution, because it means that you have to update two places whenever you add/update/remove a plugin.

A better solution, imo, is to examine the plugin directory/jar, and extract all the classes from it. Then -- preferably with a dedicated classloader -- you load all of those classes (using ClassLoader.findClass). Yes, this will take some time, and no, you definitely don't want to run over your entire classpath.

Once you've loaded the class, then you can invoke static methods via reflection. You don't have to instantiate the class to do this (which is your concern with memory). You do have to ensure that the class has the expected static methods -- and you'll probably want to use an interface to separate actual plugins from supporting classes.

I'd see PluginLoader looking something like this:

public class PluginLoader {

public PluginLoader(File pluginDir)

...

public void loadPlugins() {

List<String> validPlugins = findPlugins();

for (String plugin : validPlugins) {

instantiatePlugin(plugin);

}

}

private List<String> findPlugins() {

// create temporary classloader

// examine plugin directory/jar to find classes

// for each class, load it in classloader, examine

// if valid, add to result list

}

private void instantiatePlugin(String klass) {

// call Class.forName

// call expected constructor

// save instance somewhere?

}

}

kdgregorya at 2007-7-29 18:01:32 > top of Java-index,Java Essentials,Java Programming...
# 9

For an example of a "Plugin Factory" approach in the API, check out

imageio's Service Provider Interface:

http://java.sun.com/javase/6/docs/api/javax/imageio/spi/package-summary.html

BigDaddyLoveHandlesa at 2007-7-29 18:01:32 > top of Java-index,Java Essentials,Java Programming...
# 10

> For an example of a "Plugin Factory" approach in the

> API, check out

> imageio's Service Provider Interface:

I was thinking about JDBC Drivers and Connections.

cotton.ma at 2007-7-29 18:01:32 > top of Java-index,Java Essentials,Java Programming...
# 11

@kdgregory

I already do something like this, and I pass in the parent class or interface to get a list of the classes that extend the parent. My question wasn't how to do that part, but it was regarding whether I should be using reflection to get the information or using something that isn't static. I currently do everything you are suggesting, just looking for something that feels cleaner.

@BigDaddyLoveHandles

I was thinking about something like IIOServiceProvider, where your basic information is there in the methods, and you have a onRegistration and onDeregistration, or maybe an initialize and cleanup method that does the dirty work. The only issue with that type of approach is that it is a sort of 'on your honor' approach where you place your trust in the plugin author to only load its memory intensive portion in the register/initialize portion. I like this, I hope it is what you were thinking when you posted that.

robtafta at 2007-7-29 18:01:32 > top of Java-index,Java Essentials,Java Programming...
# 12

> I already do something like this, and I pass in the

> parent class or interface to get a list of the

> classes that extend the parent. My question wasn't

> how to do that part, but it was regarding whether I

> should be using reflection to get the information or

> using something that isn't static. I currently do

> everything you are suggesting, just looking for

> something that feels cleaner.

Oh, well, in that case I'd definitely go with reflection to first identify and then invoke static methods. I can't imagine that you'd want to instantiate a class just to verify that it should be instantiated, and having a separate "info" class means that you'd have two things to keep in sync.

I would suggest using the getDeclaredMethods() call, so that you only access classes that do follow the proper interface.

kdgregorya at 2007-7-29 18:01:32 > top of Java-index,Java Essentials,Java Programming...
# 13

actually, I use this to determine if the class is of the right type:

baseClass.isAssignableFrom(clazz)

where clazz is one class in a list of classes that is looped over, and baseClass is the Class that clazz must inherit from.

I suppose if I continued to use static methods, that I would have to check to make sure each static method is there, which I do. If it is not, I either throw an exception or put in a dumby name like 'unknown'...it's changed a few times.

The part that bothers me most is that it doesn't create errors at compile time, only at runtime, which is one reason I was looking for a change.

I was thinking over the 2 class approach, and I think it is more complicated to do it that way in my case. What I really have is a class structure like so:

Player -> AI -> GameNameAI -> UserWrittenAIs

GameName could be any game, chess, checkers, etc. Using 2 classes, would add:

AIInfo -> GameNameAIInfo -> UserWrittenAIInfos

It would grow in complexity with GameNameAIInfo, having multiple ones that essentially do nothing different than AIInfo except identify it as belonging to that game.

I like using the initialize and uninitialize methods. Although I have to trust the author to use it properly, it is no different than trusting them to not write malicious code as a plugin.

robtafta at 2007-7-29 18:01:32 > top of Java-index,Java Essentials,Java Programming...