View source | Discuss this page | Page history | Printable version   

How to Implement Polling for a model

Contents

Overview

Polling is the process where the computer or controlling device waits for an external device to check for its readiness or state, often with low-level hardware. For example, when a printer is connected via a parallel port, the computer waits until the printer has received the next character. These processes can be as minute as only reading one bit. Τhis is sometimes used synonymously with busy-wait polling. In this situation, when an I/O operation is required, the computer does nothing other than check the status of the I/O device until it is ready, at which point the device is accessed. In other words, the computer waits until the device is ready. Polling also refers to the situation where a device is repeatedly checked for readiness, and if it is not, the computer returns to a different task. Although not as wasteful of CPU cycles as busy waiting, this is generally not as efficient as the alternative to polling, interrupt-driven I/O.

In our case, we will ask for the status of each Mobile Application models(only defined as polling) messages to wait or not to continue with next task depending on the information received by the polling process.


Model definition

First of all, we need to define in our model some attributes for polling usage. See these 3 attributes to define:

Here you can see an example of a model definition:

 
      this.get('dataSyncModels').push({
        name: 'SyncTask',
        model: OB.Model.SyncTask,
        modelFunc: 'OB.Model.SyncTask',
        className: 'org.openbravo.warehouse.advancedwarehouseoperations.mobile.sync.TaskLoader',
        ...
        pollingClassName: 'org.openbravo.warehouse.advancedwarehouseoperations.mobile.sync.AWOTasksPollingHandler',
        maxAttempts: 10,
        millisecondsBetweenPollingRequests: 1000,
        ...
        criteria: {
          hasBeenProcessed: 'Y'
        },
        getIdentifier: function (model) {
          if (model && model.id) {
            return model.id;
          } else {
            return OB.I18N.getLabel('OBAWO_NoValidIdentifierForTask');
          }
        }
      });


Polling implementation Java class

We need to implement the polling execution for the mode. Each model has different polling requirements so we cannot explain exact steps to do the polling but we will explain here few tips to do a good use of the polling infrastructure.

See below an example of implementation for task polling in AWO Mobile Application:

 
public class AWOTasksPollingHandler extends MobileCoreAbstractPollingHandler {
  public static final Logger log = Logger.getLogger(AWOTasksPollingHandler.class);
 
  @Override
  protected String getFormId() {
    return OBAWO_Constants.FORM_ID;
  }
 
  @Override
  public JSONObject processPollingRequest(JSONObject jsonIn) {
    JSONObject objToReturnWrapper = new JSONObject();
    JSONObject objToReturn = new JSONObject();
    JSONArray messages;
    List<String> ids = new ArrayList<String>();
    List<String> taskIds = new ArrayList<String>();
    try {
      OBContext.setAdminMode(true);
      try {
        messages = jsonIn.getJSONArray("messages");
        for (int i = 0; i < messages.length(); i++) {
          ids.add(((JSONObject) messages.get(i)).getString("messageId"));
          JSONArray elements = ((JSONObject) messages.get(i)).getJSONArray("elements");
          for (int j = 0; j < elements.length(); j++) {
            if (((JSONObject) elements.get(j)).has("tasks")) {
              // Grouped task
              JSONArray tasks = ((JSONObject) elements.get(j)).getJSONArray("tasks");
              for (int k = 0; k < elements.length(); k++) {
                taskIds.add(((JSONObject) tasks.get(k)).getString("id"));
              }
            } else {
              // Simple task
              taskIds.add(((JSONObject) elements.get(j)).getString("id"));
            }
          }
        }
        String hqlImportEntries = "select cie.id, cie.importStatus "
            + "from C_IMPORT_ENTRY as cie where cie.id in (:ids) ";
        OBDal.getInstance().getSession().createQuery(hqlImportEntries);
        Query importEntries = OBDal.getInstance().getSession().createQuery(hqlImportEntries);
        importEntries.setParameterList("ids", ids);
 
        for (Object obj : importEntries.list()) {
          Object[] ie = (Object[]) obj;
          for (int i = 0; i < messages.length(); i++) {
            if (((JSONObject) messages.get(i)).getString("messageId").equals(ie[0])) {
              ((JSONObject) messages.get(i)).put("importStatus", ie[1]);
              ids.remove(ie[0]);
              break;
            }
          }
        }
       ...
       ...
       ...
        objToReturn.put("messages", messages);
      } catch (JSONException e1) {
        throw new OBException("Malformed Polling Request.", true);
      }
      try {
        objToReturnWrapper.put("status", 0);
        objToReturnWrapper.put("data", objToReturn);
      } catch (JSONException e) {
        throw new OBException(
            "Unknow error happened preparing response for polling request for message "
                + StringUtils.join(ids, ","), true);
      }
    } finally {
      OBContext.restorePreviousMode();
    }
    return objToReturnWrapper;
  }
}

Polling implementation client side

