private HashMap<String, String[]> getCriteria(Map<String, String> parameters) {
   if (!"AdvancedCriteria".equals(parameters.get("_constructor"))) {
     return null;
   }
   try {
     JSONArray criterias = (JSONArray) JsonUtils.buildCriteria(parameters).get("criteria");
     return getCriteria(criterias);
   } catch (JSONException e) {
     return null;
   }
 }
  ResultMapCriteriaUtils(Map<String, Object> orderMap, Map<String, String> parameters) {
    JSONArray _criteriaArray = null;
    try {
      _criteriaArray = (JSONArray) JsonUtils.buildCriteria(parameters).get("criteria");
    } catch (JSONException e) {
      _criteriaArray = null;
    }
    String mainOperator = parameters.get("operator");

    this.recordMap = orderMap;
    this.criteriaArray = _criteriaArray;
    this.mainOperatorIsAnd = OPERATOR_AND.equals(mainOperator);
  }
 @Override
 protected JSONObject execute(Map<String, Object> parameters, String data) {
   JSONObject result = new JSONObject();
   JSONObject errorMessage = new JSONObject();
   try {
     OBContext.setAdminMode(true);
     final JSONObject jsonData = new JSONObject(data);
     final String strBankStatementLineId = jsonData.getString("bankStatementLineId");
     String dateStr = jsonData.getString("updated");
     SimpleDateFormat xmlDateTimeFormat = JsonUtils.createJSTimeFormat();
     Date date = null;
     try {
       date = xmlDateTimeFormat.parse(dateStr);
     } catch (ParseException e) {
     }
     final FIN_BankStatementLine bsline =
         OBDal.getInstance().get(FIN_BankStatementLine.class, strBankStatementLineId);
     Date bbddBSLUpdated = bsline.getUpdated();
     // Remove milis
     Calendar calendar = Calendar.getInstance();
     calendar.setTime(OBDateUtils.convertDateToUTC(bbddBSLUpdated));
     calendar.setLenient(true);
     calendar.set(Calendar.MILLISECOND, 0);
     if (date.getTime() != calendar.getTimeInMillis()) {
       throw new OBStaleObjectException("@APRM_StaleDate@");
     }
     final FIN_FinaccTransaction transaction = bsline.getFinancialAccountTransaction();
     if (transaction != null) {
       APRM_MatchingUtility.unmatch(bsline);
     }
   } catch (Exception e) {
     OBDal.getInstance().rollbackAndClose();
     log.error("Error Unmatching Transaction", e);
     try {
       Throwable ex = DbUtility.getUnderlyingSQLException(e);
       String message = OBMessageUtils.translateError(ex.getMessage()).getMessage();
       errorMessage = new JSONObject();
       errorMessage.put("severity", "error");
       errorMessage.put("title", "Error");
       errorMessage.put("text", message);
       result.put("message", errorMessage);
     } catch (Exception e2) {
       log.error("Message could not be built", e2);
     }
   } finally {
     OBContext.restorePreviousMode();
   }
   return result;
 }
  private void readCriteria(Map<String, String> parameters) throws JSONException {
    JSONArray criteriaArray = (JSONArray) JsonUtils.buildCriteria(parameters).get("criteria");
    selectedIds = new ArrayList<String>();
    selectedChValues = new HashMap<String, List<CharacteristicValue>>();
    nameFilter = null;
    searchKeyFilter = null;
    variantCreated = null;

    for (int i = 0; i < criteriaArray.length(); i++) {
      JSONObject criteria = criteriaArray.getJSONObject(i);
      // Basic advanced criteria handling
      if (criteria.has("_constructor")
          && "AdvancedCriteria".equals(criteria.getString("_constructor"))
          && criteria.has("criteria")) {
        JSONArray innerCriteriaArray = new JSONArray(criteria.getString("criteria"));
        criteria = innerCriteriaArray.getJSONObject(0);
      }
      String fieldName = criteria.getString("fieldName");
      // String operatorName = criteria.getString("operator");
      String value = criteria.getString("value");
      if (fieldName.equals("name")) {
        nameFilter = value;
      } else if (fieldName.equals("searchKey")) {
        searchKeyFilter = value;
      } else if (fieldName.equals("id")) {
        selectedIds.add(value);
      } else if (fieldName.equals("variantCreated")) {
        variantCreated = criteria.getBoolean("value");
      } else if (fieldName.equals("characteristicDescription")) {
        JSONArray values = new JSONArray(value);
        // All values belong to the same characteristicId, get the first one.
        String strCharacteristicId = null;
        List<CharacteristicValue> chValueIds = new ArrayList<CharacteristicValue>();
        for (int j = 0; j < values.length(); j++) {
          CharacteristicValue chValue =
              OBDal.getInstance().get(CharacteristicValue.class, values.getString(j));
          chValueIds.add(chValue);
          if (strCharacteristicId == null) {
            strCharacteristicId = (String) DalUtil.getId(chValue.getCharacteristic());
          }
        }
        selectedChValues.put(strCharacteristicId, chValueIds);
      }
    }
  }
  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;
    }
  }
