Infinite loop in a setValue of a Groovy Script

Hi Everyone,

After a long time I got succes in the groovy script below and now it is setting a value at the Sites tab as I would like. But, when I add a second line (site) at the site tab it is causing an infinite loop and I can´t figure out why. Could anyone help me to fix this loop?

Please see the script below:

import com.agile.agileDSL.ScriptObj.IBaseScriptObj;
import com.agile.agileDSL.ScriptObj.AgileDSLException;

// add other import statements here
import com.agile.api.ItemConstants;
import com.agile.api.CommonConstants;
import com.agile.api.IRow;
import com.agile.api.IItem;
import com.agile.api.IDataObject;
import com.agile.api.ITable;
import com.agile.px.IUpdateTableEventInfo;
import com.agile.px.IEventInfo;
import com.agile.api.IAgileSession;
import com.agile.px.EventConstants;

void invokeScript(IBaseScriptObj obj) {
//script body starts here.

//loop the AI table
IAgileSession session = obj.getAgileSDKSession();
IEventInfo req = obj.getPXEventInfo();

try {
int eventType=req.getEventType();
int triggerType=req.getEventTriggerType();

//The PX is only applicable for post update event
if(eventType!=EventConstants.EVENT_UPDATE_TABLE || triggerType!=EventConstants.EVENT_TRIGGER_POST)
return;

IUpdateTableEventInfo info=(IUpdateTableEventInfo)req;
IDataObject iProd = info.getDataObject();
ITable tab = iProd.getTable(ItemConstants.TABLE_BOM);

Iterator iter = tab.iterator();

while (iter.hasNext()) {
IRow row=(IRow)iter.next();

Object ItemTypeObj = obj.getValueByAttId(ItemConstants.ATT_TITLE_BLOCK_ITEM_TYPE);
String ItemType = ItemTypeObj == null? “” : ItemTypeObj.toString();
obj.logMonitor(ItemType);

Object ItemTypeBOMObj = row.getValue(ItemConstants.ATT_BOM_ITEM_TYPE);
String ItemTypeBOM = ItemTypeBOMObj == null? “” : ItemTypeBOMObj.toString();
obj.logMonitor(ItemTypeBOM);

Object ItemNumberjob = row.getValue(ItemConstants.ATT_BOM_ITEM_NUMBER);
String ItemNumber = ItemNumberjob == null? “” : ItemNumberjob.toString();
obj.logMonitor(ItemNumber);

String ProdNumber = obj.getValueByAttId(ItemConstants.ATT_TITLE_BLOCK_NUMBER);
IItem item = (IItem) session.getObject(ItemConstants.CLASS_ITEM_BASE_CLASS, ProdNumber);
obj.logMonitor(ProdNumber);

if (ItemTypeBOM == ‘Chemical Item’){
obj.logMonitor(“IF”);
ITable tab2 = iProd.getTable(ItemConstants.TABLE_SITES);
Iterator iter2 = tab2.iterator();

while (iter2.hasNext()){
IRow rowa=(IRow)iter2.next();
// set the CI Number at Sites Tab
rowa.setValue(ItemConstants.ATT_SITES_TEXT01, ItemNumber);
obj.logMonitor(“While”);
}
}
else{
ITable tab2 = iProd.getTable(ItemConstants.TABLE_SITES);
Iterator iter2 = tab2.iterator();

while (iter2.hasNext()) {
IRow rowa=(IRow)iter2.next();
obj.logMonitor(“ELSE”);
rowa.setValue(ItemConstants.ATT_SITES_TEXT01, “N/A”);
}
}

}
}
catch (Exception e) {
e.printStackTrace();
throw new AgileDSLException(e);
} // end of try catch block
}

Thanks in advance.

Add Comment
6 Answer(s)

Infinite loops come from updating a field or table that is being monitored for an update event. For instance, triggering on the update of the description, then in the PX, updating the description. What are you triggering on? Keep in mind that Sites are a squirrelly animal. In the client when you add a site, what happens to the BOM tab?

Agile Angel Answered on November 21, 2017.
Add Comment

Hi Steve,

When I add a site for a product the script looks to items in BOM and depending on item type the script write one thing or another at an attribute on site table. According to what you said, and since the trigger is the auto update table, when I add a site to the table it auto update and the script runs. When the script run it auto update the table again and so on. Endless. The strange thing is that it occurs only at second line of the site table, for the first it works well.

So, is there a way to fix it at the script?

Just in case, the trigger Event Type is Update Table running only with a specific item (Product) and in the specific tab (sites). The trigger type is Post and it is executing Synchronous.

Thanks in advance for helping.

Agile User Answered on November 21, 2017.
Add Comment

Take a look at your overall syntax and logic of this script.  There’s some structural issues here.

As you have it, when triggered, Agile will get the item dataobject that you’re working on (iProd, in your script), then get the BOM for the item and start scanning through it.  For each item on the BOM, Agile will update the Sites table Text01 to either the BOM item or N/A, depending on if it’s a chemical item or not.  I recommend trying this asynchronously and seeing what you get because just because it’s Post doesn’t mean Agile has completely finished with the event action when starting your script.  
How many Sites do you normally have on the Sites tab?  I ask because Agile should be, as your script is written, updating each Site’s Text01 for every item on the BOM.  If you’ve got 100 items on a BOM then Agile will log entries for the 100 times it’s updating the Sites tab with N/A or the BOM item number.  I take it that’s not your goal, so try playing around with your script a bit more.

