You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ofbiz.apache.org by jl...@apache.org on 2016/12/14 10:16:04 UTC

svn commit: r1774165 [2/4] - in /ofbiz/trunk/specialpurpose: cmssite/src/main/java/org/apache/ofbiz/cmssite/multisite/ pricat/src/main/java/org/apache/ofbiz/htmlreport/ pricat/src/main/java/org/apache/ofbiz/htmlreport/sample/ pricat/src/main/java/org/a...

Modified: ofbiz/trunk/specialpurpose/pricat/src/main/java/org/apache/ofbiz/htmlreport/HtmlReport.java
URL: http://svn.apache.org/viewvc/ofbiz/trunk/specialpurpose/pricat/src/main/java/org/apache/ofbiz/htmlreport/HtmlReport.java?rev=1774165&r1=1774164&r2=1774165&view=diff
==============================================================================
--- ofbiz/trunk/specialpurpose/pricat/src/main/java/org/apache/ofbiz/htmlreport/HtmlReport.java (original)
+++ ofbiz/trunk/specialpurpose/pricat/src/main/java/org/apache/ofbiz/htmlreport/HtmlReport.java Wed Dec 14 10:16:04 2016
@@ -1,1347 +1,1347 @@
-/*******************************************************************************
- * 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>&nbsp;</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;
-    }
-}
+/*******************************************************************************
+ * 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>&nbsp;</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>
+     * 

[... 429 lines stripped ...]