class ResultMapCriteriaUtils {
  private static final String CRITERIA_KEY = "criteria";
  private static final String VALUE_KEY = "value";
  private static final String FIELD_NAME_KEY = "fieldName";
  private static final String OPERATOR_KEY = "operator";

  private static final String OPERATOR_AND = "and";
  private static final String OPERATOR_OR = "or";

  private static final String OPERATOR_EQUALS = "equals";
  private static final String OPERATOR_NOTEQUAL = "notEqual";
  private static final String OPERATOR_IEQUALS = "iEquals";
  private static final String OPERATOR_INOTEQUAL = "iNotEqual";
  private static final String OPERATOR_GREATERTHAN = "greaterThan";
  private static final String OPERATOR_LESSTHAN = "lessThan";
  private static final String OPERATOR_GREATEROREQUAL = "greaterOrEqual";
  private static final String OPERATOR_LESSOREQUAL = "lessOrEqual";
  private static final String OPERATOR_IGREATERTHAN = "iGreaterThan";
  private static final String OPERATOR_ILESSTHAN = "iLessThan";
  private static final String OPERATOR_IGREATEROREQUAL = "iGreaterOrEqual";
  private static final String OPERATOR_ILESSOREQUAL = "iLessOrEqual";
  private static final String OPERATOR_CONTAINS = "contains";
  private static final String OPERATOR_STARTSWITH = "startsWith";
  private static final String OPERATOR_ENDSWITH = "endsWith";
  private static final String OPERATOR_ICONTAINS = "iContains";
  private static final String OPERATOR_ISTARTSWITH = "iStartsWith";
  private static final String OPERATOR_IENDSWITH = "iEndsWith";
  private static final String OPERATOR_NOTCONTAINS = "notContains";
  private static final String OPERATOR_NOTSTARTSWITH = "notStartsWith";
  private static final String OPERATOR_NOTENDSWITH = "notEndsWith";
  private static final String OPERATOR_INOTCONTAINS = "iNotContains";
  private static final String OPERATOR_INOTSTARTSWITH = "iNotStartsWith";
  private static final String OPERATOR_INOTENDSWITH = "iNotEndsWith";
  // private static final String OPERATOR_REGEXP = "regexp";
  // private static final String OPERATOR_IREGEXP = "iregexp";
  private static final String OPERATOR_ISNULL = "isNull";
  private static final String OPERATOR_NOTNULL = "notNull";
  private static final String OPERATOR_INSET = "inSet";
  private static final String OPERATOR_NOTINSET = "notInSet";
  private static final String OPERATOR_EQUALSFIELD = "equalsField";
  private static final String OPERATOR_NOTEQUALFIELD = "notEqualField";
  private static final String OPERATOR_GREATERTHANFIElD = "greaterThanField";
  private static final String OPERATOR_LESSTHANFIELD = "lessThanField";
  private static final String OPERATOR_GREATEROREQUALFIELD = "greaterOrEqualField";
  private static final String OPERATOR_LESSOREQUALFIElD = "lessOrEqualField";
  private static final String OPERATOR_CONTAINSFIELD = "containsField";
  private static final String OPERATOR_STARTSWITHFIELD = "startsWithField";
  private static final String OPERATOR_ENDSWITHFIELD = "endsWithField";
  private static final String OPERATOR_NOT = "not";
  private static final String OPERATOR_BETWEEN = "between";
  private static final String OPERATOR_BETWEENINCLUSIVE = "betweenInclusive";
  private static final String OPERATOR_IBETWEEN = "iBetween";
  private static final String OPERATOR_IBETWEENINCLUSIVE = "iBetweenInclusive";
  private static final String OPERATOR_EXISTS = "exists";

