The entry point of the API is the ContainerManager
. It allows
you to define what is the Shared
classloader and to create children:
try (final ContainerManager manager = new ContainerManager( (1)
ContainerManager.DependenciesResolutionConfiguration.builder() (2)
.resolver(new MvnDependencyListLocalRepositoryResolver("META-INF/talend/dependencies.list"))
.rootRepositoryLocation(new File(System.getProperty("user.home", ".m2/repository"))
.create(),
ContainerManager.ClassLoaderConfiguration.builder() (3)
.parent(getClass().getClassLoader())
.classesFilter(name -> true)
.parentClassesFilter(name -> true)
.create())) {
// create plugins
}
-
The
ContainerManager
isAutoCloseable
, which allows you to use it in a try or finally block if needed.
This manager has two main configuration entries:-
how to resolve dependencies for plugins from the plugin file/location
-
how to configure the classloaders (what is the parent classloader, how to handle the parent first/last delegation, and so on).
NoteIt is recommended to keep the manager running if you can reuse plugins in order to avoid recreating classloaders and to mutualize them.
-
-
DependenciesResolutionConfiguration
allows you to pass a customResolver
which is used to build the plugin classloaders.
Currently, the library only providesMvnDependencyListLocalRepositoryResolver
, which reads the output ofmvn dependencies:list
. Add it to the plugin jar to resolve the dependencies from a local maven repository.
Note thatSNAPSHOT
are only resolved based on their name and not from the metadata (only useful in development).
To continue the comparison with a Servlet server, you can implement an unpacked war resolver. -
ClassLoaderConfiguration
configures the behavior of the whole container/plugin pair, including:-
What the shared classloader is
-
Which classes are loaded from the shared loader first (intended to be used for API which should not be loaded from the plugin loader)
-
Which classes are loaded from the parent classloader. This can be useful to prevent loading a "common" library from the parent classloader. For instance, it can be neat for guava, commons-lang3, an so on).
-
Once you have defined a manager, you can create plugins:
final Container plugin1 = manager.create( (1)
"plugin-id", (2)
new File("/plugin/myplugin1.jar")); (3)
-
To create a plugin
Container
, use thecreate
method of the manager. -
Give an explicit ID to the plugin. You can choose to bypass it. In that case, the manager uses the jar name.
-
Specify the plugin root jar.
To create the plugin container, the Resolver
resolves the dependencies needed for the plugin, then the manager creates the plugin classloader and registers the plugin Container
.
Some actions are needed when a plugin is registered or unregistered. For that purpose, you can use ContainerListener
:
public class MyListener implements ContainerListener {
@Override
public void onCreate(final Container container) {
System.out.println("Container #" + container.getId() + " started.");
}
@Override
public void onClose(final Container container) {
System.out.println("Container #" + container.getId() + " stopped.");
}
}
Plugins are directly registered on the manager:
final ContainerManager manager = getContainerManager();
final ContainerListener myListener = new MyListener();
manager.registerListener(myListener); (1)
// do something
manager.unregisterListener(myListener); (2)
-
registerListener
is used to add the listener going forward. However, it does not get any event for already created containers. -
You can remove a listener at any time by using
unregisterListener
.