Listeners and Listener Notifications

Overview

Listeners and listener notifications work together to create a much more powerful model than polling notifications in detecting and processing events in the adapter resource.

When the user of the adapter enables the polling notification node, the following events occur:
  • Integration Server instantiates and initializes a polling notification object with settings from the node.
  • Integration Server then invokes the polling notification object by calling its runNotification method on a periodic basis.
  • The polling notification object must retrieve a connection and use it to determine if publishable events have occurred in the adapter resource.
  • If an event has occurred, the polling notification object must generate a WmRecord object conforming to the output signature of the polling notification node, and publish it by calling the doNotify method.
  • The polling notification object then goes to sleep until the next time it is invoked.
  • If the overlap option is enabled in the notification schedule, a second object may be instantiated while the previous instance is still processing events detected in a previous invocation. The second instance retrieves another connection, and interrogates the resource again. This model can make state management significantly more difficult.
When the user of the adapter uses a listener notification, the responsibility of monitoring the adapter resource and processing any events is divided between a listener and its notification(s).
  • A listener object is instantiated and is given a connection when the user of the adapter enables the associated node.
  • The listener object remains active with the same connection to monitor the resource activity until it is disabled either explicitly or by disabling the containing package, the adapter, the connection, or Integration Server.
  • When the listener detects a publishable event in the resource, it passes an object back to Integration Server.
  • Integration Server interrogates a configured list of listener notifications associated with the listener node until it finds a listener notification node that can process the event. Integration Server accomplishes this by calling the listener notification's supports method. The first notification to return true from this call is invoked using its runNotification method. This behavior is similar to the polling notification where any data about the event that was provided by the listener is passed as an argument to the runNotification method.

Synchronous and Asynchronous Listener Notifications

The ADK includes both, synchronous and asynchronous processing model.

An asynchronous listener notification publishes a document to a configured IBM webMethods Broker, using the doNotify method.
  • An asynchronous listener notification publishes a document.
  • The notification object's runNotification method calls doNotify method.
  • The users of the adapter may process the document's data as needed. For example, the users of the adapter can create an Integration Server trigger that receives the document and executes an Integration Server flow service or a Java service.
  • Asynchronous listener notifications do not support session handling. When a synchronous listener notification calls an Integration Server service that needs that needs information contained in the session data, it may appear to work because asynchronous listener notifications themselves do not execute a service. Instead, an Integration Server trigger, which supports session handling, is used to receive the document and execute an Integration Server flow service or a Java service.
A synchronous listener notification invokes a specified Integration Server service, and potentially receives a reply from the service and delivers the results back to the adapter resource.
  • A synchronous listener notification does not publish a document.
  • The notification object's runNotification method calls invokeService.
  • The users of the adapter cannot process the document's data as the processing is done in the invokeService method.
  • Synchronous listener notifications do not support session handling. When a synchronous listener notification calls an Integration Server service that needs information contained in the session data, that service can fail.

Implementing Listeners and Listener Notifications

The implementation of a listener and listener notification is similar to the implementation of an adapter connection. Each implementation includes a Java class extending an ADK base class, and a namespace node in which design-time configuration data is stored. In the Java class, the metadata model for listeners and listener notification is nearly identical to that of adapter connections. The configuration pages are built from the listeners metadata. For more information, see Metadata Model for Connection

Listener Classes

The following figure shows the classes provided by the ADK to support listener notifications. It also shows the com.wm.adk.notification.WmConnectedListener implementation class SimpleListener.

Create a listener class by extending com.wm.adk.notification.WmConnectedListener base class. You must override the following base class methods in your WmConnectedListener implementation class:

Method Description
fillWmDescriptor Controls how metadata parameters are displayed, and defines rules for data entry for the listener's metadata parameters. From the standpoint of the adapter implementation, the model is identical to the connection model.
listenerStartup Initializes the listener. This method is called during the listener startup sequence as well as during the recovery procedure after an AdapterConnectionException is encountered.
waitForData Monitors the adapter resource. This method returns data that is analyzed by the support method of associated listener notifications. For more details, see Listener and Listener Notification Interactions.
listenerShutdown Cleans up listener resources. This method is called during the listener shutdown sequence.
Note: You may optionally override the processNotificationResults method to allow the listener implementation class to post-process listener notification results. For an example of using both methods, see Implementing Listener Methods.

In addition, the implementation class may override the following optional methods:

Method Description
restrictNotificationTypes Allows the listener implementation class to restrict the notification classes it supports by explicitly identifying them. For more information, see Restricting Listeners to Register Specified Notification Templates.
shutdownCallBack Invoked on a thread separate from the listener's thread, this method allows the listener's waitForData loop to be gracefully interrupted prior to a normal shutdown.

Asynchronous Listener Notification Classes

The following figure shows the classes provided by the ADK to support asynchronous listener notifications.

Create an asynchronous listener notification class by extending the base class com.wm.adk.notification.WmAsyncListenerNotification, as shown by the SessionLogListenerNotification class in the figure. As previously mentioned, the implementation of an asynchronous listener notification is similar to a polling notification. The key differences occur in the following methods:

