Adapter Development Kit 9.12 | webMethods Adapter Development Kit Documentation | webMethods Adapter Development Kit Installation and User’s Documentation | Usage Scenarios | How to create a polling notification implementation?
 
How to create a polling notification implementation?
A polling notification is a facility that enables an adapter to initiate activity on Integration Server, based on events that occur in the adapter resource. A polling notification monitors an adapter resource for changes (such as an insert, update, or delete operation) so that the appropriate flow or Java services can react to the data, such as sending an invoice or publishing an invoice to Integration Server.
Ensure that you have:
*webMethods Integration Server 9.12 or later installed.
*Designer 9.12 or later installed.
*Integration Server Administrator access.
*Java 1.8 or later installed.
*Basic understanding of webMethods Integration Server, Designer, Integration Server Administrator, Java.
1. Start the editor to create Java files for adapter service implementation.
2. Create directories corresponding to your Java package structure in the webMethods package you created using Designer. For example: com\mycompany\adapter\myAdapter\notifications. In the example, the folder created is com\wm\MyAdapter\notifications.
Note:
You must create your Java package and classes in the adapterPackageName\code\source folder in the webMethods package you created using Designer.
3. Create the com.wm.adk.notification.WmPollingNotification implementation class.
In the example, created a SimpleNotification class.
a. Create a constant for grouping the metadata parameters.
In the example, NOTIFICATION_SETUP_GROUP is the constant.
b. Create a class attribute, a set method, a constant, and a resource domain for each metadata parameter. For example, a constant DIRECTORY_PARM, a corresponding class attribute _directory, a corresponding set method setDirectory, and a resource domain DIRECTORIES_RD (which needs to lookup) for the parameter table name.
Class Attribute Name
Class Attribute Set Method Name
Class Attribute Name Constant
Resource Domain Name Constant
_directory
setDirectory
DIRECTORY_PARM
DIRECTORIES_RD
_checkAdded
setCheckAdded
CHECK_ADDED_PARM
None
_checkDeleted
setCheckDeleted
CHECK_DELETED_PARM
None
_fieldNames
setFieldNames
SIG_FIELD_NAMES_PARM
FIELD_NAMES_RD
_fieldTypes
setFieldTypes
SIG_FIELD_TYPES_PARM
FIELD_TYPES_RD
None
setSignature
SIG_PARM
None
c. In the fillWmTemplateDescriptor method, call WmTemplateDescriptor.createGroup method, WmTemplateDescriptor.createFieldMap method, and WmTemplateDescriptor.createTuple method.
d. In the fillWmTemplateDescriptor method, call WmTemplateDescriptor.setHidden method to hide the fields.
e. In the fillWmTemplateDescriptor method, call WmTemplateDescriptor.setResourceDomain method, and WmTemplateDescriptor.setDescriptions method.
f. In the runNotification method, call doNotify method.
g. In the adapterCheckValue method, check if a lookup is performed on the _directory value and if the specified folder exists.
h. In the adapterResourceDomainLookup method, add resource domain values if a lookup is performed on the _fieldNames and _fieldTypes.
i. In the registerResourceDomain method, register resource domain lookup for the _fieldNames and _fieldTypes metadata parameters, and add resource domain values for the _directory metadata parameter.
j. Create a createNotice method to add the information logged.
For example, the SimpleNotification class:
package com.wm.MyAdapter.notifications;

import com.wm.adk.cci.record.WmRecord;
import com.wm.adk.cci.record.WmRecordFactory;
import com.wm.adk.connection.WmManagedConnection;
import com.wm.adk.error.AdapterException;
import com.wm.adk.metadata.ResourceDomainValues;
import com.wm.adk.metadata.WmAdapterAccess;
import com.wm.adk.metadata.WmTemplateDescriptor;
import com.wm.adk.notification.WmPollingNotification;

import java.io.File;
import java.util.ArrayList;
import java.util.Locale;
import javax.resource.ResourceException;

