private static class IncrementalUpdateCriteria implements PartBuilder {
    Date lastUpdate;
    SimpleDateFormat dateFormat = JsonUtils.createDateTimeFormat();

    public IncrementalUpdateCriteria(Date lastUpdate) {
      this.lastUpdate = lastUpdate;
    }

    public String getPart() {
      String part = "";
      part +=
          " $$$$updated>'"
              + (lastUpdate == null
                  ? dateFormat.format(new Date(0))
                  : dateFormat.format(lastUpdate))
              + "' ";
      if (lastUpdate == null) {
        part += "OR (1=1) ";
      }
      return part;
    }
  }
  @Override
  protected List<Map<String, Object>> getData(
      Map<String, String> parameters, int startRow, int endRow) {
    // creation of formats is done here because they are not thread safe
    final SimpleDateFormat xmlDateFormat = JsonUtils.createDateFormat();
    final SimpleDateFormat xmlDateTimeFormat = JsonUtils.createDateTimeFormat();
    final List<Map<String, Object>> result = new ArrayList<Map<String, Object>>();

    String selectorId = parameters.get(SelectorConstants.DS_REQUEST_SELECTOR_ID_PARAMETER);

    if (StringUtils.isEmpty(selectorId)) {
      return result;
    }

    OBContext.setAdminMode();
    try {

      Selector sel = OBDal.getInstance().get(Selector.class, selectorId);
      List<SelectorField> fields =
          OBDao.getActiveOBObjectList(sel, Selector.PROPERTY_OBUISELSELECTORFIELDLIST);

      // Forcing object initialization to prevent LazyInitializationException in case session is
      // cleared when number of records is big enough
      Hibernate.initialize(fields);

      // Parse the HQL in case that optional filters are required
      String HQL = parseOptionalFilters(parameters, sel, xmlDateFormat);

      String sortBy = parameters.get("_sortBy");
      HQL += getSortClause(sortBy, sel);

      Query selQuery = OBDal.getInstance().getSession().createQuery(HQL);
      String[] queryAliases = selQuery.getReturnAliases();
      if ("true".equals(parameters.get(JsonConstants.NOCOUNT_PARAMETER))) {
        int totalRows = 0, queryListSize = 0, clearEachLoop = 100;
        // Defaulted to endRow + 2 to check for more records while scrolling.
        totalRows = endRow + 2;
        ScrollableResults queryResults = selQuery.scroll(ScrollMode.FORWARD_ONLY);
        try {
          while (queryResults.next()) {
            queryListSize++;
            if (queryListSize % clearEachLoop == 0) {
              OBDal.getInstance().getSession().clear();
            }
          }
        } finally {
          queryResults.close();
        }
        if (startRow < endRow) {
          if (queryListSize < endRow) {
            totalRows = queryListSize;
          }
          parameters.put(JsonConstants.RESPONSE_TOTALROWS, String.valueOf(totalRows));
        }
      }

      if (startRow > 0) {
        selQuery.setFirstResult(startRow);
      }
      if (endRow > startRow) {
        selQuery.setMaxResults(endRow - startRow + 1);
      }

      for (Object objResult : selQuery.list()) {
        final Map<String, Object> data = new LinkedHashMap<String, Object>();
        Object[] resultList = new Object[1];
        if (objResult instanceof Object[]) {
          resultList = (Object[]) objResult;
        } else {
          resultList[0] = objResult;
        }

        for (SelectorField field : fields) {
          // TODO: throw an exception if the display expression doesn't match any returned alias.
          for (int i = 0; i < queryAliases.length; i++) {
            if (queryAliases[i].equals(field.getDisplayColumnAlias())) {
              Object value = resultList[i];
              if (value instanceof Date) {
                value = xmlDateFormat.format(value);
              }
              if (value instanceof Timestamp) {
                value = xmlDateTimeFormat.format(value);
                value = JsonUtils.convertToCorrectXSDFormat((String) value);
              }
              data.put(queryAliases[i], value);
            }
          }
        }
        result.add(data);
      }
    } finally {
      OBContext.restorePreviousMode();
    }
    return result;
  }