All plug-ins should be installed in the location specified by the
plugins.dir setting in
While it is possible to also install them in a location that is on the
classpath, for example
it is nothing that we recommend. The rest of the information in this section
only applies to plug-ins that have been installed in the
If the above recommendation has been followed BASE will use it's own classloader to load the plug-in classes. This have several benefits:
New plug-ins can be installed and existing plug-ins can be updated
without restarting the web server. If the plugins.autounload
base.config has been enabled all you have to
do to update a plug-in is to replace the JAR file with a new version.
BASE will automatically load the new classes the next time the plug-in
is used. If the option isn't enabled, the server admin has to manually
update the plug-in from the web interface first.
Plug-ins may use it's own 3-rd party libraries without interfering with other plug-ins. This may be important because a plug-in may depend on a certain version of a library while another plug-in may depend on a different version. Since BASE is using different class-loaders for different plug-ins this is not a problem.
The classloading scheme used by BASE also means plug-in developers must pay attention to a few things:
A plug-in can only access/use classes from it's own JAR file, BASE core
classes, Java system classes and from JAR files listed in the plug-in's
MANIFEST.MF file. See Section 25.1, “How to organize your plug-in project”.
A plug-in can also access other plug-ins, but only via the methods and
interfaces defined in BASE. In the following example we assume that
there are two plug-ins,
located in two different JAR files. The code below is executing
// Prepare to load MyOtherPlugin SessionControl sc = ... DbControl dc = ... PluginDefinition def = PluginDefinition.getByClassName(dc, "ex.MyOtherPlugin"); // Ok Plugin other = def.newInstance(); // Not ok; fails with ClassCastException MyOtherPlugin other = (MyOtherPlugin)def.newInstance(); // Ok; since now we are using the correct class loader MyOtherPlugin other = def.newInstance(MyOtherPlugin.class);
The second call fails because BASE uses a different classloader to load the
ex.MyOtherPlugin class. This
class is not (in Java terms) the same as the
class loaded by the classloader that loaded the
class. If, on the other hand, both plug-ins are located in the same
JAR file BASE uses the same classloader and the second call will succeed.
The third call succeeds because now that we specify the class as an argument, BASE uses that classloader instead.
Another option is that the
lists the JAR file where
located in it's
MANIFEST.MF file. Then, the following
code can be used:
MyOtherPlugin other = new MyOtherPlugin();
Tomcat includes a good document describing how classloading is implemented in Tomcat: http://tomcat.apache.org/tomcat-6.0-doc/class-loader-howto.html. BASE's classloading scheme isn't as complex as Tomcat's, but it very similar to how Tomcat loads different web applications. The figure on the linked document could be extended with another level with separate classloaders for each plug-in as child classloaders to the web application classloaders.
As of BASE 2.13 the default search order for classes has been changed. The
default is now to first look in the plug-ins class path (eg. in the same
JAR file and in files listed in the
Only if the class is not found the search is delegated to the parent class
loader. This behaviour can be changed by setting
MANIFEST.MF file. If this property is set the
parent class loader is search first. This is the same as in BASE 2.12 and
|The benefit with the new search order is that plug-ins may use a specific version of any external package even if the same package is part of the BASE distribution. This was not possible before since the package in the BASE distribution was loaded first.|