  Map<String, Object> recordMap;
  JSONArray criteriaArray;
  boolean mainOperatorIsAnd;

  private int UTCServerMinutesTimeZoneDiff = 0;
  private int clientUTCMinutesTimeZoneDiff = 0;

  private SimpleDateFormat simpleDateFormat = JsonUtils.createDateFormat();
  private SimpleDateFormat simpleDateTimeFormat = JsonUtils.createJSTimeFormat();

  ResultMapCriteriaUtils(Map<String, Object> orderMap, Map<String, String> parameters) {
    JSONArray _criteriaArray = null;
    try {
      _criteriaArray = (JSONArray) JsonUtils.buildCriteria(parameters).get("criteria");
    } catch (JSONException e) {
      _criteriaArray = null;
    }
    String mainOperator = parameters.get("operator");

    this.recordMap = orderMap;
    this.criteriaArray = _criteriaArray;
    this.mainOperatorIsAnd = OPERATOR_AND.equals(mainOperator);
  }

  boolean applyFilter() throws JSONException {
    if (criteriaArray == null) {
      return true;
    }
    boolean finalResult = mainOperatorIsAnd;
    for (int i = 0; i < criteriaArray.length(); i++) {
      // Each element of the criteria array is added assuming an OR statement.
      JSONObject criteria = criteriaArray.getJSONObject(i);
      boolean critResult = parseCriteria(criteria);
      if (mainOperatorIsAnd) {
        finalResult &= critResult;
      } else {
        finalResult |= critResult;
      }
    }
    return finalResult;
  }

  private boolean parseCriteria(JSONObject jsonCriteria) throws JSONException {
    // a constructor so the content is an advanced criteria
    if (jsonCriteria.has("_constructor") || hasOrAndOperator(jsonCriteria)) {
      return parseAdvancedCriteria(jsonCriteria);
    }
    return parseSingleClause(jsonCriteria);
  }

  private boolean hasOrAndOperator(JSONObject jsonCriteria) throws JSONException {
    if (!jsonCriteria.has(OPERATOR_KEY)) {
      return mainOperatorIsAnd;
    }
    return OPERATOR_OR.equals(jsonCriteria.get(OPERATOR_KEY))
        || OPERATOR_AND.equals(jsonCriteria.get(OPERATOR_KEY));
  }

