V1_0.java [src/java/d/crlmod/rusle2] Revision: 61d7076cf006436b82449b37471164a34130576a  Date: Mon May 06 17:46:10 MDT 2024
/*
 * This file is part of the Cloud Services Integration Platform (CSIP),
 * a Model-as-a-Service framework, API, and application suite.
 *
 * 2012-2024, 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 d.crlmod.rusle2;

import crlmod.ServiceResources;
import static crlmod.ServiceResources.CR_LMOD_R2;
import csip.ModelDataService;
import csip.annotations.Description;
import csip.annotations.Name;
import csip.annotations.Resource;
import csip.annotations.State;
import static csip.annotations.State.RELEASED;
import csip.annotations.VersionInfo;
import csip.api.server.ServiceException;
import csip.utils.JSONUtils;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.servlet.http.HttpServletRequest;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.MultivaluedMap;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.UriInfo;
import org.apache.http.client.HttpResponseException;
import org.codehaus.jettison.json.JSONArray;

/**
 *
 * @author <a href="mailto:shaun.case@colostate.edu">Shaun Case</a>
 */
@Name("RUSLE2")
@Description("Retrieves XML data files for any RUSLE2 object")
@VersionInfo("1.0")
@State(RELEASED)
@Path("d/rusle2/1.0")
@Resource(from = ServiceResources.class)
public class V1_0 extends ModelDataService {

  public static String ID_KEY = "id";
  public static String NAME_KEY = "name";
  public static String PARTIAL_NAME_KEY = "partial_name";
  public static String PATH_KEY = "path";
  public static String PARTIAL_PATH_KEY = "partial_path";
  public static String LIMIT_KEY = "limit";

  private String[] ids;
  private String[] names;
  private String[] partial_names;
  private String[] paths;
  private String[] partial_paths;
  private int limit = 0;

  private List<TableResult> searchResults = new ArrayList<>();

  @Override
  protected void preProcess() throws Exception {
    boolean haveValidRequest = false;

    //   If we have the ids input key, don't check the other keys, that would not
    // make logical sense to structure such a request.
    if (parameter().has(ID_KEY)) {
      ids = parameter().getStringArray(ID_KEY);
      haveValidRequest = true;
    } else {

      //  If we have a names list, no need to check for a partial names list
      if (parameter().has(NAME_KEY)) {
        names = parameter().getStringArray(NAME_KEY);
        haveValidRequest = true;
      } else {
        if (parameter().has(PARTIAL_NAME_KEY)) {
          partial_names = parameter().getStringArray(PARTIAL_NAME_KEY);
          haveValidRequest = true;
        }
      }

      //  If we have a paths list, no need to check for a partial paths list
      if (parameter().has(PATH_KEY)) {
        paths = parameter().getStringArray(PATH_KEY);
        haveValidRequest = true;
      } else {
        if (parameter().has(PARTIAL_PATH_KEY)) {
          partial_paths = parameter().getStringArray(PARTIAL_PATH_KEY);
          haveValidRequest = true;
        }
      }
    }

    //  Shall we limit the return amount.  Really only useful if the client 
    // requests a list of objects by specifying an empty ids list input.
    if (parameter().has(LIMIT_KEY)) {
      limit = parameter().getInt(LIMIT_KEY);
    }

    if (!haveValidRequest) {
      throw new ServiceException("Invalid input provided.  Please check the required parameters documentation.");
    }
  }

  @Override
  protected void doProcess() throws Exception {
    if ((null != ids) && (ids.length <= 0)) {
      // ************************************************************************
      //
      //   Client wants a list of available objects.  Ideally, this should not be
      // called by any model code.  This will return a huge amount of data and a
      // model should already know what it is looking for.
      //
      //   This will return only a list of ID, Path, Name values, and will not
      // return any XML data (result would be too large otherwise)
      //
      // ************************************************************************
      String query = "SELECT " + ((limit > 0) ? " TOP " + limit : "") + " id, path, name, scienceDate FROM R2_Data ORDER BY path, name;";
      try (Connection conn = getConnection(); Statement stmnt = conn.createStatement();) {
        ResultSet results = stmnt.executeQuery(query);
        while (results.next()) {
          TableResult row = new TableResult();

          row.id = results.getString("id");
          row.path = results.getString("path");
          row.name = results.getString("name");
          row.scienceDate = results.getString("scienceDate");

          searchResults.add(row);
        }
      }

    } else {
      if (null != ids) {
        //  Client wants data by Id
        String query = "SELECT " + ((limit > 0) ? " TOP " + limit : "") + " id, path, name, scienceDate, xmlData FROM R2_Data WHERE ";
        query += buildPreparedWhereIsList("id", ids) + " ORDER BY path, name;";
        try (Connection conn = getConnection(); PreparedStatement stmnt = conn.prepareStatement(query)) {
          int counter = 1;
          for (String id : ids) {
            stmnt.setString(counter++, id);
          }

          ResultSet results = stmnt.executeQuery();

          while (results.next()) {
            TableResult row = new TableResult();

            row.id = results.getString("id");
            row.path = results.getString("path");
            row.name = results.getString("name");
            row.scienceDate = results.getString("scienceDate");
            row.XML = results.getString("xmlData");
            searchResults.add(row);
          }
        }
      } else {
        //  Client wants data by other fields.  Query other fields.
        String query = "SELECT " + ((limit > 0) ? " TOP " + limit : "") + " id, path, name, scienceDate, xmlData FROM R2_Data WHERE ";
        boolean add = false;

        if ((null != paths) && (paths.length >= 0)) {
          add = true;
          query += buildPreparedWhereIsList("path", paths);
        }

        if ((null != names) && (names.length >= 0)) {
          query += ((add) ? " AND " : " ") + buildPreparedWhereIsList("name", names);
          add = true;
        }

        if ((null != partial_paths) && (partial_paths.length >= 0)) {
          query += ((add) ? " AND " : " ") + buildPreparedWhereLikeList("path", partial_paths);
          add = true;
        }

        if ((null != partial_names) && (partial_names.length >= 0)) {
          query += ((add) ? " AND " : " ") + buildPreparedWhereLikeList("name", partial_names);
          add = true;
        }
        query += " ORDER BY path,name;";

        try (Connection conn = getConnection(); PreparedStatement stmnt = conn.prepareStatement(query)) {
          int counter = 1;

          if ((null != paths) && (paths.length >= 0)) {
            for (String path : paths) {
              stmnt.setString(counter++, path);
            }
          }

          if ((null != names) && (names.length >= 0)) {
            for (String name : names) {
              stmnt.setString(counter++, name);
            }
          }

          if ((null != partial_paths) && (partial_paths.length >= 0)) {
            for (String path : partial_paths) {
              stmnt.setString(counter++, "%" + path + "%");
            }
          }

          if ((null != partial_names) && (partial_names.length >= 0)) {
            for (String name : partial_names) {
              stmnt.setString(counter++, "%" + name + "%");
            }
          }

          ResultSet results = stmnt.executeQuery();

          while (results.next()) {
            TableResult row = new TableResult();

            row.id = results.getString("id");
            row.path = results.getString("path");
            row.name = results.getString("name");
            row.scienceDate = results.getString("scienceDate");
            row.XML = results.getString("xmlData");
            searchResults.add(row);
          }
        }
      }
    }

  }

