R2Run.java [src/java/m/rusle2] Revision: df14d966b9daf04b058d27e2b8205b0a4f3e036a  Date: Tue May 17 19:02:01 MDT 2016
/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package m.rusle2;

import csip.Config;
import csip.Executable;
import csip.ServiceException;
import java.io.File;
import java.io.IOException;
import java.util.logging.Logger;
import oms3.util.ProcessComponent;
import csip.utils.Binaries;
import csip.utils.Services;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.UnknownHostException;
import java.util.logging.Level;
import org.apache.commons.io.FileUtils;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang.StringEscapeUtils;
import org.apache.http.HttpResponse;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpUriRequest;
import org.apache.http.impl.client.DefaultHttpClient;

/**
 *
 * @author od
 */
class R2Run {

    public static final Logger LOG = Logger.getLogger("R2Run");
    String stdout;
    String stderr;
    ProcessComponent pc = new ProcessComponent();
    
    
    /**
     * Execute the r2 script.
     *
     * @param r2_rsh
     * @return
     * @throws IOException
     */
    int execute(File r2_rsh) throws IOException {
        LOG.info("Execute method");
        String binDir = Config.getString("csip.bin.dir", "/tmp/csip/bin");

        File romeshell = Binaries.unpackResource("/bin/win-x86/RomeShell.exe", new File(binDir));
        Binaries.unpackResource("/bin/win-x86/RomeDLL.dll", new File(binDir));

        pc.exe = Config.getString("wine.path", "/usr/bin/wine");
        pc.working_dir = r2_rsh.getParent();
        pc.args = new String[]{romeshell.toString(), r2_rsh.toString()};
        LOG.info("Executing");
        pc.execute();
        LOG.info("executed");
        stdout += "\n" + pc.stdout;
        stderr += "\n" + pc.stderr;
        LOG.info("stdout: "+ stdout);
        LOG.info(("stderr: "+ stderr));
        //LOG.info("rusle2 model run stdout=" + stdout);
        LOG.info("exit val: "+pc.exitValue);
        return pc.exitValue;
    }