  private boolean parseSingleClause(JSONObject jsonCriteria) throws JSONException {
    String operator = jsonCriteria.getString(OPERATOR_KEY);

    if (operator.equals(OPERATOR_BETWEEN)
        || operator.equals(OPERATOR_BETWEENINCLUSIVE)
        || operator.equals(OPERATOR_IBETWEEN)
        || operator.equals(OPERATOR_IBETWEENINCLUSIVE)) {
      return parseBetween(jsonCriteria, operator, true);
    }

    Object value = jsonCriteria.has(VALUE_KEY) ? jsonCriteria.get(VALUE_KEY) : null;

    if (operator.equals(OPERATOR_EXISTS)) {
      // not supported
      return mainOperatorIsAnd;
    }

    String fieldName = jsonCriteria.getString(FIELD_NAME_KEY);

    // translate to a OR for each value
    if (value instanceof JSONArray) {
      final JSONArray jsonArray = (JSONArray) value;
      final JSONObject advancedCriteria = new JSONObject();
      advancedCriteria.put(OPERATOR_KEY, OPERATOR_OR);
      final JSONArray subCriteria = new JSONArray();
      for (int i = 0; i < jsonArray.length(); i++) {
        final JSONObject subCriterion = new JSONObject();
        subCriterion.put(OPERATOR_KEY, operator);
        subCriterion.put(FIELD_NAME_KEY, fieldName);
        subCriterion.put(VALUE_KEY, jsonArray.get(i));
        subCriteria.put(i, subCriterion);
      }
      advancedCriteria.put(CRITERIA_KEY, subCriteria);
      return parseAdvancedCriteria(advancedCriteria);
    }

    // Retrieves the UTC time zone offset of the client
    if (jsonCriteria.has("minutesTimezoneOffset")) {
      int clientMinutesTimezoneOffset =
          Integer.parseInt(jsonCriteria.get("minutesTimezoneOffset").toString());
      Calendar now = Calendar.getInstance();
      // Obtains the UTC time zone offset of the server
      int serverMinutesTimezoneOffset =
          (now.get(Calendar.ZONE_OFFSET) + now.get(Calendar.DST_OFFSET)) / (1000 * 60);
      // Obtains the time zone offset between the server and the client
      clientUTCMinutesTimeZoneDiff = clientMinutesTimezoneOffset;
      UTCServerMinutesTimeZoneDiff = serverMinutesTimezoneOffset;
    }

    if (operator.equals(OPERATOR_ISNULL) || operator.equals(OPERATOR_NOTNULL)) {
      value = null;
    }

    // if a comparison is done on an equal date then replace
    // with a between start time and end time on that date
    if (operator.equals(OPERATOR_EQUALS) || operator.equals(OPERATOR_EQUALSFIELD)) {
      Object curValue = recordMap.get(fieldName);
      if (curValue instanceof Date) {
        if (operator.equals(OPERATOR_EQUALS)) {
          return parseSimpleClause(fieldName, OPERATOR_GREATEROREQUAL, value)
              && parseSimpleClause(fieldName, OPERATOR_LESSOREQUAL, value);

        } else {
          return parseSimpleClause(fieldName, OPERATOR_GREATEROREQUALFIELD, value)
              && parseSimpleClause(fieldName, OPERATOR_LESSOREQUALFIElD, value);
        }
      }
    }

    return parseSimpleClause(fieldName, operator, value);
  }

  private boolean parseBetween(JSONObject jsonCriteria, String operator, boolean inclusive)
      throws JSONException {
    final String fieldName = jsonCriteria.getString(FIELD_NAME_KEY);
    final Object start = jsonCriteria.get("start");
    final Object end = jsonCriteria.get("end");
    final boolean leftClause =
        parseSimpleClause(fieldName, getBetweenOperator(operator, false), start);
    final boolean rightClause =
        parseSimpleClause(fieldName, getBetweenOperator(operator, true), end);
    return leftClause && rightClause;
  }

