T-Plan Robot Enterprise 5.0.1
Build No. 5.0.1-20190308.1

com.tplan.robot.plugin
Class PluginManager

java.lang.Object
  extended by com.tplan.robot.plugin.PluginManager
All Implemented Interfaces:
java.io.FilenameFilter

public class PluginManager
extends java.lang.Object
implements java.io.FilenameFilter

Plugin manager provides framework for installation, uninstallation and loading of plugins and serves as a central point of plugin instantiation for all plugin factories.

This class implements the singleton pattern. As it has a private constructor, direct instantiation is not possible and other classes must use the getInstance() method to get a shared plugin manager instance.

The shared instance gets created when the getInstance() method is called for the first time. The manager first loads the default map of plugins from the internal XML specified by the INTERNAL_PLUGIN_XML variable. If there's a custom plugin map found at the path specified by EXTERNAL_PLUGIN_XML, it is also loaded and applied to the default plugin map. Any changes caused during runtime by plugin installation, uninstallation, enabling and disabling can be programatically saved to the external XML through the savePluginMap() method.

Plugins create hierarchy which is reflected in the plugin map structure. Each plugin must implement one of the public functional interfaces which were made loadable through the plugin mechanism. Such interfaces are called exposed functional interfaces or just functional interfaces.

Plugins implementing the same functional interface are said to belong to the same plugin group. There's an optional XML attribute allowing to assign name to such a group. As the name is displayed by the GUI, it should shortly describe functionality provided by the group (interface), for example "Desktop Clients", "Scripting Commands" etc.

Many objects in the T-Plan Robot Enterprise code base such as desktop clients, image comparison modules, script command handlers and report providers are already implemented as plugins. These are called default or built-in plugins and they are listed in the default plugin map PluginMap.xml. Plugins which are delivered in separate JAR/ZIP files or class paths are often called external plugins.

As built-in plugins form integral part of the product code, they cannot be uninstalled. They can be however disabled and/or replaced (reimplemented) by external plugins. To reimplement an internal plugin, a new one must be developed where its getCode() method must return the same value as the internal one.

Each plugin must implement the Plugin interface as well as one of the exposed functional interfaces. Its class must be publicly instantiable which means it can not be abstract or private. It also must have a default parameterless constructor which initializes the instance correctly.

Plugins can be delivered in form of directories or JAR/ZIP files with compiled Java classes. Installation of plugins can be done in several ways:

Format of the XML map is visible in the default PluginMap.xml. Meaning of individual tags/attributes are:

Tag/Attribute Description
"application" Top level tag enclosing the T-Plan Robot Enterprise plugin configuration.
"plugingroup" This tag encloses group of plugins which implement the same functional interface.
"interface" Defines class of an exposed functional interface in Java format, for example "mypackage.MyFunctionalInterface".
"name" Specifies displayable name of a plugin group. It in fact serves as short description of functionality provided by the associated functional interface.
"plugin" This tag encloses a particular plugin. Its value must be plugin class in Java format, for example "mypackage.MyPlugin" External plugins are required to specify path to the library using the "source" attribute.
"source" Attribute of the "plugin" tag. It specifies path of the library (either a JAR/ZIP file or a single Java class path) which contains the compiled plugin class, for example "file:///usr/lib/myplugins.jar". It is not mandatory for built-in plugins but other external plugins should always define it to make sure the classes are made visible to the JVM class loader. Failure to include the library path for an external plugin is likely to result in a ClassNotFoundException thrown at an attempt to install, enable or instantiate the plugin.
"enabled" Optional attribute of the "plugin" tag specifying whether the plugin is enabled or disabled. It's value may be either "true" or "false". It the attribute is not present, the attribute defaults to "true" meaning that the plugin is considered to be enabled.


T-Plan Robot Enterprise, (C) 2009-2019 T-Plan Limited. All rights reserved.


Field Summary
static java.lang.String EXTERNAL_LEGACY_PLUGIN_XML
           
static java.lang.String EXTERNAL_PLUGIN_XML
          Absolute path to external plugin map XML file.
static java.lang.String INTERNAL_PLUGIN_XML
          File name of the default plugin map XML.
static java.lang.String XML_APPLICATION
          Application XML tag ("application").
static java.lang.String XML_ENABLED
          Plugin status XML tag attribute ("enabled").
static java.lang.String XML_GROUP_NAME
          Plugin group name XML tag attribute ("name").
static java.lang.String XML_GROUP_NAME_KEY
          Resource bundle key of the plugin group name ("key").