Method Description
supports Determines whether the notification can process the object returned by the listener's waitForData method.
boolean supports(Object)
runNotification If the supports method returns true, the Integration Server calls the following runNotification method to process the data.
NotificationResults runNotification(NotificationEvent)
The implementation of this method must
  • Call one of the WmAsynchronousNotification.doNotify methods for each notification it wants to generate, based on the NotificationEvent data content.
  • Never return null.
Note: The NotificationEvent simply wraps the data object returned from the listener's waitForData method.

For more information about alternative method of managing resource domains, see to-appx_alt_approaches_metadata.html#A52135.

Synchronous Listener Notification Classes

The following figure shows the classes provided by the ADK to support synchronous listener notifications.

Create a synchronous listener notification class by extending com.wm.adk.notification.WmSyncListenerNotification base class. The examples in this section do not implement a synchronous notification, so the figure in this section only shows a placeholder class. A synchronous notification calls the WmSynchronousNotification.invokeService method, passing it a WmRecord object containing data consistent with the output signature of the notification node.

Synchronous listener notifications are expected to define both an input and output signature. The terms input and output are relative to the notification. The output signature specifies the format of the data that the notification places on the pipeline prior to invoking the service associated with the synchronous notification. The input signature describes the data that the notification expects to find on the pipeline after the invoked service has completed processing.

The service invoked by WmSynchronousNotification.invokeService method is specified at design time in the notification node data. When this service is invoked, it executes on a separate thread (and therefore in a different transactional context) from the listener. When the invoked service completes, Integration Server extracts the data on the pipeline that is identified in the notification node's input signature and delivers that data as a WmRecord wrapped in the SyncNotificationResults object returned by invokeService method.

Listener and Listener Notification Interactions

The design time interactions for listeners and listener notifications are essentially the same as the interactions for connections and polling notifications, as described in Connection Class Interactions and Polling Notification Interactions, respectively. This section describes the runtime behavior of listeners and their associated notifications.

Important: A listener and the associated listener notifications must reside in the same package in the Integration Server_directory/instances/<instance_name>/packages/<your_package> folder. Otherwise, data is lost when a package is reloaded.

The figures that illustrate listener runtime interactions with synchronous and asynchronous notifications in this section show the runtime lifecycle of a listener from the time it is started until the time it is shut down. The difference between the two diagrams begins at step 3.3, when the server calls the runNotification method of the notification. Do not interpret the separation of these diagrams to imply that a given listener can use only synchronous or asynchronous notifications. On the contrary, step 3 represents a loop that repeats continuously while the listener is running, and any iteration of the loop may follow either course depending on the class type of the notification that indicates support for the notification event.

When a listener starts (or restarts), Integration Server performs the following:
  • Retrieves a connection from the associated connection node.
  • Calls the listener's listenerStartup method. This listenerStartup method performs the following:
    • Access the connection using the retrieveConnection method from the base class.
    • Initialization required prior to the first waitForData call.
  • Disables the listener if an exception is thrown by the listenerStartup method, or if retrieving connection by Integration Server fails.
Note: A listener instance holds the connection it retrieves during listener initialization for the lifetime of the listener instance. Disabling the connection node has no impact on this connection already held by the listener, but prevents the listener from starting or restarting in the event of an AdapterConnectionException.

After initialization of the listener is complete, Integration Server initiates the notification event-processing loop represented by step 3 of the interaction diagrams. This loop continues until one of the following events occurs:

  • The user of the adapter disables the listener in the adapter's administrative interface.
  • Package containing the listener is disabled (or reloaded).
    Note: Disable the listener package before you disable the adapter package.
  • Integration Server is shut down.
  • Listener or a listener notification throws an AdapterConnectionException. This causes the listener to shut down and to attempt to restart with a new connection.
  • Listener throws an AdapterException or a RunTimeException.

The following figure shows the listener runtime interactions with synchronous notification

The event-processing loop begins with a call to the listener's waitForData method. This method performs the following:
  • Interrogates the adapter resource to determine whether an event has occurred that the listener should report.
  • If the event has not occurred, the listener should return a null object.

    The model assumes that the listener implements some form of blocking read operation with a time component that allows it to return periodically, even if no notification event has occurred. The adapter developer must provide appropriate means of configuring the timing characteristics of this blocked read, such as through a metadata parameter on either the listener or the connection.

  • If the event has occurred, the listener's waitForData method returns a non-null object, Integration Server iterates through the listener notifications that are currently registered with the listener, which must be enabled and registered.
    • The data object received from waitForData method is passed to the supports method (step 3.2) for each notification.
    • For the first notification that returns true from its supports method:
      • Integration Server calls the runNotification method passing the data object wrapped as a NotificationEvent (step 3.3).
      • Integration Server calls the listener's processNotificationResults method with a NotificationResults as input object returned from runNotification (step 3.4).
    • If no notification returned true from the supports method, or if runNotification threw an exception other than an AdapterConnectionException, then processNotificationResults is called with a null argument.