  private boolean parseSimpleClause(String fieldName, String operator, Object value)
      throws JSONException {

    String hqlOperator = getHqlOperator(operator);
    String strField = fieldName;
    boolean filterIdentifier = false;
    // if (strField.endsWith("$_identifier")) {
    // strField = strField.substring(0, strField.length() - 12);
    // filterIdentifier = true;
    // }
    Object mapValue = recordMap.get(strField);
    if (operator.equals(OPERATOR_NOTNULL)) {
      return mapValue != null;
    } else if (operator.equals(OPERATOR_ISNULL)) {
      return mapValue == null;
    }

    Object localValue = value;
    if (ignoreCase(mapValue, operator)) {
      localValue = localValue.toString().toUpperCase();
    }

    boolean returnVal = mainOperatorIsAnd;

    if ("id".equals(strField)) {
      // ID is always equals
      returnVal = mapValue != JSONObject.NULL && ((String) localValue).equals(mapValue);
    } else if (filterIdentifier) {
      BaseOBObject currentVal = (BaseOBObject) mapValue;
      String strCurrValIdentifier = currentVal.getIdentifier();
      String strCurrentFilter = (String) localValue;
      returnVal = StringUtils.containsIgnoreCase(strCurrValIdentifier, strCurrentFilter);
    } else if (mapValue instanceof Boolean) {
      returnVal = (Boolean) mapValue == (Boolean) localValue;
    } else if (mapValue instanceof BigDecimal) {
      BigDecimal filterValue = new BigDecimal((Integer) localValue);
      int compare = filterValue.compareTo((BigDecimal) mapValue);
      if ("=".equals(hqlOperator)) {
        returnVal = compare == 0;
      } else if ("!=".equals(hqlOperator)) {
        returnVal = compare != 0;
      } else if (">".equals(hqlOperator)) {
        returnVal = compare > 0;
      } else if (">=".equals(hqlOperator)) {
        returnVal = compare >= 0;
      } else if ("<".equals(hqlOperator)) {
        returnVal = compare < 0;
      } else if ("<=".equals(hqlOperator)) {
        returnVal = compare <= 0;
      }

    } else if (mapValue instanceof Date) {
      try {
        Date filterValue;
        try {
          filterValue = simpleDateTimeFormat.parse(localValue.toString());
        } catch (ParseException e) {
          // When a DateTime column is filtered, plan Date values are used
          // See issue https://issues.openbravo.com/view.php?id=23203
          filterValue = simpleDateFormat.parse(localValue.toString());
        }
        final Calendar calendar = Calendar.getInstance();
        calendar.setTime(filterValue);
        // Applies the time zone offset difference of the client
        calendar.add(Calendar.MINUTE, clientUTCMinutesTimeZoneDiff);
        // move the date to the beginning of the day
        if (isGreaterOperator(operator)) {
          calendar.set(Calendar.HOUR, 0);
          calendar.set(Calendar.MINUTE, 0);
          calendar.set(Calendar.SECOND, 0);
          calendar.set(Calendar.MILLISECOND, 0);
        } else if (isLesserOperator(operator)) {
          // move the data to the end of the day
          calendar.set(Calendar.HOUR, 23);
          calendar.set(Calendar.MINUTE, 59);
          calendar.set(Calendar.SECOND, 59);
          calendar.set(Calendar.MILLISECOND, 999);
        }
        // Applies the time zone offset difference of the server
        calendar.add(Calendar.MINUTE, -UTCServerMinutesTimeZoneDiff);
        Date mapDate = (Date) mapValue;
        boolean isBefore = mapDate.before(calendar.getTime());
        boolean isAfter = mapDate.after(calendar.getTime());
        boolean sameDate = mapDate.compareTo(calendar.getTime()) == 0;
        if ("=".equals(hqlOperator)) {
          returnVal = sameDate;
        } else if ("!=".equals(hqlOperator)) {
          returnVal = !sameDate;
        } else if (">".equals(hqlOperator)) {
          returnVal = isAfter;
        } else if (">=".equals(hqlOperator)) {
          returnVal = isAfter || sameDate;
        } else if ("<".equals(hqlOperator)) {
          returnVal = isBefore;
        } else if ("<=".equals(hqlOperator)) {
          returnVal = isBefore || sameDate;
        }
      } catch (Exception e) {
        throw new IllegalArgumentException(e);
      }
    } else if (mapValue instanceof String) {
      String strCurrentValue = (String) mapValue;
      String strCurrentFilter = (String) localValue;
      returnVal = StringUtils.containsIgnoreCase(strCurrentValue, strCurrentFilter);
    }

    if (isNot(operator)) {
      return !returnVal;
    } else {
      return returnVal;
    }
  }

  private boolean isGreaterOperator(String operator) {
    return operator != null
        && (operator.equals(OPERATOR_GREATERTHAN)
            || operator.equals(OPERATOR_GREATEROREQUAL)
            || operator.equals(OPERATOR_IGREATERTHAN)
            || operator.equals(OPERATOR_IGREATEROREQUAL)
            || operator.equals(OPERATOR_GREATERTHANFIElD)
            || operator.equals(OPERATOR_GREATEROREQUALFIELD));
  }

  private boolean isLesserOperator(String operator) {
    return operator != null
        && (operator.equals(OPERATOR_LESSTHAN)
            || operator.equals(OPERATOR_LESSOREQUAL)
            || operator.equals(OPERATOR_ILESSTHAN)
            || operator.equals(OPERATOR_ILESSOREQUAL)
            || operator.equals(OPERATOR_LESSTHANFIELD)
            || operator.equals(OPERATOR_LESSOREQUALFIElD));
  }