static java.lang.String XML_INTERFACE
          Plugin group functional interface XML tag attribute ("interface").
static java.lang.String XML_PLUGIN
          Plugin XML tag ("plugin").
static java.lang.String XML_PLUGINGROUP
          Plugin group XML tag ("plugingroup").
static java.lang.String XML_SOURCE
          Plugin library path XML tag attribute ("source").
 
Method Summary
 boolean accept(java.io.File dir, java.lang.String name)
           
 void addPluginListener(PluginListener listener)
          Add a plugin listener.
static void addURL(java.net.URL u)
          Add a URL dynamically to the class path.
static void discoverJavaTestScripts(java.io.File f)
          Load Java test scripts contained in the argument file (class path, JAR or ZIP file).
 java.util.List<PluginInfo> getAvailablePlugins(java.io.File file)
          Get plugins available in a JAR or ZIP file or Java class path.
static PluginManager getInstance()
          Get shared instance of Plugin Manager.
 java.util.Map<java.lang.Class,java.lang.String> getInterfaceKeyMap()
          Get map of exposed functional interfaces.
 java.util.Map<java.lang.Class,java.lang.String> getInterfaceMap()
          Get map of exposed functional interfaces.
 java.util.Map<java.lang.String,java.io.File> getJavaTestScriptMap()
          Get the map of known Java test scripts.
 java.util.List<PluginInfo> getPlugins()
          Get list of all installed plugins which are present in the current plugin map.
 java.util.List<PluginInfo> getPlugins(java.lang.Class implementedInterface, boolean includeDisabled)
          Get list of plugin info instances for all plugins implementing a particular functional interface.
 java.util.List<PluginInfo> getPlugins(java.lang.Object code, java.lang.Class implementedInterface, boolean includeDisabled)
          Get list of all installed plugins of the specific code and implemented interface which are present in the current plugin map.
static java.util.List<java.lang.String> getResources(java.util.regex.Pattern pattern)
           
static java.util.List<java.lang.String> getResources(java.lang.String element, java.util.regex.Pattern pattern)
           
static java.util.List<java.lang.String> getResourcesFromDirectory(java.io.File directory, java.lang.String directoryCanonicalPath, java.util.regex.Pattern pattern)
           
static java.util.Collection<java.lang.String> getResourcesFromJarFile(java.io.File file, java.util.regex.Pattern pattern)
          List resources from a JAR or ZIP file.
static boolean implementsInterface(java.lang.Class cl, java.lang.Class interf)
          Find out whether a class implements a particular interface.
 void installPlugin(java.lang.String pluginClassName, java.lang.String libraryUrl, boolean force, boolean enable)
          Install and eventually enable an external plugin.
 boolean isBuiltIn(Plugin plugin)
          Find out whether a plugin is a default (built-in) one.
 boolean isEnabled(Plugin p)
          Find out whether a plugin is disabled or enabled.
 boolean isInstalled(Plugin p)
          Find out whether a plugin is already installed.
 void removePluginListener(PluginListener listener)
          Remove an object from the list of plugin listeners.
 void savePluginMap()
          Save the current plugin map from the memory to a file specified by the EXTERNAL_PLUGIN_XML variable.
 void setEnabled(Plugin plugin, boolean enabled)
          Enable or disable a plugin.
 boolean uninstallPlugin(Plugin plugin)
          Uninstall an external plugin.
 
Methods inherited from class java.lang.Object
clone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait
 

Field Detail

EXTERNAL_PLUGIN_XML

public static final java.lang.String EXTERNAL_PLUGIN_XML
Absolute path to external plugin map XML file. Just like user preferences, the file is used to save any user modifications to the default plugin map such as installation, uninstallation, activation or deactivation of plugins. The file is typically stored in the user home folder and has the same name is the internal XML.


EXTERNAL_LEGACY_PLUGIN_XML

public static final java.lang.String EXTERNAL_LEGACY_PLUGIN_XML

INTERNAL_PLUGIN_XML

public static final java.lang.String INTERNAL_PLUGIN_XML
File name of the default plugin map XML. It is expected to be bundled with the source code in the same package as this class. It's current value is "PluginMap.xml".

See Also:
Constant Field Values

XML_PLUGINGROUP

public static final java.lang.String XML_PLUGINGROUP
Plugin group XML tag ("plugingroup").

See Also:
Constant Field Values

XML_PLUGIN

public static final java.lang.String XML_PLUGIN
Plugin XML tag ("plugin").

See Also:
Constant Field Values

