Utils.java [src/java/crlmod/utils] Revision: 48aaed8602436603ea9a206f89b1638ea8da959d  Date: Wed Nov 29 16:18:31 MST 2023
/*
 * $Id$
 *
 * This file is part of the Cloud Services Integration Platform (CSIP),
 * a Model-as-a-Service framework, API, and application suite.
 *
 * 2012-2022, OMSLab, Colorado State University.
 *
 * OMSLab licenses this file to you under the MIT license.
 * See the LICENSE file in the project root for more information.
 */
package crlmod.utils;

import static crlmod.ServiceResources.*;
import csip.api.server.PayloadParameter;
import csip.api.server.ServiceException;
import csip.SessionLogger;
import java.io.StringWriter;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.List;
import java.util.logging.Level;
import javax.xml.transform.OutputKeys;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.exception.ExceptionUtils;
import org.codehaus.jettison.json.JSONException;
import org.w3c.dom.Document;

/**
 *
 * @author LYaege
 */
public class Utils {

  public static String getTime() {
    SimpleDateFormat sdf = new SimpleDateFormat("HH:mm:ss");
    return sdf.format(Calendar.getInstance().getTime());
  }


  public static boolean isNumeric(String str) {
    return str.matches("-?\\d+(\\.\\d+)?");  //match a number with optional '-' and decimal.
  }


  public static boolean isPositiveReal(String str) {
    return str.matches("\\d+");  //match a number with optional '-' and decimal.
  }


  /**
   * Converts unit input to a standardized unit for example "Bushels" will
   * return 'bu.'
   *
   * @param unit The string that represents the harvest unit to be standardized
   * @return The string the represents the standardized harvest unit.
   */
  public static String norm_harv_units(String unit) {
    if (unit.contains("Bushels") || unit.contains("bu")) {
      return "bu.";
    }
    if (unit.contains("Cords")) {
      return "cords";
    }
    if (unit.contains("tons sugar") || unit.contains("Ton")) {
      return "tons";
    }
    if (unit.contains("box")) {
      return "boxes";
    }
    if (unit.contains("lb") || unit.contains("pounds")) {
      return "lbs";
    }
    if (unit.contains("Bundles")) {
      return "Bdl";
    }
    return unit;
  }


