Notifiers

Configuration notifiers provide a mechanism to perform application specific configuration auditing and to associate application behavior with configuration state changes.

Configuration notifiers are defined by extending com.kabira.platform.switchconfig.ConfigurationListener. Creating an instance of a user defined configuration notifier implicitly registers the notifier to be called by the configuration framework. Configuration notifiers can be created as part of application initialization and deleted as part of application termination. Another mechanism to install and remove configuration notifiers is to use TIBCO ActiveSpaces® Transactions component notifiers. See the section called “Notifiers” for details.

There are two different kinds of methods in a configuration notifier:

Audit methods are always called before its associated state change method (except for load where they are called after the load method). If a method throws the com.kabira.platform.switchconfig.ConfigurationException it is an audit method. An audit method reports an audit failure by throwing a com.kabira.platform.switchconfig.ConfigurationException exception. An audit failure prevents the requested configuration state change from occurring. Audit methods should not change the application state in any way.

A state change method cannot fail. It is only called if its associated audit method did not report an error. Any application state changes triggered by the configuration state change should be implemented in state methods.

The loaded state change method provides a mechanism to manually add additional configuration objects to the ones loaded from an external file. To add additional configuration objects, the implementation of the loaded method should create configuration instances and return them to the framework in the additions parameter.

Here is an example of a configuration notifier.

Example 9.9. Configuration notifier

//     $Revision: 1.1.2.1 $
package com.kabira.snippets.configuring;

import com.kabira.platform.switchconfig.Config;
import com.kabira.platform.switchconfig.ConfigurationException;
import com.kabira.platform.switchconfig.ConfigurationListener;
import com.kabira.platform.switchconfig.Version;

/**
 * Configuration notifier
 */
public class UserNotifier extends ConfigurationListener
{

    public UserNotifier()
    {
        super( User.class.getPackage().getName());
    }

    @Override
    public void loaded(
        Version version, java.util.List<Config> additions)
    {
        System.out.println("Loading type: "
            + version.groupKindId
            + " name: "
            + version.groupId
            + " version: "
            + version.versionId);
    }

    @Override
    public void auditLoad(Version version) throws ConfigurationException
    {        
        System.out.println("Auditing load for type: "
            + version.groupKindId
            + " name: "
            + version.groupId
            + " version: "
            + version.versionId);
    }
    
    @Override
    public void auditActivate(Version version) throws ConfigurationException
    {
        System.out.println("Auditing activation for type: "
            + version.groupKindId
            + " name: "
            + version.groupId
            + " version: "
            + version.versionId);
    }

    @Override
    public void activated(Version version)
    {
        System.out.println("Activating type: "
            + version.groupKindId
            + " name: "
            + version.groupId
            + " version: "
            + version.versionId);
    }

    @Override
    public void auditReplace(
        Version deactivating,
        Version activating) throws ConfigurationException
    {
        System.out.println("Auditing replace (deactivation) of type: "
            + deactivating.groupKindId
            + " name: "
            + deactivating.groupId
            + " version: "
            + deactivating.versionId);

        System.out.println("Auditing replace (activation) of type: "
            + activating.groupKindId
            + " name: "
            + activating.groupId
            + " version: "
            + activating.versionId);
    }

    @Override
    public void replaced(Version deactivating, Version activating)
    {
        System.out.println("Replacing (deactivation) type: "
            + deactivating.groupKindId
            + " name: "
            + deactivating.groupId
            + " version: "
            + deactivating.versionId);

        System.out.println("Replacing (activation) type: "
            + activating.groupKindId
            + " name: "
            + activating.groupId
            + " version: "
            + activating.versionId);
    }
    
    @Override
    public void auditDeactivate(Version version) throws ConfigurationException
    {
        System.out.println("Auditing deactivation of type: "
            + version.groupKindId
            + " name: "
            + version.groupId
            + " version: "
            + version.versionId);
    }

    @Override
    public void deactivated(Version version)
    {
        System.out.println("Deactivating type: "
            + version.groupKindId
            + " name: "
            + version.groupId
            + " version: "
            + version.versionId);
    }

    @Override
    public void auditRemove(Version version) throws ConfigurationException
    {
        System.out.println("Auditing removal of type: "
            + version.groupKindId
            + " name: "
            + version.groupId
            + " version: "
            + version.versionId);
    }

    @Override
    public void removed(Version version)
    {
        System.out.println("Removing type: "
            + version.groupKindId
            + " name: "
            + version.groupId
            + " version: "
            + version.versionId);
    }
}


Configuration notifiers are installed by creating an instance. They are removed by deleting the instance.

Example 9.10, “Notifier initialization and termination” contains a complete example of initializing and terminating a configuration notifier. See Example 9.9, “Configuration notifier” for the notifier that is being installed.