The listener notification's runNotification method (step 3.3) is responsible for the following:
  • Interpreting the NotificationEvent object.
  • Building a WmRecord object consistent with its output signature.

    This may or may not require additional interaction with the resource. If it does, a connection is made available for that purpose through the retrieveConnection method, which is the same connection used by the listener.

  • An asynchronous notification passes this WmRecord object to the doNotify method (step 3.3.1).
  • The doNotify method publishes the document in the same way it does for polling notifications.
  • An asynchronous notification must instantiate a new AsynchNotificationResults object (step 3.3.3), including the notification name, which can be retrieved from the base class nodeName method (step 3.3.2).
  • A synchronous notification's implementation of runNotification method passes its output, WmRecord object to invokeService method instead of doNotify method (step 3.3.1).
  • The service called by invokeService method is specified in the configuration of the synchronous listener notification node. The service is invoked on a separate thread and transaction context.
  • The results of the service invocation are returned to invokeService method as a SynchronousNotificationResults object.
  • The results are then available to be interrogated by the notification and/or the listener, using the methods provided by that class.

Listener Implementation

The example listener implementation provided in this section shows the basic mechanics of a simple listener that can be used to monitor activity on an Integration Server log file. The example listener notification parses a session log entry and produces asynchronous notifications.

The tasks for implementing a listener are as follows:

  • Defining a WmConnectedListener Implementation Class
  • Specifying Configuration Metadata for Listeners
  • Implementing Listener Methods
  • Creating getReader Method in the WmManagedConnection Implementation Class
  • Updating the Resource Bundle
  • Registering Listeners in the WmAdapter Implementation Class
  • Compiling the Adapter
  • Reloading Adapter
  • Refreshing the Designer cache
  • Configuring a Listener

Example Listener Class

package com.wm.MyAdapter.listeners;

import com.wm.adk.error.AdapterException;
import com.wm.adk.metadata.WmDescriptor;
import com.wm.adk.notification.WmConnectedListener;
import com.wm.adk.notification.NotificationResults;

import java.io.FileReader;
import java.util.Locale;
import javax.resource.ResourceException;

import com.wm.MyAdapter.MyAdapter;
import com.wm.MyAdapter.connections.SimpleConnection;
public class SimpleListener extends WmConnectedListener 
{
	public static final String FILE_NAME_PARM = "fileName";
	private String _fileName = null;
	public void setFileName(String val){_fileName = val;}

	private FileReader _reader = null;  
	private StringBuffer workingBuffer = new StringBuffer();  
	private String _lastDataObject = null;

	public void fillWmDescriptor(WmDescriptor descriptor, Locale locale)
		throws ResourceException
	{
		descriptor.setRequired(FILE_NAME_PARM);
		descriptor.setDescriptions(
			MyAdapter.getInstance().getAdapterResourceBundleManager(), locale);
	}
	public void listenerStartup() throws ResourceException  
	{
		try  
		{  
			//_reader = ((SimpleConnection)retrieveConnection()).getReader();  
			_reader = ((SimpleConnection)retrieveConnection()).getReader(_fileName);
			while(_reader.ready())  
			{  
				_reader.read();  // move to the end of the stream  
			}  
		}  
		catch (Throwable t)  
		{  
			throw MyAdapter.getInstance().createAdapterException(100,t);  
		}  
	}

	public Object waitForData() throws ResourceException  
	{  
		try  
		{  
			if(_reader.ready())  
			{  
				do  
				{  
					int i = _reader.read();  
					if (i != -1)  
					{  
						char c = (char)i;  
						workingBuffer.append(c);  
						if(c == '\n')  
						{  
							_lastDataObject = new String(workingBuffer);  
							workingBuffer = new StringBuffer();  
							break;  
						}
					}  
					else  
					{  
						break;  
					}  
				} while (_reader.ready());
			}
		}
		catch (Throwable t)  
		{  
			throw MyAdapter.getInstance().createAdapterException(100,t);  
		}  
		return _lastDataObject;  
	}
public void listenerShutdown()  
	{  
		try  
		{  
			_reader.close();  
		}  
		catch(Throwable t){}  
	}
	public void processNotificationResults(NotificationResults results)  
		throws ResourceException  
	{  
		if(results != null)  
		{  
			if(results.hadError())  
			{  
				MyAdapter.getLogger().logError(9999,  
					"Error processing: " + this._lastDataObject + 
					" errorInfo = " + (results.getErrorInfo() == null ? "" : results.getErrorInfo().toString()));  
			}  
		}  
		else  
		{  
			MyAdapter.getLogger().logError( 9999, 
				"No notification available to process:" + 
				this._lastDataObject);  
		}  
	}
}

Defining a WmConnectedListener Implementation Class

Procedure

  1. Create a class by extending com.wm.adk.notification.WmConnectedListener base class. In this example, the class created is SimpleListener.
  2. Add skeletal implementation of the abstract methods.
  3. Implement the shutdownCallBack method.

    The shutdownCallBack method is invoked on a thread separate from the listener's thread. This feature allows the listener's waitForData loop to be gracefully interrupted prior to a normal shutdown. The thread that initiates listenerShutdown method invokes shutdownCallBack method in the following situations:

    • When the listener node is disabled.
    • When the package containing the listener node is reloaded.
    • When Integration Server shuts down.

    The system passes to this method a reference to the underlying resource connection. The method is invoked prior to calling the listener's listenerShutdown method. It will not be called if the shutdown is due to an exception.

    The signature of this method is:

    public void shutdownCallBack(WmManagedConnection wmConn) throws  
                                                      ResourceException

    The listenerShutdown method is subsequently invoked by WmART on the listener's thread. This is where you must perform any listener-specific cleanup tasks.

