V1_0.java [src/java/m/DSSATProxy] Revision: default  Date:
/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */
package m.DSSATProxy;

import csip.utils.Client;
import csip.Config;
import csip.annotations.*;
import csip.ModelDataService;
import csip.api.server.PayloadParameter;
import csip.api.server.ServiceException;
import javax.ws.rs.Path;
import csip.utils.ZipFiles;
import org.codehaus.jettison.json.JSONException;
import org.codehaus.jettison.json.JSONObject;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;
import java.util.zip.ZipOutputStream;
import org.codehaus.jettison.json.JSONArray;

@Name("DSSAT Proxy Service")
@Description("DSSAT SUBSTOR csip service")
@VersionInfo("1.0")
@Path("m/dssatproxy/1.0")
@Options(timeout = "P2H")
public class V1_0 extends ModelDataService {

  static final String KEY_FILE = "param";
  static final String SIM_TYPE = "simulation_type";
  static final String KEY_LOGLEVEL = "loglevel";
  static final String ID_SOIL = "id_soil";
  static final String ID_WEATHER = "wsta....";
  static final String LONGITUDE = "longitude";
  static final String LATITUDE = "latitude";
  static final String FILE_NAME = "file_name";
  static final String COKEY = "cokey";
  static final String START_DATE_OLD = "start_date_old";
  static final String START_DATE = "start_date"; //NEW START DATE
  static final String END_DATE = "end_date";

  @Override
  protected void doProcess() throws Exception {

    PayloadParameter jsonRequest = parameter();

    double longitude;
    double latitude;
    String start_date_old;
    String start_date;
    String end_date;
    String paramFile;
    String cokey;
    String simulation_type;
    String dssatReplacedateUrl;
    String dssatUrl;
    try {
      paramFile = jsonRequest.getString(KEY_FILE);
      longitude = jsonRequest.getDouble(LONGITUDE);
      latitude = jsonRequest.getDouble(LATITUDE);
      cokey = jsonRequest.getString(COKEY);
      start_date_old = jsonRequest.getString(START_DATE_OLD);
      start_date = jsonRequest.getString(START_DATE);
      end_date = jsonRequest.getString(END_DATE);
      simulation_type = jsonRequest.getString(SIM_TYPE);
    } catch (ServiceException ex) {
      throw new RuntimeException(ex);
    }

    dssatReplacedateUrl = Config.getString("dssat.replacedate.service");
    dssatUrl = Config.getString("dssat.dssat.service");

    this.callReplaceDateService(dssatReplacedateUrl, start_date_old, start_date);
    // request csip-dssat
    // to attach json, consider https://stackoverflow.com/questions/22668660/embedding-a-file-attachment-in-json-object
    // unpack response
    this.callDSSATService(dssatUrl, paramFile, simulation_type, longitude, latitude, cokey, start_date, end_date);
  }

  @Override
  protected void postProcess() throws Exception {
    File zip = ZipFiles.zip(new File(workspace().getDir().getAbsolutePath()));
    results().put(zip);
  }

  private JSONObject getRequestObjForReplaceDates(String start_date_old, String start_date) throws JSONException {
    JSONObject requestObj = new JSONObject();

    JSONArray paramObj = new JSONArray();

    JSONObject startDateOldJSON = new JSONObject();
    JSONObject startDateJSON = new JSONObject();

    startDateOldJSON.put(KEY_NAME, START_DATE_OLD);
    startDateOldJSON.put(VALUE, start_date_old);
    paramObj.put(startDateOldJSON);
    startDateJSON.put(KEY_NAME, START_DATE);
    startDateJSON.put(VALUE, start_date);
    paramObj.put(startDateJSON);

    requestObj.put(KEY_PARAMETER, paramObj);

    return requestObj;
  }