There are two triggers sent by polling process: pollingStarted and pollingFinished. You must implement listeners by each model to get the information or status of the messages of the polling. Here you can find the information structure for both triggers:

Here you can find an example of implementation:

 
        var callbackPollingStarted;
        callbackPollingStarted = function (response) {
          OB.MobileApp.model.off('pollingStarted', callbackPollingStarted);
          if (successCallback) {
            successCallback();
          }
        };
        //Start listening to pollingStarted
        if (OB.MobileApp.model.get('connectedToERP')) {
          OB.MobileApp.model.on('pollingStarted', callbackPollingStarted);
        } else {
          if (errorCallback) {
            errorCallback({
              exception: {
                message: ' Mobile Application is Offline'
              }
            });
          }
          return;
        }
 
        var errorMessage = OB.I18N.getLabel('OBAWO_PollingOffline');
        var callbackPollingFinished;
        var callbackOffline;
        callbackPollingFinished = function (response) {
          if (response.status === 'running') {
            OB.info('[PollRequest] Polling process is running, wait until Polling execution finish');
            return;
          }
          OB.MobileApp.model.off('pollingFinished', callbackPollingFinished);
          OB.MobileApp.model.off('change:connectedToERP', callbackOffline);
          //When we are offline Polling cannot be completed
          if (!OB.MobileApp.model.get('connectedToERP')) {
            OB.error(errorMessage);
            if (errorCallback) {
              errorCallback({
                exception: {
                  message: errorMessage
                }
              });
            }
            return;
          } else if (response.status === 'error') {
            OB.UTIL.showError(OB.I18N.getLabel('OBAWO_PollingError'));
            if (errorCallback) {
              errorCallback({
                exception: {
                  message: OB.I18N.getLabel('OBAWO_PollingError')
                }
              });
            }
            return;
          } else if (response.status === 'success') {
            if (response.errorPollingRequest.length > 0) {
              OB.error('[PollRequest] Polling process confirmed next messages as error: ' + _.map(response.errorPollingRequest.models, function (mdl) {
                return mdl.get('messageId');
              }).join(','));
            }
            if (_.any(response.successPollingRequest.models, function (mdl) {
              return mdl.get('hasoBAWOErrors');
            })) {
              //Check if there are messages in Errors while Importing window and show the message error
              var content = [{
                content: OB.I18N.getLabel('OBAWO_CheckErrorWindow'),
                style: 'padding: 10px; text-align: left;'
              }];
              _.each(response.successPollingRequest.models, function (mdl) {
                _.each(mdl.get('elements'), function (elm) {
                  if (elm.tasks) {
                    //Grouped task
                    _.each(elm.tasks, function (tsk) {
                      if (tsk.oBAWOError) {
                        content.push({
                          content: OB.I18N.getLabel('OBMOBC_Character')[1] + ' ' + tsk.oBAWOError.substring(0, 150) + '...',
                          style: 'padding-left: 30px; text-align: left; font-size:16px'
                        });
                      }
                    });
                  } else if (elm.oBAWOError) {
                    //Simple task with error
                    content.push({
                      content: OB.I18N.getLabel('OBMOBC_Character')[1] + ' ' + elm.oBAWOError.substring(0, 150) + '...',
                      style: 'padding-left: 30px; text-align: left; font-size:16px'
                    });
                  }
                });
              });
              OB.UTIL.showConfirmation.display(OB.I18N.getLabel('OBAWO_TasksErrorHeader'), content, [{
                isConfirmButton: true,
                label: OB.I18N.getLabel('OBMOBC_LblOk'),
                action: function () {
                  if (successCallback) {
                    successCallback();
                  }
                  return true;
                }
              }], {
                autoDismiss: false,
                onHideFunction: function () {
                  if (successCallback) {
                    successCallback();
                  }
                  return true;
                }
              });
            } else {
              if (successCallback) {
                successCallback();
              }
            }
          }
        };
        callbackOffline = function (response) {
          //When we are offline Polling cannot be completed
          if (!OB.MobileApp.model.get('connectedToERP')) {
            OB.MobileApp.model.off('pollingFinished', callbackPollingFinished);
            OB.MobileApp.model.off('change:connectedToERP', callbackOffline);
            OB.error(errorMessage);
            if (errorCallback) {
              errorCallback({
                exception: {
                  message: errorMessage
                }
              });
            }
            return;
          }
        };
        //Start listening to pollingFinished
        if (OB.MobileApp.model.get('connectedToERP')) {
          OB.MobileApp.model.on('pollingFinished', callbackPollingFinished);
          OB.MobileApp.model.on('change:connectedToERP', callbackOffline);
        } else {
          OB.error(errorMessage);
          if (noPollingCallback) {
            noPollingCallback();
          }
          return;
        }

Retrieved from "http://wiki.openbravo.com/wiki/How_to_Implement_Polling_for_a_model"

This page has been accessed 1,481 times. This page was last modified on 28 March 2018, at 08:50. Content is available under Creative Commons Attribution-ShareAlike 2.5 Spain License.