Specifying Configuration Metadata for Listener Notifications

The next step for implementing a listener is to create the metadata constructs that the users of the adapter use for entering data when they create listener notification nodes. To do this, perform the following:

  • Create metadata parameters appropriate for the function of the listener notification nodes. Each parameter has:
    • A variable to hold the configured values.
    • A String constant containing the name of the parameter.
    • An accessor method.
    • A set of resource bundle entries with a localizable parameter name and description as shown in Updating the Resource Bundle.

    For more information on metadata parameters, see Metadata Model for Connection.

  • Describe presentation for those metadata parameters.
  • Set the data entry rules for those metadata parameters.

The example implementation includes one metadata parameter, that the users of the adapter use to create listener notification nodes. The following table describes the purpose of each of these parameters for data entry:

Parameter Description
fileName File to monitor.
Parameter Accessor Method Variable Resource Bundle Entries
fileName setFileName FILE_NAME_PARM None

Specifying the Display and Data Entry Attributes of the Data Entry Parameters

  • After creating the parameters, specify the display and data entry attributes by calling various methods of the WmDescriptor interface from the service's fillWmDescriptor method.
  • The example code places each data entry parameter into a single group (in display order) referenced by the constant NOTIFICATION_SETUP_GROUP. A constant instead of a string is used to name the group, because the same value is used in the resource bundle to specify a localizable group name.

Restricting Listeners to Register Specified Notification Templates

By default a listener supports all listener notification templates of the adapter. When the users of the adapter configure a new listener notification (either synchronous or asynchronous) using Designer, they may select from the complete list of all enabled listeners in the adapter. You may want to override this default behavior so that the listener implementation specifies exactly which notification templates it supports. To do this, implement the restrictNotificationTypes method in your listener implementation class. This method returns a String array containing the fully qualified path names of one or more notification template classes that the listener supports. When the users of the adapter attempt to configure a new listener notification in Designer, only those template classes in the returned array will appear in the Adapter Notification Editor. The following example shows how to use this method.

public class SimpleListener extends WmConnectedListener  
{  
...  
   public String[] restrictNotificationTypes()  
   {  
      return new String[]{"com.wm.myadapter.notifications.FooNotification",  
                          "com.wm.myadapter.notifications.BarNotification"};  
   }  
...  
}
Note: All names returned by this method should refer to classes that extend WmNotification.

Implementing Listener Methods

Create the private class attributes and implement the following methods:
  • listenerStartup
  • waitForData
  • listenerShutdown
  • processNotificationResults
In the example, the class created is SimpleListener. Create the private class attributes and implement the abstract methods to manage a FileReader object and variables to hold data read from the log.

The example also includes an implementation of processNotificationResults.

Creating getReader Method in WmManagedConnection Implementation Class

Create the getReader method in the WmManagedConnection implementation class. This method is called from the listenerStartup method in WmConnectedListener implementation class.
package com.wm.MyAdapter.connections;
..
..
import java.io.FileReader;
import java.io.FileNotFoundException;
..
..
public class SimpleConnection extends WmManagedConnection {
..
..
 public FileReader getReader(String fileName) throws AdapterException
	{
		FileReader _reader = null;
		
		try {
			_reader = new FileReader(fileName);
		}
		catch(Exception e) {
			throw MyAdapter.getInstance().createAdapterException(100,e);
		}
		return _reader;
	}
}

Updating the Resource Bundle

Update the resource bundle with a display name, and description to make the listener more usable. For example:

package com.wm.MyAdapter;
..
..
import com.wm.MyAdapter.listeners.SimpleListener;
..
..
public class MyAdapterResource extends ListResourceBundle implements MyAdapterConstants{
   ..
   .. 
 static final Object[][] _contents = {	
   ..
   .. 	
		//Listener 
		,{SimpleListener.class.getName() + ADKGLOBAL.RESOURCEBUNDLEKEY_DISPLAYNAME,
			"Simple Listener"}
		,{SimpleListener.class.getName() + ADKGLOBAL.RESOURCEBUNDLEKEY_DESCRIPTION,
			"Use to monitor log files"}
		,{SimpleListener.FILE_NAME_PARM + ADKGLOBAL.RESOURCEBUNDLEKEY_DISPLAYNAME,
			"Log File Name"}

  }
  protected Object[][] getContents() {
		 // TODO Auto-generated method stub
		 return _contents;
  }
}

Registering Listeners in the WmAdapter Implementation Class

You must register each listener class in the WmAdapter implementation class. You do this by passing the class name to the AdapterTypeInfo.addListenerType method in the WmAdapter.fillAdapterTypeInfo method in the WmAdapter implementation class. In the example, the listener class SimpleListener is registered in the adapter implementation class MyAdapter:

package com.wm.MyAdapter;
..
..
import com.wm.MyAdapter.listeners.SimpleListener;  
..
..  
public class MyAdapter extends WmAdapter implements MyAdapterConstants {
..
.. 
	public void fillAdapterTypeInfo(AdapterTypeInfo info, Locale locale)  
	{
    ..
    ..
    info.addListenerType(SimpleListener.class.getName());  
 }
}

Refreshing the Designer cache

About this task

Refresh the Designer cache.

Configuring a Listener

About this task

Perform the following procedure to configure a listener node. You can use Designer to configure adapter service nodes.