  /**
   *
   * @param doc
   * @return
   */
  public static String getStringFromDocument(Document doc) {
    try {
      DOMSource domSource = new DOMSource(doc);
      StringWriter writer = new StringWriter();
      StreamResult result = new StreamResult(writer);
      TransformerFactory tf = TransformerFactory.newInstance();
      Transformer transformer = tf.newTransformer();
      transformer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "yes");
      transformer.transform(domSource, result);
      return writer.toString();
    } catch (TransformerException ex) {
      ExceptionUtils.printRootCauseStackTrace(ex);
      return null;
    }
  }


  /**
   *
   * @param params
   * @param object_key
   * @param object_name
   * @param map
   * @param LOG
   * @return
   * @throws JSONException
   * @throws ServiceException
   */
  public static String createWhere(List<String> params,
      String object_key, String object_name,
      PayloadParameter map,
      SessionLogger LOG)
      throws JSONException, ServiceException {

    String where = "WHERE 1=1 \n";

    //ID***************************************************
    String[] ja_ids = map.getStringArray(KEY_ID, null);
    if (ja_ids != null) {
      String ids = "";
      for (int i = 0; i < ja_ids.length; ++i) {
        String id = ja_ids[i];
        if (!id.equals("")) {
          if (i == 0)
            where += "AND (" + object_key + "_id = " + id + "\n";
          else
            where += "OR " + object_key + "_id = " + id + "\n";

          if (i == ja_ids.length - 1)
            where += ")";

          ids += id + " ";
        } else {
          LOG.log(Level.INFO, "{0}: ID is an empty string", object_name);
        }
      }
      params.add(object_key + "_id " + ids + " ");
    } else {
      LOG.log(Level.INFO, "{0}: no ID", object_name);
    }

    //Keywords*************************************************
    String keywordStr = map.getString(KEY_KEYWORDS, null);
    if (keywordStr != null) {
      keywordStr = keywordStr.trim();
      String[] keywords = keywordStr.split(" ");
      if (keywords.length > 0 && !keywordStr.equals("")) {
        String keys = "KEYWORDS: ";
        for (int i = 0; i < keywords.length; i++) {
          if (keywords[i].charAt(0) == '-') {
            where += "AND " + object_key + "_name not LIKE '%" + keywords[i].substring(1) + "%'\n";
          } else {
            where += "AND " + object_key + "_name LIKE '%" + keywords[i] + "%'\n";
          }

          //for displayed error.
          keys += "'" + keywords[i] + "'";
          if (i < keywords.length - 1)
            keys += ", or ";
        }
        keys += " ";
        params.add(keys);
      }
    } else {
      LOG.log(Level.INFO, "{0}: no keywords", object_name);
    }

    //Name *****************************************************
    String[] ja_names = map.getStringArray(KEY_NAME, null);
    if (ja_names != null) {
      String names = "NAME: ";
      for (int i = 0; i < ja_names.length; ++i) {
        String nameStr = ja_names[i].trim();
        if (!StringUtils.isEmpty(nameStr)) {
          if (i == 0)
            where += "AND (" + object_key + "_name = '" + nameStr + "'\n";
          else
            where += "OR " + object_key + "_name = '" + nameStr + "'\n";

          if (i == ja_names.length - 1)
            where += ")\n";

          names += nameStr + ", or ";
        } else
          LOG.log(Level.INFO, "{0}: no names", object_name);
      }
      names = names.substring(0, names.length() - 5);
      params.add(names);
    } else {
      LOG.log(Level.INFO, "{0}: no names", object_name);
    }

    //Path *************************************************
    String[] ja_paths = map.getStringArray(KEY_PATH, null);
    if (ja_paths != null) {
      String paths = "PATH: ";
      for (int i = 0; i < ja_paths.length; ++i) {
        String path = ja_paths[i];

        if (!StringUtils.isEmpty(path)) {
          if (object_key != "man") {
            if (i == 0)
              where += "AND (" + object_key + "_group1 = '" + path + "'\n";
            else
              where += "OR " + object_key + "_group1 = '" + path + "'\n";
            if (i == ja_paths.length - 1)
              where += ")\n";
          } else {
            if (i == 0)
              where += "AND (man_path = '" + path + "'\n";
            else
              where += "OR man_path = '" + path + "'\n";
            if (i == ja_paths.length - 1)
              where += ")\n";
          }
          paths += path + " ";
        } else
          LOG.log(Level.INFO, "{0}: no paths", object_name);
      }

      params.add(paths);
    } else {
      LOG.log(Level.INFO, "{0}: no paths", object_name);
    }

    //Patial Path *************************************************
    String[] ja_partialPaths = map.getStringArray(KEY_PARTIAL_PATH, null);
    //TODO: make this work with the negation character '-' to exclude rather than include values.
    if (ja_partialPaths != null) {
      String partialPaths = "PATH PART: ";
      for (int i = 0; i < ja_partialPaths.length; ++i) {
        String pathPart = ja_partialPaths[i];

        if (!StringUtils.isEmpty(pathPart)) {
          String negation = "";
          if (pathPart.charAt(0) == '-') {
            negation = "not";
            pathPart = pathPart.substring(1);
          }

          if (!object_key.equals("man")) {
            if (i == 0)
              where += "AND (" + object_key + "_group1 " + negation + " LIKE '%" + pathPart + "%'\n";
            else
              where += "AND " + object_key + "_group1 " + negation + " LIKE '%" + pathPart + "%'\n";
            if (i == ja_partialPaths.length - 1)
              where += ")\n";
          } else {
            if (i == 0)
              where += "AND (man_path " + negation + " LIKE '%" + pathPart + "%'\n";
            else
              where += "AND man_path " + negation + " LIKE '%" + pathPart + "%'\n";
            if (i == ja_partialPaths.length - 1)
              where += ")\n";
          }
          partialPaths += pathPart + " ";
        } else
          LOG.log(Level.INFO, "{0}: no paths", object_name);
      }
      params.add(partialPaths);
    } else {
      LOG.log(Level.INFO, "{0}: no paths", object_name);
    }

    //CMZ ***********************************************
    String cmz = map.getString(KEY_CMZ, null);
    if (cmz != null) {
      cmz = cmz.trim();
      where += "AND man_cmz LIKE '%" + cmz + "'\n"; //  may have to change this to be more precise
      params.add("CMZ: " + cmz + " ");
    } else {
      LOG.log(Level.INFO, "{0}: no cmz", object_name);
    }

    //STIR min/max***********************************************
    String stirMIN = map.getString(KEY_STIR_MIN, "");
    if (!stirMIN.isEmpty()) {
      stirMIN = stirMIN.trim();
      where += "AND man_stir > " + stirMIN + "\n";
      params.add("STIR GREATER THAN: " + stirMIN + " ");
    } else {
      LOG.log(Level.INFO, "{0}: min stir", object_name);
    }
    String stirMAX = map.getString(KEY_STIR_MAX, "");
    if (!stirMAX.isEmpty()) {
      stirMAX = stirMAX.trim();
      where += "AND man_stir < " + stirMAX + "\n";
      params.add("STIR LESS THAN: " + stirMAX + "");
    } else {
      LOG.log(Level.INFO, "{0}: max stir", object_name);
    }
    return where;
  }


  /**
   *
   * @param params
   * @param map
   * @param LOG
   * @param object_name
   * @param object_prefix
   * @return
   * @throws JSONException
   * @throws ServiceException
   */
  public static String createOffsetAndLimits(List<String> params,
      PayloadParameter map,
      SessionLogger LOG,
      String object_name,
      String object_prefix) throws JSONException, ServiceException {

    String offsetAndLimits = "ORDER BY " + object_prefix + "_name\n";
    String off = map.getString(KEY_OFFSET, "0");
    off = off.trim();

    if (!off.equals("") && Utils.isPositiveReal(off) && Integer.parseInt(off) >= 0) {
      //Removed this line to address IET issue #504712 in search of better error messaging.
      //params.add("offset " + off + " ");
      offsetAndLimits += "OFFSET " + off + " ROWS\n";
    } else {
      offsetAndLimits += "OFFSET 0 ROWS\n";
      params.add("default offset of 0");
      LOG.log(Level.INFO, object_name + ": offset set to default of 0.  Offset parameter was either not set, or set to something non-numeric");
    }

    String lim = map.getString(KEY_LIMIT, "");
    lim = lim.trim();
    if (lim.equals("all")) {
      LOG.log(Level.INFO, "{0}: all {1}s requested", new Object[]{object_name, object_name});
    } else if (!lim.equals("") && Utils.isPositiveReal(lim)) {
      int limInt = -1;
      try {
        limInt = Integer.parseInt(lim);
      } catch (NumberFormatException ex) {
        throw new IllegalArgumentException("Invalid number of records requested.  Limit must be a positive integer between 1 and 100.");
      }

      if (limInt < 1) {
        throw new IllegalArgumentException("Limit must be a positive integer between 1 and 100.");
      }
      if (limInt > 10000) {
        limInt = 10000;
        params.add("limit automatically adjusted to 100.  This service only allows 100 rows to be requested at a time.");
      }
      //Removed line to address IEt error: #504712 in search of better error messages.
      //params.add("limit " + limInt + "");
      offsetAndLimits += "FETCH NEXT " + limInt + " ROWS ONLY\n";
    } else if (lim.equals("")) {
      LOG.log(Level.INFO, "{0}: no limit specified adujsting to 1", object_name);
      offsetAndLimits += "FETCH NEXT 1 ROWS ONLY\n";
    } else {
      throw new IllegalArgumentException(object_name + ": Error - limit specified is not numeric.  Limit must be a positive integer");
    }
    return offsetAndLimits;
  }
}