R2Run.java [src/java/m/rusle2] Revision: default Date:
/*
* $Id$
*
* This file is part of the Cloud Services Integration Platform (CSIP),
* a Model-as-a-Service framework, API, and application suite.
*
* 2012-2017, 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 m.rusle2;
import csip.Config;
import csip.api.server.Executable;
import csip.api.server.ServiceException;
import csip.SessionLogger;
import static csip.Utils.removeFirstLastChar;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.io.PrintWriter;
import java.io.Writer;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.logging.Level;
import org.apache.commons.io.FileUtils;
import org.apache.commons.lang3.StringEscapeUtils;
import util.XMLUtils;
/**
*
* @author od
*/
class R2Run {
SessionLogger LOG;
String stdout;
void setLogger(SessionLogger l) {
LOG = l;
}
/**
* Execute the rusle2 pyrome python script
*
* We assume that Python3.4 is installed under
* /home/ubuntu/.wine/drive_c/Python34 and that wine's working dir is
* /home/ubuntu/.wine The ownership of wine's working directory must
* correspond with the user running tomcat
*
* @param r2_rsh
* @return
* @throws IOException
*/
int executePyrome(File r2_rsh, Executable python, String suid) throws IOException, ServiceException {
python.setArguments("rusle2csip.py", suid);
LOG.info("Executing pyrome rusle2");
int ret = python.exec();
if (ret != 0) {
String stderr = FileUtils.readFileToString(python.stderr(), "UTF-8");
throw new ServiceException("RUSLE 2 PYTHON error: error executing pyrome:" + stderr);
}
// String runrusle2 = "winetricks vd=off ; wine /home/ubuntu/.wine/drive_c/Python34/python.exe rusle2csip.py\n";
stdout += "\n" + FileUtils.readFileToString(python.stdout(), "UTF-8");
if (LOG.isLoggable(Level.INFO)) {
LOG.info("stdout: " + stdout);
LOG.info("exit val: " + ret);
}
return ret;
}
// Must find the hydraulic element flow path element of a hydraulic element system
// download this file, and modify the header, so it can be fed to python
void prepareHydraulicElementFlowPathJ(String hydElemPtr, String r2db, File workingDir) throws IOException {
final String hydelemFile = "hydelem_file.tmp";
String hydelemflowpathFile = "";
BufferedReader br = null;
try {
// first open hydElemPtr file
getFile(hydElemPtr, workingDir.getParentFile(), hydelemFile);
// look for HYD_SYSTEM_FLOW_PATH_TYPE
LOG.info("reading --- " + workingDir.getParent() + "/" + hydelemFile);
File hydElemFile = new File(workingDir.getParent(), hydelemFile);
br = new BufferedReader(new FileReader(hydElemFile));
String inLine;
while ((inLine = br.readLine()) != null) {
if (inLine.contains("HYD_SYSTEM_FLOW_PATH_TYPE")) {
// get the text between the single two quotes- this will be the flowpathfile we need to get
// <ObR><Name>HYD_SYSTEM_FLOW_PATH_TYPE</Name><Data>'0.3% grade channel'</Data><Type>HYD_ELEMENT_FLOW_PATH</Type></ObR></Obj>
hydelemflowpathFile = inLine.split("'")[1];
LOG.info("Read hydelemflowpathFile as =" + hydelemflowpathFile);
}
}
String hydElemFlowPathPtr = r2db + "/hydraulic-element-flow-paths/" + hydelemflowpathFile + ".xml";
LOG.info("HydelemflowpathPTR is =" + hydElemFlowPathPtr);
// call ingprepareFileJ to finish the work...
// next open the flowpathfile, and perform the standard formatting
// of adding the <Obj> tag and the <Filename> tag...
prepareFileJ(hydElemFlowPathPtr, new File(workingDir.getParent(), "hydelemflowpath_file.xml"), "", "hydraulic-element-flow-paths", "hydelemflowpath", false);
} catch (Exception ioe) {
LOG.info("IO Exception while preparing file=" + ioe.toString());
} finally {
if (br != null) {
br.close();
}
}
}
int determineNumberOfFlowPaths(String hydElemPtr) {
hydElemPtr = hydElemPtr.substring(hydElemPtr.lastIndexOf("\\") + 1);
// This rediumentary algorithm for determining the number of flow paths for
// a hydaulic element system is based on conversation with Jack Carlson in late 03/2016
LOG.info("********\n\n\n\nHYD ELEM PTR=" + hydElemPtr);
//if (hydElemPtr.substring(hydElemPtr.lastIndexOf("\")+1).startsWith("1"))
if (hydElemPtr.startsWith("1")) {
if (hydElemPtr.contains("middle")) {
return 2;
} else {
return 1;
}
}
// presently there are only 2 kinds of hydraulic element systems with 2 elements.
// ones with only "middle" in the name which should have 3 flow paths (all evenly distributed along the slope),
// and ones with "middle" and "bottom" in the name which should have 2 flow paths (one in middle, one at bottom).
//
// presently there is one hydraulic element with "along" instead of "middle" in the name
// "2 Water and Sediment Control Basins along RUSLE slope.xml" This should be treated the same as middle.
//
if (hydElemPtr.startsWith("2")) {
if (((hydElemPtr.contains("middle")) || (hydElemPtr.contains("along"))) && (!hydElemPtr.contains("bottom"))) {
return 3;
} else {
// These should have middle and bottom
return 2;
}
}
// presently there are only 2 kinds of hydraulic element systems with 3 elements.
// ones with only "middle" in the name which should have 4 flow paths (all evenly distributed along the slope),
// and ones with "middle" and "bottom" in the name which should have 3 flow paths (two in middle, one at bottom).
if (hydElemPtr.startsWith("3")) {
if ((hydElemPtr.contains("middle")) && (!hydElemPtr.contains("bottom"))) {
return 4;
} else {
// These should have middle and bottom
return 3;
}
}
// Should not get here.
return 0;
}
double[] determineFlowPathDistribution(String hydElemPtr) {
hydElemPtr = hydElemPtr.substring(hydElemPtr.lastIndexOf("\\") + 1);
// This rediumentary algorithm for determining the hyd elem flow path position relative to slope length for
// a hydaulic element system is based on conversation with Jack Carlson in late 03/2016
if (hydElemPtr.substring(hydElemPtr.lastIndexOf("\\") + 1).startsWith("1")) {
if (hydElemPtr.contains("middle")) {
return new double[]{.5, 1};
} else {
return new double[]{1};
}
}
// presently there are only 2 kinds of hydraulic element systems with 2 elements.
// ones with only "middle" in the name which should have 3 flow paths (all evenly distributed along the slope),
// and ones with "middle" and "bottom" in the name which should have 2 flow paths (one in middle, one at bottom).
//
// presently there is one hydraulic element with "along" instead of "middle" in the name
// "2 Water and Sediment Control Basins along RUSLE slope.xml" This should be treated the same as middle.
//
if (hydElemPtr.startsWith("2")) {
if (((hydElemPtr.contains("middle")) || (hydElemPtr.contains("along"))) && (!hydElemPtr.contains("bottom"))) {
return new double[]{.333, .666, 1};
} else {
// These should have middle and bottom
return new double[]{.5, 1};
}
}
// presently there are only 2 kinds of hydraulic element systems with 3 elements.
// ones with only "middle" in the name which should have 4 flow paths (all evenly distributed along the slope),
// and ones with "middle" and "bottom" in the name which should have 3 flow paths (two in middle, one at bottom).
if (hydElemPtr.startsWith("3")) {
if ((hydElemPtr.contains("middle")) && (!hydElemPtr.contains("bottom"))) {
return new double[]{.25, .5, .75, 1};
} else {
// These should have middle and bottom
return new double[]{.333, .666, 1};
}
}
// Should not get here...
return new double[]{0};
}
// Generic File Preparation routine
// Downloads, and prepares a file for use in Rusle2 Pyrome
//
// fileType: the type of file to process
// Valid fileType(s) include: "contour",
//
// fileDir: the dir of the filename specified in the <Filename> tag in the R2 XML file
// Valid fileDir(s) include: "countour-systems"
//
// idx: An index value, if there are multiple items of the same type for slope segments
void prepareFileJ(String httpPtr, File outputFile, String fileType, String fileDir, String basefilename, boolean prepareSoilForPyrome) throws IOException {
BufferedReader br = null;
Writer bw = null;
String fn = (((basefilename != null) & (basefilename.length() > 0)) ? "\\" + basefilename + "1" : "\\aaa");
try {
// Generate shell script to prepare --fileType-- file for pyrome
LOG.info("******** the " + fileType + " file name=" + outputFile.getName());
String tmpFilename = outputFile.getName().substring(0, outputFile.getName().length() - 4) + ".tmp";
LOG.info("******** the " + fileType + " tmp file name=" + tmpFilename);
getFile(httpPtr, outputFile.getParentFile(), tmpFilename);
bw = new PrintWriter(outputFile);
File origFile = new File(outputFile.getParent(), tmpFilename);
br = new BufferedReader(new FileReader(origFile));
if ((fileType.contentEquals("CLIMATE")) || (fileType.contentEquals("SOIL")) || (prepareSoilForPyrome)) {
bw.write("<?xml version=\"1.0\"?>\n");
}
if (!fileType.contentEquals("SOIL")) {
bw.write("<Obj>\n");
if (fileType.length() > 1) {
bw.write("<Type>" + fileType + "</Type>\n");
}
// if an incrementing index is needed, replace "0" with counter variable
bw.write("<Filename>" + fileDir + fn + "</Filename>\n");
}
int i = 0;
String inputLine;
while ((inputLine = br.readLine()) != null) {
// skip the first line of the file, except for soil files which only have 1 line
if ((i > 0) || (fileType.contentEquals("SOIL") && (i == 0) && (inputLine.startsWith("<Obj>")))) {
bw.write(inputLine + "\n");
}
i++;
}
} catch (IOException ioe) {
LOG.info("IO Exception while preparing flie=" + outputFile.getName() + "---" + ioe.toString());
} finally {
if (br != null) {
br.close();
}
if (bw != null) {
bw.close();
}
}
}
// TO DO
// Consider moving to a helper class since this is a generally applicable function
private boolean getFile(String url, File destDir, String filename) throws FileNotFoundException, IOException {
String u = XMLUtils.escapeURL(url);
if (exists(u)) {
File f = new File(destDir, filename);
FileUtils.copyURLToFile(new URL(u), f);
return f.exists();
}
return false;
}
public static boolean exists(String URLName) throws IOException {
HttpURLConnection.setFollowRedirects(false);
// note : you may also need
// HttpURLConnection.setInstanceFollowRedirects(false)
HttpURLConnection con = (HttpURLConnection) new URL(URLName).openConnection();
con.setRequestMethod("GET");
return (con.getResponseCode() == HttpURLConnection.HTTP_OK);
}
/**
* Gets results returned from RomeShell
*
* @param key
* @return
*/
protected String getResult(String key) {
String sPattern = "RomeFileGetAttrValue " + key;
// Check if attr is available via the GetAttrValue cmd and return if so
if (stdout.contains(sPattern)) {
int start = stdout.indexOf(sPattern) + sPattern.length() + 2;
int end = stdout.indexOf('\r', start);
return stdout.substring(start, end).trim();
}
// Check if attr is available via the TestAttrValue cmd and return if so
sPattern = "RomeFileTestAttrValue " + key;
if (stdout.contains(sPattern)) {
int start = stdout.indexOf(sPattern) + sPattern.length() + 2;
int end = stdout.indexOf('\r', start);
return stdout.substring(start, end).trim();
}
sPattern = ":" + removeFirstLastChar(key) + "\"";
if (stdout.contains(sPattern)) {
int start = stdout.indexOf(sPattern) + sPattern.length() + 2;
int end = stdout.indexOf('\r', start);
String output = stdout.substring(start, end).trim();
if ((output == null) || (output.length() <= 0)) {
output = "null";
}
return output;
}
// If attr is not available return null
return "null";
}
/**
* Gets results returned from Pyrome
*
* @param key
* @return
*/
protected String getResultPyrome(String key) {
if (stdout.contains(key)) {
int start = stdout.indexOf(key) + key.length() + 1;
int end = stdout.indexOf('\r', start);
return stdout.substring(start, end).trim();
}
return "null";
}
/**
* Gets results returned from Pyrome
*
* @param key
* @return
*/
protected String getResultPyromeArray(String key, boolean bQuoted, boolean bEscape, boolean bIndexed) {
StringBuilder result = new StringBuilder("[");
String sPattern = "";
String text = "";
int idx = 0;
do {
sPattern = bIndexed ? (key + ":" + idx) : key;
LOG.info("Searching for key=" + sPattern);
text = getResultPyrome(sPattern);
LOG.info("Result of search=" + text);
if (!text.contentEquals("null")) {
if (idx > 0) {
result.append(",");
}
if (bQuoted) {
result.append("\"" + (bEscape ? StringEscapeUtils.escapeJava(text) : text) + "\"");
} else {
result.append(bEscape ? StringEscapeUtils.escapeJava(text) : text);
}
idx++;
}
} while (!text.contentEquals("null"));
result.append("]");
return result.toString();
}
public boolean isFileUrlReachable(String targetUrl) throws IOException {
String fileUrl = XMLUtils.escapeXMLFileURL(targetUrl);
return isUrlReachable(fileUrl);
}
public boolean isUrlReachable(String targetUrl) throws IOException {
String r2db = Config.getString("r2.db", "http://oms-db.engr.colostate.edu/r2");
String testUrl = r2db + "/" + targetUrl;
return exists(testUrl);
}
protected static String escapeJavaNoFwdSlash(String text) {
String javaEsc = StringEscapeUtils.escapeJava(text);
return javaEsc.replace("\\/", "/");
}
}