  private void callReplaceDateService(String url, String start_date_old, String start_date) throws IOException, Exception {
    JSONObject requestObj = this.getRequestObjForReplaceDates(start_date_old, start_date);
    JSONObject returnObj;

    LOG.info("DSSAT Request: " + requestObj.toString());
    File zip = ZipFiles.zip(new File(workspace().getDir().getAbsolutePath()));
    returnObj = new Client().doPOST(Config.getString("DSSAT replacedate", url), requestObj, new File[]{zip});
    LOG.info("DSSAT Response: " + returnObj.toString());

    JSONObject responseMeta = returnObj.getJSONObject(KEY_METAINFO);

    if (!responseMeta.getString(KEY_STATUS).equalsIgnoreCase(FAILED)) {
      JSONArray resultsObj = returnObj.getJSONArray("result");

      boolean fileFound = false;
      String resultsZipFileName = "";

      JSONObject currJSONObj;
      boolean zipFileFound = false;
      for (int i = 0; i < resultsObj.length(); i++) {
        currJSONObj = resultsObj.getJSONObject(i);
        if (!zipFileFound && ("" + currJSONObj).toLowerCase().contains("zip")) {
          fileFound = true;
          resultsZipFileName = currJSONObj.getString("value");
          //alternative way to pull the zip
          /*
                    String[] zipFileNameArray = currJSONObj.getString("value").split("/");
                    resultsZipFileName = zipFileNameArray[zipFileNameArray.length - 1];*/
          zipFileFound = true;
          continue;
        }
        // results().put(currJSONObj.getString("name"), currJSONObj.get("value"));
      }
      if (fileFound) {
        File resultsZipFile = new File(workspace().getDir(), "resultData.zip");

        //alternative way to pull the zip
        /*URI soil = new URI(JSONUtils.getStringParam(resultList, resultsZipFileName, ""));
          new Client().doGET(soil.toString(), resultsZipFile);*/
        new Client().doGET(resultsZipFileName, resultsZipFile);
        ZipFiles.unzip(resultsZipFile);
        resultsZipFile.delete();
      }

    }

  }

  //utility methods
  //returns a copy of the request object
  private JSONObject getRequestObjForDSSAT(String paramFile, String simulation_type, double longitude, double latitude, String cokey, String start_date, String end_date) {
    JSONObject requestObj = new JSONObject();
    try {
      JSONArray paramObj = new JSONArray();

      JSONObject keyFileJSON = new JSONObject();
      JSONObject simTypeJSON = new JSONObject();
      JSONObject longitudeJSON = new JSONObject();
      JSONObject latitudeJSON = new JSONObject();
      JSONObject cokeyJSON = new JSONObject();
      JSONObject startDateJSON = new JSONObject();
      JSONObject endDateJSON = new JSONObject();

      keyFileJSON.put("name", KEY_FILE);
      keyFileJSON.put("value", paramFile);
      paramObj.put(keyFileJSON);
      simTypeJSON.put("name", SIM_TYPE);
      simTypeJSON.put("value", simulation_type);
      paramObj.put(simTypeJSON);
      longitudeJSON.put("name", LONGITUDE);
      longitudeJSON.put("value", longitude);
      paramObj.put(longitudeJSON);
      latitudeJSON.put("name", LATITUDE);
      latitudeJSON.put("value", latitude);
      paramObj.put(latitudeJSON);
      cokeyJSON.put("name", COKEY);
      cokeyJSON.put("value", cokey);
      paramObj.put(cokeyJSON);
      startDateJSON.put("name", START_DATE);
      startDateJSON.put("value", start_date);
      paramObj.put(startDateJSON);
      endDateJSON.put("name", END_DATE);
      endDateJSON.put("value", end_date);
      paramObj.put(endDateJSON);

      requestObj.put(KEY_PARAMETER, paramObj);

    } catch (JSONException ex) {
      Logger.getLogger(V1_0.class.getName()).log(Level.SEVERE, null, ex);
    }
    return requestObj;
  }