  private boolean parseAdvancedCriteria(JSONObject advancedCriteria) throws JSONException {
    final String operator = advancedCriteria.getString(OPERATOR_KEY);
    if (operator.equals(OPERATOR_NOT)) {
      final boolean clause =
          parseStructuredClause(advancedCriteria.getJSONArray(CRITERIA_KEY), OPERATOR_OR);
      return !clause;
    }
    if (operator.equals(OPERATOR_AND)) {
      return parseStructuredClause(advancedCriteria.getJSONArray(CRITERIA_KEY), OPERATOR_AND);
    }
    if (operator.equals(OPERATOR_OR)) {
      final boolean value =
          parseStructuredClause(advancedCriteria.getJSONArray(CRITERIA_KEY), OPERATOR_OR);
      return value;
    }
    return parseSingleClause(advancedCriteria);
  }

  private boolean parseStructuredClause(JSONArray clauses, String hqlOperator)
      throws JSONException {
    boolean doOr = OPERATOR_OR.equals(hqlOperator);
    boolean doAnd = OPERATOR_AND.equals(hqlOperator);
    for (int i = 0; i < clauses.length(); i++) {
      final JSONObject clause = clauses.getJSONObject(i);
      if (clause.has(VALUE_KEY)
          && clause.get(VALUE_KEY) != null
          && clause.getString(VALUE_KEY).equals("")) {
        continue;
      }
      final boolean clauseResult = parseCriteria(clause);
      if (doOr && clauseResult) {
        return true;
      }
      if (doAnd && !clauseResult) {
        return false;
      }
    }
    if (doOr) {
      return false;
    } else if (doAnd) {
      return true;
    }
    return mainOperatorIsAnd;
  }

  private String getBetweenOperator(String operator, boolean rightClause) {
    if (operator.equals(OPERATOR_IBETWEEN)) {
      if (rightClause) {
        return OPERATOR_ILESSTHAN;
      } else {
        return OPERATOR_IGREATERTHAN;
      }
    }
    if (operator.equals(OPERATOR_BETWEEN)) {
      if (rightClause) {
        return OPERATOR_LESSTHAN;
      } else {
        return OPERATOR_GREATERTHAN;
      }
    }
    if (operator.equals(OPERATOR_IBETWEENINCLUSIVE)) {
      if (rightClause) {
        return OPERATOR_ILESSOREQUAL;
      } else {
        return OPERATOR_IGREATEROREQUAL;
      }
    }
    if (operator.equals(OPERATOR_BETWEENINCLUSIVE)) {
      if (rightClause) {
        return OPERATOR_LESSOREQUAL;
      } else {
        return OPERATOR_GREATEROREQUAL;
      }
    }
    throw new IllegalArgumentException("Operator not supported " + operator);
  }

  private boolean ignoreCase(Object mapValue, String operator) {
    if (mapValue instanceof BigDecimal || mapValue instanceof Date) {
      return false;
    }
    return operator.equals(OPERATOR_IEQUALS)
        || operator.equals(OPERATOR_INOTEQUAL)
        || operator.equals(OPERATOR_CONTAINS)
        || operator.equals(OPERATOR_ENDSWITH)
        || operator.equals(OPERATOR_STARTSWITH)
        || operator.equals(OPERATOR_ICONTAINS)
        || operator.equals(OPERATOR_INOTSTARTSWITH)
        || operator.equals(OPERATOR_INOTENDSWITH)
        || operator.equals(OPERATOR_NOTSTARTSWITH)
        || operator.equals(OPERATOR_NOTCONTAINS)
        || operator.equals(OPERATOR_INOTCONTAINS)
        || operator.equals(OPERATOR_NOTENDSWITH)
        || operator.equals(OPERATOR_IENDSWITH)
        || operator.equals(OPERATOR_ISTARTSWITH)
        || operator.equals(OPERATOR_IBETWEEN)
        || operator.equals(OPERATOR_IGREATEROREQUAL)
        || operator.equals(OPERATOR_ILESSOREQUAL)
        || operator.equals(OPERATOR_IGREATERTHAN)
        || operator.equals(OPERATOR_ILESSTHAN)
        || operator.equals(OPERATOR_IBETWEENINCLUSIVE);
  }