To configure a listener node

Procedure

  1. Start Integration Server Administrator.
  2. In Adapters screen, select the name of your adapter.
  3. Select Listeners.
  4. In the Listeners screen, click Configure New Listener.
  5. In theListener Types screen, select the appropriate listener type defined for the adapter.
  6. Complete the Configure Listener Type > Adapter_Name section as follows:
    Field Description\Action
    Package Namespace node package in which you want to create the listener.
    Folder Name Name of the folder in which to create the listener.
    Listener Name Name of the listener node.
    Connection Name Connection node.
    Retry Limit Number of times that the system must attempt to start the listener if the initial attempt fails. Specifically, it specifies how many times to retry the listenerStartup method before issuing an AdapterConnectionException. When the value is set to 0, the system makes a single attempt. The default value is 5.
    Retry Backoff Timeout Number of seconds the system must wait between each attempt to start the listener. This field is irrelevant if the value of Retry Limit is 0. The default value is 10.
  7. Click Save Listener.

What to do next

Note: Enabling the listener before you configure and enable its corresponding listener notification node produces a warning.
Note: A listener instance holds the connection it retrieves during listener initialization for the lifetime of the listener instance. Disabling the connection node will not impact the connection already held by the listener, but it will prevent the listener from starting or restarting in the event of an AdapterConnectionException.

Listener Notification Implementation

The following example implements an asynchronous listener notification that recognizes session log entries and generates notifications from them. To distinguish a session log entry from another type of log entry, the listener parses the entry data in the notification's supports method. The supports method model is flexible enough to permit this approach because the same listener notification object instance that returns true from the supports call is guaranteed to receive the runNotification call.

The example listener notification uses an alternative approach to implementing resource domains that redirects resource domain activities back to the notification (or adapter service) that uses it. This model does a better job of encapsulating the notification functionality into a single class. The model is described in detail in to-appx_alt_approaches_metadata.html#A52135. If you do not want to use this model, you may implement the resource domain code following the model described in Specifying Adapter Service Signature Resource Domains.

Another new concept used in this example is the "uses" metadata mechanism. This is a shortcut mechanism commonly used to manipulate a metadata signature. You use it to add a column of check boxes to the adapter's interface so that the users of the adapter can select the fields to use for the notification. When they select the check boxes, values will appear in the Signature column. This metadata mechanism is described in The useParam Argument of setResourceDomain, but you do not need to fully understand the constraint of that feature to implement this example.

The tasks for implementing an asynchronous listener notification are as follows:

  • Defining a WmAsyncListenerNotification Implementation Class
  • Specifying Configuration Metadata for Listener Notifications
  • Implementing Configuration Resource Domains for Listener Notifications
  • Implementing the supports and runNotification Method
  • Updating the Resource Bundle
  • Registering Listener Notifications in the Adapter
  • Compiling the Adapter
  • Reloading Adapter
  • Refreshing the Designer cache
  • Configuring and Testing Listener Notification Nodes

Example Listener Notification Class

package com.wm.MyAdapter.listeners;

import com.wm.adk.error.AdapterException;
import com.wm.adk.metadata.WmDescriptor;
import com.wm.adk.notification.WmAsyncListenerNotification;
import com.wm.adk.notification.NotificationResults;
import com.wm.adk.notification.AsyncNotificationResults;
import com.wm.adk.notification.NotificationEvent;
import com.wm.adk.connection.WmManagedConnection;
import com.wm.adk.metadata.*;
import com.wm.adk.cci.record.WmRecord;
import com.wm.adk.cci.record.WmRecordFactory;

import javax.resource.ResourceException;
import java.util.Locale;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.StringTokenizer;