  //calls DSSAT service with a request JSON object (and unpacks it?)
  private void callDSSATService(String url, String paramFile, String simulation_type, double longitude, double latitude, String cokey, String start_date, String end_date) throws Exception {
    JSONObject requestObj = this.getRequestObjForDSSAT(paramFile, simulation_type, longitude, latitude, cokey, start_date, end_date);
    JSONObject returnObj;

    LOG.info("DSSAT Request: " + requestObj.toString());
    File zip = ZipFiles.zip(new File(workspace().getDir().getAbsolutePath()));
    returnObj = new Client().doPOST(Config.getString("DSSAT daymet", url), requestObj, new File[]{zip});
    LOG.info("DSSAT Response: " + returnObj.toString());

    JSONObject responseMeta = returnObj.getJSONObject(KEY_METAINFO);

    if (!responseMeta.getString(KEY_STATUS).equalsIgnoreCase(FAILED)) {
      JSONArray resultsObj = returnObj.getJSONArray("result");

      boolean fileFound = false;
      String resultsZipFileName = "";

      JSONObject currJSONObj;
      boolean zipFileFound = false;
      for (int i = 0; i < resultsObj.length(); i++) {
        currJSONObj = resultsObj.getJSONObject(i);
        if (!zipFileFound && ("" + currJSONObj).toLowerCase().contains("zip")) {
          fileFound = true;
          resultsZipFileName = currJSONObj.getString("value");
          //alternative way to pull the zip
          /*
                    String[] zipFileNameArray = currJSONObj.getString("value").split("/");
                    resultsZipFileName = zipFileNameArray[zipFileNameArray.length - 1];*/
          zipFileFound = true;
          continue;
        }
        results().put(currJSONObj.getString("name"), currJSONObj.get("value"));
      }
      if (fileFound) {
        File resultsZipFile = new File(workspace().getDir(), "resultData.zip");

        //alternative way to pull the zip
        /*URI soil = new URI(JSONUtils.getStringParam(resultList, resultsZipFileName, ""));
          new Client().doGET(soil.toString(), resultsZipFile);*/
        new Client().doGET(resultsZipFileName, resultsZipFile);
        ZipFiles.unzip(resultsZipFile);
        resultsZipFile.delete();
      }

    }
  }

  private static ArrayList<File> listContentsOfZipFile(String zipFileName) {
    ArrayList<File> fileList = new ArrayList();
    try {
      ZipFile zipFile = new ZipFile(zipFileName);
      Enumeration<?> enu = zipFile.entries();
      while (enu.hasMoreElements()) {
        ZipEntry zipEntry = (ZipEntry) enu.nextElement();
        fileList.add(new File(zipEntry.getName()));
      }
      zipFile.close();
    } catch (IOException e) {
      e.printStackTrace();
    }
    return fileList;
  }

  // deletes all the files in the current folder that correspond to the files
  // in the zip file namedzipFileName
  private static void cleanUp(String zipFileName) {
    ArrayList<File> filesToDelete = listContentsOfZipFile(zipFileName);

    for (File currentFile : filesToDelete) {
      if (currentFile.delete()) {
        System.out.println(currentFile + " was deleted successfully!");
      }
    }
  }

  //renames old file name to new file name
  private static void renameFile(String oldFilePath, String newFilePath) {
    File currFile = new File(oldFilePath);
    currFile.renameTo(new File(newFilePath));
  }

  private void createZip(String zipFileName) {
    ArrayList<File> fileList = listContentsOfZipFile(zipFileName);

    renameFile(zipFileName, zipFileName + ".old");
    try {

      // create byte buffer
      byte[] buffer = new byte[1024];

      FileOutputStream fos = new FileOutputStream(zipFileName);

      ZipOutputStream zos = new ZipOutputStream(fos);

      for (File currFile : fileList) {

        FileInputStream fis = new FileInputStream(currFile);

        // begin writing a new ZIP entry, positions the stream to the start of the entry data
        zos.putNextEntry(new ZipEntry(currFile.getName()));

        int length;

        while ((length = fis.read(buffer)) > 0) {
          zos.write(buffer, 0, length);
        }

        zos.closeEntry();

        // close the InputStream
        fis.close();

      }

      // close the ZipOutputStream
      zos.close();

    } catch (IOException ioe) {
      System.out.println("Error creating zip file: " + ioe);
    }

  }
}