V1_0.java [src/java/reports] 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 reports;
import com.lowagie.text.DocumentException;
import csip.ModelDataService;
import csip.api.server.ServiceException;
import csip.annotations.*;
import static csip.annotations.ResourceType.OUTPUT;
import static csip.annotations.State.RELEASED;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.nio.file.StandardCopyOption;
import java.util.Iterator;
import java.util.logging.Level;
import javax.ws.rs.Path;
import org.apache.velocity.VelocityContext;
import org.apache.velocity.app.VelocityEngine;
import org.codehaus.jettison.json.JSONException;
import org.codehaus.jettison.json.JSONObject;
import org.apache.velocity.tools.generic.NumberTool;
import org.codehaus.jettison.json.JSONArray;
/**
* This service returns PDF versions of two WEPP reports. The template files are
* HTML files created using the Apache velocity engine markup.
*
* The data resources referenced include:
* <ul>
* <li>WEPPHillslopeProfileReport.htm - template for the WEPP hillslope report
* this is for a single hillslope simulation. </li>
* <li>328f.htm - template for the multiple WEPP run report. </li>
* <li>image001.gif - NRCS logo to insert in reports.</li>
* <li>img9.jpg - USDA logo to insert in reports.</li>
* </ul>
*
* @author jrf
*/
@Name("wepp2012")
@Description("WEPP model PDF Reports - version 2/27/2018")
@State(RELEASED)
@Path("reports/summary/1.0")
@Polling(first = 2000, next = 2000)
// template resources
@Resource(file = "/data/WEPPHillslopeProfileReport.htm", id = "profileReportTemplate")
@Resource(file = "/data/image001.gif", id = "profileReportTemplateLogo")
@Resource(file = "/data/328f.htm", id = "profileReportTemplate328")
@Resource(file = "/data/img9.jpg", id = "profileReportTemplateLogo328")
// Output to capture
@Resource(file = "*stdout.txt *stderr.txt", type = OUTPUT)
public class V1_0 extends ModelDataService {
private String sessionWorkDir;
private String pdfResourceName;
private JSONObject templateInputJson;
private String outputName;
private String outputHTML;
private double[] xdistData;
private double[] soilLossData;
private double[] elevData;
private double[] detachData;
private boolean include_graphs;
static final String WEPP_KEY_PDF_RESOURCE = "pdfResourceName";
static final String WEPP_KEY_JSON_INPUTS = "templateInputJson";
static final String PDF_OUTPUT_NAME = "outputName";
static final String HTML_OUTPUT_NAME = "outputHTML";
static final String WEPP_KEY_DETACHDATA = "detachData";
// data for graph
static final String WEPP_KEY_XDISTDATA = "xdistData";
static final String WEPP_KEY_SOILLOSSDATA = "soilLossData";
static final String WEPP_KEY_ELEVATIONDATA = "elevData";
static final String INCLUDE_GRAPHS = "IncludeGraphs";
/**
* Initialize WEPP-PDF workspace. This requires creating a couple
* subdirectories.
*
* @throws ServiceException any problem creating subdirectories
* @return true if directories created.
*/
private boolean init() throws ServiceException {
LOG.info("Initializing WEPP Service...\n");
sessionWorkDir = workspace().getDir().toString();
File file = workspace().getFile("runs");
if (!file.exists()) {
file.mkdir();
}
if (!file.exists()) {
LOG.severe("Could not create runs directory");
}
file = workspace().getFile("output");
if (!file.exists()) {
file.mkdir();
}
if (!file.exists()) {
LOG.severe("Could not create output directory");
}
outputName = "report.pdf";
outputHTML = "report.html";
return true;
}
/**
* Get any parameters from service request for PDF generation.
*
* @throws ServiceException any problems getting JSON parameters.
*/
private void loadRequiredParameters() throws ServiceException {
try {
// get run options
if (parameter().has(WEPP_KEY_PDF_RESOURCE)) {
pdfResourceName = parameter().getString(WEPP_KEY_PDF_RESOURCE);
}
if (parameter().has(WEPP_KEY_JSON_INPUTS)) {
templateInputJson = parameter().getJSON(WEPP_KEY_JSON_INPUTS);
}
if (parameter().has(PDF_OUTPUT_NAME)) {
outputName = parameter().getString(PDF_OUTPUT_NAME);
}
if (parameter().has(HTML_OUTPUT_NAME)) {
outputHTML = parameter().getString(HTML_OUTPUT_NAME);
}
include_graphs = parameter().getBoolean(INCLUDE_GRAPHS, false);
if (outputName.equals("wepp-summary.pdf") && include_graphs) {
// get data for xdist
xdistData = getGraphData(WEPP_KEY_XDISTDATA);
// get data for soil loss
soilLossData = getGraphData(WEPP_KEY_SOILLOSSDATA);
// get data for elevation
elevData = getGraphData(WEPP_KEY_ELEVATIONDATA);
// get data for soil depth detach/deposit
detachData = getGraphData(WEPP_KEY_DETACHDATA);
}
} catch (Exception e) {
throw new ServiceException("WEPP error: error processing model run parameters.");
}
}
/**
* Get data from JSON for a particular graph.
*
* @param param type of graph
* @return array of values
* @throws ServiceException
*/
private double[] getGraphData(String param) throws ServiceException {
double[] res = null;
try {
JSONArray JSONArr = parameter().getJSONArray(param, null);
res = new double[JSONArr.length()];
for (int i = 0; i < JSONArr.length(); i++) {
res[i] = JSONArr.getDouble(i);
}
} catch (Exception e) {
throw new ServiceException("WEPP error: error processing model run parameters.");
}
return res;
}
/**
* Use the velocity engine to take an HTML template and JSON data to produce a
* PDF.
*
* @param outputPath PDF output file
* @param htmlPath HTML output file
* @param pdfResourceName HTML template file
* @param templateInputJson JSON data to fill into template
* @throws ServiceException if any
* @throws IOException if any
*/
private void buildReportPDF(String outputPath, String htmlPath, String pdfResourceName, JSONObject templateInputJson) throws ServiceException, IOException {
VelocityContext injectedFields = new VelocityContext();
final Iterator<String> keys = templateInputJson.keys();
while (keys.hasNext()) {
try {
final String key = keys.next();
injectedFields.put(key, templateInputJson.get(key));
} catch (JSONException ex) {
throw new RuntimeException(ex);
}
}
injectedFields.put("numberTool", new NumberTool());
File pdfFile = new File(outputPath);
File htmlFile = new File(htmlPath);
File templateHTMLFolder = new File(sessionWorkDir + "/htmltemplate");
//templateHTMLFolder.mkdir();
//new File(templateHTMLFolder.getPath() + "/Report_files/").mkdir();
final File resourceFile = resources().getFile(pdfResourceName);
final File resourceFileLogo = resources().getFile("profileReportTemplateLogo");
final File resourceFileLogo328 = resources().getFile("profileReportTemplateLogo328");
final String templateHTMLFilepath = templateHTMLFolder.getPath() + "/template.vm";
final String pdfHTMLFilepath = templateHTMLFolder.getPath() + "/pdfresult.html";
try {
Files.copy(resourceFile.toPath(), Paths.get(templateHTMLFilepath), StandardCopyOption.REPLACE_EXISTING);
Files.copy(resourceFileLogo.toPath(), Paths.get(templateHTMLFolder.getPath() + "/Report_files/image001.gif"), StandardCopyOption.REPLACE_EXISTING);
Files.copy(resourceFileLogo328.toPath(), Paths.get(templateHTMLFolder.getPath() + "/Report_files/img9.jpg"), StandardCopyOption.REPLACE_EXISTING);
} catch (IOException ex) {
LOG.log(Level.SEVERE, null, ex);
}
VelocityEngine velocityEngine = PDFUtils.createVelocityEngine(templateHTMLFolder);
try (FileWriter writer = new FileWriter(pdfHTMLFilepath)) {
velocityEngine.getTemplate("template.vm").merge(injectedFields, writer);
}
try {
PDFUtils.createPDFFromHTML(new File(pdfHTMLFilepath).toURI().toURL().toString(), pdfFile.getPath());
} catch (DocumentException ex) {
LOG.log(Level.SEVERE, null, ex);
}
try {
Files.copy(new File(pdfHTMLFilepath).toPath(), htmlFile.toPath(), StandardCopyOption.REPLACE_EXISTING);
} catch (IOException ex) {
LOG.log(Level.SEVERE, null, ex);
}
}
/**
* Get any parameters from request.
*
* @throws Exception if any
*/
@Override
protected void preProcess() throws Exception {
init();
loadRequiredParameters();
}
/**
* Calls functions to make graphs and create PDF.
*
* @throws Exception if any
*/
@Override
protected void doProcess() throws Exception {
File templateHTMLFolder = new File(sessionWorkDir,"htmltemplate");
templateHTMLFolder.mkdir();
new File(templateHTMLFolder.getPath(),"Report_files").mkdir();
if (outputName.equals("wepp-summary.pdf") && include_graphs) {
String soilLossImage = sessionWorkDir + "/htmltemplate/Report_files/soilLoss.jpeg";
String elevImage = sessionWorkDir + "/htmltemplate/Report_files/elevation.jpeg";
String depthImage = sessionWorkDir + "/htmltemplate/Report_files/depthLoss.jpeg";
PDFGraph.generateJPEGByXY(xdistData, soilLossData, soilLossImage, "Soil Loss(ton/A/yr)");
PDFGraph.generateJPEGByXY(xdistData, elevData, elevImage, "Elevation(ft)");
PDFGraph.generateJPEGByXY(xdistData, detachData, depthImage, "Detachment/Deposition Depth (in/yr)");
}
buildReportPDF(sessionWorkDir + "/output/" + outputName, sessionWorkDir + "/output/" + outputHTML, pdfResourceName, templateInputJson);
}
/**
* File names in response.
*
* @throws Exception if any
*/
@Override
protected void postProcess() throws Exception {
LOG.info("Starting postProcess...");
results().put(workspace().getFile("/output/" + outputName), "WEPP PDF Report Output");
results().put(workspace().getFile("/output/" + outputHTML), "WEPP HTML Report Output");
LOG.info("Finished with postProcess");
}
}