import com.wm.MyAdapter.MyAdapter;
public class SimpleNotification extends WmPollingNotification
{
public static final String NOTIFICATION_SETUP_GROUP = "SimpleNotification";

public static final String DIRECTORY_PARM = "directory";
public static final String CHECK_ADDED_PARM = "checkAdded";
public static final String CHECK_DELETED_PARM = "checkDeleted";
public static final String SIG_FIELD_NAMES_PARM = "fieldNames";
public static final String SIG_FIELD_TYPES_PARM = "fieldTypes";
public static final String SIG_PARM = "signature";

public static final String DIRECTORIES_RD =
"SimpleNotification.directories.rd";
public static final String FIELD_NAMES_RD =
"SimpleNotification.fieldNames.rd";
public static final String FIELD_TYPES_RD =
"SimpleNotification.fieldTypes.rd";

private String _directory;
private boolean _checkAdded;
private boolean _checkDeleted;
private String[] _fieldNames;
private String[] _fieldTypes;

public void setDirectory(String val){_directory = val;}
public void setCheckAdded(boolean val){_checkAdded = val;}
public void setCheckDeleted(boolean val){_checkDeleted = val;}
public void setFieldNames(String[] val){_fieldNames = val;}
public void setFieldTypes(String[] val){_fieldTypes = val;}
public void setSignature(String[] val){}

private ArrayList _fileList = new ArrayList();

public SimpleNotification(){}

public void fillWmTemplateDescriptor(WmTemplateDescriptor descriptor, Locale l)
throws ResourceException
{
descriptor.createGroup(NOTIFICATION_SETUP_GROUP,
new String[]{DIRECTORY_PARM, CHECK_ADDED_PARM, CHECK_DELETED_PARM,
SIG_FIELD_NAMES_PARM, SIG_FIELD_TYPES_PARM, SIG_PARM});
descriptor.createFieldMap(
new String[]{SIG_FIELD_NAMES_PARM, SIG_FIELD_TYPES_PARM, SIG_PARM},
false);

descriptor.setHidden(SIG_FIELD_NAMES_PARM);
descriptor.setHidden(SIG_FIELD_TYPES_PARM);
descriptor.setHidden(SIG_PARM);
descriptor.createTuple(
new String[]{SIG_FIELD_NAMES_PARM, SIG_FIELD_TYPES_PARM});

descriptor.setResourceDomain(DIRECTORY_PARM, DIRECTORIES_RD, null);
descriptor.setResourceDomain(SIG_FIELD_NAMES_PARM, FIELD_NAMES_RD, null);
descriptor.setResourceDomain(SIG_FIELD_TYPES_PARM, FIELD_TYPES_RD, null);
descriptor.setResourceDomain(SIG_PARM, WmTemplateDescriptor.OUTPUT_FIELD_NAMES,
new String[]{SIG_FIELD_NAMES_PARM, SIG_FIELD_TYPES_PARM});
descriptor.setDescriptions(
MyDemoAdapter.getInstance().getAdapterResourceBundleManager(),l);
}

public void runNotification() throws ResourceException
{
File thisDir = new File(_directory);
File [] newList = thisDir.listFiles();
ArrayList scratchCopy = new ArrayList(this._fileList);

for (int nlIndex = 0;nlIndex < newList.length;nlIndex++)
{
String name = newList[nlIndex].getName();
if(newList[nlIndex].isFile())
{
if(scratchCopy.contains(name))
{
scratchCopy.remove(name);
}
else
{
this._fileList.add(name);
if(this._checkAdded)
{
this.doNotify(createNotice(name,_directory,true,false));
}
}
}
else
{
scratchCopy.remove(name);
}

}
// now anything left in the scratch copy is missing from the directory

String[] deadList = new String[scratchCopy.size()];
scratchCopy.toArray(deadList);
for(int dlIndex = 0; dlIndex < deadList.length;dlIndex++)
{
this._fileList.remove(deadList[dlIndex]);
if(this._checkDeleted)
{
this.doNotify(createNotice(deadList[dlIndex], _directory,false,true));
}
}

}

public Boolean adapterCheckValue(WmManagedConnection connection,
String resourceDomainName, String[][] values, String testValue)
throws AdapterException
{

boolean result = true;

if(resourceDomainName.equals(DIRECTORIES_RD))
{
File testDir = new File(testValue);
if (!testDir.exists())
{
result = false;
}
else if(!testDir.isDirectory())
{
result = false;
}
}

return new Boolean(result);
}

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,new String[] {
"FileName", "Path","isAdded","isDeleted"});

ResourceDomainValues types =
new ResourceDomainValues(FIELD_TYPES_RD,new String[] {
"java.lang.String", "java.lang.String",
"java.lang.Boolean","java.lang.Boolean"});
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);

ResourceDomainValues rd = new ResourceDomainValues(DIRECTORIES_RD,
new String[] {""});
rd.setComplete(false);
rd.setCanValidate(true);
access.addResourceDomain(rd);
access.addCheckValue(DIRECTORIES_RD, connection);
}