  private boolean isNot(String operator) {
    return operator.equals(OPERATOR_NOTCONTAINS)
        || operator.equals(OPERATOR_NOTENDSWITH)
        || operator.equals(OPERATOR_NOTSTARTSWITH)
        || operator.equals(OPERATOR_INOTCONTAINS)
        || operator.equals(OPERATOR_INOTENDSWITH)
        || operator.equals(OPERATOR_INOTSTARTSWITH)
        || operator.equals(OPERATOR_NOT)
        || operator.equals(OPERATOR_NOTINSET);
  }

  private String getHqlOperator(String operator) {
    if (operator.equals(OPERATOR_EQUALS)) {
      return "=";
    } else if (operator.equals(OPERATOR_INSET)) {
      return "in";
    } else if (operator.equals(OPERATOR_NOTINSET)) {
      return "in";
    } else if (operator.equals(OPERATOR_NOTEQUAL)) {
      return "!=";
    } else if (operator.equals(OPERATOR_IEQUALS)) {
      return "=";
    } else if (operator.equals(OPERATOR_INOTEQUAL)) {
      return "!=";
    } else if (operator.equals(OPERATOR_GREATERTHAN)) {
      return ">";
    } else if (operator.equals(OPERATOR_LESSTHAN)) {
      return "<";
    } else if (operator.equals(OPERATOR_GREATEROREQUAL)) {
      return ">=";
    } else if (operator.equals(OPERATOR_LESSOREQUAL)) {
      return "<=";
    } else if (operator.equals(OPERATOR_IGREATERTHAN)) {
      return ">";
    } else if (operator.equals(OPERATOR_ILESSTHAN)) {
      return "<";
    } else if (operator.equals(OPERATOR_IGREATEROREQUAL)) {
      return ">=";
    } else if (operator.equals(OPERATOR_ILESSOREQUAL)) {
      return "<=";
    } else if (operator.equals(OPERATOR_CONTAINS)) {
      return "like";
    } else if (operator.equals(OPERATOR_STARTSWITH)) {
      return "like";
    } else if (operator.equals(OPERATOR_ENDSWITH)) {
      return "like";
    } else if (operator.equals(OPERATOR_ICONTAINS)) {
      return "like";
    } else if (operator.equals(OPERATOR_ISTARTSWITH)) {
      return "like";
    } else if (operator.equals(OPERATOR_IENDSWITH)) {
      return "like";
    } else if (operator.equals(OPERATOR_NOTCONTAINS)) {
      return "like";
    } else if (operator.equals(OPERATOR_NOTSTARTSWITH)) {
      return "like";
    } else if (operator.equals(OPERATOR_NOTENDSWITH)) {
      return "like";
    } else if (operator.equals(OPERATOR_INOTCONTAINS)) {
      return "like";
    } else if (operator.equals(OPERATOR_INOTSTARTSWITH)) {
      return "like";
    } else if (operator.equals(OPERATOR_INOTENDSWITH)) {
      return "like";
    } else if (operator.equals(OPERATOR_EQUALSFIELD)) {
      return "=";
    } else if (operator.equals(OPERATOR_NOTEQUALFIELD)) {
      return "!=";
    } else if (operator.equals(OPERATOR_GREATERTHANFIElD)) {
      return ">";
    } else if (operator.equals(OPERATOR_LESSTHANFIELD)) {
      return "<";
    } else if (operator.equals(OPERATOR_GREATEROREQUALFIELD)) {
      return ">=";
    } else if (operator.equals(OPERATOR_LESSOREQUALFIElD)) {
      return "<=";
    } else if (operator.equals(OPERATOR_CONTAINSFIELD)) {
      return "like";
    } else if (operator.equals(OPERATOR_STARTSWITHFIELD)) {
      return "like";
    } else if (operator.equals(OPERATOR_ENDSWITHFIELD)) {
      return "like";
    } else if (operator.equals(OPERATOR_ISNULL)) {
      return "is";
    } else if (operator.equals(OPERATOR_NOTNULL)) {
      return "is not";
    } else if (operator.equals(OPERATOR_EXISTS)) {
      return "exists";
    }
    // todo throw exception
    return null;
  }
}
  @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;
  }