XML_APPLICATION

public static final java.lang.String XML_APPLICATION
Application XML tag ("application").

See Also:
Constant Field Values

XML_GROUP_NAME

public static final java.lang.String XML_GROUP_NAME
Plugin group name XML tag attribute ("name").

See Also:
Constant Field Values

XML_GROUP_NAME_KEY

public static final java.lang.String XML_GROUP_NAME_KEY
Resource bundle key of the plugin group name ("key").

See Also:
Constant Field Values

XML_INTERFACE

public static final java.lang.String XML_INTERFACE
Plugin group functional interface XML tag attribute ("interface").

See Also:
Constant Field Values

XML_ENABLED

public static final java.lang.String XML_ENABLED
Plugin status XML tag attribute ("enabled").

See Also:
Constant Field Values

XML_SOURCE

public static final java.lang.String XML_SOURCE
Plugin library path XML tag attribute ("source").

See Also:
Constant Field Values
Method Detail

getJavaTestScriptMap

public java.util.Map<java.lang.String,java.io.File> getJavaTestScriptMap()
Get the map of known Java test scripts.

Returns:
map of Java test scripts where the fully qualified class name is the key and the value is the class source (class path, JAR or ZIP).
Since:
3.5.2

getInstance

public static PluginManager getInstance()
Get shared instance of Plugin Manager.

Returns:
shared instance of Plugin Manager. Never returns null.

uninstallPlugin

public boolean uninstallPlugin(Plugin plugin)

