Help For Navigating Lists

  • When working with the Interstage BPM API, there are three kinds of lists you might need to use: lists of process definitions, lists of process instances, and lists of work items.  All of these are considered WFObjects and you get them all from a WFObject list.


    The pattern is that you specify filter criteria to specify exactly what you want to retrieve.  Then you ask for the list.  From the list object, you retrieve items in batches of up to 100.  When done with a batch, fetch the next batch.  This allows you to retrieve any endless number of objects without requiring that they all be in memory at the same time.


    Working batch by batch can be difficult because you have to remember your place in the current batch, and then fetch the next batch at the right time.  If you want to just process all the objects sequentially, this bookkeeping can be complicated.


    So we created the WFObject stream object.  This work like the list, except that it returns object (either process definitino, process instance, or workitem) an object at a time.  It gets a batch, and it remembers where you are in the batch, and it requests additional batches.  It makes the batch oriented API look like a stream of individual objects, however it is faster than retrieving each object in a batch of one record at a time.


    The entire class is given below.  It is a template-style JAva class whichmeans you can declare it for Plan (process definition) and the methods will return the right type without having to case all over the place.  


    You set up the filter and sort using addFilter and addSortOrder.  When ready, call open.  Then you make a loop that tests hasMore and then nextItem returns the next object from the stream, one at a time.  Don't forget to call close at the end.


    It works on the normal Interstage BPM Model API, but it just does the bookkeeping to keep track of where you are, so you can get the object one at a time in the right order.






    package com.yourcompany.yourproject;


    public class WFObjectStream {
        private WFObjectList     list;
        private Object[]         buffer;
        private static final int BATCH_SIZE = 100;
        private int              posInBatch = 0;
        private boolean          finished   = false;
        private int              planFilter;
        private int              requestedOffset = 0;
        private int              requestedBatch  = 100;
        public WFObjectStream(WFSession wfSession, int _planFilter) {
            list = WFObjectFactory.getWFObjectList(wfSession);
            planFilter = _planFilter;

         * When the list has been set up properly, then call open in
         * order to actually start to get the objects.
        public void open() throws Exception {
            //actually open the stream
            //automatically skip the offset records

        public void addFilter(int fieldCode, String sqlOp, String searchValue) throws Exception {
            list.addFilter(fieldCode, sqlOp, searchValue);
        public void addFilter(String udaName, String udaType, String sqlOp, String searchValue) throws Exception {
            list.addFilter(udaName, udaType, sqlOp, searchValue);
        public void addSortOrder(String udaName, String udaType, boolean sortOrder) throws Exception {
            list.addSortOrder(udaName, udaType, sortOrder);
        public void addSortOrder(int fieldCode, boolean sortOrder) throws Exception {
            list.addSortOrder(fieldCode, sortOrder);
        public void close() throws Exception {
            finished = true;
        public boolean hasMore() throws Exception {
            if (finished) {
                return false;
            if (buffer==null || posInBatch>=buffer.length) {
                buffer = list.getNextBatch(BATCH_SIZE);
                posInBatch = 0;
                //now detect .... are we done?
                if (buffer==null) {
                    finished = true;
                    return false;
                else if (buffer.length==0) {
                    buffer = null;
                    finished = true;
                    return false;
            return true;
        public T nextItem() throws Exception {
            if (!hasMore()) {
                return null;
            T resOb = (T) buffer[posInBatch];
            return resOb;

         * In the filter set, the user can set to skip a number of records from the
         * beginning of the result set.  This is called the 'batchOffset' in the
         * filter JSON structure.   
         * This method just gets and throws away the number of objects specified in
         * the requested batch offset.
        public void skipOffset() throws Exception {
            int numLeft = requestedOffset;
            while (hasMore() && numLeft>0) {
            //now cancel it so it can not be done twice
            requestedOffset = 0;
        public int getBatchSize() {
            return requestedBatch;