Plugins
A plugin is a zip file. It contains at least the files plugin.properties
and <plugin id>.jar
in the root of the zip file in order to work.
The plugin.properties defines the start class (the property is named entrypoint) which implements the interface com.inet.plugin.ServerPlugin
. All dependencies, id, description and included internal jar libraries must be defined in this file.
The <plugin id>.jar contains the code of your plugin. At least one implementation of the interface com.inet.plugin.ServerPlugin
is required.
If the plugin contains a public API then you can find the API documentation in the file: <plugin id>-javadoc.jar
.
Lifecycle
The lifecycle of a plugin is as follows.
-
On start-up, the application loads all plugins that are available in the
plugins
directory. -
All located plugins are opened and their <plugin id>.jar is extracted into a temporary directory.
-
The plugin.properties files of the plugins are read and a dependency tree is created.
-
If the dependency of a plugin is not fulfilled, it is disabled.
-
Now each plugin gets its own classloader which has access to the plugin classes, internal and external referenced libraries and classes that are made public by other plugins (if the current plugin has an appropriate dependency defined).
-
The next step is to instantiate the entrypoint class.
-
The registerHelp method is called. Each plugin may now register any help content it may have.
-
The registerExtension method is called. Each plugin may now register instances of extensions it provides. This phase is meant only for registration, initialization is discouraged here. As a result, it is not allowed to query the
ServerPluginManager
for already registered instances. This call would fail with an exception. If any plugin throws an exception during this phase, then the plugin will be disabled. -
After the register phase, the init phase is started which calls the init method of your plugin's entrypoint instance. Now all required instances can be initialized and connected. Since all extensions have been registered by this point, it's allowed to fetch registered extensions from the provided ServerPluginManager instance. Registering additional extensions is no longer allowed in this phase and will result in an exception.
If background threads are needed, they can be started in the init method. Please make sure to stop these threads in the reset method. A restart of the background thread should be performed if the restart method is invoked. Resetting and restarting is only invoked by some application servers that support unloading unused web containers.
Plugin Properties
The file plugin.properties can contain the following properties.
Mandatory
The mandatory properties are the minimum required properties for the plugin to be loaded successfully.
Property | Description | |
---|---|---|
id | A unique identifier with only lowercase characters. In general it is equal to the filename of the plugin. | |
entrypoint | The fully qualified class name of the server plugin entry class. Packages are separated with dots. |
Optional
The optional properties can be left empty or entirely left out of the properties file. Some are only used for the configuration manager web application and can be ignored if this is not important for your scenario.
Property | Description | |
---|---|---|
dependencies | A semi-colon (or comma) separated list of required plugins identified by their ID. | |
optionalDependencies | A list of optional dependencies. The current plugin will run even if these dependencies are missing. It gives access to the exported classpath of this plugins. You need to check the availability with isPluginLoaded(id) . |
|
internal | An optional semi-colon separated list of additional jar files in the zip file. These jar files will be added to the classpath of the plugin. | |
external | Any external library jar files required by this plugin. A semi-colon separated list with absolute paths or paths relative to the current working directory. | |
version | The version number of this plugin. It will be shown in the log file and in the GUI of the configuration manager. It has to be a valid float number and can also be used to define the dependency to a plugin with a special version. | |
description | A description for the plugin that will be shown in the configuration web application. | |
description_<locale> | A localized description for the plugin that will be shown in the configuration web application. | |
initAfter | A semi-colon separated list of dependencies identified by their ID. The plugin manager will try to init any of the plugins in this list before the current one. In case of a cyclic reference the order in this cycle is undefined. | |
flags | A semi-colon separated list of flags: | |
designer | Set if the plugin is to be loaded by the i-net Designer (Standalone or JNLP) - otherwise the plugin will not be loaded by the Designer. | |
rootAccess | Set if the plugin needs access to the root classloader of the application. A setting of the dependencies property is to be preferred. | |
core | Set if the plugin is to be hidden from the plugin manager in the configuration manager web application and can not be disabled. If this flag is not set, the plugin will be visible in the configuration manager web application for disabling/enabling by the administrator. | |
optional | Set if this plugin is not enabled by default. The user will need to enable it in the configuration manager web application. If this flag is not set, the plugin will be enabled by default and the user will need to disable it if this is desired. | |
group | Grouping in the plugin manager dialog of the configuration manager. | |
icon | Path to icon resource to be used in the plugin manager dialog of the configuration manager. | |
permissions | Permissions in the plugin manager dialog of the configuration manager. | |
packages | A semi-colon separated list of packages which are shared by this plugin. Plugins depending on this plugin only have access to classes from these packages. |
Optional Dependencies
If you implement a more complex feature then it can be that you have dependencies to more than one other plugin. For example, you might have a dependency to remotegui
, maintenance
and taskplanner
. If the user deactivates one of these plugins, then your plugin will also be deactivated because of a missing dependency.
This situation is where optional dependencies can help. In your plugin's plugin.properties
, you can specify dependencies with optionalDependencies
instead of dependencies
. Your plugin will then also start up if optional dependencies are missing. To prevent a ClassNotFoundException at runtime, however, you must check if the plugin is available. Here is how you can do this:
import com.inet.plugin.*; import com.inet.maintenance.api.backup.BackupTask; ... public void registerExtension( ServerPluginManager spm ) { if( spm.isPluginLoaded( "maintenance" ) ) { spm.register( BackupTask.class, new MyBackupTask() ); } }
Debugging
If you write your own plugin then it can be very helpful to debug it in an IDE. Because Java uses a hierarchical classloader and the plugins use cross-linked classloaders, this can be a little complicated. With the following steps it should work in Eclipse. But it should work similarly with other IDEs such as IntelliJ IDEA.
-
First you must build your plugin with its plugin.properties and the needed jar files. Let's say your plugin name is MyPlugin.
-
Then, you create a new Java project for running the server in debug mode.
-
Copy the folders "core", "lib" (if it exists) and "plugins" of an installation into the project root. The "core" folder can also have the name "java". The "lib" folder does not necessarily exist for every product by i-net software.
-
Add the main jar files to the classpath of the project. For example
core/inetcore.jar
. -
Stop all other servers of the product. If one is running as a service then set the service to manual startup. Else you can have problems if the port your server is trying to bind to is already in use.
-
Add a launcher for the main class. For example
com.inet.Start
. -
Start the launcher and test in the browser if it works at this point.
-
Copy your plugin MyPlugin.zip into the
plugins
subfolder of the project. -
Add to the launcher the following JVM parameters:
-DMyPlugin.classpath="${workspace_loc}/MyPluginProj/bin"
(replacing MyPlugin with the id of your plugin and MyPluginProj with your plugin project).
-
Restart the launcher.
-
Set a breakpoint in your plugin's source files and then cause your plugin to be run or used. Your breakpoint should be hit, and you may need to first set the source file location for your IDE the first time you hit a breakpoint.
Location of Plugins
The plugins ZIP file need to be located in the folder plugins
. This folder need to be parallel to the folder which contains the library inetcore.jar/.dll. The folder structure should look like:
<...>/<anydir>/inetcore.jar <...>/plugins/*.zip
If you develop a WAR file for a Java application server then the plugins folder need to be in the root of the WAR file.