private WmRecord createNotice(String file, String dir, boolean isAdded,
boolean isDeleted)
{
WmRecord notice =
WmRecordFactory.getFactory().createWmRecord("notUsed");
notice.put("FileName",file);
notice.put("Path",dir);
notice.put("isAdded",new Boolean(isAdded));
notice.put("isDeleted", new Boolean(isDeleted));

return notice;
}

}
4. Update the WmManagedConnection implementation class to add the polling notification metadata parameters with resource domain lookup.
In the example, update SimpleConnection class's registerResourceDomain method as follows:
package com.wm.MyAdapter.connection;

import com.wm.adk.connection.WmManagedConnection;
import com.wm.adk.metadata.*;
import com.wm.adk.error.AdapterException;

import com.wm.MyAdapter.MyAdapter;
import com.wm.MyAdapter.services.MockDbUpdate;
import com.wm.MyAdapter.notifications.SimpleNotification;


public class SimpleConnection extends WmManagedConnection {
..
..
public void registerResourceDomain(WmAdapterAccess access)
throws AdapterException
{
..
..

//Simple Notification Registering Resource Domain
access.addResourceDomainLookup(SimpleNotification.DIRECTORIES_RD, this);
access.addResourceDomainLookup(SimpleNotification.FIELD_NAMES_RD, this);
access.addResourceDomainLookup(SimpleNotification.FIELD_TYPES_RD, this);
}
5. Update the resource bundle implementation class to add the display name, and description of the polling notification class and the fields in the polling notification class.
In the example, update MyAdapterResource class's Object[][] _contents as follows:
package com.wm.MyAdapter;
..
..
import com.wm.MyAdapter.notifications.SimpleNotification;

public class MyAdapterResource extends ListResourceBundle implements MyAdapterConstants{
..
..
static final Object[][] _contents = {
..
..
//Polling Notifications
,{SimpleNotification.class.getName() + ADKGLOBAL.RESOURCEBUNDLEKEY_DISPLAYNAME,
"Simple Polling Notification"}
,{SimpleNotification.class.getName() + ADKGLOBAL.RESOURCEBUNDLEKEY_DESCRIPTION,
"Looks for file updates to a specified directory"}
,{SimpleNotification.NOTIFICATION_SETUP_GROUP + ADKGLOBAL.RESOURCEBUNDLEKEY_GROUP,
"Simple Notification Settings"}
,{SimpleNotification.DIRECTORY_PARM + ADKGLOBAL.RESOURCEBUNDLEKEY_DISPLAYNAME,
"Directory Path"}
,{SimpleNotification.DIRECTORY_PARM + ADKGLOBAL.RESOURCEBUNDLEKEY_DESCRIPTION,
"Directory to monitor"}
,{SimpleNotification.CHECK_ADDED_PARM + ADKGLOBAL.RESOURCEBUNDLEKEY_DISPLAYNAME,
"Notify on Add"}
,{SimpleNotification.CHECK_ADDED_PARM + ADKGLOBAL.RESOURCEBUNDLEKEY_DESCRIPTION,
"Check if notification should be generated when file added"}
,{SimpleNotification.CHECK_DELETED_PARM + ADKGLOBAL.RESOURCEBUNDLEKEY_DISPLAYNAME,
"Notify on Delete"}
,{SimpleNotification.CHECK_DELETED_PARM + ADKGLOBAL.RESOURCEBUNDLEKEY_DESCRIPTION,
"Check if notification should be generated when file deleted"}

}
protected Object[][] getContents() {
// TODO Auto-generated method stub
return _contents;
}
}
6. Register the polling notification type in the adapter by updating your fillAdapterTypeInfo method in your WmAdapter implementation class.
In the example, the polling notification class SimpleNotification is registered using the addNotificationType method in the adapter implementation class's MyAdapter.fillAdapterTypeInfo method:
package com.wm.MyAdapter;
..
..
import com.wm.MyAdapter.notifications.*;
..
..
public class MyAdapter extends WmAdapter implements MyAdapterConstants {
..
..
public void fillAdapterTypeInfo(AdapterTypeInfo info, Locale locale)
{
..
..
info.addNotificationType(SimpleNotification.class.getName());
}
}
7. Execute the ANT script created in adapter definition to compile, and deploy the adapter in Integration Server.
Use the files build.xml and build.properties.
ant deploy
8. Restart Integration Server.
9. In Integration Server Administrator, navigate to Adapters > MyAdapter .
Polling Notifications appears in the menu.
10. In Designer, create the Adapter Notification.
a. In Package Navigator, select the Default package.
b. Select File > New > Folder.
c. Enter the Folder name. For example: TestMyAdapter.
d. In Package Navigator, select the Default > TestMyAdapter.
e. Select File > New > Adapter Notification.
f. In the Create a New Adapter Notification screen, enter the Element name and click Next. For example: TestMyPollingNotification.
g. In the Select Adapter Type screen, select an adapter type for which you want to create the polling notification. For example: MyAdapter.
h. In the Select a Template screen, select a polling notification template, and click Finish. For example: Simple Polling Notification.
i. In the Select an Adapter Connection Alias screen, select an adapter connection. For example: TestMyAdapter:Conn1. .
j. In the Publish Document Name screen, select Finish.
In Designer, you can see the following two items created:
a. A new adapter notification TestMyPollingNotification is created with two tabs: Simple Notification Settings, and Adapter Settings.
b. A new Document Type TestMyPollingNotificationPublishDocument is created with two tabs: Tree, and Comments.
11. In Designer, select a Directory Path to monitor and the polling event Notify on Add and Notify on Delete to monitor.
12. Select File > Save.
13. Create a Flow Service for the Polling Notification Node using Designer.
a. Navigate to the folder Default > TestMyAdapter.
b. Select New > Flow Service.
c. In the Create a New Flow Service screen, add TestMyAdapterFlowService in the Element name field and click Finish.
d. In the Flow Service > Tree tab, right-click and select Insert > savePipelineToFile.
e. In the Flow Service, Tree tab, select the savePipelineToFile method. You can see the Service In > fileName in the Pipeline tab.
f. Update Service In > fileName in the Pipeline tab. In this example, the value is MonitorPollingNotificationPipeline.log.
g. Click OK, and save the flow service.
14. Create a trigger using Designer.
a. Navigate to the folder Default > TestMyAdapter.
b. Create the webMethods Messaging Trigger and select Finish. In the example, TestMyAdapterMsgTrigger is created.
c. In the webMethods Messaging Trigger, Trigger Settings tab, Condition Detail section, perform the following:
*In the trigger editor, in the Conditions section, accept the default Condition1.
*In the Condition detail section, in the Service field, select or type the flow service name TestMyAdapterFlowService.
*Click to insert the Document Type TestMyPollingNotificationPublishDocument.
d. Save the messaging trigger.
15. Schedule and enable the polling notification.
a. In Integration Server Administrator, select Adapters > MyAdapter > Polling Notifications, the list of polling notifications appear.
b. Select Edit Schedule for TestMyPollingNotification.
c. Modify the schedule parameters for the TestMyPollingNotification.
d. Select Save Settings.
e. In Adapters > MyAdapter > Polling Notifications screen, select State as Enabled.
16. Add a file to the folder that is monitored. In this example, the folder is C:\Monitor and file is added Testing-1.txt.
The file MonitorPollingNotificationPipeline.log is created in Integration Server_directory /instances/<instance_name>/pipeline. This file contains the following entry for the file added in C:\Monitor:
<?xml version="1.0" encoding="UTF-8"?>

<IDataXMLCoder version="1.0">
<record javaclass="com.wm.data.ISMemDataImpl">
<value name="fileName">MonitorPollingNotificationPipeline.log</value>
<record name="TestMyAdapter:TestMyAdapterNotificationPublishDocument" javaclass="com.wm.data.ISMemDataImpl">
<value name="FileName">Testing-1.txt</value>
<value name="Path">C:\Monitor</value>
<jboolean name="isAdded">true</jboolean>
<jboolean name="isDeleted">false</jboolean>
<record name="_env" javaclass="com.wm.data.ISMemDataImpl">
<value name="locale"></value>
<value name="activation">wm6bfd23a95-1c84-4e3e-b687-5858453777bc</value>
<value name="businessContext">wm6:bfd23a95-1c84-4e3e-b687-5858453777bc\snull\
snull:wm6bfd23a95-1c84-4e3e-b687-5858453777bc:null:IS_61:null</value>
<value name="uuid">wm:c3fb4d30-2f23-11ec-8723-000000000002</value>
<value name="trackId">wm:c3fb4d30-2f23-11ec-8723-000000000002</value>
<value name="pubId">islocalpubid</value>
<Date name="enqueueTime" type="java.util.Date">Sun Oct 17 13:55:20 IST 2021</Date>
<Date name="recvTime" type="java.util.Date">Sun Oct 17 13:55:20 IST 2021</Date>
<number name="age" type="java.lang.Integer">0</number>
</record>
</record>
</record>
</IDataXMLCoder>