Example 9.10. Notifier initialization and termination

//     $Revision: 1.1.2.1 $
package com.kabira.snippets.configuring;

import com.kabira.platform.ManagedObject;
import com.kabira.platform.Transaction;
import com.kabira.test.management.Client;
import com.kabira.test.management.CommandFailed;
import java.net.URL;

/**
 * Snippet to install and terminate configuration notifiers
 *
 * NOTE: This snippet requires the classpath to include the
 * directory where the configuration files are located.  This
 * allows the get resource call to locate the configuration files
 *
 * <p>
 * <h2> Target Nodes</h2>
 * <ul>
 * <li> <b>domainnode</b> = A
 * </ul>
 */
public class NotifierLifeCycle
{
    /**
     * Initialize the configuration notifier
     */
    public void initialize()
    {
        new Transaction("Initialize Configuration Notifier")
        {
            @Override
            protected void run() throws Rollback
            {
                m_userNotifier = new UserNotifier();
            }
        }.execute();
    }

    /**
     * Terminate the configuration notifier
     */
    public void terminate()
    {
        new Transaction("Terminate Configuration Notifier")
        {
            @Override
            protected void run() throws Rollback
            {
                //
                //  Delete the configuration notifier
                //
                ManagedObject.delete(m_userNotifier);
                m_userNotifier = null;
            }
        }.execute();
    }

    /**
     * Execute snippet
     * 
     * @param args              Not used
     * @throws CommandFailed    Configuration command failed
     * @throws ClassNotFoundException   Configuration class not found
     */
    public static void main(String[] args) throws CommandFailed, ClassNotFoundException
    {
        Client client = new Client("guest", "guest");

        URL url1 = client.getClass().getClassLoader().getResource("user1.kcs");
        URL url2 = client.getClass().getClassLoader().getResource("user2.kcs");

        if ((url1 == null) || (url2 == null))
        {
            throw new Error(
                "Configuration files not located - are they installed into "
                + "current class path?");
        }

        Client.Configuration version1 = client.new Configuration(url1);
        Client.Configuration version2 = client.new Configuration(url2);

        //
        //  Install configuration notifiers
        //
        NotifierLifeCycle   notifierLifeCycle = new NotifierLifeCycle();
        notifierLifeCycle.initialize();
        
        //
        //  Resolve configuration classes
        //
        Class.forName("com.kabira.snippets.configuring.User");

        //
        //  Load configuration files
        //
        version1.load();
        version2.load();

        //
        //  Activate version 1
        //
        version1.activate();

        //
        //  Activate version 2 - causes replace notifier to be called
        //
        version2.activate();


        //
        //  Deactive version 2
        //
        version2.deactivate();

        //
        //  Remove configurations
        //
        version1.remove();
        version2.remove();

        //
        //  Remove configuration notifiers
        //
        notifierLifeCycle.terminate();

    }
    private UserNotifier m_userNotifier;
}

When Example 9.10, “Notifier initialization and termination” is run it outputs the following (annotation added):

#
#    Load and audit version 1.0
#
[A] Loading type: com.kabira.snippets.configuring name: user version: 1.0
[A] Auditing load for type: com.kabira.snippets.configuring name: user version: 1.0

#
#     Load and audit version 2.0
#
[A] Loading type: com.kabira.snippets.configuring name: user version: 2.0
[A] Auditing load for type: com.kabira.snippets.configuring name: user version: 2.0

#
#    Audit activation, and activate version 1.0
#
[A] Auditing activation for type: com.kabira.snippets.configuring name: user version: 1.0
[A] Activating type: com.kabira.snippets.configuring name: user version: 1.0

#
#    Audit replace, and then replace version 1.0 with version 2.0
#
[A] Auditing replace (deactivation) of type: com.kabira.snippets.configuring name: user version: 1.0
[A] Auditing replace (activation) of type: com.kabira.snippets.configuring name: user version: 2.0
[A] Replacing (deactivation) type: com.kabira.snippets.configuring name: user version: 1.0
[A] Replacing (activation) type: com.kabira.snippets.configuring name: user version: 2.0

#
#     Audit deactivation, and then deactivate version 2.0
#
[A] Auditing deactivation of type: com.kabira.snippets.configuring name: user version: 2.0
[A] Deactivating type: com.kabira.snippets.configuring name: user version: 2.0

#
#    Audit removal, and then remove, version 1.0
#
[A] Auditing removal of type: com.kabira.snippets.configuring name: user version: 1.0
[A] Removing type: com.kabira.snippets.configuring name: user version: 1.0

#
#    Audit removal, and then remove, version 2.0
#
[A] Auditing removal of type: com.kabira.snippets.configuring name: user version: 2.0
[A] Removing type: com.kabira.snippets.configuring name: user version: 2.0