import com.wm.MyAdapter.MyAdapter;
import com.wm.MyAdapter.MyAdapterConstants;
import com.wm.MyAdapter.connections.SimpleConnection;
public class SessionLogListenerNotification extends WmAsyncListenerNotification
	implements MyAdapterConstants
{

	private String[] _fieldNames = null;
	private String[] _fieldTypes = null;
	private boolean[] _uses = null;

	public void setFieldNames(String[] val){_fieldNames = val;}
	public void setFieldTypes(String[] val){_fieldTypes = val;}
	public void setUses (boolean[] val){_uses = val;}
	public void setSignature(String[] val){}

	public static final String NOTIFICATION_SETUP_GROUP =
	"SessionLogListenerNotification.setup";

	public static final String FIELD_NAMES_PARM = "fieldNames";
	public static final String FIELD_TYPES_PARM = "fieldTypes";
	public static final String USES_PARM = "uses";
	public static final String SIG_PARM = "signature";

	public static final String FIELD_NAMES_RD =	
		"SessionLogListenerNotification.fieldNames.rd";
	public static final String FIELD_TYPES_RD = 
		"SessionLogListenerNotification.fieldTypes.rd";

	public static final String[] _sigFieldNames = {
		"timeStamp",
		"component",
		"rootContext",
		"parentContext",
		"currentContext",
		"server",
		"eventCode",
		"user",
		"sessionName",
		"RPCs",
		"age"};
	private Object[] _parsedValues = new Object[_sigFieldNames.length];
public void fillWmTemplateDescriptor(WmTemplateDescriptor descriptor,Locale l)
		throws ResourceException
	{
		String[] parms = new String[] {FIELD_NAMES_PARM,
			FIELD_TYPES_PARM,
			USES_PARM,
			SIG_PARM};
		descriptor.createGroup(NOTIFICATION_SETUP_GROUP, parms);
		descriptor.createFieldMap(parms, false);
		descriptor.createTuple(new String[]{FIELD_NAMES_PARM, FIELD_TYPES_PARM});

		descriptor.setResourceDomain(FIELD_NAMES_PARM, FIELD_NAMES_RD, null);
		descriptor.setResourceDomain(FIELD_TYPES_PARM, FIELD_TYPES_RD, null);
		descriptor.setResourceDomain(SIG_PARM, 
			WmTemplateDescriptor.OUTPUT_FIELD_NAMES,new String[]{
				FIELD_NAMES_PARM,FIELD_TYPES_PARM}, USES_PARM);

		descriptor.setDescriptions( MyAdapter.getInstance().
			getAdapterResourceBundleManager(), l);
	}

	public Boolean adapterCheckValue(WmManagedConnection connection,
		String resourceDomainName, String[][] values, 
		String testValue) throws AdapterException
	{
		return true;
	}
	public ResourceDomainValues[] adapterResourceDomainLookup(
		WmManagedConnection connection, String resourceDomainName,
		String[][] values) throws AdapterException
	{
		ResourceDomainValues[] results = null;
		if (resourceDomainName.equals(FIELD_NAMES_RD)
			|| resourceDomainName.equals(FIELD_TYPES_RD))
		{
			ResourceDomainValues names = new ResourceDomainValues(
				FIELD_NAMES_RD, _sigFieldNames);
			ResourceDomainValues types = new ResourceDomainValues(
				FIELD_TYPES_RD,new String[] {
					Date.class.getName(), //timestamp
					String.class.getName(), // component
					String.class.getName(), // rootContext
					String.class.getName(), // parentContext
					String.class.getName(), // currentContext
					String.class.getName(), // server
					Integer.class.getName(), // eventCode
					String.class.getName(), // user
					String.class.getName(), // sessionName
					Integer.class.getName(), // RPCs
					Long.class.getName() // age
				});
			results = new ResourceDomainValues[] {names,types};
		}
		return results;
	}
	public void registerResourceDomain(WmManagedConnection connection,
		WmAdapterAccess access) throws AdapterException
	{
		access.addResourceDomainLookup(this.getClass().getName(), 
			FIELD_NAMES_RD, connection);
		access.addResourceDomainLookup(this.getClass().getName(), 
			FIELD_TYPES_RD, connection);
	}

	public boolean supports(Object data) throws ResourceException
	{
		boolean result = false;
		try
		{
			SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd H:mm:ss zzz");
			String sData = (String)data;
			this._parsedValues[0] = sdf.parse(sData.substring(0,48));
			StringTokenizer st = new StringTokenizer(sData.substring(49)," ",false);
			this._parsedValues[1] = st.nextToken();
			this._parsedValues[2] = st.nextToken();
			this._parsedValues[3] = st.nextToken();
			this._parsedValues[4] = st.nextToken();
			/*
			st.nextToken(); // skip the session ID
			this._parsedValues[5] = st.nextToken();
			this._parsedValues[6] = new Integer(st.nextToken());
			this._parsedValues[7] = st.nextToken();
			this._parsedValues[8] = st.nextToken();
			this._parsedValues[9] = new Integer(st.nextToken());
			this._parsedValues[10] = new Long(st.nextToken());
			*/
			result = true;
		}
		catch(Throwable t){}
		return result;
	}
	
	public NotificationResults runNotification(NotificationEvent event)
		throws ResourceException
	{
		NotificationResults result = null;
		WmRecord notice = WmRecordFactory.getFactory().createWmRecord("notUsed");
		for(int i = 0; i< _sigFieldNames.length;i++)
		{
			if (_uses[i])
			{
				notice.put(_sigFieldNames[i],_parsedValues[i]);
			}
		}
		this.doNotify(notice);
		result = new AsyncNotificationResults(this.nodeName(),true,null);
		return result;

	}
}

Defining a WmAsyncListenerNotification Implementation Class

Create a class by extending com.wm.adk.notification.WmAsyncListenerNotification base class. This class must provide default implementations for the following abstract methods
  • fillWmTemplateDescriptor
  • supports
  • runNotification
If you are not using the alternative resource domain management model, skip the following methods:
  • adapterCheckValue
  • adapterResourceDomainLookup
  • registerResourceDomain

Specifying Configuration Metadata for Listener Notifications

The example listener notification in this section includes only those configuration parameters that are directly related to the signature. The only new concept in this section is the use of the useParam argument of theWmTemplateDescriptor.setResourceDomain method.

The useParam Argument of setResourceDomain

The WmTemplateDescriptor interface provides two signatures for the setResourceDomain method, one of which includes the argument useParam:

public void setResourceDomain(java.lang.String name,  
                              java.lang.String resourceDomainName,  
                              java.lang.String[] dependencies,  
                              java.lang.String useParam)
  • Use this argument as a filter to determine which of the available fields will be included in the signature. The example implements the useParam argument as USES_PARM constant, in the setResourceDomain method near the end of the example.
  • The USES_PARM parameter is only meaningful when the parameter identified in the name argument and the parameter names in useParam parameter are in the same fieldMap, and the data type of the useParam parameter is boolean[]. When these conditions are satisfied, the adapter service editor treats the useParam setting as a filter on the resource domain association. When this occurs, the resource domain values are only applied to the name parameter row in the fieldMap if the corresponding value in the useParam is true which occurs when the user of the adapter selects the check box.
  • When the user of the adapter selects the fields to use for the notification by selecting the check boxes in the Uses column, values appear in the Signature column. When you save changes to the notification node, the signature changes are reflected in the associated document type.

Implementing Configuration Resource Domains for Listener Notifications

Note: In this example, notice the use of class.getName method when specifying data types. Using this technique enables you to catch spelling errors at compile time.

Implementing the supports and runNotification Method

This example implementation of the supports method parses the contents of the data object that is originally returned from the listener's waitForData method, into the _parsedValues object variable. Any error in the parsing process indicates that the data object was not a session log entry, and the supports method returns a false value.

The runNotification method implementation assumes that the supports method was successful in parsing the data object, so it does not need the NotificationEvent argument. It merely populates a WmRecord object by inserting the parsed names, using the same key names array that populate the resource domain.

Note: The runNotification method calls doNotify method to publish the document. The doNotify method has two forms. When calling the WmAsynchronousNotification.doNotify(WmRecord rec, String msgId) form of this method, the length (the number of characters) of the value in msgId should not exceed a particular limit. To determine this limit, call the WmAsynchronousNotification.adapterMaxMessageIdLen() method. There is a fixed number of characters available in Integration Server to hold a notification ID. Of these, the WmART package reserves a certain number to hold a unique ID that it inserts prior to dispatching a notification. The remaining characters are available to you when calling WmAsynchronousNotification.doNotify(WmRecord rec, String msgId). For more information, see the Javadoc for WmAsynchronousNotifcation.doNotify.

Updating the Resource Bundle

Update the resource bundle with a display name, and description to make the listener notification more usable.

package com.wm.MyAdapter;
..
..
import com.wm.MyAdapter.listeners.SessionLogListenerNotification;
..
..
public class MyAdapterResource extends ListResourceBundle implements MyAdapterConstants{
   ..
   .. 
 static final Object[][] _contents = {	
   ..
   .. 	
  //SessionLog Listener Notification
		,{SessionLogListenerNotification.class.getName() + ADKGLOBAL.RESOURCEBUNDLEKEY_DISPLAYNAME,
			"SessionLog Listener Notification"}
		,{SessionLogListenerNotification.class.getName() + ADKGLOBAL.RESOURCEBUNDLEKEY_DESCRIPTION,
			"Use SessionLog Listener Notification to monitor log files"}
		,{SessionLogListenerNotification.FIELD_NAMES_PARM + ADKGLOBAL.RESOURCEBUNDLEKEY_DISPLAYNAME,
			"Field Name"}
		,{SessionLogListenerNotification.FIELD_NAMES_PARM + ADKGLOBAL.RESOURCEBUNDLEKEY_DESCRIPTION,
			"Field Name To Check"}
		,{SessionLogListenerNotification.FIELD_TYPES_PARM + ADKGLOBAL.RESOURCEBUNDLEKEY_DISPLAYNAME,
			"Field Types"}
		,{SessionLogListenerNotification.FIELD_TYPES_PARM + ADKGLOBAL.RESOURCEBUNDLEKEY_DESCRIPTION,
			"Field Types To Check"}

  }
  protected Object[][] getContents() {
		 // TODO Auto-generated method stub
		 return _contents;
  }
}

Registering Listener Notifications in the Adapter

You must register each listener notification class in the WmAdapter implementation class. You do this by passing the class name to the AdapterTypeInfo.addNotificationType method in the WmAdapter.fillAdapterTypeInfo method in the WmAdapter implementation class. In the example, the listener notification class SessionLogListenerNotification is registered in the adapter implementation class MyAdapter:

For example:

package com.wm.MyAdapter;
..
..
import com.wm.MyAdapter.listeners.SessionLogListenerNotification;  
..
..  
public class MyAdapter extends WmAdapter implements MyAdapterConstants {
..
.. 
	public void fillAdapterTypeInfo(AdapterTypeInfo info, Locale locale)  
	{
    ..
    ..
    info.addNotificationType(SessionLogListenerNotification.class.getName());  
 }
}

Refreshing the Designer cache

About this task

Refresh the Designer cache.

Configuring and Testing Listener Nodes and Listener Notification Nodes

Now you are ready to configure a listener notification node as follows:

  • Configuring Listener Notification Nodes
  • Testing Listener Nodes and Listener Notification Nodes

Configuring Listener Notification Nodes

About this task

A listener notification node can be either synchronous or asynchronous. When an event occurs, an asynchronous listener notification publishes a document. You must create a trigger that receives the document and executes a service to process the document's data. With a synchronous listener notification, you can designate a flow service to process the data produced by the notification. A synchronous notification does not use a trigger.

To configure a listener notification node