Agile Angel Answered on November 21, 2017.
Add Comment
Best answer

Matt, thanks for the inputs.

I will not have so many sites, the maximum is 10. But with your inputs I add some if inside the while and now it is working well without infinite loops.
My script is not organized well but it is working. I am sure that there is a way to simplify this code but my knowledge in codes is not enough at all… 🙂

One last improvement that I would like to do is auto-refresh the tab after running the code since everytime I add a new line at site tab I need to refresh the tab in order to have the value wrote at the attribute.

Please see below the code which is working. I keep the trigger as Post and Synchronous.

——————————————–
import com.agile.agileDSL.ScriptObj.IBaseScriptObj;
import com.agile.agileDSL.ScriptObj.AgileDSLException;

// add other import statements here
import com.agile.api.ItemConstants;
import com.agile.api.CommonConstants;
import com.agile.api.IRow;
import com.agile.api.IItem;
import com.agile.api.IDataObject;
import com.agile.api.ITable;
import com.agile.px.IUpdateTableEventInfo;
import com.agile.px.IEventInfo;
import com.agile.api.IAgileSession;
import com.agile.px.EventConstants;

void invokeScript(IBaseScriptObj obj) {
//script body starts here.

//loop the AI table
IAgileSession session = obj.getAgileSDKSession();
IEventInfo req = obj.getPXEventInfo();

try {
int eventType=req.getEventType();
int triggerType=req.getEventTriggerType();

//The PX is only applicable for post update event
if(eventType!=EventConstants.EVENT_UPDATE_TABLE || triggerType!=EventConstants.EVENT_TRIGGER_POST)
return;

IUpdateTableEventInfo info=(IUpdateTableEventInfo)req;
IDataObject iProd = info.getDataObject();
ITable tab = iProd.getTable(ItemConstants.TABLE_BOM);

Iterator iter = tab.iterator();

while (iter.hasNext()) {
IRow row=(IRow)iter.next();

// Object ItemTypeObj = obj.getValueByAttId(ItemConstants.ATT_TITLE_BLOCK_ITEM_TYPE);
// String ItemType = ItemTypeObj == null? “” : ItemTypeObj.toString();
// obj.logMonitor(ItemType);

Object ItemTypeBOMObj = row.getValue(ItemConstants.ATT_BOM_ITEM_TYPE);
String ItemTypeBOM = ItemTypeBOMObj == null? “” : ItemTypeBOMObj.toString();
// obj.logMonitor(ItemTypeBOM);

Object ItemNumberjob = row.getValue(ItemConstants.ATT_BOM_ITEM_NUMBER);
String ItemNumber = ItemNumberjob == null? “” : ItemNumberjob.toString();
// obj.logMonitor(ItemNumber);

String ProdNumber = obj.getValueByAttId(ItemConstants.ATT_TITLE_BLOCK_NUMBER);
IItem item = (IItem) session.getObject(ItemConstants.CLASS_ITEM_BASE_CLASS, ProdNumber);
// obj.logMonitor(ProdNumber);

ITable tab2 = iProd.getTable(ItemConstants.TABLE_SITES);
Iterator iter2 = tab2.iterator();

if (ItemTypeBOM == ‘Chemical Item’) {
// obj.logMonitor(“IF”);

while (iter2.hasNext()){
IRow rowa=(IRow)iter2.next();
// set the CI Number at Sites Tab
Object PCItemObj = rowa.getValue(ItemConstants.ATT_SITES_TEXT01);
String PCItem = PCItemObj;
// obj.logMonitor(“While” + “…” + PCItem + “…”);
if (PCItem == ”){
rowa.setValue(ItemConstants.ATT_SITES_TEXT01, ItemNumber);
// obj.logMonitor(“Escreveu”)
}
else {
// obj.logMonitor(“ELSE2”);
continue;
}

}
break;
}
else {

while (iter2.hasNext()) {
IRow rowa=(IRow)iter2.next();
Object PCItemObj = rowa.getValue(ItemConstants.ATT_SITES_TEXT01);
String PCItem = PCItemObj;
if (PCItem == ”){
rowa.setValue(ItemConstants.ATT_SITES_TEXT01, “N/A”);
}
else {
// obj.logMonitor(“ELSE2”);
continue;
}
}
}

}
}
catch (Exception e) {
e.printStackTrace();
throw new AgileDSLException(e);
} // end of try catch block
}
———-

Thanks again everyone for helping.

Agile User Answered on November 22, 2017.
Add Comment

Good call adding a break and continue statement – that was one of the options I thought of yesterday (because you’re telling Agile to stop iterating through the rest of the BOM once it’s found a chemical item).  
Another idea that I’ve done is to add a boolean flag to my script.  For example, up at the very top of the try block add a “boolean b = false” line just to define ‘b’ (or call the variable “boolean is_there_a_chemical_item = false” if that’s easier).  Later in your script, if the BOM is a chemical item, set b to true and break from the loop.  After the script is done iterating through the BOM, if b is true, then have Agile separately get the sites table, iterate through it, and update Text01 to the item number.  Else if after iterating though the BOM, boolean ‘b’ is still false, have Agile get the sites table, iterate through it, and update Text01 to the ‘N/A’ value.  Using this logic, Agile won’t have the infinite loop.

Agile Angel Answered on November 22, 2017.
Add Comment

It is a good idea, I will see which one works better.
Thanks for all help!

Agile User Answered on November 22, 2017.
Add Comment

Your Answer

By posting your answer, you agree to the privacy policy and terms of service.