Sterling oms taskq based agent server
In Sterling OMS we have 2 type of servers
- Agent Server
- TaskQ based
- Non TaskQ based
- Integration Server
Please read this post to get different between agent and integration servers
In this post we are going to see how to create simple TaskQ based agent.
Sterling OMS TaskQ based Agent Server
Requirement: When order stays in Draft order Status for 30 days, automatically delete order after 30 days.
Note: Deleting draft order using order purge agent available as OOB (Out-of-Box) functionality. this blog created to explain how to create TaskQ agent in Sterling OMS.
Task Q Records can be created in 2 ways
if Draft Order Confirm transaction enabled with “This transaction is task based”, during draft order creation system automatically generates record into YFS_TASK_Q table. This record will be picked-up by agent server for processing.
- Manual way : Calling manageTaskQueue API
In this post we are going to see how to use manageTaskQueue API and deleteOrder API.
Configuration Steps
- Create new transaction with name DELETE_DRAFT_ORDER_AUTO
- Under time triggered tab give the Java class name as “com.oms94.agent.TaskQDemoAgent” (Code given below)
- Create New Agent Server (DraftOrderDelete) by clicking green color + symbol
- Configure Run Time Properties as shown below
- Configure Criteria Parameter as shown below
- Create New Sync Service with name DraftOrderTaskQRecordInsert
- API : Extended API
- API Name : createTaskQRecord
- Class Name : com.oms94.agent.CreateTaskQRecord
- Method Name : createTaskQRecord
- Create New Action and configure DraftOrderTaskQRecordInsert service into action
- Configure newly created action part of Draft Order Creation transactions ON_SUCCESS event
Java code Changes
Add below given code in eclipse and generate jar file.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 |
package com.oms94.agent; import java.rmi.RemoteException; import java.text.SimpleDateFormat; import java.util.Calendar; import java.util.GregorianCalendar; import org.w3c.dom.Document; import com.oms94.util.XMLUtil; import com.yantra.interop.japi.YIFApi; import com.yantra.interop.japi.YIFClientFactory; import com.yantra.yfc.dom.YFCDocument; import com.yantra.yfs.japi.YFSEnvironment; import com.yantra.yfs.japi.YFSException; /** * Demo class for creating yfs_task_q record manually * */ public class CreateTaskQRecord { protected static YIFApi api = null; public Document createTaskQRecord(YFSEnvironment env, Document doc) throws YFSException, RemoteException, Exception { if(doc == null) { return doc; } System.out.println("Input createTaskRecord: " + XMLUtil.getStringFromDocument(doc)); YFCDocument document = createManageTaskQueueInputXML(doc); System.out.println("Input manageTaskQueue: " + XMLUtil.getStringFromDocument(document.getDocument())); doc = getApi().manageTaskQueue(env, document.getDocument()); return doc; } private YFCDocument createManageTaskQueueInputXML(Document doc) { String orderHeaderKey = doc.getDocumentElement().getAttribute("OrderHeaderKey"); YFCDocument document = YFCDocument.createDocument("TaskQueue"); document.getDocumentElement().setAttribute("DataKey", orderHeaderKey); document.getDocumentElement().setAttribute("DataType", "OrderHeaderKey"); document.getDocumentElement().setAttribute("HoldFlag", "N"); document.getDocumentElement().setAttribute("Operation", "Manage"); document.getDocumentElement().setAttribute("TransactionId", "DELETE_DRAFT_ORDER_AUTO.0001.ex"); document.getDocumentElement().setAttribute("AvailableDate", getNextAvilDate()); return document; } private String getNextAvilDate() { SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss"); Calendar currentCal = new GregorianCalendar(); currentCal.add(Calendar.DATE, 30); // this value should be read from configuration String sNextAvailableTime = sdf.format(currentCal.getTime()); System.out.println("sNextAvailableTime:" + sNextAvailableTime); return sNextAvailableTime; } protected YIFApi getApi() throws Exception { if(api == null) { api = YIFClientFactory.getInstance().getApi(); } return api; } } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 |
package com.oms94.agent; import java.rmi.RemoteException; import org.w3c.dom.Document; import com.oms94.util.XMLUtil; import com.yantra.interop.japi.YIFApi; import com.yantra.interop.japi.YIFClientFactory; import com.yantra.ycp.japi.util.YCPBaseTaskAgent; import com.yantra.yfc.dom.YFCDocument; import com.yantra.yfs.japi.YFSEnvironment; import com.yantra.yfs.japi.YFSException; public class TaskQDemoAgent extends YCPBaseTaskAgent { protected static YIFApi api = null; /* * * <?xml version="1.0" encoding="UTF-8"?> <TaskQueue DataKey="2017111300523176633" DataType="OrderHeaderKey" HoldFlag="N" TaskQKey="2017111300523476638" TransactionKey="2017111223535276390"> <TransactionFilters Action="Get" DAYS_TO_WAIT="30" DocumentParamsKey="0001" DocumentType="0001" NumRecordsToBuffer="5000" ProcessType="ORDER_FULFILLMENT" ProcessTypeKey="ORDER_FULFILLMENT" TransactionId="DELETE_DRAFT_ORDER_AUTO.0001.ex" TransactionKey="2017111223535276390" /> </TaskQueue> */ @Override public Document executeTask(YFSEnvironment env, Document doc) throws Exception { System.out.println("Input executeTask: " + XMLUtil.getStringFromDocument(doc)); Document deleteOrderResult = getApi().deleteOrder(env, createDeleteOrderInput(doc).getDocument()); System.out.println("deleteOrderResult:" + XMLUtil.getStringFromDocument(deleteOrderResult)); return doc; } private YFCDocument createDeleteOrderInput(Document doc) { String orderHeaderKey = doc.getDocumentElement().getAttribute("DataKey"); YFCDocument document = YFCDocument.createDocument("Order"); document.getDocumentElement().setAttribute("OrderHeaderKey", orderHeaderKey); document.getDocumentElement().setAttribute("Action", "DELETE"); return document; } protected YIFApi getApi() throws Exception { if(api == null) { api = YIFClientFactory.getInstance().getLocalApi(); } return api; } } |
Build and Deployment
Build the jar file and replace it in <OMS_INSTALL_DIR>\jar\customjar\1\SterlingCustom94.jar. Read here how to create custom jar and add part of install.
Build the application using below command
1 |
buildear.cmd -Dappserver=weblogic -Dwarfiles=smcfs,sbc -Dearfile=smcfs.ear -Dnowebservice=true -Ddevmode=true -Dnodocear=true -Dwls-10=true create-ear |
Deploy the newly created EAR.
How to test this change ?
- Go to Sterling Order Create Console and create Order in Draft order
- Run query and find Task_Q record got created with AvailableDate as current date + 30 days
1 2 3 4 5 |
select * from yfs_task_q where data_type='OrderHeaderKey' and transaction_key in (select transaction_key from yfs_transaction where tranid='DELETE_DRAFT_ORDER_AUTO.0001.ex') order by 1 desc |
- For testing purpose modify the AvailableDate with below query (your agent will not pickup this record for next 30 days)
1 2 |
update yfs_task_q set AVAILABLE_DATE=sysdate where task_q_key='?' commit; |
- run the agent <OMS_INSTALL_DIR>/bin/agentserver.cmd DraftOrderDelete
- Draft Order got deleted and yfs_task_q record got deleted successfully.
Points to remember ?
- While extending YCPBaseTaskAgent we need to override executeTask(YFSEnvironment env, Document doc) method
- If transaction executed successfully yfs_task_q record gets removed
- if transaction fails yfs_task_q tables lock_id column value will be incremented by 1 and AvailableDate = sysdate + 4 hours (try after 4 hours; configurable)
- If some one confirms the draft order (By calling API or from screen), from ON_SUCCESS event need to invoke manageTaskQueue API to clear the YFS_Task_Q table record
- In the above example deleteOrder API cleans the records from YFS_TASK_Q table automatically. if not we should implement registerProcessCompletion or manageTaskQueue API to clear the record.
1 2 3 4 5 6 7 8 9 10 |
private Document registerProcessCompletion(YFSEnvironment env, String taskQKey) throws YFSException, RemoteException, Exception { return getApi().registerProcessCompletion(env, createRegisterProcessCompletionInput(taskQKey)); } private Document createRegisterProcessCompletionInput(String taskQKey) { YFCDocument document = YFCDocument.getDocumentFor("<RegisterProcessCompletionInput KeepTaskOpen='N'>" + "<CurrentTask TaskQKey='" + taskQKey + "'/></RegisterProcessCompletionInput>"); return document.getDocument(); } |
If you have any question or suggestion please email to : support@activekite.com
Very Good topics after long interval of time..
Thanks Ravi. We love to update every week. But due to many reason not able to do. Will try our best to update more.
Dear Team,
I was looking for the interview questions from couple of years. Now I found very good website which has cleaned ,detailed and nice explanation. It’s very easily understandable for who does not about sterling OMS basics.
Thank you so much for the interview questions.
Could you please provide some details about Sourcing and Scheduling rules.
Thank you in advance.
Suneetha,
Thanks lot for your feedback. yes for sure will add more details on sourcing and scheduling. First we are trying to over the basic before going to advanced
topics. if any specific question please write to support@activekite.com
Thanks
can you Please provide import com.oms94.util.XMLUtil i.e XMLUtil.java also. Please?
XMLUtil can be found from following post
http://activekite.com/2017/09/11/sterling-oms-how-to-use-junit-and-code-coverage/
Please let me know if any method missing in this java file. Will update and share with you.
Thanks
Thanks for update , i have got it on below path..
Thanks Ravi for the update. You are one person who try to do all my blogs. Thanks lot for that. Just email us if any place need more clarity we will help you. Thanks again for all your support.
What is Sterling Agent and Integration server architecture ?
Praveen,
Below link has the details on agent vs integration server.
http://activekite.com/2017/05/18/agent-vs-integration-server-ibm-oms/
and also we have shared one PDF document to your email for more detailed information. Hope this helps !!!
Thanks for the Update. That is really helpful.
I have another doubt related to Hang Off Table.
Suppose we have created a Hang Off table (EG: ABC_HANG_ORDER_HDR) having parent YFS_ORDER_HEADER table.
Is it possible to get HangOff table data using standard API call like getOrderDetails? If so how to do that?
Lets approach this by considering the hang-off table EXTN_ITEM_ACTIVATION which has the parent YFS_ORDER_HEADER. Assuming that AUDITREQUIRED is ‘N’ in the extensions.xml for this hang-off table. If we want to insert records in the hang-off table while the order is created i.e while createOrder API is invoked then we can pass the below XML to the createOrder API: In the above XML please note that the hang-off table attributes are present under EXTN element. After the XML is passed to the createOrder API, we can see that corresponding records are inserted in the Order related tables as well as the EXTN_ITEM_ACTIVATION table. Similarly, if we want to make any changes to the values in EXTN_ITEM_ACTIVATION table, we can do it by passing relevant XML to changeOrder API : At the Order level, we pass the Order Header Key for reference. At the EXTN level, we pass the value that we want to modify. Here we are trying to modify the earlier Serial_Number to a new value i.e 1111.
with Services :-
To insert/modify/getDetails/getList/delete data to/from the hang-off table, we can use services as extended Database APIs cannot be called directly. If we insert data to EXTN_ITEM_ACTIVATION table by invoking service configured for createEXTNItemActivation API from HTTP API Tester, we can pass the sample xml generated from the command below: sci_ant.sh -Dtable=EXTN_ITEM_ACTIVATION -f templateXmlGen.xml This will insert the corresponding record in EXTN_ITEM_ACTIVATION table. Now to modify this record we can call a service which in turn invokes modifyEXTNItemActivation API. This will audit no records in yfs_order_audit and yfs_order_audit_detail table. If the Auditrequired is ‘Y’ in the Extensions.xml, then the audits will be recorded in the yfs_audit table else not.
Thanks for the information Ravi.
But if possible please let me know the sample template format in case we need to make getOrderDetails/getOrderList call to retrieve records from hang off table.
As per the above mentioned details it should be in the format like
Kindly correct me if I miss understood.
Thanks
can you give me more examples of Non task Q agents other than RTAM?
Example 1: Assume any custom table needs purge process (No connection with pipeline), we need to implement as non-task-q based.
Example 2: Purges – After inventory Sync clear out data that may be discarded after having been processed. Example SUPPLYTEMPPRG
Hi
Can we purge a custom standalone table in sterling. How we will set up the purge agent for this?
Varun,
Yes we can create purge for custom table. In this case we need to implement non task-q based agent. Need to implement getJob() and executeJobs() method to achieve the same. Soon we will try to come with example for this. Hope helps. Happy learning.
Actually i was posted template here but not populating Please sent provide email is , i will sent you on it.
Ravi XML getting filtered. Please share with me directly.
Genarte the template sci_ant.sh -Dtable=EXTN_ITEM_ACTIVATION -f templateXmlGen.xml
Hi ravi,
I tried this but getting below error, please suggest what I should do…
[sterling@ip-10-156-0-211 bin]$ ./sci_ant.sh -Dtable=MS_INVENTORY_AVAILABLE_CHANGE -f templateXmlGen.xml
Buildfile: /opt/IBM/bin/templateXmlGen.xml
init:
[mkdir] Created dir: /opt/IBM/extn/sampleXML
verifyTable:
xmlGen:
samplexmlgen:
BUILD FAILED
/opt/IBM/bin/templateXmlGen.xml:17: The following error occurred while executing this line:
/opt/IBM/bin/templateXmlGen.xml:37: java.lang.NullPointerException
at java.util.Hashtable.hash(Hashtable.java:147)
at java.util.Hashtable.get(Hashtable.java:617)
at java.util.PropertyResourceBundle.handleGetObject(PropertyResourceBundle.java:151)
at java.util.ResourceBundle.getObject(ResourceBundle.java:414)
at com.ibm.icu.impl.ResourceBundleWrapper.handleGetObject(ResourceBundleWrapper.java:47)
at java.util.ResourceBundle.getObject(ResourceBundle.java:414)
at java.util.ResourceBundle.getString(ResourceBundle.java:435)
Team,
We are also getting same error. We are looking for solution for this problem. Does any found solution for this issue ? Please let us know
Regards
Active Kite Admin
I can understand that this topic is about task q based where it will put an entry in task q table, either through oob transaction or manually created task q based custom agents.
What about non task q based agent –> i just know it will not put in task q table so that next transaction in the pipeline is not dependent on the parent transaction. So can you please tell me about this.
In java class you need to extend YCPBaseAgent which ask you to override getJobs() and executeJob(Document doc)
As part of getJob() method we write logic to fetch records to be processed and executeJob will process the records. Let say if you want to perform purge for custom table
getJob() — based on the number of days records to keep fetch record and return List
executeJob() — will be called with single Document object, here user has to call api to purge
Hope this help. Soon will try to get post with example. Thanks. Keep learning
How to implement synchronization on a particular table in Sterling.
Ex: I have 5 different intergration servers, which insert record in a particular table. How can I make sure at a time, only integration server, can insert record in the table. Without using NO_WAIT on table.
Hi
I wanted to clear my following concept :
1. What happens in the background while buiding EAR? I.e what gets build and re-included in EAR? why is there a need to build the same? The changes in which folder makes it necessary to build EAR
Does it re-build jar folder,resources,entity or what?
Please help 🙂
THANKS
Hi
We use following comments
To build EAR file : creates properties.jar file and uses resources.jar and entities.jar part of EAR (Created by other commands)
buildear.cmd -Dappserver=weblogic -Dwarfiles=smcfs -Dearfile=smcfs.ear -Dnowebservice=true -Ddevmode=true -Dnodocear=true -Dwls-10=true create-ear
here create-ear is ant target name
To build resource jar : Resource jar build required when change happened in template or resource folder. By default resource jar build happens when entity build requested.
deployer.cmd -t resourcejar
To build entity jar : Entity build required only when you make change related to database.
deployer.cmd -t entitydeployer
To update sandbox.cfg change config
setupfiles.cmd
Hope this helps !!! Keep Learning.
Please help me understand architecture in case of multi threaded agent. How does a thread pick up a message from Q. How do we avoid 2 threads to pick same message from Q. How do we avoid such a conflict.
Thanks
Ankit,
This is very good question. Question you asked need real good discussion. But will try to explain here
1. In OMS we have agent server / Integration server (both supports multi thread and multi instance)
2. Integration server : when started with multi thread (Thread count = 5), 5 listeners will be attached to the queue.listeners will read one message at time parallel. So there no way same message can be picked.
3. In case agent server we have 2 types TaskQ and NonTaskQ
4. In TaskQ we will have executeJob() method
5. In NonTaskQ we will have getJobs() and executeJob()
6. Here getJobs() is single thread because DB lock on yfs_object_lock table
7. executeJob() is multi threaded
This is very high level. If you need more details, please let us know. we can connect and discuss. Thanks
I also had a similar question. Could you please send me the details ?