How to create a polling notification implementation?
About this task
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:
- IBM 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 IBM webMethods Integration Server, Designer, Integration Server Administrator, Java.
Procedure
- Start the editor to create Java files for adapter service implementation.
-
Create directories corresponding to your Java package structure
in the
IBM 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 IBM webMethods package you created using Designer.
-
Create the
com.wm.adk.notification.WmPollingNotification
implementation class.
In the example, created a SimpleNotification class.
-
Create a constant for grouping the metadata parameters.
In the example, NOTIFICATION_SETUP_GROUP is the constant.
-
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 - In the fillWmTemplateDescriptor method, call WmTemplateDescriptor.createGroup method, WmTemplateDescriptor.createFieldMap method, and WmTemplateDescriptor.createTuple method.
- In the fillWmTemplateDescriptor method, call WmTemplateDescriptor.setHidden method to hide the fields.
- In the fillWmTemplateDescriptor method, call WmTemplateDescriptor.setResourceDomain method, and WmTemplateDescriptor.setDescriptions method.
- In the runNotification method, call doNotify method.
- In the adapterCheckValue method, check if a lookup is performed on the _directory value and if the specified folder exists.
- In the adapterResourceDomainLookup method, add resource domain values if a lookup is performed on the _fieldNames and _fieldTypes.
- 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.
- 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; } } -
Create a constant for grouping the metadata parameters.
-
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); } -
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[][] _contentsas 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; } } -
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()); } } -
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 - Restart Integration Server.
-
In
Integration Server Administrator,
navigate to
Adapters >
MyAdapter .
Polling Notifications appears in the menu.
-
In
Designer,
create the
Adapter Notification.
- In Package Navigator, select the Default package.
-
Select
File > New > Folder.
-
Enter the
Folder name. For example:
TestMyAdapter.
- In Package Navigator, select the Default > TestMyAdapter.
-
Select
File > New > Adapter Notification.
-
In the
Create a New Adapter Notification screen,
enter the
Element name and click
Next. For example:
TestMyPollingNotification.
-
In the
Select Adapter Type screen, select an
adapter type for which you want to create the polling notification. For
example:
MyAdapter.
-
In the
Select a Template screen, select a polling
notification template, and click
Finish. For example:
Simple Polling
Notification.
-
In the
Select an Adapter Connection Alias screen,
select an adapter connection. For example:
TestMyAdapter:Conn1.
.
-
In the
Publish Document Name screen, select
Finish.
In Designer, you can see the following two items created:
- A new adapter notification
TestMyPollingNotification is created with two
tabs:
Simple Notification Settings, and
Adapter Settings.
- A new Document Type
TestMyPollingNotificationPublishDocument is
created with two tabs:
Tree, and
Comments.
-
In
Designer,
select a
Directory Path to monitor and the polling
event
Notify on
Add and
Notify on
Delete to monitor.
- Select File > Save.
-
Create a Flow Service for the Polling Notification Node using
Designer.
- Navigate to the folder Default > TestMyAdapter.
-
Select
New > Flow
Service.
- In the Create a New Flow Service screen, add TestMyAdapterFlowService in the Element name field and click Finish.
-
In the
Flow Service >
Tree tab, right-click and select
Insert > savePipelineToFile.
-
In the
Flow Service,
Tree tab, select the
savePipelineToFile method. You can see the
Service In >
fileName in the
Pipeline tab.
-
Update
Service In >
fileName in the
Pipeline tab. In this example, the value
is
MonitorPollingNotificationPipeline.log.
- Click OK, and save the flow service.
-
Create a trigger using
Designer.
- Navigate to the folder Default > TestMyAdapter.
-
Create the
webMethods Messaging Trigger and select
Finish. In the example,
TestMyAdapterMsgTrigger is created.
-
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.
- Save the messaging trigger.
-
Schedule and enable the polling notification.
-
In
Integration Server Administrator,
select
Adapters >
MyAdapter > Polling
Notifications, the list of polling notifications appear.
- Select Edit Schedule for TestMyPollingNotification.
-
Modify the schedule parameters for the
TestMyPollingNotification.
- Select Save Settings.
-
In
Adapters >
MyAdapter > Polling
Notifications screen, select
State as
Enabled.
-
In
Integration Server Administrator,
select
Adapters >
MyAdapter > Polling
Notifications, the list of polling notifications appear.
- Add a file to the folder that is monitored. In this example, the folder is C:\Monitor and file is added Testing-1.txt.
Results
<?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>