  @Override
  protected void postProcess() throws Exception {
    JSONArray rows = new JSONArray();

    for (TableResult row : searchResults) {
      rows.put(row.toJSON());
    }

    results().put("r2_data_list", rows);
  }

  protected String buildPreparedWhereIsList(String fieldName, String[] values) {
    String where = "";
    if ((null != values) && (values.length > 0)) {
      where = fieldName + " IN (";
      for (int i = 0; i < values.length; i++) {
        where += "?";
        if ((i + 1) < values.length) {
          where += ",";
        }
      }
      where += ")";
    }

    return where;
  }

  protected String buildPreparedWhereLikeList(String fieldName, String[] values) {
    String where = "";
    if ((null != values) && (values.length > 0)) {
      where = "(";
      for (int i = 0; i < values.length; i++) {
        where += fieldName + " LIKE ? ";
        if ((i + 1) < values.length) {
          where += " OR ";
        }
      }
      where += ")";
    }

    return where;
  }

  protected Connection getConnection() throws ServiceException {
    return resources().getJDBC(CR_LMOD_R2);
  }

  protected class TableResult {

    String id;
    String path;
    String name;
    String scienceDate;
    String XML = null;

    public JSONArray toJSON() {
      JSONArray result = new JSONArray();

      result.put(JSONUtils.data(ID_KEY, id, "The unique id for this path/name combination.", null));
      result.put(JSONUtils.data(PATH_KEY, path, "The path for this object", null));
      result.put(JSONUtils.data(NAME_KEY, name, "The name for this object.", null));
      result.put(JSONUtils.data("science_date", scienceDate, "The date associated with this version of the XML file in this record.", null));
      result.put(JSONUtils.data("xml_file", XML, "The formatted XML file, if any, for this path/name combination..", null));
      return result;
    }
  }

  @GET
  @Produces(MediaType.APPLICATION_XML)
  public Response fetchFile(@Context UriInfo uriInfo,
      @Context HttpServletRequest httpReq){

    String requestString = httpReq.getQueryString();
    MultivaluedMap<String, String> requestMap = uriInfo.getQueryParameters();

    if ((null != requestMap) && (requestMap.size() > 0)) {
      if (requestMap.containsKey("path")) {
        String path = requestMap.getFirst("path").replaceAll("//", "/").replaceAll("//", "/");
        String name = path.substring(path.lastIndexOf("/") + 1);
        path = path.substring(0, path.lastIndexOf("/"));
        path = path.replaceAll("/", "\\");

        String query = "SELECT xmlData FROM R2_Data WHERE path=? AND name=?";
        try (Connection conn = createDataSource(); PreparedStatement stmnt = conn.prepareStatement(query)) {
          stmnt.setString(1, path);
          stmnt.setString(2, name);

          ResultSet results = stmnt.executeQuery();

          while (results.next()) {
            return Response.status(Response.Status.OK)
                .entity(results.getString("xmlData"))
                .build();
          }

          return Response.status(Response.Status.NOT_FOUND)
              .build();
        } catch (ClassNotFoundException | SQLException ex) {
          return Response.status(Response.Status.INTERNAL_SERVER_ERROR)
              .entity(ex.getMessage())
              .build();
        }
      }
      return Response.status(Response.Status.NOT_FOUND)
          .build();
    }

    return Response.status(Response.Status.INTERNAL_SERVER_ERROR)
        .build();
  }

  private static synchronized Connection createDataSource() throws ClassNotFoundException, SQLException {
    Connection connection = null;

    Class.forName("com.microsoft.sqlserver.jdbc.SQLServerDriver");
    //System.out.println("Driver was loaded for: com.microsoft.sqlserver.jdbc.SQLServerDriver");
    connection = DriverManager.getConnection("jdbc:sqlserver://129.82.20.129:1433;databaseName=CR_LMOD_2022_step_r2;user=sa;password=csurams#1");

    //System.out.println("Connection to the local Conservation Resources DB Service was successful\n================================================================================\n");
    connection.setAutoCommit(true);
    return connection;
  }
}