    /**
     * 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) throws IOException, ServiceException {
        LOG.info("Execute method");
        //String binDir = Config.getString("m.bin.dir", "/tmp/csip/bin");

        //File romeshell = Binaries.unpackResource("/bin/win-x86/RomeShell.exe", new File(binDir));

        //Executable python = getResourceExe(V2_0_1.PYTHON);
        python.setArguments("rusle2csip.py");
        LOG.info("Executing pyrome rusle2");
        int ret = python.exec();
        LOG.info("executed pyrome rusle2");
        if (ret != 0) {
            throw new ServiceException("RUSLE 2 PYTHON error: error executing pyrome:" + ret);
        }
        
//        Binaries.unpackResource("/bin/win-x86/RomeDLL.dll", new File(binDir));
//        Binaries.unpackResource("/bin/win-x86/pyrome.py", new File(binDir));
//        Binaries.unpackResource("/bin/win-x86/_pyrome.pyd", new File(binDir));  
//        File runpyrome = new File(r2_rsh.getParent() + "/runrusle2.sh");
//        String runrusle2 = "winetricks vd=off ; wine /home/ubuntu/.wine/drive_c/Python34/python.exe rusle2csip.py\n"; 
//        FileUtils.writeStringToFile(runpyrome, runrusle2);
//        runpyrome.setExecutable(true);
//        pc.exe = "./runrusle2.sh";
//        pc.working_dir = r2_rsh.getParent();
//        pc.args = new String[]{};
        stdout += "\n" + FileUtils.readFileToString(python.stdout());
        stderr += "\n" + FileUtils.readFileToString(python.stderr());
//        LOG.info("Executing pyrome rusle2");
//        pc.execute();
//        LOG.info("executed pyrome rusle2");
//        stdout += "\n" + pc.stdout;
//        stderr += "\n" + pc.stderr;
        LOG.info("stdout: "+ stdout);
        LOG.info(("stderr: "+ stderr));
        //LOG.info("rusle2 model run stdout=" + stdout);
        LOG.info("exit val: "+ret);
        return ret;
    }
    
    int executePyromeLegacy(File r2_rsh) throws IOException, ServiceException {
        LOG.info("Execute method");
        String binDir = Config.getString("m.bin.dir", "/tmp/csip/bin");

        File romeshell = Binaries.unpackResource("/bin/win-x86/RomeShell.exe", new File(binDir));

        Binaries.unpackResource("/bin/win-x86/RomeDLL.dll", new File(binDir));
        Binaries.unpackResource("/bin/win-x86/pyrome.py", new File(binDir));
        Binaries.unpackResource("/bin/win-x86/_pyrome.pyd", new File(binDir));  
        File runpyrome = new File(r2_rsh.getParent() + "/runrusle2.sh");
        String runrusle2 = "winetricks vd=off ; wine /home/ubuntu/.wine/drive_c/Python34/python.exe rusle2csip.py\n"; 
        FileUtils.writeStringToFile(runpyrome, runrusle2);
        runpyrome.setExecutable(true);
        pc.exe = "./runrusle2.sh";
        pc.working_dir = r2_rsh.getParent();
        pc.args = new String[]{};
        LOG.info("Executing pyrome rusle2");
        pc.execute();
        LOG.info("executed pyrome rusle2");
        stdout += "\n" + pc.stdout;
        stderr += "\n" + pc.stderr;
        LOG.info("stdout: "+ stdout);
        LOG.info(("stderr: "+ stderr));
        LOG.info("exit val: "+pc.exitValue);
        return pc.exitValue;
    }
    
    // prepares soils file for legacy 1.3 rusle2 service
    int prepareSoilsFile(String soilsHttpPtr, File workingDir, boolean bPyrome, String idx) throws IOException {
        // Generate shell script to prepare soils file for romeshell or pyrome
        ProcessComponent pcPrepareSoils = new ProcessComponent();        
        File preparesoils = new File(workingDir.getParent() + "/preparesoils" + idx + ".sh");
        String prepsoils = "wget \"" + soilsHttpPtr + "\" -O soils_file" + idx + ".tmp\n"; 
        if (bPyrome) 
        {
            prepsoils += "echo \"<?xml version=\"\\\"1.0\\\"\"?>\" > soils_file" + idx + ".xml\n";
        }
        prepsoils += "numlines=`cat soils_file" + idx + ".tmp | wc -l`\n";
        prepsoils += "if [ $numlines -eq 1 ]\n";
        prepsoils += "then\n";
        prepsoils += "  tail -n +1 soils_file" + idx + ".tmp >> soils_file" + idx + ".xml\n";
        prepsoils += "else\n";
        prepsoils += "  tail -n +2 soils_file" + idx + ".tmp >> soils_file" + idx + ".xml\n";
        prepsoils += "fi\n";
        FileUtils.writeStringToFile(preparesoils, prepsoils);
        preparesoils.setExecutable(true);
        LOG.info("soilsHttpPtr=" + soilsHttpPtr);
        LOG.info("the pc-exe is=" + pcPrepareSoils.exe);
        pcPrepareSoils.working_dir = workingDir.getParent();
        pcPrepareSoils.exe = "./preparesoils" + idx + ".sh";
        pcPrepareSoils.args = new String[]{};
        pcPrepareSoils.execute();
        stdout += "\n" + pcPrepareSoils.stdout;
        stderr += "\n" + pcPrepareSoils.stderr;
        return pcPrepareSoils.exitValue;
    }
    
////    @Deprecated
//    int prepareClimateFile(String climateHttpPtr, File workingDir) throws IOException
//    {
//        ProcessComponent pcPrepareCli = new ProcessComponent();
//        // Generate shell script to prepare climate file for pyrome
//        File preparecli = new File(workingDir.getParent() + "/preparecli.sh");
//        String prepcli = "wget \"" + climateHttpPtr + "\" -O cli_file0.tmp\n"; 
//        prepcli += "echo \"<?xml version=\\\"1.0\\\"?>\" > cli_file0.xml\n";
//        prepcli += "echo \"<Obj>\" >> cli_file0.xml\n";
//        prepcli += "echo \"<Type>CLIMATE</Type>\" >> cli_file0.xml\n";        
//        prepcli += "echo \"<Filename>climates\\\\\\\\aaa</Filename>\" >> cli_file0.xml\n";
//        prepcli += "tail -n +2 cli_file0.tmp >> cli_file0.xml\n";
//        FileUtils.writeStringToFile(preparecli, prepcli);
//        preparecli.setExecutable(true);
//        LOG.info("climateHttpPtr=" + climateHttpPtr);
//        LOG.info("the pc-exe is=" + pcPrepareCli.exe);
//        pcPrepareCli.working_dir = workingDir.getParent();
//        pcPrepareCli.exe = "./preparecli.sh";
//        pcPrepareCli.args = new String[]{};
//        pcPrepareCli.execute();
//        stdout += "\n" + pcPrepareCli.stdout;
//        stderr += "\n" + pcPrepareCli.stderr;
//        return pcPrepareCli.exitValue;
//    }
    
//    void prepareClimateFileJ(String climateHttpPtr, File workingDir) throws IOException
//    {
//        prepareFileJ(climateHttpPtr, new File(workingDir.getParent(), "cli_file0.xml"), "CLIMATE", "climates", "");
//
//    }    
//    // 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
//    @Deprecated
//    int prepareHydraulicElementFlowPath(String hydElemPtr, String r2db, File workingDir) throws IOException
//    {
//        ProcessComponent pcPrepareHydElemFP = new ProcessComponent();
//        File preparehydElemFP = new File(workingDir.getParent() + "/preparehydraulic-element.sh");
//        String sPrepHydElemFP = "#! /bin/bash\n";
//        sPrepHydElemFP += "wget \"" + hydElemPtr + "\" -O hydelem_file.tmp\n";
//        sPrepHydElemFP += "flowpathline=`grep HYD_SYSTEM_FLOW_PATH_TYPE hydelem_file.tmp`\n";
//        sPrepHydElemFP += "flowpathfile=`echo $flowpathline | cut -d\"'\" -f 2`\n";
//        sPrepHydElemFP += "wget \"" + r2db + "/hydraulic-element-flow-paths/" + "$flowpathfile.xml\" -O hydelemflowpath_file.tmp\n";
//        sPrepHydElemFP += "echo \"<Obj>\" > hydelemflowpath_file.xml\n";
//        sPrepHydElemFP += "echo \"<Filename>hydraulic-element-flow-paths\\hydelemflowpath1</Filename>\" >> hydelemflowpath_file.xml\n";
//        sPrepHydElemFP += "tail -n +2 hydelemflowpath_file.tmp >> hydelemflowpath_file.xml\n";
//        FileUtils.writeStringToFile(preparehydElemFP, sPrepHydElemFP);
//        preparehydElemFP.setExecutable(true);
//        pcPrepareHydElemFP.working_dir = workingDir.getParent();
//        pcPrepareHydElemFP.exe = ".//preparehydraulic-element.sh";
//        pcPrepareHydElemFP.args = new String []{};
//        pcPrepareHydElemFP.execute();
//        stdout += "\n" + pcPrepareHydElemFP.stdout;
//        stderr += "\n" + pcPrepareHydElemFP.stderr;
//        return pcPrepareHydElemFP.exitValue;
//    }

    void prepareHydraulicElementFlowPathJ(String hydElemPtr, String r2db, File workingDir) throws IOException
    {
        final String hydelemFile = "hydelem_file.tmp";
        String hydelemflowpathFile = "";
        BufferedReader br = null;
        BufferedWriter bw = null;
        try
        {
            // first open hydElemPtr file
            getFile(hydElemPtr, workingDir.getParent(), hydelemFile);
            // look for HYD_SYSTEM_FLOW_PATH_TYPE
            LOG.info("trying to open --- " + workingDir.getParent() + "/" + hydelemFile);
            File hydElemFile = new File(workingDir.getParent() + "/" + hydelemFile);
            FileInputStream fis = new FileInputStream(hydElemFile);
            br = new BufferedReader(new InputStreamReader(fis));
            LOG.info("opened --- " + workingDir.getParent() + "/" + 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());
            ioe.printStackTrace();
        }
        finally
        {
            if (br != null)  br.close();
            if (bw != null)  bw.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
//    @Deprecated
//    int prepareFile(String httpPtr, File outputFile, String fileType, String fileDir, String idx) throws IOException
//    {
//        ProcessComponent pcPrepare = new ProcessComponent();
//        // 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);
//        File prepare = new File(outputFile.getParent() + "/prepare" + fileType + ".sh");
//        String prep = "#! /bin/bash\n" ;
//        prep += "wget \"" + httpPtr + "\" -O " + tmpFilename + "\n"; 
//        //prep += "echo \"<?xml version=\\\"1.0\\\"?>\" > " + workingDir.getName() + "\n";
//        prep += "echo \"<Obj>\" >> " + outputFile.getName() + "\n";
//        //prep += "echo \"<Type>" + fileType.toUpperCase() + "</Type>\" >> " + workingDir.getName() + "\n";        
//        prep += "echo \"<Filename>" + fileDir + "\\\\aaa" + idx + "</Filename>\" >> " + outputFile.getName() + "\n";
//        //prep += "echo \"<Science>20030415</Science>\" >> " + workingDir.getName() + "\n";
//        prep += "tail -n +2 " + tmpFilename + " >> " + outputFile.getName() + "\n";
//        FileUtils.writeStringToFile(prepare, prep);
//        prepare.setExecutable(true);
//        LOG.info(fileType + "--HttpPtr=" + httpPtr);
//        LOG.info("the pc-exe is=" + pcPrepare.exe);
//        pcPrepare.working_dir = outputFile.getParent();
//        pcPrepare.exe = "./prepare" + fileType + ".sh";
//        pcPrepare.args = new String[]{};
//        pcPrepare.execute();
//        stdout += "\n" + pcPrepare.stdout;
//        stderr += "\n" + pcPrepare.stderr;
//        return pcPrepare.exitValue;
//    }

    void prepareFileJ(String httpPtr, File outputFile, String fileType, String fileDir, String basefilename, boolean prepareSoilForPyrome) throws IOException
    {
        BufferedReader br = null;
        BufferedWriter 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.getParent(), tmpFilename);
            FileOutputStream fos = new FileOutputStream(outputFile);
            bw = new BufferedWriter(new OutputStreamWriter(fos));
            File origFile = new File(outputFile.getParent() + "/" + tmpFilename);
            FileInputStream fis = new FileInputStream(origFile);
            br = new BufferedReader(new InputStreamReader(fis));
            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 != null) && (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++;
            }        
            fis.close();
        }
        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 void getFile(String url, String destDir, String filename) {
        FileOutputStream fos = null;
        String escapedUrl = XMLUtils.escapeURL(url)  ;
        try 
        {
            LOG.info("*************************************\n\n\n\nTRYING TO GET FILE=" + url + "\n");
            LOG.info("Where the URI is =");
            LOG.info(escapedUrl + "\n\n\n\n\n*************************************************************");
            HttpClient client = new DefaultHttpClient();
            HttpGet httpget = new HttpGet(escapedUrl);
            HttpResponse response = client.execute((HttpUriRequest) httpget);

            byte[] soilData = IOUtils.toByteArray(response.getEntity().getContent());
            fos = new FileOutputStream(new File(destDir + "/" + filename));
            fos.write(soilData);
            fos.close();
        } catch (IOException ie) {
            LOG.log(Level.SEVERE, "ERROR GETTING SOILS IFC FILE!:" + ie.toString());
            throw new RuntimeException(ie);
        } finally {
            if (fos != null) {
                try {
                    fos.close();
                } catch (Exception fe) {
                }
            }
        }
    }
    
    /**
     * Gets results returned from RomeShell
     * @param key
     * @return
     */
    protected String getResult(String key) {
        String sPattern = "RomeFileGetAttrValue " + key;
        
        //LOG.info("seeking='" + sPattern + "'");
        // 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.toString().indexOf('\r', start); 
            //LOG.info("returning='" + stdout.substring(start, end).trim() + "'");
            return stdout.substring(start, end).trim();
        }
        
