Class PluginRegistry

  • All Implemented Interfaces:
    ConfMgrRegistry, ADEPT2Service, AuthenticatingService, LogService, NameResolution, ServiceThreadHandling
    Direct Known Subclasses:
    InstanceToInstanceRegistry

    @ConfigurationDescription(properties={@Property(name="Instances.<ComponentTypeName>",documentationOnly=true,description="The PluginRegistry extends the semantic of the comma-separated list as follows:\nThe first declared instance is the default instacne of the corresponding component type.\nIf the list is empty, an implicit (default) instance will exist having the same name as the component type, e. g. \"C.C\". This is called the anonymous instance.\nOne element of the list but not the first one can be \"*\". This enablesdynamic and runtime instances for this component type. Dynamic plugins are declared by separate configuration files being somewhere in the classpath ofthis PluginRegistry. The name of the configuration files are the name of the corresponding component/plugin type. The configurations contain the same information as a plugin configuration read by this PluginRegistry. "),,,},validator=ConfigurationValidator.class)
    public abstract class PluginRegistry
    extends AbstractRegistry
    While the AbstractRegistry does not allow to be directly accessed, this class supports the retrieval of specific component instances as well as default component instances. For this the component instance using a plugin declares a component type as plugin type. At runtime it may request the default instance or a specific instance of the plugin type. For instance, a worklist manager is declared as follows:
    • Components.WorklistManager = de.aristaflow.adept2.core.worklistmanager.WorklistManager
    • Instances.WorklistManager = WL1, WL2
    • WL1.PluginTypes = DelegationHandling
    • WL2.PluginTypes = EscalationHandling
    This tells this PluginRegistry that the used implementation for the worklist manager instance WL1 may use instances for the handling of delegation, while WL2 is able to use external escalation handling. The corresponding types have to be declared explicitly:
    • Components.DelegationHandling = de.aristaflow.adept2.core.worklistmanager.DelegationHandling
    • Instances.DelegationHandling = DH1, DH2, DH3
    • Components.EscalationHandling = de.aristaflow.adept2.core.worklistmanager.EscalationHandling
    At runtime the component instance WL1 may request a component instance for delegation handling. The name of the component instance may be arbitrary, for instance, it is retrieved from a worklist item which requires special delegation handling.
    The corresponding plugin instance is just instantiated by the registry. The constructor is provided a configuration for the plugin and the instance of the component which declares the plugin type. In the example above, the implementation class for the DelegationHandling needs a public constructor with org.apache.commons.configuration2.Configuration and the implementation class (or an appropriate superclass or interface) of WL1. Accordingly, EscalationHandling needs Configuration and the implementation class (or an appropriate superclass or interface) for WL2 in the public constructor. All communication between plugins and the using components, for instance initialisation and shutting down of used plugins, is under the responsibility of the using components.

    To simplify the configuration of usage relations, every component type has a default instance. This is either the first declared instance from the configuration file (Instances.<ComponentType>) or the anonymous instance in case no instance is declared at all. In the example, WL1, DH1 and the anonymous instance EscalationHandling are default instances. This allows a component to retrieve a plugin without knowing its name: If a worklist item has no specific delegation handling defined, it asks for the default instance and retrieves DH1.
    The plugin type can be configured for all instances of the using type by configuring it: WorklistManager.PluginTypes = EscalationHandling . This configuration is used, in case no specific plugin type for the using instance is found.

    If a plugin is declared as singleton, the singleton behaviour will be relative to the using instance. That is, a using instance will always get the very same plugin instance. However, a new plugin instance will be created if a different using instance requests a plugin instance with the same type and the same name.

    Besides the pre-configured plugin instances, plugin instances can also be retrieved dynamically or at runtime. This is enabled by declaring the special instance "*" as instance. This instance must not be default instance, that is, it must not be the first in the list of instances.

    • Components.DelegationHandling = de.aristaflow.adept2.core.worklistmanager.DelegationHandling
    • Instances.DelegationHandling = DH1, DH2, DH3, *
    • DelegationHandling.PluginClassPath = ${arflow:arflow.libdir}/plugins
    This is treated in two ways by the plugin registry. When initialising the registry, it looks for configuration files having the name of a declared plugin type via its classloader (plugin type name prepended by ".properties" (ConfigurationConstants.CONFIG_FILE_EXTENSION )). All found configurations are parsed for declarations of plugin instance implementations (plugin instance name prepended by ".Implementation" ( ConfigurationConstants.PROPERTY_REGISTRY_IMPLEMENTATION)). All corresponding entries in the configuration file will be considered as declared plugin instances. This configuration file will also be used as configuration for the plugin instances it declares.

    Additionally, the plugin registry allows for plugin instances determined at runtime. If a plugin instance is requested at runtime but neither declared statically nor found dynamically when initialising the registry and its type has a plugin classpath ("PluginClassPath", ConfigurationConstants.PROPERTY_REGISTRY_CLASSPATH), this classpath will be searched for the requested plugin instance. This can be a normal classpath, for instance jar-files, directories or arbitrary URLs (as long as the corresponding protocol handler is installed). This classpath needs to contain an entry with the name of the requested plugin. This can either be a jar-file, a file, a subdirectory (containing several libraries), or a configuration file having the plugin instance name prepended by ".properties" (ConfigurationConstants.CONFIG_FILE_EXTENSION ).
    Depending on the found data, the (separate) classpath for the plugin instance will be created. In case of a jar-file as base classpath entry, a directory with the name of the requested plugin instance will be added to the plugin instance classpath. In case of a file as base classpath entry it is first checked whether this file or directory exists. If this is a file, it will be added directly to the plugin instance classpath. If this is a directory, a jar-file with the name of the plugin instance is appended. If this file exists, it will be added to the plugin instance classpath. Afterwards a directory having the name of the plugin instance is appended. If this exists, it is added to the plugin instance classpath as well as all its direct subdirectories and its jar-files (not transitively). All base classpaths with other URL-protocols are added to the plugin instance classpath without modification. This results in the implicit classpath for the plugin instance.
    If the plugin type classpath contains a plugin instance (meta) configuration file, this can contain an explicit classpath for a plugin instance as well as the other information necessary to find the plugin instance. This includes the implementation class, the instantiation mode and the explicit classpath ( ConfigurationConstants.PROPERTY_REGISTRY_CLASSPATH) of the plugin instance.

    A runtime plugin needs to have/may have its own configuration file in its classpath (which is the extended plugin type classpath, see above). The configuration has to be a PropertiesConfiguration. In case of an implicit classpath this file has to exist somewhere in the plugin instance classpath and it has to have the name of the plugin type prepended by ".properties" (ConfigurationConstants.CONFIG_FILE_EXTENSION ), for instance "ActivityTypeCheck.properties". It must provide at least the implementation class of the plugin instance. Optionally it may have an instantiation mode. Both of these configuration entries need to be prefixed with the plugin instance name!
    In case of an explicit classpath there needs to be a PropertiesConfiguration in the plugin type classpath providing at least the implementation class, the explicit classpath and optionally the instantiation mode. They also have to be prefixed with the plugin instance name! This (meta) configuration needs to have the name of the plugin instance prepended by ".properties", for instance "pluginName.properties".
    With implicit classpaths there may be arbitrary additional entries in the one configuration file; the whole configuration will be provided to the plugin instance in its constructor (see above). With explicit classpaths there may be an additional PropertiesConfiguration besides the meta configuration named by the corresponding plugin type, for instance "ActivityTypeCheck.properties" in the explicitly set plugin instance classpath. This configuration may provide arbitrary additional entries. With explicit classpaths only this configuration will be provided in the constructor (excluding the meta configuration values). It will be empty if the configuration file is not in the classpath of the plugin instance.

    • Mandatory example configuration file "PluginType.properties" with implicit classpath somewhere in the extended classpath of the plugin instance (applies to dynamic as well as runtime plugins):
       DelegationHandling4.Implementation = de.aristaflow.adept2.ext.MyDelegationHandling
       # Singleton-behaviour; this need not be set explicitly
       DelegationHandling4.InstantiationMode = Singleton
       # Arbitrary configuration values for DelegationHandling4
       Database = jdbc: ...
       DelegateTo = Agent(id=4711)
       
    • Same example for explicit classpath
      • Mandatory configuration file "de.aristaflow.adept2.ext.MyDelegationHandling.properties" in the plugin type classpath (here: ${arflow:arflow.libdir}/plugins):
         DelegationHandling4.Implementation = de.aristaflow.adept2.ext.MyDelegationHandling
         DelegationHandling4.ClassPath = ${arflow:arflow.libdir}/../MyDelegationHandling
         # Singleton-behaviour; this need not be set explicitly
         DelegationHandling4.InstantiationMode = Singleton
         
      • Optional configuration file "${arflow:arflow.libdir}/../MyDelegationHandling /PluginType.properties" in the plugin instance classpath:
         # Arbitrary configuration values for DelegationHandling4
         Database = jdbc: ...
         DelegateTo = Agent(id=4711)
         

    This class parses the following properties from the registry configuration - besides the properties parsed by super classes:

    And the following property besides the properties parsed by super classes from plugin type configurations:
    • Field Detail

      • defaultInstances

        protected Map<String,​String> defaultInstances
        The default instance per component type. The default instance of a component is the first declared instance. If no instance has been declared, it is the instance /ComponentType/ComponentType.

        Maps from the component type to the hierarchical name of the default instance.

      • declaredPluginTypes

        protected Map<String,​Set<String>> declaredPluginTypes
        The declared plugin types. It maps (hierarchical) instanceName to pluginTypes.
      • pluginInstances

        protected Map<String,​Collection<String>> pluginInstances
        Map from plugin type, to the set of configured plugin instances (simple names). This includes dynamic plugins but does not consider runtime plugins.
      • dynamicPlugins

        protected Map<String,​org.apache.commons.configuration2.Configuration> dynamicPlugins
        Map from hierarchical plugin instance name to the corresponding plugin instance configuration.
      • runtimePluginTypeCLs

        protected Map<String,​URLClassLoader> runtimePluginTypeCLs
        Map from plugin types having declared runtime loading (one plugin instance is named "*") to the class loaders having the classpath set to the declared plugin path for loading runtime plugins.
      • runtimePlugins

        protected Map<String,​Pair<URLClassLoader,​org.apache.commons.configuration2.Configuration>> runtimePlugins
        Map from hierarchical plugin instance names to the classloader and the configuration of the plugin instance.
      • singletonPlugins

        protected Map<String,​Map<String,​Object>> singletonPlugins
        All plugins are singletons relative to the using/requesting component. So we store all plugin instances for the respective using component. This mapping is (hierarchical) name of using component instance -> (hierarchical) name of plugin instance -> plugin instance.
    • Constructor Detail

      • PluginRegistry

        protected PluginRegistry​(UrlConfigurationManager confMgr,
                                 org.apache.commons.configuration2.Configuration configuration,
                                 Registry registry)
                          throws ConfigurationException
        Constructs a new registry supporting plugins, that is components extending an existing component. It calls the constructor of AbstractRegistry which sets the registry configuration and the configuration manager.
        Parameters:
        confMgr - The initial configuration manager that provides configurations for the loaded component instances.
        configuration - The configuration of the created registry instance.
        registry - The parent registry of this registry.
        Throws:
        ConfigurationException - If the password cannot be parsed from the configuration, a ConfigurationException will be thrown.
    • Method Detail

      • shutdown

        public void shutdown​(boolean emergency)
        Signals the shutdown of this registry. No access except the privileged threads may access this registry afterwards.

        This method has to be called at an arbitrary time in the shutdown-procedure of overriding classes. Closes all corresponding class loaders in case of a non-emergency shutdown.

        Specified by:
        shutdown in interface ADEPT2Service
        Overrides:
        shutdown in class AbstractRegistry
        Parameters:
        emergency - Whether the shutdown will be an emergency shutdown.
      • renewConfiguration

        protected void renewConfiguration​(org.apache.commons.configuration2.Configuration conf)
                                   throws ConfigurationException
        Renews the configuration of this registry by renewing via the superclass and reading of default instances as well as declared plugin types.
        Overrides:
        renewConfiguration in class AbstractRegistry
        Parameters:
        conf - The (new) root configuration for this registry.
        Throws:
        ConfigurationException - If a plugin type is declared but the type is not known by this registry, a ConfigurationException will be thrown.
      • readMetaConfiguration

        protected void readMetaConfiguration​(org.apache.commons.configuration2.Configuration registryConfiguration,
                                             String componentType)
                                      throws ConfigurationException
        Description copied from class: AbstractRegistry
        Reads the available meta-configuration for components loaded at runtime. This meta-configuration is usually restricted to a classpath where the components and their configuration can be found at runtime. The necessary checks normally done in AbstractRegistry.readMetaConfiguration(Configuration, String, String) has to be done when loading the corresponding components.
        This method is called in the initialisation and may therefore not rely on a fully initialised registry.
        Specified by:
        readMetaConfiguration in class AbstractRegistry
        Parameters:
        registryConfiguration - The configuration which contains the (registry) information for runtime instances of the designated component type.
        componentType - The type of the component to retrieve the meta-configuration.
        Throws:
        ConfigurationException - If some of the required information is missing, for instance, the classpath for loading the components at runtime is not specified, a ConfigurationException will be thrown.
      • getConfiguredPluginTypes

        protected Map<String,​Class<?>> getConfiguredPluginTypes​(SessionToken session,
                                                                      String usingInstanceName)
        Retrieves all plugin types declared for the designated using instance.
        If the component type of a declared plugin type cannot be retrieved, this will be logged and the plugin type will be ignored.
        Parameters:
        session - The session which is used to check for access rights on this method.
        usingInstanceName - The hierarchical name of the using component instance. This may neither be null nor the empty.
        Returns:
        All plugin types (names and corresponding classes) declared for the designated instance. This may be empty.
      • getConfiguredPlugin

        protected <T> T getConfiguredPlugin​(SessionToken session,
                                            String usingInstanceName,
                                            Object usingInstance,
                                            String pluginTypeName,
                                            Class<T> componentType,
                                            String pluginInstanceName)
                                     throws ConfigurationException
        Retrieves the plugin with the designated name of the designated type if it is declared by the using instance or if it is declared and found as runtime plugin. A new plugin instance will be created if the instance is not singleton or it has not been instantiated before.
        Type Parameters:
        T - The type which the used object is expected to be of.
        Parameters:
        session - The session which is used to check for access rights on this method.
        usingInstanceName - The hierarchical name of the using component instance. This may neither be null nor the empty.
        usingInstance - The using component instance which is provided in the constructor of the requested plugin to allow for data exchange.
        pluginTypeName - The component type of the plugin instance to be retrieved for usage. This may neither be null nor the empty string.
        componentType - The type which the used object is expected to be of.
        pluginInstanceName - The simple (!) name of the plugin instance to retrieve.
        Returns:
        The instance with the designated name of designated plugin type for which the designated parameters are used when the instance needs to be instantiated.
        Throws:
        InvalidServiceStateException - If this registry failed to start or is shut down, an InvalidServiceStateException will be thrown.
        ConfigurationException - If
        • the requested plugin type is not declared for the designated instance or its type,
        • the requested plugin instance name is not declared in the corresponding component type configuration (AbstractRegistry.getInstanceInformation(String))
        • no component interface is registered/configured for the designated plugin type (AbstractRegistry.componentInterfaces),
        • the designated using instance is not declared in the corresponding component type configuration (AbstractRegistry.getInstanceInformation(String)),
        • the configuration of the requested plugin instance does not provide required configuration values,
        • the creation or the initialisation of the plugin instance fails,
        a ConfigurationException will be thrown.
      • getConfiguredPlugin

        protected <T> T getConfiguredPlugin​(SessionToken session,
                                            String usingInstanceName,
                                            Object usingInstance,
                                            String pluginTypeName,
                                            Class<T> componentType)
                                     throws ConfigurationException
        Retrieves the default instance of the designated plugin type. A new plugin instance will be created if the instance is not singleton or it has not been instantiated before.
        Type Parameters:
        T - The type which the used object is expected to be of.
        Parameters:
        session - The session which is used to check for access rights on this method.
        usingInstanceName - The hierarchical name of the using component instance. This may neither be null nor the empty string.
        usingInstance - The using component instance which is provided in the constructor of the requested plugin to allow for data exchange.
        pluginTypeName - The component type of the plugin instance to be retrieved for usage. This may neither be null nor the empty string.
        componentType - The type which the used object is expected to be of. retrieve.
        Returns:
        The instance with the designated name of designated plugin type.
        Throws:
        InvalidServiceStateException - If this registry failed to start or is shut down, an InvalidServiceStateException will be thrown.
        ConfigurationException - If
        • the requested plugin type is not declared for the designated instance or its type,
        • no default instance is declared for the requested plugin type,
        • no component interface is registered/configured for the designated plugin type (AbstractRegistry.componentInterfaces),
        • the designated using instance is not declared in the corresponding component type configuration (AbstractRegistry.getInstanceInformation(String)),
        • the configuration of the requested plugin instance does not provide required configuration values,
        • the creation or the initialisation of the plugin instance fails,
        a ConfigurationException will be thrown.
      • getConfiguredPlugins

        protected <T> Map<String,​T> getConfiguredPlugins​(SessionToken session,
                                                               String usingInstanceName,
                                                               Object usingInstance,
                                                               String pluginTypeName,
                                                               Class<T> componentType)
                                                        throws ConfigurationException
        Retrieves all plugin instances (pre-configured and dynamic) of the designated plugin type. A new plugin instance will be created if an instance is not singleton or it has not been instantiated before.
        Type Parameters:
        T - The plugin type of the requested instances.
        Parameters:
        session - The session which is used to check for access rights on this method.
        usingInstanceName - The hierarchical name of the using component instance. This may neither be null nor the empty.
        usingInstance - The instance which is using the plugins and which is provided to the plugins when creating them. This allows the plugins to access the instance they extend.
        pluginTypeName - The component type of the plugin instance to be retrieved for usage. This may neither be null nor the empty string. The type name is specified in the configuration.
        componentType - The type of the requested plugin.
        Returns:
        The requested plugin instances, mapped to their instance id. This map may be empty.
        Throws:
        InvalidServiceStateException - If this registry failed to start or is shut down, an InvalidServiceStateException will be thrown.
        ConfigurationException - If
        • the requested plugin type is not declared for the designated instance or its type,
        • no component interface is registered/configured for the designated plugin type (AbstractRegistry.componentInterfaces),
        • the designated using instance is not declared in the corresponding component type configuration ( AbstractRegistry.getInstanceInformation(String)),
        • the configuration of a plugin instance does not provide required configuration values,
        • the creation or the initialisation of a plugin instance fails,
        a ConfigurationException will be thrown.
      • getConfiguredPlugin

        protected <T> T getConfiguredPlugin​(SessionToken session,
                                            String usingInstanceName,
                                            Object usingInstance,
                                            String pluginTypeName,
                                            Class<T> componentType,
                                            String pluginInstanceName,
                                            Class<?>[] additionalParameterTypes,
                                            Object[] additionalParameterValues)
                                     throws ConfigurationException
        Retrieves the plugin with the designated name of the designated type if it is declared by the using instance or if it is declared and found as runtime plugin. A new plugin instance will be created if the instance is not singleton or it has not been instantiated before. If it is declared as singleton, the singleton behaviour will be relative to the using instance. Therefore if the using instance (name) has not requested the plugin before, it will be instantiated (again).
        When instantiating the constructor with the designated additional parameter types (besides Configuration and the class/interface of the using instance) will be called providing the designated additional parameter values (besides its configuration and the using instance).
        Type Parameters:
        T - The type which the used object is expected to be of.
        Parameters:
        session - The session which is used to check for access rights on this method.
        usingInstanceName - The hierarchical name of the using component instance. This may neither be null nor the empty.
        usingInstance - The using component instance which is provided in the constructor of the requested plugin to allow for data exchange.
        pluginTypeName - The component type of the plugin instance to be retrieved for usage. This may neither be null nor the empty string.
        componentType - The type which the used object is expected to be of.
        pluginInstanceName - The simple (!) name of the plugin instance to retrieve.
        additionalParameterTypes - Additional parameter types (besides Configuration and the class/interface of the using instance) of the constructor to be used for instantiation. If no additional parameter is to be used, an empty array will need to be provided. This has to correspond to additionalParameterValues.
        additionalParameterValues - Additional parameter (besides the configuration and the using instance) of the constructor to be used for instantiation. If no additional parameter is to be used, an empty array will need to be provided. This has to correspond to additionalParameterTypes.
        Returns:
        The instance with the designated name of designated plugin type for which the designated parameters are used when the instance needs to be instantiated.
        Throws:
        InvalidServiceStateException - If this registry failed to start or is shut down, an InvalidServiceStateException will be thrown.
        ConfigurationException - If a ConfigurationException will be thrown.
      • prepareRuntimePlugin

        protected void prepareRuntimePlugin​(String typeName,
                                            String instanceName)
                                     throws ConfigurationException
        Prepares the designated runtime plugin, that is, the meta configuration providing the implementation class and an optional classpath is loaded, the instance information is set appropriately, the classloader for the plugin instance is created and the normal configuration is loaded.
        Parameters:
        typeName - The component type of the plugin instance to be retrieved for usage. This may neither be null nor the empty string.
        instanceName - The simple (!) name of the plugin instance to retrieve.
        Throws:
        ConfigurationException - If
        • no meta configuration can be found in the plugin type classpath or the plugin instance classpath,
        • the meta configuration cannot be loaded, for instance due to an invalid format,
        • the meta configuration does not provide the required or inconsistent information,
        • the configuration cannot be loaded, for instance due to an invalid format,
        a ConfigurationException will be thrown.
      • createPluginLoader

        protected URLClassLoader createPluginLoader​(String pluginInstanceName,
                                                    URL[] classpaths)
        Creates a new classloader for the designated plugin instance having the appropriate classpaths. The classpaths are the ones declared for the plugin type prepended by the plugin instance name in case of jar- and file-protocols for a classpath. A file protocol will have the plugin instance name as sub-directory (if it exists) including all existing direct sub-directories and jar-files, as well as the instance name prepended to the plugin type classpath as jar-file.

        For instance, instName and [file:/C:/Program%20Files/Java/jre1.5.0_07/lib/, jar:file:/var/lib/security/local_policy.jar!/, http://aristaflow.de/adept2.jar] is converted to

        • file:/C:/Program%20Files/Java/jre1.5.0_07/lib/instName/
        • all direct subdirectories of and jar-files in C:/Program%20Files/Java/jre1.5.0_07/lib/instName/
        • file:/C:/Program%20Files/Java/jre1.5.0_07/lib/instName.jar
        • jar:file://localhost/var/lib/security/local_policy.jar!/instName/
        • http://aristaflow.de/adept2.jar
        If a constructed classpath is no valid URL, the corresponding classpath will be ignored.
        Parameters:
        pluginInstanceName - The simple name of the requested plugin. This name will be appended to the jar and file classpaths as directory and as name of a jar file if appropriate.
        classpaths - The classpaths that are declared for the corresponding plugin type of the designated plugin instance. This may be null.
        Returns:
        The created classloader for the designated plugin instance having the classpath set appropriately as specified above.