Procedure
  1. Start Designer.
  2. Select a namespace node package where you want to create the listener notification.
  3. Create a folder in the selected package, and navigate to that folder in Package Navigator.
  4. Select File > New.
  5. Select Adapter Notification from the list of elements.
  6. In the Create a New Adapter Notification screen, type a name for your listener notification in the Element name field, and click Next.
  7. In the Select Adapter Type screen, select the name of your adapter, and click Next.
  8. In the Select a Template screen, select a listener notification template, and click Next.
  9. In the Select an Adapter Notification Listener screen, select the appropriate adapter listener name, and click Next.
  10. Perform one of the following steps:
    • If you selected an asynchronous listener notification template, click Finish.
    • If you selected a synchronous listener notification template, select a flow service to process the data produced by the notification, click Next, and then click Finish.

    The Adapter Notification Editor opens.

  11. In the Adapter Notification Editor, select an event.
  12. Select File > Save.

    If you selected an asynchronous listener notification template, the adapter creates a listener notification and a document named notificationNamePublishDocument. The publishable document contains the fields which are configured in the Listener Notification template.

    Note: Documents are not created for synchronous listener notifications.

    When choosing the service for a synchronous notification, ensure that it does not require session data. For more information, see Synchronous and Asynchronous Listener Notifications.

Testing Listener and Listener Notification Nodes

Creating the Flow Service for the Listener Notification Node
About this task

Perform the following procedure to create the flow service for the listener notification node.

To create the flow service for the listener notification node

Procedure
  1. Start Designer.
  2. In the Package Navigator, select the folder where you want to create the flow service.
  3. Select File > New.
  4. Select Flow Service from the list of elements.
  5. In the Create a New Flow Service screen, type TestMyAdapterFlowService in the Element name field, and click Next.
  6. On the Select the Source Type screen, select Empty Flow, and click Finish.
  7. Click to insert a flow step.
  8. Navigate to the pub.flow:savePipelineToFile service in the WmPublic package, and click OK.
    Note: The savePipelineToFile service saves the contents of the pipeline (from the listener notification event) to the file that you specify in the fileName parameter.
  9. Click the Pipeline tab.
  10. Open the fileName parameter in the pipeline and set its value to MonitorListenerNotificationPipeline.log.

    Click OK.

Creating the Trigger for the Listener Notification Node
About this task

Perform the following procedure to create the trigger for the Polling notification node.

To create the trigger for the Polling notification node

Procedure
  1. Start Designer.
  2. In the Package Navigator, select the folder where you want to create the trigger.
  3. Select File > New.
  4. Select webMethods Messaging Trigger from the list of elements.
  5. On the webMethods Messaging Trigger screen, type TestMyAdapterMsgTrigger in the Element name field and click Finish.
  6. In the trigger editor, in the Conditions section, accept the default Condition1.
  7. In the Condition detail section, in the Service field, select or type the flow service name TestMyAdapterFlowService.
  8. Click to insert document types. Select TestMyListenerNotificationPublishDocument and click OK.
  9. Click to save your trigger.
Enabling Listener Notification Nodes and Listener Nodes
About this task

Enabling the listener before you configure and enable its corresponding listener notification node produces a warning.

To enable a listener node and a listener notification node

Procedure
  1. Start Integration Server Administrator.
  2. In Adapters screen, select the name of your adapter.
  3. Select Listener Notifications.
  4. In the Listener Notification screen, enable the listener notification node by clicking No in the Enabled column. The Enabled column now shows Yes (enabled).
  5. Select Listeners.
  6. In the Listeners screen, enable the listener by clicking No in the Enabled column. The Enabled column now shows Yes (enabled).
Testing Listener
About this task
The file MonitorListenerNotificationPipeline.log is created in Integration Server_directory/instances/<instance_name>/pipeline/ folder. This file contains one entry each time the file added in the listener is updated:
<?xml version="1.0" encoding="UTF-8"?>

<IDataXMLCoder version="1.0">
  <record javaclass="com.wm.data.ISMemDataImpl">
    <value name="fileName">MonitorListenerNotificationPipeline.log</value>
    <record name="TestMyAdapterListener:TestMyAdapterListenerNotificationPublishDocument" 
javaclass="com.wm.data.ISMemDataImpl">
      <Date name="timeStamp" type="java.util.Date">Thu Oct 21 12:34:45 IST 2021</Date>
      <value name="component">)</value>
      <value name="rootContext">Unable</value>
      <record name="_env" javaclass="com.wm.data.ISMemDataImpl">
        <value name="locale"></value>
        <value name="activation">wm624455fb0-b66d-4344-b92f-cee92639b14c</value>
        <value name="businessContext">wm6:2281c61b-a0dd-4dc2-bb31-6eaea2052a1c\snull\snull:
wm624455fb0-b66d-4344-b92f-cee92639b14c:null:IS_61:null</value>
        <value name="uuid">wm:14c48f70-323e-11ec-b7fd-000000000152</value>
        <value name="trackId">wm:14c48f70-323e-11ec-b7fd-000000000152</value>
        <value name="pubId">islocalpubid</value>
        <Date name="enqueueTime" type="java.util.Date">Thu Oct 21 12:41:15 IST 2021</Date>
        <Date name="recvTime" type="java.util.Date">Thu Oct 21 12:41:15 IST 2021</Date>
        <number name="age" type="java.lang.Integer">0</number>
      </record>
    </record>
  </record>
</IDataXMLCoder>