/******************************************************************************* | |
* Licensed to the Apache Software Foundation (ASF) under one | |
* or more contributor license agreements. See the NOTICE file | |
* distributed with this work for additional information | |
* regarding copyright ownership. The ASF licenses this file | |
* to you under the Apache License, Version 2.0 (the | |
* "License"); you may not use this file except in compliance | |
* with the License. You may obtain a copy of the License at | |
* | |
* http://www.apache.org/licenses/LICENSE-2.0 | |
* | |
* Unless required by applicable law or agreed to in writing, | |
* software distributed under the License is distributed on an | |
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY | |
* KIND, either express or implied. See the License for the | |
* specific language governing permissions and limitations | |
* under the License. | |
*******************************************************************************/ | |
package org.apache.ofbiz.htmlreport; | |
import java.io.File; | |
import java.io.FileNotFoundException; | |
import java.io.FileOutputStream; | |
import java.io.IOException; | |
import java.io.Serializable; | |
import java.lang.reflect.InvocationTargetException; | |
import java.lang.reflect.Method; | |
import java.util.ArrayList; | |
import java.util.Collection; | |
import java.util.Collections; | |
import java.util.HashMap; | |
import java.util.Iterator; | |
import java.util.List; | |
import java.util.Map; | |
import javax.servlet.http.HttpServletRequest; | |
import javax.servlet.http.HttpServletResponse; | |
import org.apache.ofbiz.base.util.Debug; | |
import org.apache.ofbiz.base.util.FileUtil; | |
import org.apache.ofbiz.base.util.StringUtil; | |
import org.apache.ofbiz.base.util.UtilHttp; | |
import org.apache.ofbiz.base.util.UtilProperties; | |
import org.apache.ofbiz.base.util.UtilValidate; | |
import org.apache.ofbiz.htmlreport.util.ReportEncoder; | |
import org.apache.ofbiz.htmlreport.util.ReportStringUtil; | |
/** | |
* HTML report output to be used in report.ftl.<p> | |
* | |
*/ | |
public class HtmlReport extends AbstractReport { | |
public static final String module = HtmlReport.class.getName(); | |
/** The delimiter that is used in the resource list request parameter. */ | |
public static final String DELIMITER_RESOURCES = "|"; | |
/** Request parameter name for the resource list. */ | |
public static final String PARAM_RESOURCELIST = "resourcelist"; | |
/** Constant for a HTML linebreak with added "real" line break. */ | |
protected static final String LINEBREAK = "<br>"; | |
/** | |
* Constant for a HTML linebreak with added "real" line break- | |
* traditional style for report threads that still use XML templates for their output. | |
*/ | |
protected static final String LINEBREAK_TRADITIONAL = "<br>\n"; | |
/** The list of report objects e.g. String, Exception ... */ | |
protected List<Serializable> content; | |
/** The list of report objects e.g. String, Exception ... */ | |
protected List<Serializable> logContent; | |
/** | |
* Counter to remember what is already shown, | |
* indicates the next index of the content list that has to be reported. | |
*/ | |
protected int indexNext; | |
/** Flag to indicate if an exception should be displayed long or short. */ | |
protected boolean showExceptionStackTrace; | |
/** If set to <code>true</code> nothing is kept in memory. */ | |
protected boolean isTransient; | |
/** Boolean flag indicating whether this report should generate HTML or JavaScript output. */ | |
protected boolean writeHtml; | |
/** Helper variable to deliver the html end part. */ | |
public static final int HTML_END = 1; | |
/** Helper variable to deliver the html start part. */ | |
public static final int HTML_START = 0; | |
/** The thread to display in this report. */ | |
protected String paramThread; | |
/** The next thread to display after this report. */ | |
protected String paramThreadHasNext; | |
protected String paramAction; | |
protected String paramTitle; | |
protected String paramResource; | |
/** Flag for refreching workplace .*/ | |
protected String paramRefreshWorkplace; | |
/** Constant for the "OK" button in the build button methods. */ | |
public static final int BUTTON_OK = 0; | |
/** Constant for the "Cancel" button in the build button methods. */ | |
public static final int BUTTON_CANCEL = 1; | |
/** Constant for the "Close" button in the build button methods. */ | |
public static final int BUTTON_CLOSE = 2; | |
/** Constant for the "Advanced" button in the build button methods. */ | |
public static final int BUTTON_ADVANCED = 3; | |
/** Constant for the "Set" button in the build button methods. */ | |
public static final int BUTTON_SET = 4; | |
/** Constant for the "Details" button in the build button methods. */ | |
public static final int BUTTON_DETAILS = 5; | |
/** Constant for the "OK" button in the build button methods (without form submission). */ | |
public static final int BUTTON_OK_NO_SUBMIT = 6; | |
/** Constant for the "Edit" button in the build button methods (same function as "Ok" button but different text on button. */ | |
public static final int BUTTON_EDIT = 7; | |
/** Constant for the "Discard" button in the build button methods (same function as "Cancel" button but different text on button. */ | |
public static final int BUTTON_DISCARD = 8; | |
/** Constant for the "Back" button in the build button methods. */ | |
public static final int BUTTON_BACK = 9; | |
/** Constant for the "Continue" button in the build button methods. */ | |
public static final int BUTTON_CONTINUE = 10; | |
/** Constant for the "Download" button in the build button methods. */ | |
public static final int BUTTON_DOWNLOAD = 11; | |
/** Request parameter value for the action: back. */ | |
public static final String DIALOG_BACK = "back"; | |
/** Request parameter value for the action: cancel. */ | |
public static final String DIALOG_CANCEL = "cancel"; | |
/** Request parameter value for the action: continue. */ | |
public static final String DIALOG_CONTINUE = "continue"; | |
/** Request parameter value for the action: set. */ | |
public static final String DIALOG_SET = "set"; | |
/** The resource list parameter value. */ | |
protected String paramResourcelist; | |
/** The list of resource names for the multi operation. */ | |
protected List<String> resourceList; | |
/** The key name which contains the localized message for the continue checkbox. */ | |
protected String paramReportContinueKey; | |
public static final String DIALOG_URI = "dialoguri"; | |
public static final String FORM_URI = "formuri"; | |
public static final String resource = "PricatUiLabels"; | |
/** Log file. */ | |
protected File logFile; | |
/** Log file name. */ | |
protected String logFileName; | |
/** Log file output stream. */ | |
protected FileOutputStream logFileOutputStream; | |
protected long sequenceNum = -1; | |
/** | |
* Constructs a new report using the provided locale for the output language.<p> | |
* | |
* @param request HttpServletRequest | |
* @param response HttpServletResponse | |
*/ | |
public HtmlReport(HttpServletRequest request, HttpServletResponse response) { | |
this(request, response, false, false); | |
} | |
/** | |
* Constructs a new report using the provided locale for the output language.<p> | |
* | |
* @param request HttpServletRequest | |
* @param response HttpServletResponse | |
* @param writeHtml if <code>true</code>, this report should generate HTML instead of JavaScript output | |
* @param isTransient If set to <code>true</code> nothing is kept in memory | |
*/ | |
public HtmlReport(HttpServletRequest request, HttpServletResponse response, boolean writeHtml, boolean isTransient) { | |
init(UtilHttp.getLocale(request)); | |
content = new ArrayList<Serializable>(256); | |
logContent = new ArrayList<Serializable>(256); | |
showExceptionStackTrace = true; | |
this.writeHtml = writeHtml; | |
this.isTransient = isTransient; | |
} | |
public static HtmlReport getInstance(HttpServletRequest request, HttpServletResponse response) { | |
HtmlReport wp = (HtmlReport) request.getSession().getAttribute(SESSION_REPORT_CLASS); | |
if (wp == null) { | |
wp = new HtmlReport(request, response, true, true); | |
request.getSession().setAttribute(SESSION_REPORT_CLASS, wp); | |
} | |
return wp; | |
} | |
public static HtmlReport getInstance(HttpServletRequest request, HttpServletResponse response, boolean writeHtml, boolean isTransient) { | |
HtmlReport wp = (HtmlReport) request.getSession().getAttribute(SESSION_REPORT_CLASS); | |
if (wp == null) { | |
wp = new HtmlReport(request, response, writeHtml, isTransient); | |
request.getSession().setAttribute(SESSION_REPORT_CLASS, wp); | |
} | |
return wp; | |
} | |
public static HtmlReport getInstance(HttpServletRequest request, HttpServletResponse response, boolean writeHtml, boolean isTransient, String logFileName) { | |
HtmlReport wp = (HtmlReport) request.getSession().getAttribute(SESSION_REPORT_CLASS); | |
if (wp == null || UtilValidate.isEmpty(wp.getLogFileName()) || !wp.getLogFileName().equals(logFileName)) { | |
wp = new HtmlReport(request, response, writeHtml, isTransient); | |
request.getSession().setAttribute(SESSION_REPORT_CLASS, wp); | |
} | |
return wp; | |
} | |
public String getParamAction(HttpServletRequest request) { | |
paramAction = request.getParameter("action"); | |
return paramAction != null ? paramAction : "reportbegin"; | |
} | |
public void setParamAction(String action) { | |
paramAction = action; | |
} | |
public void setParamThread(String name) { | |
paramThread = name; | |
} | |
public synchronized String getReportUpdate() { | |
StringBuffer result = new StringBuffer(); | |
StringBuffer logResult = new StringBuffer(); | |
int indexEnd = content.size(); | |
for (int i = indexNext; i < indexEnd; i++) { | |
int pos = isTransient ? 0 : i; | |
Object obj = content.get(pos); | |
if ((obj instanceof String) || (obj instanceof StringBuffer)) { | |
result.append(obj); | |
} else if (obj instanceof Throwable) { | |
result.append(getExceptionElementJS((Throwable)obj)); | |
} | |
if (isTransient) { | |
content.remove(indexNext); | |
} | |
if (UtilValidate.isNotEmpty(logContent)) { | |
Object logObj = logContent.get(pos); | |
if ((logObj instanceof String) || (logObj instanceof StringBuffer)) { | |
logResult.append(logObj); | |
} else if (logObj instanceof Throwable) { | |
result.append(getExceptionElementHtml((Throwable) logObj)); | |
} | |
if (isTransient) { | |
logContent.remove(indexNext); | |
} | |
} | |
} | |
indexNext = isTransient ? 0 : indexEnd; | |
if (isTransient && logFileOutputStream != null && logResult.toString().length() > 0) { | |
try { | |
logFileOutputStream.write((logResult.toString() + "\n").getBytes()); | |
logFileOutputStream.flush(); | |
} catch (IOException e) { | |
Debug.logError(e.getMessage(), module); | |
} | |
} | |
return result.toString(); | |
} | |
/** | |
* Returns if the report writes html or javascript code.<p> | |
* | |
* @return <code>true</code> if the report writes html, and <code>false</code> if the report writes javascript code | |
*/ | |
public boolean isWriteHtml() { | |
return writeHtml; | |
} | |
public synchronized void print(String value, int format) { | |
StringBuffer buf = null; | |
value = ReportStringUtil.escapeJavaScript(value); | |
switch (format) { | |
case FORMAT_HEADLINE: | |
buf = new StringBuffer(); | |
buf.append("aH('"); | |
buf.append(value); | |
buf.append("'); "); | |
break; | |
case FORMAT_WARNING: | |
buf = new StringBuffer(); | |
buf.append("aW('"); | |
buf.append(value); | |
buf.append("'); "); | |
addWarning(value); | |
break; | |
case FORMAT_ERROR: | |
buf = new StringBuffer(); | |
buf.append("aE('"); | |
buf.append(value); | |
buf.append("'); "); | |
addError(value); | |
break; | |
case FORMAT_NOTE: | |
buf = new StringBuffer(); | |
buf.append("aN('"); | |
buf.append(value); | |
buf.append("'); "); | |
break; | |
case FORMAT_OK: | |
buf = new StringBuffer(); | |
buf.append("aO('"); | |
buf.append(value); | |
buf.append("'); "); | |
break; | |
case FORMAT_DEFAULT: | |
default: | |
buf = new StringBuffer(); | |
buf.append("a('"); | |
buf.append(value); | |
buf.append("'); "); | |
} | |
if (value.trim().endsWith(getLineBreak())) { | |
buf.append("aB(); "); | |
} | |
content.add(buf.toString()); | |
switch (format) { | |
case FORMAT_HEADLINE: | |
buf = new StringBuffer(); | |
buf.append("<span class='head'>"); | |
buf.append(value); | |
buf.append("</span>"); | |
break; | |
case FORMAT_WARNING: | |
buf = new StringBuffer(); | |
buf.append("<span class='warn'>"); | |
buf.append(value); | |
buf.append("</span>"); | |
addWarning(value); | |
break; | |
case FORMAT_ERROR: | |
buf = new StringBuffer(); | |
buf.append("<span class='err'>"); | |
buf.append(value); | |
buf.append("</span>"); | |
addError(value); | |
break; | |
case FORMAT_NOTE: | |
buf = new StringBuffer(); | |
buf.append("<span class='note'>"); | |
buf.append(value); | |
buf.append("</span>"); | |
break; | |
case FORMAT_OK: | |
buf = new StringBuffer(); | |
buf.append("<span class='ok'>"); | |
buf.append(value); | |
buf.append("</span>"); | |
break; | |
case FORMAT_DEFAULT: | |
default: | |
buf = new StringBuffer(value); | |
} | |
if (value.trim().endsWith(getLineBreak())) { | |
buf.append("\n"); | |
} | |
logContent.add(buf.toString()); | |
} | |
public void println() { | |
print(getLineBreak()); | |
} | |
public synchronized void println(Throwable t) { | |
addError(t.getMessage()); | |
content.add(getExceptionElementJS(t)); | |
logContent.add(getExceptionElementHtml(t)); | |
} | |
/** | |
* Returns the correct line break notation depending on the output style of this report. | |
* | |
* @return the correct line break notation | |
*/ | |
protected String getLineBreak() { | |
return writeHtml ? LINEBREAK_TRADITIONAL : LINEBREAK; | |
} | |
/** | |
* Output helper method to format a reported <code>Throwable</code> element.<p> | |
* | |
* This method ensures that exception stack traces are properly escaped | |
* when they are added to the report.<p> | |
* | |
* There is a member variable {@link #showExceptionStackTrace} in this | |
* class that controls if the stack track is shown or not. | |
* In a later version this might be configurable on a per-user basis.<p> | |
* | |
* @param throwable the exception to format | |
* @return the formatted StringBuffer | |
*/ | |
private StringBuffer getExceptionElementJS(Throwable throwable) { | |
StringBuffer buf = new StringBuffer(256); | |
if (showExceptionStackTrace) { | |
buf.append("aT('"); | |
buf.append(UtilProperties.getMessage(resource, "REPORT_EXCEPTION", getLocale())); | |
String exception = ReportEncoder.escapeXml(throwable.getLocalizedMessage()); | |
if (UtilValidate.isEmpty(exception)) { | |
exception = ReportEncoder.escapeXml(throwable.getMessage()); | |
} | |
if (UtilValidate.isNotEmpty(exception)) { | |
exception = exception.replaceAll("[\r\n]+", LINEBREAK); | |
buf.append(ReportStringUtil.escapeJavaScript(exception) + LINEBREAK); | |
} else { | |
buf.append(throwable.toString()); | |
} | |
buf.append("'); "); | |
} else { | |
buf.append("aT('"); | |
buf.append(UtilProperties.getMessage(resource, "REPORT_EXCEPTION", getLocale())); | |
buf.append(ReportStringUtil.escapeJavaScript(throwable.toString())); | |
buf.append("'); "); | |
} | |
return buf; | |
} | |
private StringBuffer getExceptionElementHtml(Throwable throwable) { | |
StringBuffer buf = new StringBuffer(256); | |
if (showExceptionStackTrace) { | |
buf.append("<span class='throw'>"); | |
buf.append(UtilProperties.getMessage(resource, "REPORT_EXCEPTION", getLocale())); | |
String exception = ReportEncoder.escapeXml(throwable.getLocalizedMessage()); | |
if (UtilValidate.isEmpty(exception)) { | |
exception = ReportEncoder.escapeXml(throwable.getMessage()); | |
} | |
if (UtilValidate.isNotEmpty(exception)) { | |
exception = exception.replaceAll("[\r\n]+", LINEBREAK); | |
buf.append(exception); | |
} else { | |
buf.append(throwable.toString()); | |
} | |
buf.append("</span>"); | |
} else { | |
buf.append("<span class='throw'>"); | |
buf.append(UtilProperties.getMessage(resource, "REPORT_EXCEPTION", getLocale())); | |
buf.append(throwable.toString()); | |
buf.append("</span>"); | |
buf.append(getLineBreak()); | |
} | |
return buf; | |
} | |
public void printMessageWithParam(String uiLabel, Object param) { | |
print(uiLabel, InterfaceReport.FORMAT_NOTE); | |
} | |
public void printMessageWithParam(int m, int n, String uiLabel, Object param) { | |
print(uiLabel, InterfaceReport.FORMAT_NOTE); | |
} | |
/** | |
* Builds the start html of the page, including setting of DOCTYPE and | |
* inserting a header with the content-type.<p> | |
* | |
* This overloads the default method of the parent class.<p> | |
* | |
* @return the start html of the page | |
*/ | |
public String htmlStart() { | |
return pageHtml(HTML_START, true); | |
} | |
/** | |
* Builds the start html of the page, including setting of DOCTYPE and | |
* inserting a header with the content-type.<p> | |
* | |
* This overloads the default method of the parent class.<p> | |
* | |
* @param loadStyles if true, the defaul style sheet will be loaded | |
* @return the start html of the page | |
*/ | |
public String htmlStart(boolean loadStyles) { | |
return pageHtml(HTML_START, loadStyles); | |
} | |
/** | |
* Builds the start html of the page, including setting of DOCTYPE and | |
* inserting a header with the content-type.<p> | |
* | |
* This overloads the default method of the parent class.<p> | |
* | |
* @param segment the HTML segment (START / END) | |
* @param loadStyles if true, the defaul style sheet will be loaded | |
* @return the start html of the page | |
*/ | |
public String pageHtml(int segment, boolean loadStyles) { | |
if (segment == HTML_START) { | |
StringBuffer result = new StringBuffer(512); | |
result.append("<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01//EN\">\n"); | |
result.append("<html>\n<head>\n"); | |
result.append("<meta HTTP-EQUIV=\"Content-Type\" CONTENT=\"text/html; charset=UTF-8\">\n"); | |
if (loadStyles) { | |
result.append("<link rel=\"stylesheet\" type=\"text/css\" href=\""); | |
result.append("/pricat/includes/pricat.css"); | |
result.append("\">\n"); | |
result.append("<script type=\"text/javascript\">\n"); | |
result.append(dialogScriptSubmit()); | |
result.append("</script>\n"); | |
} | |
return result.toString(); | |
} else { | |
return "</html>"; | |
} | |
} | |
/** | |
* Builds the standard javascript for submitting the dialog.<p> | |
* | |
* @return the standard javascript for submitting the dialog | |
*/ | |
public String dialogScriptSubmit() { | |
StringBuffer result = new StringBuffer(512); | |
result.append("function submitAction(actionValue, theForm, formName) {\n"); | |
result.append("\tif (theForm == null) {\n"); | |
result.append("\t\ttheForm = document.forms[formName];\n"); | |
result.append("\t}\n"); | |
result.append("\ttheForm.action.value = actionValue;\n"); | |
result.append("\ttheForm.submit();\n"); | |
result.append("\treturn false;\n"); | |
result.append("}\n"); | |
return result.toString(); | |
} | |
/** | |
* Returns true if the report Thread is still alive (i.e. running), false otherwise.<p> | |
* | |
* @return true if the report Thread is still alive | |
*/ | |
public boolean isAlive(HttpServletRequest request) { | |
ThreadGroup threadGroup = Thread.currentThread().getThreadGroup(); | |
int i = threadGroup.activeCount(); | |
Thread[] threads = new Thread[i]; | |
threadGroup.enumerate(threads, true); | |
AbstractReportThread thread = null; | |
for (int j=0; j<threads.length; j++) { | |
Thread threadInstance = threads[j]; | |
if (threadInstance instanceof AbstractReportThread) { | |
if(((AbstractReportThread)threadInstance).getUUID().toString().equals(getParamThread(request))) { | |
thread = (AbstractReportThread) threadInstance; | |
break; | |
} | |
} | |
} | |
if (thread != null) { | |
return thread.isAlive(); | |
} else { | |
return false; | |
} | |
} | |
/** | |
* Returns the thread parameter value.<p> | |
* | |
* @return the thread parameter value | |
*/ | |
public String getParamThread(HttpServletRequest request) { | |
String thread = request.getParameter("thread"); | |
return ReportStringUtil.isNotEmptyOrWhitespaceOnly(thread) ? thread : (paramThread == null? "" : paramThread); | |
} | |
/** | |
* Returns the threadhasnext parameter value.<p> | |
* | |
* @return the threadhasnext parameter value | |
*/ | |
public String getParamThreadHasNext(HttpServletRequest request) { | |
String threadhasnext = request.getParameter("threadhasnext"); | |
return ReportStringUtil.isNotEmptyOrWhitespaceOnly(threadhasnext) ? threadhasnext : "false"; | |
} | |
/** | |
* Builds the start html of the body.<p> | |
* | |
* @param className optional class attribute to add to the body tag | |
* @param parameters optional parameters to add to the body tag | |
* @return the start html of the body | |
*/ | |
public String bodyStart(String className, String parameters) { | |
return pageBody(HTML_START, className, parameters); | |
} | |
/** | |
* Builds the html of the body.<p> | |
* | |
* @param segment the HTML segment (START / END) | |
* @param className optional class attribute to add to the body tag | |
* @param parameters optional parameters to add to the body tag | |
* @return the html of the body | |
*/ | |
public String pageBody(int segment, String className, String parameters) { | |
if (segment == HTML_START) { | |
StringBuffer result = new StringBuffer(128); | |
result.append("</head>\n<body unselectable=\"on\""); | |
if (ReportStringUtil.isNotEmptyOrWhitespaceOnly(className)) { | |
result.append(" class=\""); | |
result.append(className); | |
result.append("\""); | |
} | |
if (ReportStringUtil.isNotEmpty(parameters)) { | |
result.append(" "); | |
result.append(parameters); | |
} | |
result.append(">\n"); | |
return result.toString(); | |
} else { | |
return "</body>"; | |
} | |
} | |
/** | |
* Builds the end html of the body.<p> | |
* | |
* @return the end html of the body | |
*/ | |
public String bodyEnd() { | |
return pageBody(HTML_END, null, null); | |
} | |
/** | |
* Builds the end html of the page.<p> | |
* | |
* @return the end html of the page | |
*/ | |
public String htmlEnd() { | |
return pageHtml(HTML_END, null); | |
} | |
/** | |
* Returns the default html for a workplace page, including setting of DOCTYPE and | |
* inserting a header with the content-type.<p> | |
* | |
* @param segment the HTML segment (START / END) | |
* @param title the title of the page, if null no title tag is inserted | |
* @return the default html for a workplace page | |
*/ | |
public String pageHtml(int segment, String title) { | |
return pageHtmlStyle(segment, title, null); | |
} | |
/** | |
* Returns the default html for a workplace page, including setting of DOCTYPE and | |
* inserting a header with the content-type, allowing the selection of an individual style sheet.<p> | |
* | |
* @param segment the HTML segment (START / END) | |
* @param title the title of the page, if null no title tag is inserted | |
* @param stylesheet the used style sheet, if null the default stylesheet 'workplace.css' is inserted | |
* @return the default html for a workplace page | |
*/ | |
public String pageHtmlStyle(int segment, String title, String stylesheet) { | |
if (segment == HTML_START) { | |
StringBuffer result = new StringBuffer(512); | |
// result.append("<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01//EN\">\n"); | |
// result.append("<html>\n<head>\n"); | |
// if (title != null) { | |
// result.append("<title>"); | |
// result.append(title); | |
// result.append("</title>\n"); | |
// } | |
// result.append("<meta HTTP-EQUIV=\"Content-Type\" CONTENT=\"text/html; charset=UTF-8\">\n"); | |
result.append("<link rel=\"stylesheet\" type=\"text/css\" href=\""); | |
result.append("/pricat/includes/pricat.css"); | |
result.append("\">\n"); | |
return result.toString(); | |
} else { | |
return ""; | |
// return "</html>"; | |
} | |
} | |
/** | |
* Returns the start html for the outer dialog window border. | |
* | |
* @return the start html for the outer dialog window border | |
*/ | |
public String dialogStart() { | |
return dialog(HTML_START, null); | |
} | |
/** | |
* Builds the outer dialog window border. | |
* | |
* @param segment the HTML segment (START / END) | |
* @param attributes optional additional attributes for the opening dialog table | |
* | |
* @return a dialog window start / end segment | |
*/ | |
public String dialog(int segment, String attributes) { | |
if (segment == HTML_START) { | |
StringBuffer html = new StringBuffer(512); | |
html.append("<table class=\"dialog\" cellpadding=\"0\" cellspacing=\"0\""); | |
if (attributes != null) { | |
html.append(" "); | |
html.append(attributes); | |
} | |
html.append("><tr><td>\n<table class=\"dialogbox\" cellpadding=\"0\" cellspacing=\"0\">\n"); | |
html.append("<tr><td>\n"); | |
return html.toString(); | |
} else { | |
return "</td></tr></table>\n</td></tr></table>\n<p> </p>\n"; | |
} | |
} | |
/** | |
* Returns the start html for the content area of the dialog window.<p> | |
* | |
* @param title the title for the dialog | |
* | |
* @return the start html for the content area of the dialog window | |
*/ | |
public String dialogContentStart(String title) { | |
return dialogContent(HTML_START, title); | |
} | |
/** | |
* Builds the content area of the dialog window.<p> | |
* | |
* @param segment the HTML segment (START / END) | |
* @param title the title String for the dialog window | |
* | |
* @return a content area start / end segment | |
*/ | |
public String dialogContent(int segment, String title) { | |
if (segment == HTML_START) { | |
StringBuffer result = new StringBuffer(512); | |
// null title is ok, we always want the title headline | |
result.append(dialogHead(title)); | |
result.append("<div class=\"dialogcontent\" unselectable=\"on\">\n"); | |
result.append("<!-- dialogcontent start -->\n"); | |
return result.toString(); | |
} else { | |
return "<!-- dialogcontent end -->\n</div>\n"; | |
} | |
} | |
/** | |
* Builds the title of the dialog window.<p> | |
* | |
* @param title the title String for the dialog window | |
* | |
* @return the HTML title String for the dialog window | |
*/ | |
public String dialogHead(String title) { | |
return "<div class=\"dialoghead\" unselectable=\"on\">" + (title == null ? "" : title) + "</div>"; | |
} | |
/** | |
* Returns the value of the title parameter, | |
* or null if this parameter was not provided.<p> | |
* | |
* This parameter is used to build the title | |
* of the dialog. It is a parameter so that the title | |
* can be passed to included elements.<p> | |
* | |
* @return the value of the title parameter | |
*/ | |
public String getParamTitle(HttpServletRequest request) { | |
if (paramTitle == null) { | |
paramTitle = request.getParameter("title"); | |
} | |
return paramTitle != null ? paramTitle : ""; | |
} | |
/** | |
* Returns all initialized parameters of the current workplace class | |
* as hidden field tags that can be inserted in a form.<p> | |
* | |
* @return all initialized parameters of the current workplace class | |
* as hidden field tags that can be inserted in a html form | |
*/ | |
public String paramsAsHidden(HttpServletRequest request) { | |
return paramsAsHidden(request, null); | |
} | |
/** | |
* Returns all initialized parameters of the current workplace class | |
* that are not in the given exclusion list as hidden field tags that can be inserted in a form.<p> | |
* | |
* @param excludes the parameters to exclude | |
* | |
* @return all initialized parameters of the current workplace class | |
* that are not in the given exclusion list as hidden field tags that can be inserted in a form | |
*/ | |
public String paramsAsHidden(HttpServletRequest request, Collection<?> excludes) { | |
StringBuffer result = new StringBuffer(512); | |
Map<String, Object> params = paramValues(request); | |
Iterator<?> i = params.entrySet().iterator(); | |
while (i.hasNext()) { | |
Map.Entry entry = (Map.Entry)i.next(); | |
String param = (String)entry.getKey(); | |
if ((excludes == null) || (!excludes.contains(param))) { | |
result.append("<input type=\"hidden\" name=\""); | |
result.append(param); | |
result.append("\" value=\""); | |
String encoded = ReportEncoder.encode( | |
entry.getValue().toString(), | |
"UTF-8"); | |
result.append(encoded); | |
result.append("\">\n"); | |
} | |
} | |
return result.toString(); | |
} | |
/** | |
* Returns the values of all parameter methods of this workplace class instance.<p> | |
* | |
* @return the values of all parameter methods of this workplace class instance | |
*/ | |
protected Map<String, Object> paramValues(HttpServletRequest request) { | |
List<Method> methods = paramGetMethods(); | |
Map<String, Object> map = new HashMap<String, Object>(methods.size()); | |
Iterator<Method> i = methods.iterator(); | |
while (i.hasNext()) { | |
Method m = (Method)i.next(); | |
Object o = null; | |
try { | |
o = m.invoke(this, new Object[0]); | |
} catch (InvocationTargetException ite) { | |
// can usually be ignored | |
} catch (IllegalAccessException eae) { | |
// can usually be ignored | |
} | |
if (o != null) { | |
map.put(m.getName().substring(8).toLowerCase(), o); | |
} | |
} | |
return map; | |
} | |
/** | |
* Returns a list of all methods of the current class instance that | |
* start with "getParam" and have no parameters.<p> | |
* | |
* @return a list of all methods of the current class instance that | |
* start with "getParam" and have no parameters | |
*/ | |
private List<Method> paramGetMethods() { | |
List<Method> list = new ArrayList<Method>(); | |
Method[] methods = this.getClass().getMethods(); | |
int length = methods.length; | |
for (int i = 0; i < length; i++) { | |
Method method = methods[i]; | |
if (method.getName().startsWith("getParam") && (method.getParameterTypes().length == 0)) { | |
// Debug.logInfo("getMethod: " + method.getName(), module); | |
list.add(method); | |
} | |
} | |
return list; | |
} | |
/** | |
* Returns an optional introduction text to be displayed above the report output.<p> | |
* | |
* @return an optional introduction text | |
*/ | |
public String reportIntroductionText() { | |
return ""; | |
} | |
/** | |
* Returns an optional conclusion text to be displayed below the report output.<p> | |
* | |
* @return an optional conclusion text | |
*/ | |
public String reportConclusionText() { | |
return ""; | |
} | |
/** | |
* Returns the end html for the content area of the dialog window.<p> | |
* | |
* @return the end html for the content area of the dialog window | |
*/ | |
public String dialogContentEnd() { | |
return dialogContent(HTML_END, null); | |
} | |
/** | |
* Builds a button row with an "Ok" and a "Cancel" button.<p> | |
* | |
* This row is displayed when the first report is running.<p> | |
* | |
* @param okAttrs optional attributes for the ok button | |
* @param cancelAttrs optional attributes for the cancel button | |
* @return the button row | |
*/ | |
public String dialogButtonsContinue(String okAttrs, String cancelAttrs) { | |
return dialogButtons(new int[] {BUTTON_OK, BUTTON_CANCEL}, new String[] { | |
okAttrs, | |
cancelAttrs}); | |
} | |
/** | |
* Builds a button row with an "OK" and a "Cancel" button.<p> | |
* | |
* This row is used when a single report is running or after the first report has finished.<p> | |
* | |
* @param okAttrs optional attributes for the ok button | |
* @param cancelAttrs optional attributes for the cancel button | |
* @return the button row | |
*/ | |
public String dialogButtonsOkCancel(HttpServletRequest request, String okAttrs, String cancelAttrs) { | |
if (Boolean.valueOf(getParamThreadHasNext(request)).booleanValue() | |
&& ReportStringUtil.isNotEmpty(getParamReportContinueKey())) { | |
return dialogButtons(new int[] {BUTTON_OK, BUTTON_CANCEL}, new String[] { | |
okAttrs, | |
cancelAttrs}); | |
} | |
return dialogButtons(new int[] {BUTTON_OK}, new String[] {okAttrs}); | |
} | |
/** | |
* Builds a button row with an "OK", a "Cancel" and a "Download" button.<p> | |
* | |
* This row is used when a single report is running or after the first report has finished.<p> | |
* | |
* @param okAttrs optional attributes for the ok button | |
* @param cancelAttrs optional attributes for the cancel button | |
* @param downloadAttrs optional attributes for the download button | |
* @return the button row | |
*/ | |
public String dialogButtonsOkCancelDownload(HttpServletRequest request, String okAttrs, String cancelAttrs, String downloadAttrs) { | |
if (ReportStringUtil.isEmptyOrWhitespaceOnly(downloadAttrs)) { | |
downloadAttrs = ""; | |
} else { | |
downloadAttrs += " "; | |
} | |
if (Boolean.valueOf(getParamThreadHasNext(request)).booleanValue() | |
&& ReportStringUtil.isNotEmpty(getParamReportContinueKey())) { | |
return dialogButtons(new int[] {BUTTON_OK, BUTTON_CANCEL, BUTTON_DOWNLOAD}, new String[] { | |
okAttrs, | |
cancelAttrs, | |
downloadAttrs + "onclick=\"downloadPricat(" + (sequenceNum > 0 ? sequenceNum : "") + ");\""}); | |
} | |
return dialogButtons(new int[] {BUTTON_OK, BUTTON_DOWNLOAD}, new String[] { | |
okAttrs, | |
downloadAttrs + "onclick=\"downloadPricat(" + (sequenceNum > 0 ? sequenceNum : "") + ");\""}); | |
} | |
/** | |
* Builds the html for the button row under the dialog content area, including buttons.<p> | |
* | |
* @param buttons array of constants of which buttons to include in the row | |
* @param attributes array of Strings for additional button attributes | |
* | |
* @return the html for the button row under the dialog content area, including buttons | |
*/ | |
public String dialogButtons(int[] buttons, String[] attributes) { | |
StringBuffer result = new StringBuffer(256); | |
result.append(dialogButtonRow(HTML_START)); | |
for (int i = 0; i < buttons.length; i++) { | |
dialogButtonsHtml(result, buttons[i], attributes[i]); | |
} | |
result.append(dialogButtonRow(HTML_END)); | |
return result.toString(); | |
} | |
/** | |
* Builds the button row under the dialog content area without the buttons.<p> | |
* | |
* @param segment the HTML segment (START / END) | |
* | |
* @return the button row start / end segment | |
*/ | |
public String dialogButtonRow(int segment) { | |
if (segment == HTML_START) { | |
return "<!-- button row start -->\n<div class=\"dialogbuttons\" unselectable=\"on\">\n"; | |
} else { | |
return "</div>\n<!-- button row end -->\n"; | |
} | |
} | |
/** | |
* Renders the HTML for a single input button of a specified type.<p> | |
* | |
* @param result a string buffer where the rendered HTML gets appended to | |
* @param button a integer key to identify the button | |
* @param attribute an optional string with possible tag attributes, or null | |
*/ | |
protected void dialogButtonsHtml(StringBuffer result, int button, String attribute) { | |
attribute = appendDelimiter(attribute); | |
switch (button) { | |
case BUTTON_OK: | |
result.append("<input name=\"ok\" value=\""); | |
result.append(UtilProperties.getMessage(resource, "DIALOG_BUTTON_OK", getLocale()) + "\""); | |
if (attribute.toLowerCase().indexOf("onclick") == -1) { | |
result.append(" type=\"submit\""); | |
} else { | |
result.append(" type=\"button\""); | |
} | |
result.append(" class=\"dialogbutton\""); | |
result.append(attribute); | |
result.append(">\n"); | |
break; | |
case BUTTON_CANCEL: | |
result.append("<input name=\"cancel\" type=\"button\" value=\""); | |
result.append(UtilProperties.getMessage(resource, "DIALOG_BUTTON_CANCEL", getLocale()) + "\""); | |
if (attribute.toLowerCase().indexOf("onclick") == -1) { | |
result.append(" onclick=\"submitAction('" + DIALOG_CANCEL + "', form);\""); | |
} | |
result.append(" class=\"dialogbutton\""); | |
result.append(attribute); | |
result.append(">\n"); | |
break; | |
case BUTTON_EDIT: | |
result.append("<input name=\"ok\" value=\""); | |
result.append(UtilProperties.getMessage(resource, "DIALOG_BUTTON_EDIT", getLocale()) + "\""); | |
if (attribute.toLowerCase().indexOf("onclick") == -1) { | |
result.append(" type=\"submit\""); | |
} else { | |
result.append(" type=\"button\""); | |
} | |
result.append(" class=\"dialogbutton\""); | |
result.append(attribute); | |
result.append(">\n"); | |
break; | |
case BUTTON_DISCARD: | |
result.append("<input name=\"cancel\" type=\"button\" value=\""); | |
result.append(UtilProperties.getMessage(resource, "DIALOG_BUTTON_DISCARD", getLocale()) + "\""); | |
if (attribute.toLowerCase().indexOf("onclick") == -1) { | |
result.append(" onclick=\"submitAction('" + DIALOG_CANCEL + "', form);\""); | |
} | |
result.append(" class=\"dialogbutton\""); | |
result.append(attribute); | |
result.append(">\n"); | |
break; | |
case BUTTON_CLOSE: | |
result.append("<input name=\"close\" type=\"button\" value=\""); | |
result.append(UtilProperties.getMessage(resource, "DIALOG_BUTTON_CLOSE", getLocale()) + "\""); | |
if (attribute.toLowerCase().indexOf("onclick") == -1) { | |
result.append(" onclick=\"submitAction('" + DIALOG_CANCEL + "', form);\""); | |
} | |
result.append(" class=\"dialogbutton\""); | |
result.append(attribute); | |
result.append(">\n"); | |
break; | |
case BUTTON_ADVANCED: | |
result.append("<input name=\"advanced\" type=\"button\" value=\""); | |
result.append(UtilProperties.getMessage(resource, "DIALOG_BUTTON_ADVANCE", getLocale()) + "\""); | |
result.append(" class=\"dialogbutton\""); | |
result.append(attribute); | |
result.append(">\n"); | |
break; | |
case BUTTON_SET: | |
result.append("<input name=\"set\" type=\"button\" value=\""); | |
result.append(UtilProperties.getMessage(resource, "DIALOG_BUTTON_SET", getLocale()) + "\""); | |
if (attribute.toLowerCase().indexOf("onclick") == -1) { | |
result.append(" onclick=\"submitAction('" + DIALOG_SET + "', form);\""); | |
} | |
result.append(" class=\"dialogbutton\""); | |
result.append(attribute); | |
result.append(">\n"); | |
break; | |
case BUTTON_BACK: | |
result.append("<input name=\"set\" type=\"button\" value=\""); | |
result.append(UtilProperties.getMessage(resource, "DIALOG_BUTTON_BACK", getLocale()) + "\""); | |
if (attribute.toLowerCase().indexOf("onclick") == -1) { | |
result.append(" onclick=\"submitAction('" + DIALOG_BACK + "', form);\""); | |
} | |
result.append(" class=\"dialogbutton\""); | |
result.append(attribute); | |
result.append(">\n"); | |
break; | |
case BUTTON_CONTINUE: | |
result.append("<input name=\"set\" type=\"button\" value=\""); | |
result.append(UtilProperties.getMessage(resource, "DIALOG_BUTTON_CONTINUE", getLocale()) + "\""); | |
if (attribute.toLowerCase().indexOf("onclick") == -1) { | |
result.append(" onclick=\"submitAction('" + DIALOG_CONTINUE + "', form);\""); | |
} | |
result.append(" class=\"dialogbutton\""); | |
result.append(attribute); | |
result.append(">\n"); | |
break; | |
case BUTTON_DETAILS: | |
result.append("<input name=\"details\" type=\"button\" value=\""); | |
result.append(UtilProperties.getMessage(resource, "DIALOG_BUTTON_DETAIL", getLocale()) + "\""); | |
result.append(" class=\"dialogbutton\""); | |
result.append(attribute); | |
result.append(">\n"); | |
break; | |
case BUTTON_DOWNLOAD: | |
result.append("<input name=\"download\" type=\"button\" value=\""); | |
result.append(UtilProperties.getMessage(resource, "DIALOG_BUTTON_DOWNLOAD", getLocale()) + "\""); | |
result.append(" class=\"dialogbutton\""); | |
result.append(attribute); | |
result.append(">\n"); | |
break; | |
default: | |
// not a valid button code, just insert a warning in the HTML | |
result.append("<!-- invalid button code: "); | |
result.append(button); | |
result.append(" -->\n"); | |
} | |
} | |
/** | |
* Appends a space char. between tag attributes.<p> | |
* | |
* @param attribute a tag attribute | |
* | |
* @return the tag attribute with a leading space char | |
*/ | |
protected String appendDelimiter(String attribute) { | |
if (ReportStringUtil.isNotEmpty(attribute)) { | |
if (!attribute.startsWith(" ")) { | |
// add a delimiter space between the beginning button HTML and the button tag attributes | |
return " " + attribute; | |
} else { | |
return attribute; | |
} | |
} | |
return ""; | |
} | |
/** | |
* Returns true if the dialog operation has to be performed on multiple resources.<p> | |
* | |
* @return true if the dialog operation has to be performed on multiple resources, otherwise false | |
*/ | |
public boolean isMultiOperation(HttpServletRequest request) { | |
return (getResourceList(request).size() > 1); | |
} | |
/** | |
* Returns the resources that are defined for the dialog operation. | |
* | |
* For single resource operations, the list contains one item: the resource name found | |
* in the request parameter value of the "resource" parameter. | |
* | |
* @return the resources that are defined for the dialog operation | |
*/ | |
public List<String> getResourceList(HttpServletRequest request) { | |
if (resourceList == null) { | |
// use lazy initializing | |
if (getParamResourcelist(request) != null) { | |
// found the resourcelist parameter | |
resourceList = StringUtil.split(getParamResourcelist(request), DELIMITER_RESOURCES); | |
Collections.sort(resourceList); | |
} else { | |
// this is a single resource operation, create list containing the resource name | |
resourceList = new ArrayList<String>(1); | |
String resource = getParamResource(request); | |
if (ReportStringUtil.isNotEmptyOrWhitespaceOnly(resource)) { | |
resourceList.add(resource); | |
} else { | |
resourceList.add(""); | |
} | |
} | |
} | |
return resourceList; | |
} | |
/** | |
* Returns the value of the resource list parameter, or null if the parameter is not provided.<p> | |
* | |
* This parameter selects the resources to perform operations on.<p> | |
* | |
* @return the value of the resource list parameter or null, if the parameter is not provided | |
*/ | |
public String getParamResourcelist(HttpServletRequest request) { | |
if (ReportStringUtil.isNotEmpty(paramResourcelist) && !"null".equals(paramResourcelist)) { | |
return paramResourcelist; | |
} else { | |
return null; | |
} | |
} | |
/** | |
* Returns the value of the file parameter, | |
* or null if this parameter was not provided.<p> | |
* | |
* The file parameter selects the file on which the dialog action | |
* is to be performed.<p> | |
* | |
* @return the value of the file parameter | |
*/ | |
public String getParamResource(HttpServletRequest request) { | |
paramResource = request.getParameter("resource"); | |
if ((paramResource != null) && !"null".equals(paramResource)) { | |
return paramResource; | |
} else { | |
return null; | |
} | |
} | |
/** | |
* Returns if the workplace must be refreshed.<p> | |
* | |
* @return <code>"true"</code> if the workplace must be refreshed. | |
*/ | |
public String getParamRefreshWorkplace() { | |
return paramRefreshWorkplace; | |
} | |
/** | |
* Returns the key name which contains the localized message for the continue checkbox.<p> | |
* | |
* @return the key name which contains the localized message for the continue checkbox | |
*/ | |
public String getParamReportContinueKey() { | |
if (paramReportContinueKey == null) { | |
paramReportContinueKey = ""; | |
} | |
return paramReportContinueKey; | |
} | |
/** | |
* Returns the value of the resourcelist parameter in form of a String separated | |
* with {@link #DELIMITER_RESOURCES}, or the value of the resource parameter if the | |
* first parameter is not provided (no multiple choice has been done.<p> | |
* | |
* This may be used for jsps as value for the parameter for resources {@link #PARAM_RESOURCELIST}.<p> | |
* | |
* @return the value of the resourcelist parameter or null, if the parameter is not provided | |
*/ | |
public String getResourceListAsParam(HttpServletRequest request) { | |
String result = getParamResourcelist(request); | |
if (ReportStringUtil.isEmptyOrWhitespaceOnly(result)) { | |
result = getParamResource(request); | |
} | |
return result; | |
} | |
/** | |
* Returns the end html for the outer dialog window border.<p> | |
* | |
* @return the end html for the outer dialog window border | |
*/ | |
public String dialogEnd() { | |
return dialog(HTML_END, null); | |
} | |
/** | |
* Returns the http URI of the current dialog, to be used | |
* as value for the "action" attribute of a html form.<p> | |
* | |
* This URI is the real one.<p> | |
* | |
* @return the http URI of the current dialog | |
*/ | |
public String getDialogRealUri(HttpServletRequest request) { | |
return String.valueOf(request.getAttribute(DIALOG_URI)); | |
} | |
/** | |
* Set the report form uri. | |
* | |
* @param request | |
* @param formUri | |
*/ | |
public void setFormRealUri(HttpServletRequest request, String formUri) { | |
request.setAttribute(FORM_URI, formUri); | |
} | |
/** | |
* Get the report form uri. | |
* | |
* @param request | |
* @return | |
*/ | |
public String getFormRealUri(HttpServletRequest request) { | |
return (String) request.getAttribute(FORM_URI); | |
} | |
public void addLogFile(String logFileName) { | |
if (logFile == null || logFileOutputStream == null) { | |
this.logFileName = logFileName; | |
logFile = FileUtil.getFile(logFileName); | |
try { | |
logFileOutputStream = new FileOutputStream(logFile); | |
} catch (FileNotFoundException e) { | |
// do nothing | |
} | |
} | |
} | |
public String closeLogFile() { | |
if (logFileOutputStream != null) { | |
try { | |
logFileOutputStream.flush(); | |
} catch (IOException e) { | |
// do nothing | |
} finally { | |
if (logFileOutputStream != null) { | |
try { | |
logFileOutputStream.close(); | |
} catch (IOException e) { | |
// do nothing | |
Debug.logError(e, HtmlReport.module); | |
} | |
} | |
} | |
} | |
return logFileName; | |
} | |
public String getLogFileName() { | |
return logFileName; | |
} | |
public long getSequenceNum() { | |
return sequenceNum; | |
} | |
public void setSequenceNum(long sequenceNum) { | |
this.sequenceNum = sequenceNum; | |
} | |
} |