        // Check if attr is available via the TestAttrValue cmd and return if so
        sPattern = "RomeFileTestAttrValue " + key;
        //LOG.info("seeking='" + sPattern + "'");        
        if (stdout.contains(sPattern))
        {
            int start = stdout.indexOf(sPattern) + sPattern.length() + 2;
            int end = stdout.toString().indexOf('\r', start);   
            //LOG.info("returning='" + stdout.substring(start, end).trim() + "'");            
            return stdout.substring(start, end).trim();
        }

        //String key2 = "\"#RD:MAN_PTR:#RD:MAN_IRRIG_SUB_OBJ_PTR:" + key.substring(1);
        sPattern = ":" + Services.removeFirstLastChar(key) + "\"";
        //LOG.info("seeking='" +  sPattern + "'");        
        if (stdout.contains(sPattern))
        {
            int start = stdout.indexOf(sPattern) + sPattern.length() + 2;
            int end = stdout.toString().indexOf('\r', start); 
            String output = stdout.substring(start, end).trim();
            if ((output == null) || (output.length() <= 0))
                output = "null";
            //LOG.info("returning='" + output + "'");            
            return output;
        }

        // If attr is not available return null
        LOG.info("returning='null'");
        return "null";
    }
    
    /**
     * Gets results returned from Pyrome
     * @param key
     * @return
     */
    protected String getResultPyrome(String key) {
        String sPattern = key + "=";
        
        if (stdout.contains(key))
        {
            int start = stdout.indexOf(key) + key.length() + 1;
            int end = stdout.toString().indexOf('\r', start); 
            //LOG.info("returning='" + stdout.substring(start, end).trim() + "'");
            return stdout.substring(start, end).trim();
        }
        
        LOG.info("returning='null'");
        return "null";
    }

    /**
     * Gets results returned from Pyrome
     * @param key
     * @return
     */
    protected String getResultPyromeArray(String key, Boolean bQuoted, Boolean bEscape, Boolean bIndexed) {
        String result = "[";
        String sPattern = "";
        String text = "";
        int idx = 0;
        do
        {
            sPattern = bIndexed ? (key + ":" + idx) : key;
            System.out.println("Searching for key=" + sPattern);
            text = getResultPyrome(sPattern);
            System.out.println("Result of search=" + text);
            if (!text.contentEquals("null"))
            {
                if (idx > 0)
                    result += ",";
                if (bQuoted)
                    result += "\"" + (bEscape ? StringEscapeUtils.escapeJava(text) : text) + "\"";
                else
                    result += (bEscape ? StringEscapeUtils.escapeJava(text) : text);
                idx ++;
            }
        } while(!text.contentEquals("null"));
        
        result += "]";
        return result;
    }
    
    public boolean isUrlReachable(String targetUrl) throws IOException
    {
        String r2db = Config.getString("r2.db", "http://oms-db.engr.colostate.edu/r2");
        String testUrl = r2db + "/" + targetUrl;
        testUrl = XMLUtils.escapeXMLFileURL(testUrl);
        System.out.println("Testing URL=" + testUrl);
        URL url = new URL(testUrl);
        
        HttpURLConnection httpUrlConnection = (HttpURLConnection) url.openConnection();
        //httpUrlConnection.setRequestMethod("HEAD");
        httpUrlConnection.setRequestMethod("GET");
        try
        {
            int responseCode = httpUrlConnection.getResponseCode();
            System.out.println("response code=" + responseCode);
            return responseCode == HttpURLConnection.HTTP_OK;
        } 
        catch (UnknownHostException noInternetConnection)
        {
            return false;
        }
    }

    protected static String escapeJavaNoFwdSlash(String text)
    {
        String javaEsc = StringEscapeUtils.escapeJava(text);
        return javaEsc.replace("\\/", "/");
    }
}