Uninstall an external plugin. This is not applicable to internal built-in plugins which cannot be uninstalled. The method removes the plugin from the map of plugins in the memory. If the plugin is loaded from a library which is not needed any more (i.e. there's no other plugin installed from the library), it is removed from the internal list of libraries and also from the application Java class path. Successful uninstallation of a plugin fires a plugin event with the PluginEvent.PLUGIN_UNINSTALLED code to all registered listeners.

After the plugin is uninstalled, the method checks the default plugin map for any built-in plugin providing the same functionality (with the same code returned by getCode()) and enables it automatically if it exists. This logic is not applied to external plugins and enabling of an already installed external plugin must be done programatically.

The method doesn't save plugin map changes to the file system. Users calling this method programatically have to call the savePluginMap() method afterwards.

Parameters:
plugin - a plugin. If the argument is null or it represents an internal built-in plugin, the method does nothing and returns false.
Returns:
true if the plugin was successfully uninstalled, false otherwise.

getPlugins

public java.util.List<PluginInfo> getPlugins()
Get list of all installed plugins which are present in the current plugin map.

Returns:
list of all installed plugins (PluginInfo instances).

isInstalled

public boolean isInstalled(Plugin p)
Find out whether a plugin is already installed. Two plugins are considered to be equal when they return the same unique code and version.

Parameters:
p - a plugin.
Returns:
true if the plugin is installed, false if not.

isEnabled

public boolean isEnabled(Plugin p)
Find out whether a plugin is disabled or enabled. See the setEnabled(com.tplan.robot.plugin.Plugin, boolean) method documentation for more information.

Parameters:
p - a plugin.
Returns:
true if the plugin is enabled, false if not or if the plugin is not installed.

isBuiltIn

public boolean isBuiltIn(Plugin plugin)
Find out whether a plugin is a default (built-in) one. All plugins defined by the default XML plugin map bundled with the code are supposed to be built-in.

Parameters:
plugin - a plugin.
Returns:
true if the plugin is a built-in plugin, false if not or if the plugin is not installed.

setEnabled

public void setEnabled(Plugin plugin,
                       boolean enabled)
                throws CodeConflictException

Enable or disable a plugin. A disabled plugin is not visible to other classes (through plugin factories) but remains installed and can be reenabled any time. If the method is called to enable an already enabled plugin or disable an already disabled one, it does nothing. Any change of the plugin status fires a plugin event with the PluginEvent.PLUGIN_ENABLED or PluginEvent.PLUGIN_DISABLED code to all registered listeners.

Disabling of plugins is used in case of plugin reimplementations, which means installation of a plugin which replaces functionality of a built-in plugin or an already installed external one. The method can be however also used to disable plugins programatically at a runtime.

If an external plugin is being disabled, the method checks the default plugin map for a built-in plugin providing the same functionality (with the same code returned by getCode()) and enables it automatically if it exists. This logic is not applied to external plugins and enabling of an already installed external plugins must be done programatically.

Parameters:
plugin - a plugin (Plugin instance).
enabled - true enables functionality of the plugin, false disables.
Throws:
CodeConflictException

getPlugins

public java.util.List<PluginInfo> getPlugins(java.lang.Class implementedInterface,
                                             boolean includeDisabled)
Get list of plugin info instances for all plugins implementing a particular functional interface.

Parameters:
implementedInterface - class of the exposed functional interface implemented by the plugin.
includeDisabled - false returns just the enabled plugin, true lists all plugins regardless whether they are enabled or disabled.
Returns:
list of plugin info instances for all installed plugins implementing the specified functional interface.

getPlugins

public java.util.List<PluginInfo> getPlugins(java.lang.Object code,
                                             java.lang.Class implementedInterface,
                                             boolean includeDisabled)
Get list of all installed plugins of the specific code and implemented interface which are present in the current plugin map.

Parameters:
code - plugin code.
implementedInterface - exposed functional interface implemented by the plugin.
includeDisabled - true will include disabled plugins, false lists just enabled ones.
Returns:
list of all installed plugins (PluginInfo instances) which return the specified plugin code and implement the specified interface.

getInterfaceMap

public java.util.Map<java.lang.Class,java.lang.String> getInterfaceMap()
Get map of exposed functional interfaces.

Returns:
map of exposed functional interfaces where key is the interface class and value is the plugin group name assigned to the interface by the "name" attribute in the XML map.

getInterfaceKeyMap

public java.util.Map<java.lang.Class,java.lang.String> getInterfaceKeyMap()
Get map of exposed functional interfaces.

Returns:
map of exposed functional interfaces where key is the interface class and value is the plugin group name key assigned to the interface by the "key" attribute in the XML map.

savePluginMap

public void savePluginMap()
                   throws java.io.FileNotFoundException

Save the current plugin map from the memory to a file specified by the EXTERNAL_PLUGIN_XML variable. Format of this XML file is specified in description of this class.

Note that saving of the plugin map is not performed automatically and users who modify the plugin map from custom programs must call this method to save their changes.

Throws:
java.io.FileNotFoundException - when the file cannot be opened for writing.

installPlugin

public void installPlugin(java.lang.String pluginClassName,
                          java.lang.String libraryUrl,
                          boolean force,
                          boolean enable)
                   throws java.lang.InstantiationException,
                          java.lang.IllegalAccessException,
                          java.io.IOException,
                          java.lang.ClassNotFoundException,
                          UnsupportedVersionException,
                          HigherVersionInstalledException,
                          CodeConflictException,
                          DependencyMissingException,
                          java.net.MalformedURLException,
                          java.lang.NoSuchMethodException,
                          java.lang.IllegalArgumentException,
                          java.lang.reflect.InvocationTargetException

Install and eventually enable an external plugin. The method adds the plugin to the internal plugin map and if the enable flag is set to true, it makes it enabled and thus immediatelly visible to all plugin factories. If the plugin library is not present on the Java class path, it is dynamically added and all its classes are made available to the default JVM class loader. Successful installation of a plugin fires a plugin event with the PluginEvent.PLUGIN_INSTALLED code to all registered listeners.

When value of the force argument is false, the method supports the following standard error scenarios:

Non-standard errors are reported through other exceptions declared by this method such as InstantiationException, IllegalAccessException, IOException and ClassNotFoundException. They typically indicate an internal or misconfiguration error where the plugin class (library) is missing, it cannot be instantiated or added to the plugin map.

The method doesn't save plugin map changes to the file system. Users calling this method programatically have to call the savePluginMap() method afterwards.

Parameters:
pluginClassName - full plugin class name, for example "mypackage.MyPlugin".
libraryUrl - URL of the library which contains the plugin class.
force - true overrides some standard error situations. See the method description.
enable - true enables the plugin after installation, false just installs and leaves the plugin disabled.
Throws:
java.io.IOException - when the map is not writable or the specified library is not available/readable due to an I/O error.
java.lang.ClassNotFoundException - when class of a plugin specified in the map is not found. It typically means that the plugin class or any of its dependencies are not present in the class path of the current Java runtime.
java.lang.InstantiationException - when the plugin can't be instantiated. Each plugin must have a default parameterless constructor and must be instantiable.
java.lang.IllegalAccessException - An IllegalAccessException is thrown when plugin manager tries to create a plugin instance or invoke its method through the Java Reflection API, but the currently executing method does not have access to the definition of the specified plugin class, method or constructor.
UnsupportedVersionException - thrown when the plugin requires higher T-Plan Robot Enterprise version than the current one.
HigherVersionInstalledException - thrown when a higher version of the same plugin is already installed.
CodeConflictException - thrown when another plugin providing the same functionality is already installed and enabled.
DependencyMissingException - when one or more dependencies (other plugins) required by the plugin is not installed.
java.net.MalformedURLException
java.lang.NoSuchMethodException
java.lang.IllegalArgumentException
java.lang.reflect.InvocationTargetException

implementsInterface

public static boolean implementsInterface(java.lang.Class cl,
                                          java.lang.Class interf)
Find out whether a class implements a particular interface. Unlike the Class.getImplementedInterfaces() the method also checks all superclasses. It provides the same functionality as the "instanceof" operator save that it avoids any class instantiation.

Parameters:
cl - a class to be checked for the implemented interface.
interf - an interface class.
Returns:
true if the class or any of its superclasses implements the specified interface or false otherwise.

getAvailablePlugins

public java.util.List<PluginInfo> getAvailablePlugins(java.io.File file)
                                               throws java.io.IOException,
                                                      java.lang.ClassNotFoundException,
                                                      java.lang.IllegalAccessException
Get plugins available in a JAR or ZIP file or Java class path. The method searches the specified resource and finds all classes that implement the Plugin interface.

Parameters:
file - a JAR/ZIP file or a directory with compiled Java classes.
Returns:
list of PluginInfo instances describing available plugins.
Throws:
java.io.IOException - when the input stream is not readable due to an I/O error.
java.lang.ClassNotFoundException - when class of a plugin specified in the map is not found. It typically means that the plugin class or any of its dependencies are not present in the class path of the current Java runtime.
java.lang.IllegalAccessException - An IllegalAccessException is thrown when plugin manager tries to create a plugin instance or invoke its method through the Java Reflection API, but the currently executing method does not have access to the definition of the specified plugin class, method or constructor.

getResources

public static java.util.List<java.lang.String> getResources(java.util.regex.Pattern pattern)
                                                     throws java.io.IOException
Throws:
java.io.IOException

getResources

public static java.util.List<java.lang.String> getResources(java.lang.String element,
                                                            java.util.regex.Pattern pattern)
                                                     throws java.io.IOException
Throws:
java.io.IOException

getResourcesFromDirectory

public static java.util.List<java.lang.String> getResourcesFromDirectory(java.io.File directory,
                                                                         java.lang.String directoryCanonicalPath,
                                                                         java.util.regex.Pattern pattern)
                                                                  throws java.io.IOException
Throws:
java.io.IOException

getResourcesFromJarFile

public static java.util.Collection<java.lang.String> getResourcesFromJarFile(java.io.File file,
                                                                             java.util.regex.Pattern pattern)
List resources from a JAR or ZIP file. This is used to get all Java file names contained in an archive.

Parameters:
file - a JAR or ZIP file.
pattern - a pattern to apply to the resource list.
Returns:
collection of resources available in the argument archive.

addURL

public static void addURL(java.net.URL u)
                   throws java.io.IOException
Add a URL dynamically to the class path. This is used to load plug in JAR files or classes.

Parameters:
u - a JAR file or class path URL.
Throws:
java.io.IOException

addPluginListener

public void addPluginListener(PluginListener listener)
Add a plugin listener. Plugin listeners are notified of plugin map changes such as plugin installation, uninstallation, activation or deactivation.

Parameters:
listener - a listener to be registered for plugin map changes.

removePluginListener

public void removePluginListener(PluginListener listener)
Remove an object from the list of plugin listeners. If the specified object is not present in the listener list, the method does nothing. See the addPluginListener(com.tplan.robot.plugin.PluginListener) method for more information.

Parameters:
listener - a listener to be registered for plugin events.

accept

public boolean accept(java.io.File dir,
                      java.lang.String name)
Specified by:
accept in interface java.io.FilenameFilter

discoverJavaTestScripts

public static void discoverJavaTestScripts(java.io.File f)
                                    throws java.io.IOException,
                                           java.lang.ClassNotFoundException,
                                           java.lang.IllegalAccessException
Load Java test scripts contained in the argument file (class path, JAR or ZIP file). This makes the test scripts visible to the Robot scripting framework.

Parameters:
f - a class path, JAR or ZIP file to search for Java test scripts.
Throws:
java.io.IOException
java.lang.ClassNotFoundException
java.lang.IllegalAccessException

T-Plan Robot Enterprise 5.0.1
Build No. 5.0.1-20190308.1