Complex tuples have fields which are tuples, lists, lists of tuples, lists of lists, and more complex combinations to any depth.
You may modify any tuple field directly. However, if you need to modify a list (by adding, reordering, or removing an index), you must instead make a copy of that list, make your changes to the copied list, and then update the parent tuple's list field using Tuple.setList().
Consider this example:
1) Task: Modify portfolio.holdings.transform.dbls values by multiplying all double values by a scaling factor.
2) The custom function implementation:
package com.sb.support;
import java.util.ArrayList;
import java.util.List;
import com.streambase.sb.CompleteDataType;
import com.streambase.sb.Tuple;
import com.streambase.sb.TupleException;
import com.streambase.sb.client.CustomFunctionResolver;
public class ModifyUtils {
@SuppressWarnings("unchecked")
@CustomFunctionResolver("doModCustomFunctionResolver0")
public static Tuple doMod(Tuple arg0, Double arg1) {
//Modify portfolioSch.holdings.transform.dbls (multiply all double values by a scaling factor)
try {
// Don't modify an empty list field
if (!arg0.isNull("holdings")) {
List<Tuple> holdings = (List<Tuple>) arg0.getList("holdings");
(c1) for (int ind_holdings = 0; ind_holdings<holdings.size(); ind_holdings++) {
// Don't modify null elements and Don't modify an empty list field
if ((holdings.get(ind_holdings) != null) && (!holdings.get(ind_holdings).isNull("transform"))) {
List<Tuple> transforms = (List<Tuple>) holdings.get(ind_holdings).getList("transform");
(c2) for (int ind_transforms = 0; ind_transforms<transforms.size(); ind_transforms++) {
// Don't modify null elements and Don't modify an empty list field
if ((transforms.get(ind_transforms) != null) && (!transforms.get(ind_transforms).isNull("dbls"))) {
// Make modifiable copy of the list
ArrayList<Double> dbls = new ArrayList<Double>();
(b) dbls.addAll( (List<Double>) transforms.get(ind_transforms).getList("dbls") );
for (int ind_dbls = 0; ind_dbls<dbls.size(); ind_dbls++) {
// Don't modify null elements
if (dbls.get(ind_dbls) != null) {
dbls.set(ind_dbls, dbls.get(ind_dbls)*arg1);
}
} // loop
// Set the tuple field with updated value
(a) transforms.get(ind_transforms).setList("dbls", dbls);
}
} // loop through transforms elements
}
} // loop through holdings elements
}
} catch (TupleException e) {
e.printStackTrace();
} catch (NullPointerException e) {
e.printStackTrace();
}
return arg0;
}
public static CompleteDataType doModCustomFunctionResolver0(
CompleteDataType arg0, CompleteDataType arg1) {
return arg0;
}
}
Following the rule to only modify tuple fields in-place, the tuple at line
(a) (in the code snippet shown above) gets it's list field updated with a new list. This is the only place the input tuple is modified in this example.
Similarly, since changes are made to the values in a list, a duplicate of that list is created at
(b) and changes are only made to the copy which will replace the original at
(a).
To visit all instances of each outer list of tuples, we iterate at lines
(c1) and
(c2).
The outer lists do not need to be modified because the objects they point to in memory are not changed. If direct list index values need to be changed, or indexes added or removed, then the list needs to be copied following the pattern at
(b) for modifying
dbls. In addition, the parent tuple of the list would need to have
setList() called, thereby replacing the old list with the modified copy.