No functional change, assures that all Java files are svn:native
This is mostly related with the new pricat component and 2 files in cmssite (I 
guess also related with the new pricat component )

git-svn-id: https://svn.apache.org/repos/asf/ofbiz/trunk@1774165 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/specialpurpose/pricat/src/main/java/org/apache/ofbiz/htmlreport/AbstractHtmlReport.java b/specialpurpose/pricat/src/main/java/org/apache/ofbiz/htmlreport/AbstractHtmlReport.java
index f5a7b5e..fddd936 100644
--- a/specialpurpose/pricat/src/main/java/org/apache/ofbiz/htmlreport/AbstractHtmlReport.java
+++ b/specialpurpose/pricat/src/main/java/org/apache/ofbiz/htmlreport/AbstractHtmlReport.java
@@ -1,140 +1,140 @@
-/*******************************************************************************

- * 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.IOException;

-import javax.servlet.ServletException;

-import javax.servlet.http.HttpServletRequest;

-import javax.servlet.http.HttpServletResponse;

-import javax.servlet.jsp.JspException;

-

-import org.apache.ofbiz.htmlreport.util.ReportStringUtil;

-

-/**

- * HTML report output to be used for database create tables / drop tables operations.

- * 

- */

-public abstract class AbstractHtmlReport extends HtmlReport {

-    

-    public static final String module = AbstractHtmlReport.class.getName();

-

-    public final static String THREAD_TYPE = "thread_type";

-    

-    public final static String RUN_CREATETABLE_SCRIPT = "runcreatetablescript";

-    

-    public final static String RUN_DROPTABLE_SCRIPT = "rundroptablescript";

-    

-    public final static String FILE_REPORT_OUTPUT = "specialpurpose/pricat/webapp/pricat/ftl/report.ftl";

-    

-    /**

-     * Constructs a new report using the provided locale for the output language.

-     * 

-     * @param request HttpServletRequest

-     * @param response HttpServletResponse

-     */

-    public AbstractHtmlReport(HttpServletRequest request, HttpServletResponse response) {

-        this(request, response, false, false);

-    }

-

-    /**

-     * Constructs a new report using the provided locale for the output language.

-     *  

-     * @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 AbstractHtmlReport(HttpServletRequest request, HttpServletResponse response, boolean writeHtml, boolean isTransient) {

-        super(request, response, writeHtml, isTransient);

-    }

-    

-    /**

-     * Prepare display an html report.

-     * 

-     * @throws IOException 

-     */

-    public void prepareDisplayReport(HttpServletRequest request, HttpServletResponse response, String name, String dialogUri) throws IOException {

-

-        if (ReportStringUtil.isNotEmpty(dialogUri)) {

-            setDialogRealUri(request, dialogUri);

-        }

-        

-        String action = getParamAction(request);

-        if (action == null) action = "";

-        if (action.equals("reportend") || action.equals("cancel")) {

-            setParamAction("reportend");

-        } else if (action.equals("reportupdate")) {

-            setParamAction("reportupdate");

-        } else {

-            InterfaceReportThread thread = initializeThread(request, response, name);

-            thread.start();

-            setParamAction("reportbegin");

-            setParamThread(thread.getUUID().toString());

-        }

-    }

-

-    /**

-     * Initializes the report thread to use for this report.<p>

-     * 

-     * @return the reported thread to use for this report.

-     */

-    public abstract InterfaceReportThread initializeThread(HttpServletRequest request, HttpServletResponse response, String name);

-

-    /**

-     * Set the report dialog uri.

-     * 

-     * @param dialogUri

-     */

-    public void setDialogRealUri(HttpServletRequest request, String dialogUri) {

-        request.setAttribute(DIALOG_URI, dialogUri);

-    }

-

-    public static String checkButton(HttpServletRequest request, HttpServletResponse response) {

-        String action = request.getParameter("action");

-        if (ReportStringUtil.isNotEmpty(action)) {

-            if (action.equalsIgnoreCase("ok")) {

-                request.removeAttribute(SESSION_REPORT_CLASS);

-                request.removeAttribute(DIALOG_URI);

-                return "ok";

-            } else if (action.equalsIgnoreCase("cancel")) {

-                request.removeAttribute(SESSION_REPORT_CLASS);

-                request.removeAttribute(DIALOG_URI);

-                return "cancel";

-            }

-        }

-        action = request.getParameter("ok");

-        if (ReportStringUtil.isNotEmpty(action)) {

-            if (action.equalsIgnoreCase("ok")) {

-                request.removeAttribute(SESSION_REPORT_CLASS);

-                request.removeAttribute(DIALOG_URI);

-                return "ok";

-            }

-        }

-        action = request.getParameter("cancel");

-        if (ReportStringUtil.isNotEmpty(action)) {

-            if (action.equalsIgnoreCase("cancel")) {

-                request.removeAttribute(SESSION_REPORT_CLASS);

-                request.removeAttribute(DIALOG_URI);

-                return "cancel";

-            }

-        }

-        

-        return "success";

-    }

+/*******************************************************************************
+ * 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.IOException;
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import javax.servlet.jsp.JspException;
+
+import org.apache.ofbiz.htmlreport.util.ReportStringUtil;
+
+/**
+ * HTML report output to be used for database create tables / drop tables operations.
+ * 
+ */
+public abstract class AbstractHtmlReport extends HtmlReport {
+    
+    public static final String module = AbstractHtmlReport.class.getName();
+
+    public final static String THREAD_TYPE = "thread_type";
+    
+    public final static String RUN_CREATETABLE_SCRIPT = "runcreatetablescript";
+    
+    public final static String RUN_DROPTABLE_SCRIPT = "rundroptablescript";
+    
+    public final static String FILE_REPORT_OUTPUT = "specialpurpose/pricat/webapp/pricat/ftl/report.ftl";
+    
+    /**
+     * Constructs a new report using the provided locale for the output language.
+     * 
+     * @param request HttpServletRequest
+     * @param response HttpServletResponse
+     */
+    public AbstractHtmlReport(HttpServletRequest request, HttpServletResponse response) {
+        this(request, response, false, false);
+    }
+
+    /**
+     * Constructs a new report using the provided locale for the output language.
+     *  
+     * @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 AbstractHtmlReport(HttpServletRequest request, HttpServletResponse response, boolean writeHtml, boolean isTransient) {
+        super(request, response, writeHtml, isTransient);
+    }
+    
+    /**
+     * Prepare display an html report.
+     * 
+     * @throws IOException 
+     */
+    public void prepareDisplayReport(HttpServletRequest request, HttpServletResponse response, String name, String dialogUri) throws IOException {
+
+        if (ReportStringUtil.isNotEmpty(dialogUri)) {
+            setDialogRealUri(request, dialogUri);
+        }
+        
+        String action = getParamAction(request);
+        if (action == null) action = "";
+        if (action.equals("reportend") || action.equals("cancel")) {
+            setParamAction("reportend");
+        } else if (action.equals("reportupdate")) {
+            setParamAction("reportupdate");
+        } else {
+            InterfaceReportThread thread = initializeThread(request, response, name);
+            thread.start();
+            setParamAction("reportbegin");
+            setParamThread(thread.getUUID().toString());
+        }
+    }
+
+    /**
+     * Initializes the report thread to use for this report.<p>
+     * 
+     * @return the reported thread to use for this report.
+     */
+    public abstract InterfaceReportThread initializeThread(HttpServletRequest request, HttpServletResponse response, String name);
+
+    /**
+     * Set the report dialog uri.
+     * 
+     * @param dialogUri
+     */
+    public void setDialogRealUri(HttpServletRequest request, String dialogUri) {
+        request.setAttribute(DIALOG_URI, dialogUri);
+    }
+
+    public static String checkButton(HttpServletRequest request, HttpServletResponse response) {
+        String action = request.getParameter("action");
+        if (ReportStringUtil.isNotEmpty(action)) {
+            if (action.equalsIgnoreCase("ok")) {
+                request.removeAttribute(SESSION_REPORT_CLASS);
+                request.removeAttribute(DIALOG_URI);
+                return "ok";
+            } else if (action.equalsIgnoreCase("cancel")) {
+                request.removeAttribute(SESSION_REPORT_CLASS);
+                request.removeAttribute(DIALOG_URI);
+                return "cancel";
+            }
+        }
+        action = request.getParameter("ok");
+        if (ReportStringUtil.isNotEmpty(action)) {
+            if (action.equalsIgnoreCase("ok")) {
+                request.removeAttribute(SESSION_REPORT_CLASS);
+                request.removeAttribute(DIALOG_URI);
+                return "ok";
+            }
+        }
+        action = request.getParameter("cancel");
+        if (ReportStringUtil.isNotEmpty(action)) {
+            if (action.equalsIgnoreCase("cancel")) {
+                request.removeAttribute(SESSION_REPORT_CLASS);
+                request.removeAttribute(DIALOG_URI);
+                return "cancel";
+            }
+        }
+        
+        return "success";
+    }
 }
\ No newline at end of file
diff --git a/specialpurpose/pricat/src/main/java/org/apache/ofbiz/htmlreport/AbstractReport.java b/specialpurpose/pricat/src/main/java/org/apache/ofbiz/htmlreport/AbstractReport.java
index b565b8b..bd01ccf 100644
--- a/specialpurpose/pricat/src/main/java/org/apache/ofbiz/htmlreport/AbstractReport.java
+++ b/specialpurpose/pricat/src/main/java/org/apache/ofbiz/htmlreport/AbstractReport.java
@@ -1,187 +1,187 @@
-/*******************************************************************************

- * 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.util.ArrayList;

-import java.util.List;

-import java.util.Locale;

-

-/**

- * Base report class.

- * 

- */

-public abstract class AbstractReport implements InterfaceReport {

-

-    /** Contains all error messages generated by the report. */

-    private List<Object> errors;

-

-    /** The locale this report is written in. */

-    private Locale locale;

-

-    /** Runtime of the report. */

-    private long startTime;

-

-    /** Contains all warning messages generated by the report. */

-    private List<Object> warnings = new ArrayList<Object>();

-

-    /** Day constant. */

-    private static final long DAYS = 1000 * 60 * 60 * 24;

-

-    /** Hour constant. */

-    private static final long HOURS = 1000 * 60 * 60;

-

-    /** Minute constant. */

-    private static final long MINUTES = 1000 * 60;

-

-    /** Second constant. */

-    private static final long SECONDS = 1000;

-    

-    public static final String SESSION_REPORT_CLASS = "OFBIZ_HTML_REPORT";

-

-    public void addError(Object obj) {

-

-        errors.add(obj);

-    }

-

-    public void addWarning(Object obj) {

-

-        warnings.add(obj);

-    }

-

-    public String formatRuntime() {

-

-        long runtime = getRuntime();

-        long seconds = (runtime / SECONDS) % 60;

-        long minutes = (runtime / MINUTES) % 60;

-        long hours = (runtime / HOURS) % 24;

-        long days = runtime / DAYS;

-        StringBuffer strBuf = new StringBuffer();

-

-        if (days > 0) {

-            if (days < 10) {

-                strBuf.append('0');

-            }

-            strBuf.append(days);

-            strBuf.append(':');

-        }

-

-        if (hours < 10) {

-            strBuf.append('0');

-        }

-        strBuf.append(hours);

-        strBuf.append(':');

-

-        if (minutes < 10) {

-            strBuf.append('0');

-        }

-        strBuf.append(minutes);

-        strBuf.append(':');

-

-        if (seconds < 10) {

-            strBuf.append('0');

-        }

-        strBuf.append(seconds);

-

-        return strBuf.toString();

-    }

-

-    public List<Object> getErrors() {

-        return errors;

-    }

-

-    public Locale getLocale() {

-        return locale;

-    }

-

-    public long getRuntime() {

-        return System.currentTimeMillis() - startTime;

-    }

-

-    public List<Object> getWarnings() {

-        return warnings;

-    }

-

-    public boolean hasError() {

-        return (errors.size() > 0);

-    }

-    

-    public boolean hasWarning() {

-        return (warnings.size() > 0);

-    }

-

-    public void resetRuntime() {

-        startTime = System.currentTimeMillis();

-    }

-

-    /**

-     * Initializes some member variables for this report.<p>

-     * 

-     * @param locale the locale for this report

-     */

-    protected void init(Locale locale) {

-        startTime = System.currentTimeMillis();

-        this.locale = locale;

-        errors = new ArrayList<Object>();

-    }

-

-    /**

-     * Prints a String to the report.<p>

-     *

-     * @param value the String to add

-     */

-    public void print(String value) {

-        print(value, FORMAT_DEFAULT);

-    }

-

-    /**

-     * Prints a String to the report, using the indicated formatting.<p>

-     * 

-     * Use the contants starting with <code>FORMAT</code> from this interface

-     * to indicate which formatting to use.<p>

-     *

-     * @param value the message container to add

-     * @param format the formatting to use for the output

-     */

-    public abstract void print(String value, int format);

-

-    /**

-     * Prints a String with line break to the report.<p>

-     * 

-     * @param value the message container to add

-     */

-    public void println(String value) {

-

-        println(value, FORMAT_DEFAULT);

-    }

-

-    /**

-     * Prints a String with line break to the report, using the indicated formatting.<p>

-     * 

-     * Use the contants starting with <code>FORMAT</code> from this interface

-     * to indicate which formatting to use.<p>

-     *

-     * @param value the String to add

-     * @param format the formatting to use for the output

-     */

-    public void println(String value, int format) {

-        print(value, format);

-        println();

-    }

-

+/*******************************************************************************
+ * 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.util.ArrayList;
+import java.util.List;
+import java.util.Locale;
+
+/**
+ * Base report class.
+ * 
+ */
+public abstract class AbstractReport implements InterfaceReport {
+
+    /** Contains all error messages generated by the report. */
+    private List<Object> errors;
+
+    /** The locale this report is written in. */
+    private Locale locale;
+
+    /** Runtime of the report. */
+    private long startTime;
+
+    /** Contains all warning messages generated by the report. */
+    private List<Object> warnings = new ArrayList<Object>();
+
+    /** Day constant. */
+    private static final long DAYS = 1000 * 60 * 60 * 24;
+
+    /** Hour constant. */
+    private static final long HOURS = 1000 * 60 * 60;
+
+    /** Minute constant. */
+    private static final long MINUTES = 1000 * 60;
+
+    /** Second constant. */
+    private static final long SECONDS = 1000;
+    
+    public static final String SESSION_REPORT_CLASS = "OFBIZ_HTML_REPORT";
+
+    public void addError(Object obj) {
+
+        errors.add(obj);
+    }
+
+    public void addWarning(Object obj) {
+
+        warnings.add(obj);
+    }
+
+    public String formatRuntime() {
+
+        long runtime = getRuntime();
+        long seconds = (runtime / SECONDS) % 60;
+        long minutes = (runtime / MINUTES) % 60;
+        long hours = (runtime / HOURS) % 24;
+        long days = runtime / DAYS;
+        StringBuffer strBuf = new StringBuffer();
+
+        if (days > 0) {
+            if (days < 10) {
+                strBuf.append('0');
+            }
+            strBuf.append(days);
+            strBuf.append(':');
+        }
+
+        if (hours < 10) {
+            strBuf.append('0');
+        }
+        strBuf.append(hours);
+        strBuf.append(':');
+
+        if (minutes < 10) {
+            strBuf.append('0');
+        }
+        strBuf.append(minutes);
+        strBuf.append(':');
+
+        if (seconds < 10) {
+            strBuf.append('0');
+        }
+        strBuf.append(seconds);
+
+        return strBuf.toString();
+    }
+
+    public List<Object> getErrors() {
+        return errors;
+    }
+
+    public Locale getLocale() {
+        return locale;
+    }
+
+    public long getRuntime() {
+        return System.currentTimeMillis() - startTime;
+    }
+
+    public List<Object> getWarnings() {
+        return warnings;
+    }
+
+    public boolean hasError() {
+        return (errors.size() > 0);
+    }
+    
+    public boolean hasWarning() {
+        return (warnings.size() > 0);
+    }
+
+    public void resetRuntime() {
+        startTime = System.currentTimeMillis();
+    }
+
+    /**
+     * Initializes some member variables for this report.<p>
+     * 
+     * @param locale the locale for this report
+     */
+    protected void init(Locale locale) {
+        startTime = System.currentTimeMillis();
+        this.locale = locale;
+        errors = new ArrayList<Object>();
+    }
+
+    /**
+     * Prints a String to the report.<p>
+     *
+     * @param value the String to add
+     */
+    public void print(String value) {
+        print(value, FORMAT_DEFAULT);
+    }
+
+    /**
+     * Prints a String to the report, using the indicated formatting.<p>
+     * 
+     * Use the contants starting with <code>FORMAT</code> from this interface
+     * to indicate which formatting to use.<p>
+     *
+     * @param value the message container to add
+     * @param format the formatting to use for the output
+     */
+    public abstract void print(String value, int format);
+
+    /**
+     * Prints a String with line break to the report.<p>
+     * 
+     * @param value the message container to add
+     */
+    public void println(String value) {
+
+        println(value, FORMAT_DEFAULT);
+    }
+
+    /**
+     * Prints a String with line break to the report, using the indicated formatting.<p>
+     * 
+     * Use the contants starting with <code>FORMAT</code> from this interface
+     * to indicate which formatting to use.<p>
+     *
+     * @param value the String to add
+     * @param format the formatting to use for the output
+     */
+    public void println(String value, int format) {
+        print(value, format);
+        println();
+    }
+
 }
\ No newline at end of file
diff --git a/specialpurpose/pricat/src/main/java/org/apache/ofbiz/htmlreport/AbstractReportThread.java b/specialpurpose/pricat/src/main/java/org/apache/ofbiz/htmlreport/AbstractReportThread.java
index 2e86a40..9b2c956 100644
--- a/specialpurpose/pricat/src/main/java/org/apache/ofbiz/htmlreport/AbstractReportThread.java
+++ b/specialpurpose/pricat/src/main/java/org/apache/ofbiz/htmlreport/AbstractReportThread.java
@@ -1,213 +1,213 @@
-/*******************************************************************************

- * 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.util.List;

-import java.util.Locale;

-

-import javax.servlet.http.HttpServletRequest;

-import javax.servlet.http.HttpServletResponse;

-

-import org.apache.ofbiz.base.util.UtilHttp;

-import org.safehaus.uuid.EthernetAddress;

-import org.safehaus.uuid.UUID;

-import org.safehaus.uuid.UUIDGenerator;

-

-/** 

- * Provides a common Thread class for the reports.

- * 

- */

-public abstract class AbstractReportThread extends Thread implements InterfaceReportThread {

-

-    /** Indicates if the thread was already checked by the grim reaper. */

-    private boolean doomed;

-    

-    /** The report that belongs to the thread. */

-    private InterfaceReport report;

-

-    /** The time this report is running. */

-    private long startTime;

-    

-    private UUID uuid;

-

-    private Locale locale;

-

-    /**

-     * Constructs a new report Thread with the given name.

-     */

-    protected AbstractReportThread(HttpServletRequest request, HttpServletResponse response, String name) {

-

-        super(Thread.currentThread().getThreadGroup(), name);

-        // report Threads are never daemon Threads

-        setDaemon(false);

-        // the session must not be updated when it is used in a report

-        EthernetAddress ethernetAddress = UUIDGenerator.getInstance().getDummyAddress();

-        uuid = UUIDGenerator.getInstance().generateTimeBasedUUID(ethernetAddress);

-

-        setName(name + " [" + uuid.toString() + "]");

-        // new Threads are not doomed

-        doomed = false;

-        // set start time

-        startTime = System.currentTimeMillis();

-        locale = UtilHttp.getLocale(request);

-    }

-    

-    

-    public UUID getUUID() {

-        return uuid;

-    }

-

-    /**

-     * Adds an error object to the list of errors that occured during the report.

-     * 

-     * @param obj the error object

-     */

-    public void addError(Object obj) {

-

-        if (getReport() != null) {

-            getReport().addError(obj);

-        }

-    }

-

-    /**

-     * Returns the error exception in case there was an error during the execution of

-     * this Thread, null otherwise.

-     * 

-     * @return the error exception in case there was an error, null otherwise

-     */

-    public Throwable getError() {

-

-        return null;

-    }

-

-    /**

-     * Returns a list of all errors that occured during the report.

-     * 

-     * @return an error list that occured during the report

-     */

-    public List<?> getErrors() {

-

-        if (getReport() != null) {

-            return getReport().getErrors();

-        } else {

-            return null;

-        }

-    }

-

-    /**

-     * Returns the part of the report that is ready for output.

-     * 

-     * @return the part of the report that is ready for output

-     */

-    public abstract String getReportUpdate();

-

-    /** 

-     * Returns the time this report has been running.

-     * 

-     * @return the time this report has been running

-     */

-    public synchronized long getRuntime() {

-

-        if (doomed) {

-            return startTime;

-        } else {

-            return System.currentTimeMillis() - startTime;

-        }

-    }

-

-    /**

-     * Returns if the report generated an error output.

-     * 

-     * @return true if the report generated an error, otherwise false

-     */

-    public boolean hasError() {

-

-        if (getReport() != null) {

-            return (getReport().getErrors().size() > 0);

-        } else {

-            return false;

-        }

-    }

-

-    /**

-     * Returns true if this thread is already "doomed" to be deleted.

-     * 

-     * A OFBiz deamon Thread (the "Grim Reaper") will collect all 

-     * doomed Threads, i.e. threads that are not longer active for some

-     * time.

-     * 

-     * @return true if this thread is already "doomed" to be deleted

-     */

-    public synchronized boolean isDoomed() {

-

-        if (isAlive()) {

-            // as long as the Thread is still active it is never doomed

-            return false;

-        }

-        if (doomed) {

-            // not longer active, and already doomed, so rest in peace...

-            return true;

-        }

-        // condemn the Thread to be collected by the grim reaper next time  

-        startTime = getRuntime();

-        doomed = true;

-        return false;

-    }

-

-    /**

-     * Returns the report where the output of this Thread is written to.

-     * 

-     * @return the report where the output of this Thread is written to

-     */

-    protected InterfaceReport getReport() {

-

-        return report;

-    }

-

-    /**

-     * Initialize a HTML report for this Thread.

-     * 

-     */

-    protected void initHtmlReport(HttpServletRequest request, HttpServletResponse response) {

-

-        report = HtmlReport.getInstance(request, response);

-        ((HtmlReport) report).setParamThread(getUUID().toString());

-    }

-    

-    /**

-     * Initialize a HTML report for this Thread.

-     * 

-     */

-    protected void initHtmlReport(HttpServletRequest request, HttpServletResponse response, boolean writeHtml, boolean isTransient) {

-

-        report = HtmlReport.getInstance(request, response, writeHtml, isTransient);

-        ((HtmlReport) report).setParamThread(getUUID().toString());

-    }

-    

-    protected void initHtmlReport(HttpServletRequest request, HttpServletResponse response, boolean writeHtml, boolean isTransient, String logFileName) {

-

-        report = HtmlReport.getInstance(request, response, writeHtml, isTransient, logFileName);

-        ((HtmlReport) report).setParamThread(getUUID().toString());

-    }

-    

-    protected Locale getLocale() {

-        return locale;

-    }

-

-}

+/*******************************************************************************
+ * 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.util.List;
+import java.util.Locale;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.apache.ofbiz.base.util.UtilHttp;
+import org.safehaus.uuid.EthernetAddress;
+import org.safehaus.uuid.UUID;
+import org.safehaus.uuid.UUIDGenerator;
+
+/** 
+ * Provides a common Thread class for the reports.
+ * 
+ */
+public abstract class AbstractReportThread extends Thread implements InterfaceReportThread {
+
+    /** Indicates if the thread was already checked by the grim reaper. */
+    private boolean doomed;
+    
+    /** The report that belongs to the thread. */
+    private InterfaceReport report;
+
+    /** The time this report is running. */
+    private long startTime;
+    
+    private UUID uuid;
+
+    private Locale locale;
+
+    /**
+     * Constructs a new report Thread with the given name.
+     */
+    protected AbstractReportThread(HttpServletRequest request, HttpServletResponse response, String name) {
+
+        super(Thread.currentThread().getThreadGroup(), name);
+        // report Threads are never daemon Threads
+        setDaemon(false);
+        // the session must not be updated when it is used in a report
+        EthernetAddress ethernetAddress = UUIDGenerator.getInstance().getDummyAddress();
+        uuid = UUIDGenerator.getInstance().generateTimeBasedUUID(ethernetAddress);
+
+        setName(name + " [" + uuid.toString() + "]");
+        // new Threads are not doomed
+        doomed = false;
+        // set start time
+        startTime = System.currentTimeMillis();
+        locale = UtilHttp.getLocale(request);
+    }
+    
+    
+    public UUID getUUID() {
+        return uuid;
+    }
+
+    /**
+     * Adds an error object to the list of errors that occured during the report.
+     * 
+     * @param obj the error object
+     */
+    public void addError(Object obj) {
+
+        if (getReport() != null) {
+            getReport().addError(obj);
+        }
+    }
+
+    /**
+     * Returns the error exception in case there was an error during the execution of
+     * this Thread, null otherwise.
+     * 
+     * @return the error exception in case there was an error, null otherwise
+     */
+    public Throwable getError() {
+
+        return null;
+    }
+
+    /**
+     * Returns a list of all errors that occured during the report.
+     * 
+     * @return an error list that occured during the report
+     */
+    public List<?> getErrors() {
+
+        if (getReport() != null) {
+            return getReport().getErrors();
+        } else {
+            return null;
+        }
+    }
+
+    /**
+     * Returns the part of the report that is ready for output.
+     * 
+     * @return the part of the report that is ready for output
+     */
+    public abstract String getReportUpdate();
+
+    /** 
+     * Returns the time this report has been running.
+     * 
+     * @return the time this report has been running
+     */
+    public synchronized long getRuntime() {
+
+        if (doomed) {
+            return startTime;
+        } else {
+            return System.currentTimeMillis() - startTime;
+        }
+    }
+
+    /**
+     * Returns if the report generated an error output.
+     * 
+     * @return true if the report generated an error, otherwise false
+     */
+    public boolean hasError() {
+
+        if (getReport() != null) {
+            return (getReport().getErrors().size() > 0);
+        } else {
+            return false;
+        }
+    }
+
+    /**
+     * Returns true if this thread is already "doomed" to be deleted.
+     * 
+     * A OFBiz deamon Thread (the "Grim Reaper") will collect all 
+     * doomed Threads, i.e. threads that are not longer active for some
+     * time.
+     * 
+     * @return true if this thread is already "doomed" to be deleted
+     */
+    public synchronized boolean isDoomed() {
+
+        if (isAlive()) {
+            // as long as the Thread is still active it is never doomed
+            return false;
+        }
+        if (doomed) {
+            // not longer active, and already doomed, so rest in peace...
+            return true;
+        }
+        // condemn the Thread to be collected by the grim reaper next time  
+        startTime = getRuntime();
+        doomed = true;
+        return false;
+    }
+
+    /**
+     * Returns the report where the output of this Thread is written to.
+     * 
+     * @return the report where the output of this Thread is written to
+     */
+    protected InterfaceReport getReport() {
+
+        return report;
+    }
+
+    /**
+     * Initialize a HTML report for this Thread.
+     * 
+     */
+    protected void initHtmlReport(HttpServletRequest request, HttpServletResponse response) {
+
+        report = HtmlReport.getInstance(request, response);
+        ((HtmlReport) report).setParamThread(getUUID().toString());
+    }
+    
+    /**
+     * Initialize a HTML report for this Thread.
+     * 
+     */
+    protected void initHtmlReport(HttpServletRequest request, HttpServletResponse response, boolean writeHtml, boolean isTransient) {
+
+        report = HtmlReport.getInstance(request, response, writeHtml, isTransient);
+        ((HtmlReport) report).setParamThread(getUUID().toString());
+    }
+    
+    protected void initHtmlReport(HttpServletRequest request, HttpServletResponse response, boolean writeHtml, boolean isTransient, String logFileName) {
+
+        report = HtmlReport.getInstance(request, response, writeHtml, isTransient, logFileName);
+        ((HtmlReport) report).setParamThread(getUUID().toString());
+    }
+    
+    protected Locale getLocale() {
+        return locale;
+    }
+
+}
diff --git a/specialpurpose/pricat/src/main/java/org/apache/ofbiz/htmlreport/HtmlReport.java b/specialpurpose/pricat/src/main/java/org/apache/ofbiz/htmlreport/HtmlReport.java
index 95b161d..761e8f6 100644
--- a/specialpurpose/pricat/src/main/java/org/apache/ofbiz/htmlreport/HtmlReport.java
+++ b/specialpurpose/pricat/src/main/java/org/apache/ofbiz/htmlreport/HtmlReport.java
@@ -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>
+     * 
+     * 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;
+    }
+}
diff --git a/specialpurpose/pricat/src/main/java/org/apache/ofbiz/htmlreport/InterfaceReport.java b/specialpurpose/pricat/src/main/java/org/apache/ofbiz/htmlreport/InterfaceReport.java
index 931ee50..4146278 100644
--- a/specialpurpose/pricat/src/main/java/org/apache/ofbiz/htmlreport/InterfaceReport.java
+++ b/specialpurpose/pricat/src/main/java/org/apache/ofbiz/htmlreport/InterfaceReport.java
@@ -1,230 +1,230 @@
-/*******************************************************************************

- * 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.util.List;

-import java.util.Locale;

-

-/** 

- * This is the interface for the report classes which are used for the output

- * during operations that run on a separate Thread in OFBiz,

- * like import, export etc.<p>

- * 

- */

-public interface InterfaceReport {

-

-    /** Indicates default formatting. */

-    int FORMAT_DEFAULT = 0;

-

-    /** Indicates error formatting. */

-    int FORMAT_ERROR = 5;

-

-    /** Indicates headline formatting. */

-    int FORMAT_HEADLINE = 2;

-

-    /** Indicates note formatting. */

-    int FORMAT_NOTE = 3;

-

-    /** Indicates OK formatting. */

-    int FORMAT_OK = 4;

-

-    /** Indicates warning formatting. */

-    int FORMAT_WARNING = 1;

-

-    /** Request parameter value that this report should create an "extended" output. */

-    String REPORT_TYPE_EXTENDED = "extended";

-

-    /** Request parameter value that this report should create a "simple" output. */

-    String REPORT_TYPE_SIMPLE = "simple";

-

-    /**

-     * Adds an error object to the list of errors that occured during the report.<p>

-     * 

-     * @param obj the error object

-     */

-    void addError(Object obj);

-

-    /**

-     * Adds a warning object to the list of warnings that occured during the report.<p>

-     * 

-     * @param obj the error object

-     */

-    void addWarning(Object obj);

-

-    /**

-     * Formats the runtime formatted as "hh:mm:ss".<p>

-     * 

-     * @return the runtime formatted as "hh:mm:ss"

-     */

-    String formatRuntime();

-

-    /**

-     * Returns a list of all errors that occured during the report.<p>

-     * 

-     * @return an error list that occured during the report

-     */

-    List<Object> getErrors();

-

-    /**

-     * Returns the locale this report was initialized with.<p>

-     * 

-     * @return the locale this report was initialized with

-     */

-    Locale getLocale();

-

-    /**

-     * Updates this report, this processes all new output added since 

-     * the last call to this method.<p>

-     * 

-     * This is only required in case the output is written to a HTML page,

-     * if the shell output is used, this will just return an empty String.<p>

-     * 

-     * @return new elements that have been added to the report and not yet processed.

-     */

-    String getReportUpdate();

-

-    /** 

-     * Returns the time this report has been running.<p>

-     * 

-     * @return the time this report has been running

-     */

-    long getRuntime();

-

-    /**

-     * Returns a list of all warnings that occured during the report.<p>

-     * 

-     * @return a warning list that occured during the report

-     */

-    List<Object> getWarnings();

-

-    /**

-     * Returns if the report generated an error output.<p>

-     * 

-     * @return true if the report generated an error, otherwise false

-     */

-    boolean hasError();

-

-    /**

-     * Returns if the report generated a warning output.<p>

-     * 

-     * @return true if the report generated a warning, otherwise false

-     */

-    boolean hasWarning();

-

-    /**

-     * Prints a localized message to the report.<p>

-     * 

-     * @param uiLabel the String to add

-     */

-    void print(String uiLabel);

-

-    /**

-     * Prints a localized message to the report, using the indicated formatting.<p>

-     * 

-     * Use the contants starting with <code>FORMAT</code> from this interface

-     * to indicate which formatting to use.<p>

-     *

-     * @param uiLabel the String to add

-     * @param format the formatting to use for the output

-     */

-    void print(String uiLabel, int format);

-

-    /**

-     * Adds a line break to the report.<p>

-     */

-    void println();

-

-    /**

-     * Prints a localized message to the report.<p>

-     * 

-     * @param uiLabel the message to add

-     */

-    void println(String uiLabel);

-

-    /**

-     * Prints a localized message to the report, using the indicated formatting.<p>

-     *

-     * Use the contents starting with <code>FORMAT</code> from this interface

-     * to indicate which formatting to use.

-     *

-     * @param uiLabel the message container to add

-     * @param format the formatting to use for the output

-     */

-    void println(String uiLabel, int format);

-

-    /**

-     * Adds an Exception to the report, ensuring that the Exception content is

-     * processed to generate a valid output esp. for HTML pages.<p>

-     * 

-     * The exception will be stored and the output will later be processed

-     * in a special way.<p>    

-     * 

-     * @param t the exception to add

-     * 

-     */

-    void println(Throwable t);

-

-    /**

-     * Prints a localized message followed by a parameter and dots to the report.<p>

-     * 

-     * @param uiLabel the Message to add

-     * @param param the Parameter to add

-     */

-    void printMessageWithParam(String uiLabel, Object param);

-

-    /**

-     * Convenience method to print a localized message, followed by a parameter and dots to the report.<p>

-     * 

-     * The output follows the pattern: ( 3 / 8 ) Deleting filename.txt ...

-     * 

-     * @param m the number of the report output

-     * @param n the total number of report outputs

-     * @param uiLabel the Message to add

-     * @param param the Parameter to add

-     * 

-     */

-    void printMessageWithParam(int m, int n, String uiLabel, Object param);

-

-    /**

-     * Resets the runtime to 0 milliseconds.<p>

-     */

-    void resetRuntime();

-

-    /**

-     * Add a log file to the report.

-     * 

-     * @param logFileName

-     */

-    void addLogFile(String logFileName);

-

-    /**

-     * Close log file if necessary.

-     * 

-     */

-    String closeLogFile();

-    

-    /**

-     * Set log's sequence number.

-     * @param sequenceNum

-     */

-    void setSequenceNum(long sequenceNum);

-    

-    long getSequenceNum();

-

+/*******************************************************************************
+ * 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.util.List;
+import java.util.Locale;
+
+/** 
+ * This is the interface for the report classes which are used for the output
+ * during operations that run on a separate Thread in OFBiz,
+ * like import, export etc.<p>
+ * 
+ */
+public interface InterfaceReport {
+
+    /** Indicates default formatting. */
+    int FORMAT_DEFAULT = 0;
+
+    /** Indicates error formatting. */
+    int FORMAT_ERROR = 5;
+
+    /** Indicates headline formatting. */
+    int FORMAT_HEADLINE = 2;
+
+    /** Indicates note formatting. */
+    int FORMAT_NOTE = 3;
+
+    /** Indicates OK formatting. */
+    int FORMAT_OK = 4;
+
+    /** Indicates warning formatting. */
+    int FORMAT_WARNING = 1;
+
+    /** Request parameter value that this report should create an "extended" output. */
+    String REPORT_TYPE_EXTENDED = "extended";
+
+    /** Request parameter value that this report should create a "simple" output. */
+    String REPORT_TYPE_SIMPLE = "simple";
+
+    /**
+     * Adds an error object to the list of errors that occured during the report.<p>
+     * 
+     * @param obj the error object
+     */
+    void addError(Object obj);
+
+    /**
+     * Adds a warning object to the list of warnings that occured during the report.<p>
+     * 
+     * @param obj the error object
+     */
+    void addWarning(Object obj);
+
+    /**
+     * Formats the runtime formatted as "hh:mm:ss".<p>
+     * 
+     * @return the runtime formatted as "hh:mm:ss"
+     */
+    String formatRuntime();
+
+    /**
+     * Returns a list of all errors that occured during the report.<p>
+     * 
+     * @return an error list that occured during the report
+     */
+    List<Object> getErrors();
+
+    /**
+     * Returns the locale this report was initialized with.<p>
+     * 
+     * @return the locale this report was initialized with
+     */
+    Locale getLocale();
+
+    /**
+     * Updates this report, this processes all new output added since 
+     * the last call to this method.<p>
+     * 
+     * This is only required in case the output is written to a HTML page,
+     * if the shell output is used, this will just return an empty String.<p>
+     * 
+     * @return new elements that have been added to the report and not yet processed.
+     */
+    String getReportUpdate();
+
+    /** 
+     * Returns the time this report has been running.<p>
+     * 
+     * @return the time this report has been running
+     */
+    long getRuntime();
+
+    /**
+     * Returns a list of all warnings that occured during the report.<p>
+     * 
+     * @return a warning list that occured during the report
+     */
+    List<Object> getWarnings();
+
+    /**
+     * Returns if the report generated an error output.<p>
+     * 
+     * @return true if the report generated an error, otherwise false
+     */
+    boolean hasError();
+
+    /**
+     * Returns if the report generated a warning output.<p>
+     * 
+     * @return true if the report generated a warning, otherwise false
+     */
+    boolean hasWarning();
+
+    /**
+     * Prints a localized message to the report.<p>
+     * 
+     * @param uiLabel the String to add
+     */
+    void print(String uiLabel);
+
+    /**
+     * Prints a localized message to the report, using the indicated formatting.<p>
+     * 
+     * Use the contants starting with <code>FORMAT</code> from this interface
+     * to indicate which formatting to use.<p>
+     *
+     * @param uiLabel the String to add
+     * @param format the formatting to use for the output
+     */
+    void print(String uiLabel, int format);
+
+    /**
+     * Adds a line break to the report.<p>
+     */
+    void println();
+
+    /**
+     * Prints a localized message to the report.<p>
+     * 
+     * @param uiLabel the message to add
+     */
+    void println(String uiLabel);
+
+    /**
+     * Prints a localized message to the report, using the indicated formatting.<p>
+     *
+     * Use the contents starting with <code>FORMAT</code> from this interface
+     * to indicate which formatting to use.
+     *
+     * @param uiLabel the message container to add
+     * @param format the formatting to use for the output
+     */
+    void println(String uiLabel, int format);
+
+    /**
+     * Adds an Exception to the report, ensuring that the Exception content is
+     * processed to generate a valid output esp. for HTML pages.<p>
+     * 
+     * The exception will be stored and the output will later be processed
+     * in a special way.<p>    
+     * 
+     * @param t the exception to add
+     * 
+     */
+    void println(Throwable t);
+
+    /**
+     * Prints a localized message followed by a parameter and dots to the report.<p>
+     * 
+     * @param uiLabel the Message to add
+     * @param param the Parameter to add
+     */
+    void printMessageWithParam(String uiLabel, Object param);
+
+    /**
+     * Convenience method to print a localized message, followed by a parameter and dots to the report.<p>
+     * 
+     * The output follows the pattern: ( 3 / 8 ) Deleting filename.txt ...
+     * 
+     * @param m the number of the report output
+     * @param n the total number of report outputs
+     * @param uiLabel the Message to add
+     * @param param the Parameter to add
+     * 
+     */
+    void printMessageWithParam(int m, int n, String uiLabel, Object param);
+
+    /**
+     * Resets the runtime to 0 milliseconds.<p>
+     */
+    void resetRuntime();
+
+    /**
+     * Add a log file to the report.
+     * 
+     * @param logFileName
+     */
+    void addLogFile(String logFileName);
+
+    /**
+     * Close log file if necessary.
+     * 
+     */
+    String closeLogFile();
+    
+    /**
+     * Set log's sequence number.
+     * @param sequenceNum
+     */
+    void setSequenceNum(long sequenceNum);
+    
+    long getSequenceNum();
+
 }
\ No newline at end of file
diff --git a/specialpurpose/pricat/src/main/java/org/apache/ofbiz/htmlreport/InterfaceReportThread.java b/specialpurpose/pricat/src/main/java/org/apache/ofbiz/htmlreport/InterfaceReportThread.java
index 78e46df..344ef11 100644
--- a/specialpurpose/pricat/src/main/java/org/apache/ofbiz/htmlreport/InterfaceReportThread.java
+++ b/specialpurpose/pricat/src/main/java/org/apache/ofbiz/htmlreport/InterfaceReportThread.java
@@ -1,41 +1,41 @@
-/*******************************************************************************

- * 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 org.safehaus.uuid.UUID;

-

-/**

- * Identifies a class that can be used as a report thread.

- * 

- */

-public interface InterfaceReportThread {

-

-    /**

-     * Starts the report thread.<p>

-     */

-    void start();

-

-    /**

-     * Returns the UUID of this report thread.<p>

-     * 

-     * @return the UUID of this report thread

-     */

-    UUID getUUID();

-

-}

+/*******************************************************************************
+ * 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 org.safehaus.uuid.UUID;
+
+/**
+ * Identifies a class that can be used as a report thread.
+ * 
+ */
+public interface InterfaceReportThread {
+
+    /**
+     * Starts the report thread.<p>
+     */
+    void start();
+
+    /**
+     * Returns the UUID of this report thread.<p>
+     * 
+     * @return the UUID of this report thread
+     */
+    UUID getUUID();
+
+}
diff --git a/specialpurpose/pricat/src/main/java/org/apache/ofbiz/htmlreport/util/ReportEncoder.java b/specialpurpose/pricat/src/main/java/org/apache/ofbiz/htmlreport/util/ReportEncoder.java
index e787742..d82d3d0 100644
--- a/specialpurpose/pricat/src/main/java/org/apache/ofbiz/htmlreport/util/ReportEncoder.java
+++ b/specialpurpose/pricat/src/main/java/org/apache/ofbiz/htmlreport/util/ReportEncoder.java
@@ -1,678 +1,678 @@
-/*******************************************************************************

- * 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.util;

-

-import java.io.UnsupportedEncodingException;

-import java.net.URLDecoder;

-import java.net.URLEncoder;

-import java.nio.CharBuffer;

-import java.nio.charset.Charset;

-import java.nio.charset.CharsetEncoder;

-import java.util.HashMap;

-import java.util.Map;

-import java.util.regex.Matcher;

-import java.util.regex.Pattern;

-

-/**

- * The ReportEncoder class provides static methods to decode and encode data.<p>

- * 

- * The methods in this class are substitutes for <code>java.net.URLEncoder.encode()</code> and

- * <code>java.net.URLDecoder.decode()</code>.<p>

- * 

- * The de- and encoding uses the same coding mechanism as JavaScript, special characters are

- * replaced with <code>%hex</code> where hex is a two digit hex number.<p>

- * 

- * <b>Note:</b> On the client side (browser) instead of using corresponding <code>escape</code>

- * and <code>unescape</code> JavaScript functions, better use <code>encodeURIComponent</code> and

- * <code>decodeURIComponent</code> functions which are work properly with unicode characters.

- * These functions are supported in IE 5.5+ and NS 6+ only.<p>

- * 

- */

-public final class ReportEncoder {

-

-    /** Constant for the standard <code>ISO-8859-1</code> encoding. */

-    public static final String ENCODING_ISO_8859_1 = "ISO-8859-1";

-

-    /** Constant for the standard <code>US-ASCII</code> encoding. */

-    public static final String ENCODING_US_ASCII = "US-ASCII";

-

-    /** 

-     * Constant for the standard <code>UTF-8</code> encoding.<p>

-     * 

-     * Default encoding for JavaScript decodeUriComponent methods is <code>UTF-8</code> by w3c standard. 

-     */

-    public static final String ENCODING_UTF_8 = "UTF-8";

-

-    /** The regex pattern to match HTML entities. */

-    private static final Pattern ENTITIY_PATTERN = Pattern.compile("\\&#\\d+;");

-

-    /** The prefix for HTML entities. */

-    private static final String ENTITY_PREFIX = "&#";

-

-    /** The replacement for HTML entity prefix in parameters. */

-    private static final String ENTITY_REPLACEMENT = "$$";

-

-    /** A cache for encoding name lookup. */

-    private static Map<String, String> encodingCache = new HashMap<String, String>(16);

-

-    /** The plus entity. */

-    private static final String PLUS_ENTITY = ENTITY_PREFIX + "043;";

-

-    /**

-     * Constructor.<p>

-     */

-    private ReportEncoder() {

-        // empty

-    }

-

-    /**

-     * Adjusts the given String by making sure all characters that can be displayed 

-     * in the given charset are contained as chars, whereas all other non-displayable

-     * characters are converted to HTML entities.<p> 

-     * 

-     * Just calls {@link #decodeHtmlEntities(String, String)} first and feeds the result

-     * to {@link #encodeHtmlEntities(String, String)}. <p>

-     *  

-     * @param input the input to adjust the HTML encoding for

-     * @param encoding the charset to encode the result with\

-     * 

-     * @return the input with the decoded/encoded HTML entities

-     */

-    public static String adjustHtmlEncoding(String input, String encoding) {

-

-        return encodeHtmlEntities(decodeHtmlEntities(input, encoding), encoding);

-    }

-

-    /**

-     * Changes the encoding of a byte array that represents a String.<p>

-     * 

-     * @param input the byte array to convert

-     * @param oldEncoding the current encoding of the byte array

-     * @param newEncoding the new encoding of the byte array

-     * 

-     * @return the byte array encoded in the new encoding

-     */

-    public static byte[] changeEncoding(byte[] input, String oldEncoding, String newEncoding) {

-

-        if ((oldEncoding == null) || (newEncoding == null)) {

-            return input;

-        }

-        if (oldEncoding.trim().equalsIgnoreCase(newEncoding.trim())) {

-            return input;

-        }

-        byte[] result = input;

-        try {

-            result = (new String(input, oldEncoding)).getBytes(newEncoding);

-        } catch (UnsupportedEncodingException e) {

-            // return value will be input value

-        }

-        return result;

-    }

-

-    /**

-     * Creates a String out of a byte array with the specified encoding, falling back

-     * to the system default in case the encoding name is not valid.<p>

-     * 

-     * Use this method as a replacement for <code>new String(byte[], encoding)</code>

-     * to avoid possible encoding problems.<p>

-     * 

-     * @param bytes the bytes to decode 

-     * @param encoding the encoding scheme to use for decoding the bytes

-     * 

-     * @return the bytes decoded to a String

-     */

-    public static String createString(byte[] bytes, String encoding) {

-

-        String enc = encoding.intern();

-        if (enc != ENCODING_UTF_8) {

-            enc = lookupEncoding(enc, null);

-        }

-        if (enc != null) {

-            try {

-                return new String(bytes, enc);

-            } catch (UnsupportedEncodingException e) {

-                // this can _never_ happen since the charset was looked up first 

-            }

-        } else {

-            enc = ENCODING_UTF_8;

-            try {

-                return new String(bytes, enc);

-            } catch (UnsupportedEncodingException e) {

-                // this can also _never_ happen since the default encoding is always valid

-            }

-        }

-        // this code is unreachable in practice

-        return null;

-    }

-

-    /**

-     * Decodes a String using UTF-8 encoding, which is the standard for http data transmission

-     * with GET ant POST requests.<p>

-     * 

-     * @param source the String to decode

-     * 

-     * @return String the decoded source String

-     */

-    public static String decode(String source) {

-

-        return decode(source, ENCODING_UTF_8);

-    }

-

-    /**

-     * This method is a substitute for <code>URLDecoder.decode()</code>.<p>

-     * 

-     * In case you don't know what encoding to use, set the value of 

-     * the <code>encoding</code> parameter to <code>null</code>. 

-     * This method will then default to UTF-8 encoding, which is probably the right one.<p>

-     * 

-     * @param source The string to decode

-     * @param encoding The encoding to use (if null, the system default is used)

-     * 

-     * @return The decoded source String

-     */

-    public static String decode(String source, String encoding) {

-

-        if (source == null) {

-            return null;

-        }

-        if (encoding != null) {

-            try {

-                return URLDecoder.decode(source, encoding);

-            } catch (java.io.UnsupportedEncodingException e) {

-                // will fallback to default

-            }

-        }

-        // fallback to default decoding

-        try {

-            return URLDecoder.decode(source, ENCODING_UTF_8);

-        } catch (java.io.UnsupportedEncodingException e) {

-            // ignore

-        }

-        return source;

-    }

-

-    /**

-     * Decodes HTML entity references like <code>&amp;#8364;</code> that are contained in the 

-     * String to a regular character, but only if that character is contained in the given 

-     * encodings charset.<p> 

-     * 

-     * @param input the input to decode the HTML entities in

-     * @param encoding the charset to decode the input for

-     * @return the input with the decoded HTML entities

-     * 

-     * @see #encodeHtmlEntities(String, String)

-     */

-    public static String decodeHtmlEntities(String input, String encoding) {

-

-        Matcher matcher = ENTITIY_PATTERN.matcher(input);

-        StringBuffer result = new StringBuffer(input.length());

-        Charset charset = Charset.forName(encoding);

-        CharsetEncoder encoder = charset.newEncoder();

-

-        while (matcher.find()) {

-            String entity = matcher.group();

-            String value = entity.substring(2, entity.length() - 1);

-            int c = Integer.valueOf(value).intValue();

-            if (c < 128) {

-                // first 128 chars are contained in almost every charset

-                entity = new String(new char[] {(char)c});

-                // this is intended as performance improvement since 

-                // the canEncode() operation appears quite CPU heavy

-            } else if (encoder.canEncode((char)c)) {

-                // encoder can encode this char

-                entity = new String(new char[] {(char)c});

-            }

-            matcher.appendReplacement(result, entity);

-        }

-        matcher.appendTail(result);

-        return result.toString();

-    }

-

-    /**

-     * Decodes a string used as parameter in an uri in a way independent of other encodings/decodings applied before.<p>

-     * 

-     * @param input the encoded parameter string

-     * 

-     * @return the decoded parameter string

-     * 

-     * @see #encodeParameter(String)

-     */

-    public static String decodeParameter(String input) {

-

-        String result = ReportStringUtil.substitute(input, ENTITY_REPLACEMENT, ENTITY_PREFIX);

-        return ReportEncoder.decodeHtmlEntities(result, ENCODING_UTF_8);

-    }

-

-    /**

-     * Encodes a String using UTF-8 encoding, which is the standard for http data transmission

-     * with GET ant POST requests.<p>

-     * 

-     * @param source the String to encode

-     * 

-     * @return String the encoded source String

-     */

-    public static String encode(String source) {

-

-        return encode(source, ENCODING_UTF_8);

-    }

-

-    /**

-     * This method is a substitute for <code>URLEncoder.encode()</code>.<p>

-     * 

-     * In case you don't know what encoding to use, set the value of 

-     * the <code>encoding</code> parameter to <code>null</code>. 

-     * This method will then default to UTF-8 encoding, which is probably the right one.<p>

-     * 

-     * @param source the String to encode

-     * @param encoding the encoding to use (if null, the system default is used)

-     * 

-     * @return the encoded source String

-     */

-    public static String encode(String source, String encoding) {

-

-        if (source == null) {

-            return null;

-        }

-        if (encoding != null) {

-            try {

-                return URLEncoder.encode(source, encoding);

-            } catch (java.io.UnsupportedEncodingException e) {

-                // will fallback to default

-            }

-        }

-        // fallback to default encoding

-        try {

-            return URLEncoder.encode(source, ENCODING_UTF_8);

-        } catch (java.io.UnsupportedEncodingException e) {

-            // ignore

-        }

-        return source;

-    }

-

-    /**

-     * Encodes all characters that are contained in the String which can not displayed 

-     * in the given encodings charset with HTML entity references

-     * like <code>&amp;#8364;</code>.<p>

-     * 

-     * This is required since a Java String is 

-     * internally always stored as Unicode, meaning it can contain almost every character, but 

-     * the HTML charset used might not support all such characters.<p>

-     * 

-     * @param input the input to encode for HTML

-     * @param encoding the charset to encode the result with

-     * 

-     * @return the input with the encoded HTML entities

-     * 

-     * @see #decodeHtmlEntities(String, String)

-     */

-    public static String encodeHtmlEntities(String input, String encoding) {

-

-        StringBuffer result = new StringBuffer(input.length() * 2);

-        CharBuffer buffer = CharBuffer.wrap(input.toCharArray());

-        Charset charset = Charset.forName(encoding);

-        CharsetEncoder encoder = charset.newEncoder();

-        for (int i = 0; i < buffer.length(); i++) {

-            int c = buffer.get(i);

-            if (c < 128) {

-                // first 128 chars are contained in almost every charset

-                result.append((char)c);

-                // this is intended as performance improvement since 

-                // the canEncode() operation appears quite CPU heavy

-            } else if (encoder.canEncode((char)c)) {

-                // encoder can encode this char

-                result.append((char)c);

-            } else {

-                // append HTML entity reference

-                result.append(ENTITY_PREFIX);

-                result.append(c);

-                result.append(";");

-            }

-        }

-        return result.toString();

-    }

-

-    /**

-     * Encodes all characters that are contained in the String which can not displayed 

-     * in the given encodings charset with Java escaping like <code>\u20ac</code>.<p>

-     * 

-     * This can be used to escape values used in Java property files.<p>

-     * 

-     * @param input the input to encode for Java

-     * @param encoding the charset to encode the result with

-     * 

-     * @return the input with the encoded Java entities

-     */

-    public static String encodeJavaEntities(String input, String encoding) {

-

-        StringBuffer result = new StringBuffer(input.length() * 2);

-        CharBuffer buffer = CharBuffer.wrap(input.toCharArray());

-        Charset charset = Charset.forName(encoding);

-        CharsetEncoder encoder = charset.newEncoder();

-        for (int i = 0; i < buffer.length(); i++) {

-            int c = buffer.get(i);

-            if (c < 128) {

-                // first 128 chars are contained in almost every charset

-                result.append((char)c);

-                // this is intended as performance improvement since 

-                // the canEncode() operation appears quite CPU heavy

-            } else if (encoder.canEncode((char)c)) {

-                // encoder can encode this char

-                result.append((char)c);

-            } else {

-                // append Java entity reference

-                result.append("\\u");

-                String hex = Integer.toHexString(c);

-                int pad = 4 - hex.length();

-                for (int p = 0; p < pad; p++) {

-                    result.append('0');

-                }

-                result.append(hex);

-            }

-        }

-        return result.toString();

-    }

-

-    /**

-     * Encodes a string used as parameter in an uri in a way independent of other encodings/decodings applied later.<p>

-     * 

-     * Used to ensure that GET parameters are not wrecked by wrong or incompatible configuration settings.

-     * In order to ensure this, the String is first encoded with html entities for any character that cannot encoded

-     * in US-ASCII; additionally, the plus sign is also encoded to avoid problems with the white-space replacer.

-     * Finally, the entity prefix is replaced with characters not used as delimiters in urls.<p>

-     * 

-     * @param input the parameter string

-     * 

-     * @return the encoded parameter string

-     */

-    public static String encodeParameter(String input) {

-

-        String result = ReportEncoder.encodeHtmlEntities(input, ReportEncoder.ENCODING_US_ASCII);

-        result = ReportStringUtil.substitute(result, "+", PLUS_ENTITY);

-        return ReportStringUtil.substitute(result, ENTITY_PREFIX, ENTITY_REPLACEMENT);

-    }

-

-    /**

-     * Encodes a String in a way that is compatible with the JavaScript escape function.

-     * 

-     * @param source The text to be encoded

-     * @param encoding the encoding type

-     * 

-     * @return The JavaScript escaped string

-     */

-    public static String escape(String source, String encoding) {

-

-        // the blank is encoded into "+" not "%20" when using standard encode call

-        return ReportStringUtil.substitute(encode(source, encoding), "+", "%20");

-    }

-

-    /**

-     * Escapes special characters in a HTML-String with their number-based 

-     * entity representation, for example &amp; becomes &amp;#38;.<p>

-     * 

-     * A character <code>num</code> is replaced if<br>

-     * <code>((ch != 32) && ((ch > 122) || (ch < 48) || (ch == 60) || (ch == 62)))</code><p>

-     * 

-     * @param source the String to escape

-     * 

-     * @return String the escaped String

-     * 

-     * @see #escapeXml(String)

-     */

-    public static String escapeHtml(String source) {

-

-        int terminatorIndex;

-        if (source == null) {

-            return null;

-        }

-        StringBuffer result = new StringBuffer(source.length() * 2);

-        for (int i = 0; i < source.length(); i++) {

-            int ch = source.charAt(i);

-            // avoid escaping already escaped characters            

-            if (ch == 38) {

-                terminatorIndex = source.indexOf(";", i);

-                if (terminatorIndex > 0) {

-                    if (source.substring(i + 1, terminatorIndex).matches("#[0-9]+|lt|gt|amp|quote")) {

-                        result.append(source.substring(i, terminatorIndex + 1));

-                        // Skip remaining chars up to (and including) ";"

-                        i = terminatorIndex;

-                        continue;

-                    }

-                }

-            }

-            if ((ch != 32) && ((ch > 122) || (ch < 48) || (ch == 60) || (ch == 62))) {

-                result.append(ENTITY_PREFIX);

-                result.append(ch);

-                result.append(";");

-            } else {

-                result.append((char)ch);

-            }

-        }

-        return new String(result);

-    }

-

-    /**

-     * Escapes non ASCII characters in a HTML-String with their number-based 

-     * entity representation, for example &amp; becomes &amp;#38;.<p>

-     * 

-     * A character <code>num</code> is replaced if<br>

-     * <code>(ch > 255)</code><p>

-     * 

-     * @param source the String to escape

-     * 

-     * @return String the escaped String

-     * 

-     * @see #escapeXml(String)

-     */

-    public static String escapeNonAscii(String source) {

-

-        if (source == null) {

-            return null;

-        }

-        StringBuffer result = new StringBuffer(source.length() * 2);

-        for (int i = 0; i < source.length(); i++) {

-            int ch = source.charAt(i);

-            if (ch > 255) {

-                result.append(ENTITY_PREFIX);

-                result.append(ch);

-                result.append(";");

-            } else {

-                result.append((char)ch);

-            }

-        }

-        return new String(result);

-    }

-

-    /**

-     * Encodes a String in a way that is compatible with the JavaScript escape function.

-     * Multiple blanks are encoded _multiply _with <code>%20</code>.<p>

-     * 

-     * @param source The text to be encoded

-     * @param encoding the encoding type

-     * 

-     * @return The JavaScript escaped string

-     */

-    public static String escapeWBlanks(String source, String encoding) {

-

-        if (ReportStringUtil.isEmpty(source)) {

-            return source;

-        }

-        StringBuffer ret = new StringBuffer(source.length() * 2);

-

-        // URLEncode the text string

-        // this produces a very similar encoding to JavaSscript encoding, 

-        // except the blank which is not encoded into "%20" instead of "+"

-

-        String enc = encode(source, encoding);

-        for (int z = 0; z < enc.length(); z++) {

-            char c = enc.charAt(z);

-            if (c == '+') {

-                ret.append("%20");

-            } else {

-                ret.append(c);

-            }

-        }

-        return ret.toString();

-    }

-

-    /**

-     * Escapes a String so it may be printed as text content or attribute

-     * value in a HTML page or an XML file.<p>

-     * 

-     * This method replaces the following characters in a String:

-     * <ul>

-     * <li><b>&lt;</b> with &amp;lt;

-     * <li><b>&gt;</b> with &amp;gt;

-     * <li><b>&amp;</b> with &amp;amp;

-     * <li><b>&quot;</b> with &amp;quot;

-     * </ul><p>

-     * 

-     * @param source the string to escape

-     * 

-     * @return the escaped string

-     * 

-     * @see #escapeHtml(String)

-     */

-    public static String escapeXml(String source) {

-

-        return escapeXml(source, false);

-    }

-

-    /**

-     * Escapes a String so it may be printed as text content or attribute

-     * value in a HTML page or an XML file.<p>

-     * 

-     * This method replaces the following characters in a String:

-     * <ul>

-     * <li><b>&lt;</b> with &amp;lt;

-     * <li><b>&gt;</b> with &amp;gt;

-     * <li><b>&amp;</b> with &amp;amp;

-     * <li><b>&quot;</b> with &amp;quot;

-     * </ul><p>

-     * 

-     * @param source the string to escape

-     * @param doubleEscape if <code>false</code>, all entities that already are escaped are left untouched

-     * 

-     * @return the escaped string

-     * 

-     * @see #escapeHtml(String)

-     */

-    public static String escapeXml(String source, boolean doubleEscape) {

-

-        if (source == null) {

-            return null;

-        }

-        StringBuffer result = new StringBuffer(source.length() * 2);

-

-        for (int i = 0; i < source.length(); ++i) {

-            char ch = source.charAt(i);

-            switch (ch) {

-                case '<':

-                    result.append("&lt;");

-                    break;

-                case '>':

-                    result.append("&gt;");

-                    break;

-                case '&':

-                    // don't escape already escaped international and special characters

-                    if (!doubleEscape) {

-                        int terminatorIndex = source.indexOf(";", i);

-                        if (terminatorIndex > 0) {

-                            if (source.substring(i + 1, terminatorIndex).matches("#[0-9]+")) {

-                                result.append(ch);

-                                break;

-                            }

-                        }

-                    }

-                    // note that to other "break" in the above "if" block

-                    result.append("&amp;");

-                    break;

-                case '"':

-                    result.append("&quot;");

-                    break;

-                default:

-                    result.append(ch);

-            }

-        }

-        return new String(result);

-    }

-

-    /**

-     * Checks if a given encoding name is actually supported, and if so

-     * resolves it to it's canonical name, if not it returns the given fallback 

-     * value.<p> 

-     * 

-     * Charsets have a set of aliases. For example, valid aliases for "UTF-8"

-     * are "UTF8", "utf-8" or "utf8". This method resolves any given valid charset name 

-     * to it's "canonical" form, so that simple String comparison can be used

-     * when checking charset names internally later.<p>

-     * 

-     * Please see <a href="http://www.iana.org/assignments/character-sets">http://www.iana.org/assignments/character-sets</a> 

-     * for a list of valid charset alias names.<p>

-     * 

-     * @param encoding the encoding to check and resolve

-     * @param fallback the fallback encoding scheme

-     * 

-     * @return the resolved encoding name, or the fallback value

-     */

-    public static String lookupEncoding(String encoding, String fallback) {

-

-        String result = (String) encodingCache.get(encoding);

-        if (result != null) {

-            return result;

-        }

-

-        try {

-            result = Charset.forName(encoding).name();

-            encodingCache.put(encoding, result);

-            return result;

-        } catch (Throwable t) {

-            // we will use the default value as fallback

-        }

-

-        return fallback;

-    }

-

-    /**

-     * Decodes a String in a way that is compatible with the JavaScript 

-     * unescape function.<p>

-     * 

-     * @param source The String to be decoded

-     * @param encoding the encoding type

-     * 

-     * @return The JavaScript unescaped String

-     */

-    public static String unescape(String source, String encoding) {

-

-        if (source == null) {

-            return null;

-        }

-        int len = source.length();

-        // to use standard decoder we need to replace '+' with "%20" (space)

-        StringBuffer preparedSource = new StringBuffer(len);

-        for (int i = 0; i < len; i++) {

-            char c = source.charAt(i);

-            if (c == '+') {

-                preparedSource.append("%20");

-            } else {

-                preparedSource.append(c);

-            }

-        }

-        return decode(preparedSource.toString(), encoding);

-    }

+/*******************************************************************************
+ * 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.util;
+
+import java.io.UnsupportedEncodingException;
+import java.net.URLDecoder;
+import java.net.URLEncoder;
+import java.nio.CharBuffer;
+import java.nio.charset.Charset;
+import java.nio.charset.CharsetEncoder;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+/**
+ * The ReportEncoder class provides static methods to decode and encode data.<p>
+ * 
+ * The methods in this class are substitutes for <code>java.net.URLEncoder.encode()</code> and
+ * <code>java.net.URLDecoder.decode()</code>.<p>
+ * 
+ * The de- and encoding uses the same coding mechanism as JavaScript, special characters are
+ * replaced with <code>%hex</code> where hex is a two digit hex number.<p>
+ * 
+ * <b>Note:</b> On the client side (browser) instead of using corresponding <code>escape</code>
+ * and <code>unescape</code> JavaScript functions, better use <code>encodeURIComponent</code> and
+ * <code>decodeURIComponent</code> functions which are work properly with unicode characters.
+ * These functions are supported in IE 5.5+ and NS 6+ only.<p>
+ * 
+ */
+public final class ReportEncoder {
+
+    /** Constant for the standard <code>ISO-8859-1</code> encoding. */
+    public static final String ENCODING_ISO_8859_1 = "ISO-8859-1";
+
+    /** Constant for the standard <code>US-ASCII</code> encoding. */
+    public static final String ENCODING_US_ASCII = "US-ASCII";
+
+    /** 
+     * Constant for the standard <code>UTF-8</code> encoding.<p>
+     * 
+     * Default encoding for JavaScript decodeUriComponent methods is <code>UTF-8</code> by w3c standard. 
+     */
+    public static final String ENCODING_UTF_8 = "UTF-8";
+
+    /** The regex pattern to match HTML entities. */
+    private static final Pattern ENTITIY_PATTERN = Pattern.compile("\\&#\\d+;");
+
+    /** The prefix for HTML entities. */
+    private static final String ENTITY_PREFIX = "&#";
+
+    /** The replacement for HTML entity prefix in parameters. */
+    private static final String ENTITY_REPLACEMENT = "$$";
+
+    /** A cache for encoding name lookup. */
+    private static Map<String, String> encodingCache = new HashMap<String, String>(16);
+
+    /** The plus entity. */
+    private static final String PLUS_ENTITY = ENTITY_PREFIX + "043;";
+
+    /**
+     * Constructor.<p>
+     */
+    private ReportEncoder() {
+        // empty
+    }
+
+    /**
+     * Adjusts the given String by making sure all characters that can be displayed 
+     * in the given charset are contained as chars, whereas all other non-displayable
+     * characters are converted to HTML entities.<p> 
+     * 
+     * Just calls {@link #decodeHtmlEntities(String, String)} first and feeds the result
+     * to {@link #encodeHtmlEntities(String, String)}. <p>
+     *  
+     * @param input the input to adjust the HTML encoding for
+     * @param encoding the charset to encode the result with\
+     * 
+     * @return the input with the decoded/encoded HTML entities
+     */
+    public static String adjustHtmlEncoding(String input, String encoding) {
+
+        return encodeHtmlEntities(decodeHtmlEntities(input, encoding), encoding);
+    }
+
+    /**
+     * Changes the encoding of a byte array that represents a String.<p>
+     * 
+     * @param input the byte array to convert
+     * @param oldEncoding the current encoding of the byte array
+     * @param newEncoding the new encoding of the byte array
+     * 
+     * @return the byte array encoded in the new encoding
+     */
+    public static byte[] changeEncoding(byte[] input, String oldEncoding, String newEncoding) {
+
+        if ((oldEncoding == null) || (newEncoding == null)) {
+            return input;
+        }
+        if (oldEncoding.trim().equalsIgnoreCase(newEncoding.trim())) {
+            return input;
+        }
+        byte[] result = input;
+        try {
+            result = (new String(input, oldEncoding)).getBytes(newEncoding);
+        } catch (UnsupportedEncodingException e) {
+            // return value will be input value
+        }
+        return result;
+    }
+
+    /**
+     * Creates a String out of a byte array with the specified encoding, falling back
+     * to the system default in case the encoding name is not valid.<p>
+     * 
+     * Use this method as a replacement for <code>new String(byte[], encoding)</code>
+     * to avoid possible encoding problems.<p>
+     * 
+     * @param bytes the bytes to decode 
+     * @param encoding the encoding scheme to use for decoding the bytes
+     * 
+     * @return the bytes decoded to a String
+     */
+    public static String createString(byte[] bytes, String encoding) {
+
+        String enc = encoding.intern();
+        if (enc != ENCODING_UTF_8) {
+            enc = lookupEncoding(enc, null);
+        }
+        if (enc != null) {
+            try {
+                return new String(bytes, enc);
+            } catch (UnsupportedEncodingException e) {
+                // this can _never_ happen since the charset was looked up first 
+            }
+        } else {
+            enc = ENCODING_UTF_8;
+            try {
+                return new String(bytes, enc);
+            } catch (UnsupportedEncodingException e) {
+                // this can also _never_ happen since the default encoding is always valid
+            }
+        }
+        // this code is unreachable in practice
+        return null;
+    }
+
+    /**
+     * Decodes a String using UTF-8 encoding, which is the standard for http data transmission
+     * with GET ant POST requests.<p>
+     * 
+     * @param source the String to decode
+     * 
+     * @return String the decoded source String
+     */
+    public static String decode(String source) {
+
+        return decode(source, ENCODING_UTF_8);
+    }
+
+    /**
+     * This method is a substitute for <code>URLDecoder.decode()</code>.<p>
+     * 
+     * In case you don't know what encoding to use, set the value of 
+     * the <code>encoding</code> parameter to <code>null</code>. 
+     * This method will then default to UTF-8 encoding, which is probably the right one.<p>
+     * 
+     * @param source The string to decode
+     * @param encoding The encoding to use (if null, the system default is used)
+     * 
+     * @return The decoded source String
+     */
+    public static String decode(String source, String encoding) {
+
+        if (source == null) {
+            return null;
+        }
+        if (encoding != null) {
+            try {
+                return URLDecoder.decode(source, encoding);
+            } catch (java.io.UnsupportedEncodingException e) {
+                // will fallback to default
+            }
+        }
+        // fallback to default decoding
+        try {
+            return URLDecoder.decode(source, ENCODING_UTF_8);
+        } catch (java.io.UnsupportedEncodingException e) {
+            // ignore
+        }
+        return source;
+    }
+
+    /**
+     * Decodes HTML entity references like <code>&amp;#8364;</code> that are contained in the 
+     * String to a regular character, but only if that character is contained in the given 
+     * encodings charset.<p> 
+     * 
+     * @param input the input to decode the HTML entities in
+     * @param encoding the charset to decode the input for
+     * @return the input with the decoded HTML entities
+     * 
+     * @see #encodeHtmlEntities(String, String)
+     */
+    public static String decodeHtmlEntities(String input, String encoding) {
+
+        Matcher matcher = ENTITIY_PATTERN.matcher(input);
+        StringBuffer result = new StringBuffer(input.length());
+        Charset charset = Charset.forName(encoding);
+        CharsetEncoder encoder = charset.newEncoder();
+
+        while (matcher.find()) {
+            String entity = matcher.group();
+            String value = entity.substring(2, entity.length() - 1);
+            int c = Integer.valueOf(value).intValue();
+            if (c < 128) {
+                // first 128 chars are contained in almost every charset
+                entity = new String(new char[] {(char)c});
+                // this is intended as performance improvement since 
+                // the canEncode() operation appears quite CPU heavy
+            } else if (encoder.canEncode((char)c)) {
+                // encoder can encode this char
+                entity = new String(new char[] {(char)c});
+            }
+            matcher.appendReplacement(result, entity);
+        }
+        matcher.appendTail(result);
+        return result.toString();
+    }
+
+    /**
+     * Decodes a string used as parameter in an uri in a way independent of other encodings/decodings applied before.<p>
+     * 
+     * @param input the encoded parameter string
+     * 
+     * @return the decoded parameter string
+     * 
+     * @see #encodeParameter(String)
+     */
+    public static String decodeParameter(String input) {
+
+        String result = ReportStringUtil.substitute(input, ENTITY_REPLACEMENT, ENTITY_PREFIX);
+        return ReportEncoder.decodeHtmlEntities(result, ENCODING_UTF_8);
+    }
+
+    /**
+     * Encodes a String using UTF-8 encoding, which is the standard for http data transmission
+     * with GET ant POST requests.<p>
+     * 
+     * @param source the String to encode
+     * 
+     * @return String the encoded source String
+     */
+    public static String encode(String source) {
+
+        return encode(source, ENCODING_UTF_8);
+    }
+
+    /**
+     * This method is a substitute for <code>URLEncoder.encode()</code>.<p>
+     * 
+     * In case you don't know what encoding to use, set the value of 
+     * the <code>encoding</code> parameter to <code>null</code>. 
+     * This method will then default to UTF-8 encoding, which is probably the right one.<p>
+     * 
+     * @param source the String to encode
+     * @param encoding the encoding to use (if null, the system default is used)
+     * 
+     * @return the encoded source String
+     */
+    public static String encode(String source, String encoding) {
+
+        if (source == null) {
+            return null;
+        }
+        if (encoding != null) {
+            try {
+                return URLEncoder.encode(source, encoding);
+            } catch (java.io.UnsupportedEncodingException e) {
+                // will fallback to default
+            }
+        }
+        // fallback to default encoding
+        try {
+            return URLEncoder.encode(source, ENCODING_UTF_8);
+        } catch (java.io.UnsupportedEncodingException e) {
+            // ignore
+        }
+        return source;
+    }
+
+    /**
+     * Encodes all characters that are contained in the String which can not displayed 
+     * in the given encodings charset with HTML entity references
+     * like <code>&amp;#8364;</code>.<p>
+     * 
+     * This is required since a Java String is 
+     * internally always stored as Unicode, meaning it can contain almost every character, but 
+     * the HTML charset used might not support all such characters.<p>
+     * 
+     * @param input the input to encode for HTML
+     * @param encoding the charset to encode the result with
+     * 
+     * @return the input with the encoded HTML entities
+     * 
+     * @see #decodeHtmlEntities(String, String)
+     */
+    public static String encodeHtmlEntities(String input, String encoding) {
+
+        StringBuffer result = new StringBuffer(input.length() * 2);
+        CharBuffer buffer = CharBuffer.wrap(input.toCharArray());
+        Charset charset = Charset.forName(encoding);
+        CharsetEncoder encoder = charset.newEncoder();
+        for (int i = 0; i < buffer.length(); i++) {
+            int c = buffer.get(i);
+            if (c < 128) {
+                // first 128 chars are contained in almost every charset
+                result.append((char)c);
+                // this is intended as performance improvement since 
+                // the canEncode() operation appears quite CPU heavy
+            } else if (encoder.canEncode((char)c)) {
+                // encoder can encode this char
+                result.append((char)c);
+            } else {
+                // append HTML entity reference
+                result.append(ENTITY_PREFIX);
+                result.append(c);
+                result.append(";");
+            }
+        }
+        return result.toString();
+    }
+
+    /**
+     * Encodes all characters that are contained in the String which can not displayed 
+     * in the given encodings charset with Java escaping like <code>\u20ac</code>.<p>
+     * 
+     * This can be used to escape values used in Java property files.<p>
+     * 
+     * @param input the input to encode for Java
+     * @param encoding the charset to encode the result with
+     * 
+     * @return the input with the encoded Java entities
+     */
+    public static String encodeJavaEntities(String input, String encoding) {
+
+        StringBuffer result = new StringBuffer(input.length() * 2);
+        CharBuffer buffer = CharBuffer.wrap(input.toCharArray());
+        Charset charset = Charset.forName(encoding);
+        CharsetEncoder encoder = charset.newEncoder();
+        for (int i = 0; i < buffer.length(); i++) {
+            int c = buffer.get(i);
+            if (c < 128) {
+                // first 128 chars are contained in almost every charset
+                result.append((char)c);
+                // this is intended as performance improvement since 
+                // the canEncode() operation appears quite CPU heavy
+            } else if (encoder.canEncode((char)c)) {
+                // encoder can encode this char
+                result.append((char)c);
+            } else {
+                // append Java entity reference
+                result.append("\\u");
+                String hex = Integer.toHexString(c);
+                int pad = 4 - hex.length();
+                for (int p = 0; p < pad; p++) {
+                    result.append('0');
+                }
+                result.append(hex);
+            }
+        }
+        return result.toString();
+    }
+
+    /**
+     * Encodes a string used as parameter in an uri in a way independent of other encodings/decodings applied later.<p>
+     * 
+     * Used to ensure that GET parameters are not wrecked by wrong or incompatible configuration settings.
+     * In order to ensure this, the String is first encoded with html entities for any character that cannot encoded
+     * in US-ASCII; additionally, the plus sign is also encoded to avoid problems with the white-space replacer.
+     * Finally, the entity prefix is replaced with characters not used as delimiters in urls.<p>
+     * 
+     * @param input the parameter string
+     * 
+     * @return the encoded parameter string
+     */
+    public static String encodeParameter(String input) {
+
+        String result = ReportEncoder.encodeHtmlEntities(input, ReportEncoder.ENCODING_US_ASCII);
+        result = ReportStringUtil.substitute(result, "+", PLUS_ENTITY);
+        return ReportStringUtil.substitute(result, ENTITY_PREFIX, ENTITY_REPLACEMENT);
+    }
+
+    /**
+     * Encodes a String in a way that is compatible with the JavaScript escape function.
+     * 
+     * @param source The text to be encoded
+     * @param encoding the encoding type
+     * 
+     * @return The JavaScript escaped string
+     */
+    public static String escape(String source, String encoding) {
+
+        // the blank is encoded into "+" not "%20" when using standard encode call
+        return ReportStringUtil.substitute(encode(source, encoding), "+", "%20");
+    }
+
+    /**
+     * Escapes special characters in a HTML-String with their number-based 
+     * entity representation, for example &amp; becomes &amp;#38;.<p>
+     * 
+     * A character <code>num</code> is replaced if<br>
+     * <code>((ch != 32) && ((ch > 122) || (ch < 48) || (ch == 60) || (ch == 62)))</code><p>
+     * 
+     * @param source the String to escape
+     * 
+     * @return String the escaped String
+     * 
+     * @see #escapeXml(String)
+     */
+    public static String escapeHtml(String source) {
+
+        int terminatorIndex;
+        if (source == null) {
+            return null;
+        }
+        StringBuffer result = new StringBuffer(source.length() * 2);
+        for (int i = 0; i < source.length(); i++) {
+            int ch = source.charAt(i);
+            // avoid escaping already escaped characters            
+            if (ch == 38) {
+                terminatorIndex = source.indexOf(";", i);
+                if (terminatorIndex > 0) {
+                    if (source.substring(i + 1, terminatorIndex).matches("#[0-9]+|lt|gt|amp|quote")) {
+                        result.append(source.substring(i, terminatorIndex + 1));
+                        // Skip remaining chars up to (and including) ";"
+                        i = terminatorIndex;
+                        continue;
+                    }
+                }
+            }
+            if ((ch != 32) && ((ch > 122) || (ch < 48) || (ch == 60) || (ch == 62))) {
+                result.append(ENTITY_PREFIX);
+                result.append(ch);
+                result.append(";");
+            } else {
+                result.append((char)ch);
+            }
+        }
+        return new String(result);
+    }
+
+    /**
+     * Escapes non ASCII characters in a HTML-String with their number-based 
+     * entity representation, for example &amp; becomes &amp;#38;.<p>
+     * 
+     * A character <code>num</code> is replaced if<br>
+     * <code>(ch > 255)</code><p>
+     * 
+     * @param source the String to escape
+     * 
+     * @return String the escaped String
+     * 
+     * @see #escapeXml(String)
+     */
+    public static String escapeNonAscii(String source) {
+
+        if (source == null) {
+            return null;
+        }
+        StringBuffer result = new StringBuffer(source.length() * 2);
+        for (int i = 0; i < source.length(); i++) {
+            int ch = source.charAt(i);
+            if (ch > 255) {
+                result.append(ENTITY_PREFIX);
+                result.append(ch);
+                result.append(";");
+            } else {
+                result.append((char)ch);
+            }
+        }
+        return new String(result);
+    }
+
+    /**
+     * Encodes a String in a way that is compatible with the JavaScript escape function.
+     * Multiple blanks are encoded _multiply _with <code>%20</code>.<p>
+     * 
+     * @param source The text to be encoded
+     * @param encoding the encoding type
+     * 
+     * @return The JavaScript escaped string
+     */
+    public static String escapeWBlanks(String source, String encoding) {
+
+        if (ReportStringUtil.isEmpty(source)) {
+            return source;
+        }
+        StringBuffer ret = new StringBuffer(source.length() * 2);
+
+        // URLEncode the text string
+        // this produces a very similar encoding to JavaSscript encoding, 
+        // except the blank which is not encoded into "%20" instead of "+"
+
+        String enc = encode(source, encoding);
+        for (int z = 0; z < enc.length(); z++) {
+            char c = enc.charAt(z);
+            if (c == '+') {
+                ret.append("%20");
+            } else {
+                ret.append(c);
+            }
+        }
+        return ret.toString();
+    }
+
+    /**
+     * Escapes a String so it may be printed as text content or attribute
+     * value in a HTML page or an XML file.<p>
+     * 
+     * This method replaces the following characters in a String:
+     * <ul>
+     * <li><b>&lt;</b> with &amp;lt;
+     * <li><b>&gt;</b> with &amp;gt;
+     * <li><b>&amp;</b> with &amp;amp;
+     * <li><b>&quot;</b> with &amp;quot;
+     * </ul><p>
+     * 
+     * @param source the string to escape
+     * 
+     * @return the escaped string
+     * 
+     * @see #escapeHtml(String)
+     */
+    public static String escapeXml(String source) {
+
+        return escapeXml(source, false);
+    }
+
+    /**
+     * Escapes a String so it may be printed as text content or attribute
+     * value in a HTML page or an XML file.<p>
+     * 
+     * This method replaces the following characters in a String:
+     * <ul>
+     * <li><b>&lt;</b> with &amp;lt;
+     * <li><b>&gt;</b> with &amp;gt;
+     * <li><b>&amp;</b> with &amp;amp;
+     * <li><b>&quot;</b> with &amp;quot;
+     * </ul><p>
+     * 
+     * @param source the string to escape
+     * @param doubleEscape if <code>false</code>, all entities that already are escaped are left untouched
+     * 
+     * @return the escaped string
+     * 
+     * @see #escapeHtml(String)
+     */
+    public static String escapeXml(String source, boolean doubleEscape) {
+
+        if (source == null) {
+            return null;
+        }
+        StringBuffer result = new StringBuffer(source.length() * 2);
+
+        for (int i = 0; i < source.length(); ++i) {
+            char ch = source.charAt(i);
+            switch (ch) {
+                case '<':
+                    result.append("&lt;");
+                    break;
+                case '>':
+                    result.append("&gt;");
+                    break;
+                case '&':
+                    // don't escape already escaped international and special characters
+                    if (!doubleEscape) {
+                        int terminatorIndex = source.indexOf(";", i);
+                        if (terminatorIndex > 0) {
+                            if (source.substring(i + 1, terminatorIndex).matches("#[0-9]+")) {
+                                result.append(ch);
+                                break;
+                            }
+                        }
+                    }
+                    // note that to other "break" in the above "if" block
+                    result.append("&amp;");
+                    break;
+                case '"':
+                    result.append("&quot;");
+                    break;
+                default:
+                    result.append(ch);
+            }
+        }
+        return new String(result);
+    }
+
+    /**
+     * Checks if a given encoding name is actually supported, and if so
+     * resolves it to it's canonical name, if not it returns the given fallback 
+     * value.<p> 
+     * 
+     * Charsets have a set of aliases. For example, valid aliases for "UTF-8"
+     * are "UTF8", "utf-8" or "utf8". This method resolves any given valid charset name 
+     * to it's "canonical" form, so that simple String comparison can be used
+     * when checking charset names internally later.<p>
+     * 
+     * Please see <a href="http://www.iana.org/assignments/character-sets">http://www.iana.org/assignments/character-sets</a> 
+     * for a list of valid charset alias names.<p>
+     * 
+     * @param encoding the encoding to check and resolve
+     * @param fallback the fallback encoding scheme
+     * 
+     * @return the resolved encoding name, or the fallback value
+     */
+    public static String lookupEncoding(String encoding, String fallback) {
+
+        String result = (String) encodingCache.get(encoding);
+        if (result != null) {
+            return result;
+        }
+
+        try {
+            result = Charset.forName(encoding).name();
+            encodingCache.put(encoding, result);
+            return result;
+        } catch (Throwable t) {
+            // we will use the default value as fallback
+        }
+
+        return fallback;
+    }
+
+    /**
+     * Decodes a String in a way that is compatible with the JavaScript 
+     * unescape function.<p>
+     * 
+     * @param source The String to be decoded
+     * @param encoding the encoding type
+     * 
+     * @return The JavaScript unescaped String
+     */
+    public static String unescape(String source, String encoding) {
+
+        if (source == null) {
+            return null;
+        }
+        int len = source.length();
+        // to use standard decoder we need to replace '+' with "%20" (space)
+        StringBuffer preparedSource = new StringBuffer(len);
+        for (int i = 0; i < len; i++) {
+            char c = source.charAt(i);
+            if (c == '+') {
+                preparedSource.append("%20");
+            } else {
+                preparedSource.append(c);
+            }
+        }
+        return decode(preparedSource.toString(), encoding);
+    }
 }
\ No newline at end of file
diff --git a/specialpurpose/pricat/src/main/java/org/apache/ofbiz/htmlreport/util/ReportStringUtil.java b/specialpurpose/pricat/src/main/java/org/apache/ofbiz/htmlreport/util/ReportStringUtil.java
index f1baa0b..fb2c1af 100644
--- a/specialpurpose/pricat/src/main/java/org/apache/ofbiz/htmlreport/util/ReportStringUtil.java
+++ b/specialpurpose/pricat/src/main/java/org/apache/ofbiz/htmlreport/util/ReportStringUtil.java
@@ -1,570 +1,570 @@
-/*******************************************************************************

- * 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.util;

-

-import java.util.Collection;

-import java.util.Iterator;

-

-/**

- * Provides String utility functions.<p>

- * 

- */

-public final class ReportStringUtil {

-

-    /** Constant for <code>"false"</code>. */

-    public static final String FALSE = Boolean.toString(false);

-

-    /** a convenient shorthand to the line separator constant. */

-    public static final String LINE_SEPARATOR = System.getProperty("line.separator");

-

-    /** Contains all chars that end a sentence in the {@link #trimToSize(String, int, int, String)} method. */

-    public static final char[] SENTENCE_ENDING_CHARS = {'.', '!', '?'};

-

-    /** a convenient shorthand for tabulations.  */

-    public static final String TABULATOR = "  ";

-

-    /** Constant for <code>"true"</code>. */

-    public static final String TRUE = Boolean.toString(true);

-

-    /** Day constant. */

-    private static final long DAYS = 1000 * 60 * 60 * 24;

-

-    /** Hour constant. */

-    private static final long HOURS = 1000 * 60 * 60;

-

-    /** Minute constant. */

-    private static final long MINUTES = 1000 * 60;

-

-    /** Second constant. */

-    private static final long SECONDS = 1000;

-

-    /** 

-     * Default constructor (empty), private because this class has only 

-     * static methods.<p>

-     */

-    private ReportStringUtil() {

-        // empty

-    }

-

-    /**

-     * Changes the filename suffix. 

-     * 

-     * @param filename the filename to be changed

-     * @param suffix the new suffix of the file

-     * 

-     * @return the filename with the replaced suffix

-     */

-    public static String changeFileNameSuffixTo(String filename, String suffix) {

-

-        int dotPos = filename.lastIndexOf('.');

-        if (dotPos != -1) {

-            return filename.substring(0, dotPos + 1) + suffix;

-        } else {

-            // the string has no suffix

-            return filename;

-        }

-    }

-

-    /**

-     * Returns a string representation for the given collection using the given separator.<p>

-     * 

-     * @param collection the collection to print

-     * @param separator the item separator

-     * 

-     * @return the string representation for the given collection

-     */

-    public static String collectionAsString(Collection<String> collection, String separator) {

-

-        StringBuffer string = new StringBuffer(128);

-        Iterator<String> it = collection.iterator();

-        while (it.hasNext()) {

-            string.append(it.next());

-            if (it.hasNext()) {

-                string.append(separator);

-            }

-        }

-        return string.toString();

-    }

-

-    /**

-     * Replaces occurrences of special control characters in the given input with 

-     * a HTML representation.<p>

-     * 

-     * This method currently replaces line breaks to <code>&lt;br/&gt;</code> and special HTML chars 

-     * like <code>&lt; &gt; &amp; &quot;</code> with their HTML entity representation.<p>

-     * 

-     * @param source the String to escape

-     * 

-     * @return the escaped String

-     */

-    public static String escapeHtml(String source) {

-

-        if (source == null) {

-            return null;

-        }

-        source = ReportEncoder.escapeXml(source);

-        source = substitute(source, "\r", "");

-        source = substitute(source, "\n", "<br/>\n");

-        return source;

-    }

-

-    /**

-     * Escapes a String so it may be used in JavaScript String definitions.<p>

-     * 

-     * This method replaces line breaks, quotation marks and \ characters.<p>

-     * 

-     * @param source the String to escape

-     * 

-     * @return the escaped String

-     */

-    public static String escapeJavaScript(String source) {

-

-        source = substitute(source, "\\", "\\\\");

-        source = substitute(source, "\"", "\\\"");

-        source = substitute(source, "\'", "\\\'");

-        source = substitute(source, "\r\n", "\\n");

-        source = substitute(source, "\n", "\\n");

-        return source;

-    }

-

-    /**

-     * Escapes a String so it may be used as a Perl5 regular expression.<p>

-     * 

-     * This method replaces the following characters in a String:<br>

-     * <code>{}[]()\$^.*+/</code><p>

-     * 

-     * @param source the string to escape

-     * 

-     * @return the escaped string

-     */

-    public static String escapePattern(String source) {

-

-        if (source == null) {

-            return null;

-        }

-        StringBuffer result = new StringBuffer(source.length() * 2);

-        for (int i = 0; i < source.length(); ++i) {

-            char ch = source.charAt(i);

-            switch (ch) {

-                case '\\':

-                    result.append("\\\\");

-                    break;

-                case '/':

-                    result.append("\\/");

-                    break;

-                case '$':

-                    result.append("\\$");

-                    break;

-                case '^':

-                    result.append("\\^");

-                    break;

-                case '.':

-                    result.append("\\.");

-                    break;

-                case '*':

-                    result.append("\\*");

-                    break;

-                case '+':

-                    result.append("\\+");

-                    break;

-                case '|':

-                    result.append("\\|");

-                    break;

-                case '?':

-                    result.append("\\?");

-                    break;

-                case '{':

-                    result.append("\\{");

-                    break;

-                case '}':

-                    result.append("\\}");

-                    break;

-                case '[':

-                    result.append("\\[");

-                    break;

-                case ']':

-                    result.append("\\]");

-                    break;

-                case '(':

-                    result.append("\\(");

-                    break;

-                case ')':

-                    result.append("\\)");

-                    break;

-                default:

-                    result.append(ch);

-            }

-        }

-        return new String(result);

-    }

-

-    /**

-     * Formats a runtime in the format hh:mm:ss, to be used e.g. in reports.<p>

-     * 

-     * If the runtime is greater then 24 hours, the format dd:hh:mm:ss is used.<p> 

-     * 

-     * @param runtime the time to format

-     * 

-     * @return the formatted runtime

-     */

-    public static String formatRuntime(long runtime) {

-

-        long seconds = (runtime / SECONDS) % 60;

-        long minutes = (runtime / MINUTES) % 60;

-        long hours = (runtime / HOURS) % 24;

-        long days = runtime / DAYS;

-        StringBuffer strBuf = new StringBuffer();

-

-        if (days > 0) {

-            if (days < 10) {

-                strBuf.append('0');

-            }

-            strBuf.append(days);

-            strBuf.append(':');

-        }

-

-        if (hours < 10) {

-            strBuf.append('0');

-        }

-        strBuf.append(hours);

-        strBuf.append(':');

-

-        if (minutes < 10) {

-            strBuf.append('0');

-        }

-        strBuf.append(minutes);

-        strBuf.append(':');

-

-        if (seconds < 10) {

-            strBuf.append('0');

-        }

-        strBuf.append(seconds);

-

-        return strBuf.toString();

-    }

-

-    /**

-     * Returns <code>true</code> if the provided String is either <code>null</code>

-     * or the empty String <code>""</code>.<p> 

-     * 

-     * @param value the value to check

-     * 

-     * @return true, if the provided value is null or the empty String, false otherwise

-     */

-    public static boolean isEmpty(String value) {

-

-        return (value == null) || (value.length() == 0);

-    }

-

-    /**

-     * Returns <code>true</code> if the provided String is either <code>null</code>

-     * or contains only white spaces.<p> 

-     * 

-     * @param value the value to check

-     * 

-     * @return true, if the provided value is null or contains only white spaces, false otherwise

-     */

-    public static boolean isEmptyOrWhitespaceOnly(String value) {

-

-        return isEmpty(value) || (value.trim().length() == 0);

-    }

-

-    /**

-     * Returns <code>true</code> if the provided Objects are either both <code>null</code> 

-     * or equal according to {@link Object#equals(Object)}.<p>

-     * 

-     * @param value1 the first object to compare

-     * @param value2 the second object to compare

-     * 

-     * @return <code>true</code> if the provided Objects are either both <code>null</code> 

-     *              or equal according to {@link Object#equals(Object)} 

-     */

-    public static boolean isEqual(Object value1, Object value2) {

-

-        if (value1 == null) {

-            return (value2 == null);

-        }

-        return value1.equals(value2);

-    }

-

-    /**

-     * Returns <code>true</code> if the provided String is neither <code>null</code>

-     * nor the empty String <code>""</code>.<p> 

-     * 

-     * @param value the value to check

-     * 

-     * @return true, if the provided value is not null and not the empty String, false otherwise

-     */

-    public static boolean isNotEmpty(String value) {

-

-        return (value != null) && (value.length() != 0);

-    }

-

-    /**

-     * Returns <code>true</code> if the provided String is neither <code>null</code>

-     * nor contains only white spaces.<p> 

-     * 

-     * @param value the value to check

-     * 

-     * @return <code>true</code>, if the provided value is <code>null</code> 

-     *          or contains only white spaces, <code>false</code> otherwise

-     */

-    public static boolean isNotEmptyOrWhitespaceOnly(String value) {

-

-        return (value != null) && (value.trim().length() > 0);

-    }

-

-    /**

-     * Returns the last index of any of the given chars in the given source.<p> 

-     * 

-     * If no char is found, -1 is returned.<p>

-     * 

-     * @param source the source to check

-     * @param chars the chars to find

-     * 

-     * @return the last index of any of the given chars in the given source, or -1

-     */

-    public static int lastIndexOf(String source, char[] chars) {

-

-        // now try to find an "sentence ending" char in the text in the "findPointArea"

-        int result = -1;

-        for (int i = 0; i < chars.length; i++) {

-            int pos = source.lastIndexOf(chars[i]);

-            if (pos > result) {

-                // found new last char

-                result = pos;

-            }

-        }

-        return result;

-    }

-

-    /**

-     * Returns the last index a whitespace char the given source.<p> 

-     * 

-     * If no whitespace char is found, -1 is returned.<p>

-     * 

-     * @param source the source to check

-     * 

-     * @return the last index a whitespace char the given source, or -1

-     */

-    public static int lastWhitespaceIn(String source) {

-

-        if (isEmpty(source)) {

-            return -1;

-        }

-        int pos = -1;

-        for (int i = source.length() - 1; i >= 0; i--) {

-            if (Character.isWhitespace(source.charAt(i))) {

-                pos = i;

-                break;

-            }

-        }

-        return pos;

-    }

-

-    /**

-     * Substitutes <code>searchString</code> in the given source String with <code>replaceString</code>.<p>

-     * 

-     * This is a high-performance implementation which should be used as a replacement for 

-     * <code>{@link String#replaceAll(java.lang.String, java.lang.String)}</code> in case no

-     * regular expression evaluation is required.<p>

-     * 

-     * @param source the content which is scanned

-     * @param searchString the String which is searched in content

-     * @param replaceString the String which replaces <code>searchString</code>

-     * 

-     * @return the substituted String

-     */

-    public static String substitute(String source, String searchString, String replaceString) {

-

-        if (source == null) {

-            return null;

-        }

-

-        if (isEmpty(searchString)) {

-            return source;

-        }

-

-        if (replaceString == null) {

-            replaceString = "";

-        }

-        int len = source.length();

-        int sl = searchString.length();

-        int rl = replaceString.length();

-        int length;

-        if (sl == rl) {

-            length = len;

-        } else {

-            int c = 0;

-            int s = 0;

-            int e;

-            while ((e = source.indexOf(searchString, s)) != -1) {

-                c++;

-                s = e + sl;

-            }

-            if (c == 0) {

-                return source;

-            }

-            length = len - (c * (sl - rl));

-        }

-

-        int s = 0;

-        int e = source.indexOf(searchString, s);

-        if (e == -1) {

-            return source;

-        }

-        StringBuffer sb = new StringBuffer(length);

-        while (e != -1) {

-            sb.append(source.substring(s, e));

-            sb.append(replaceString);

-            s = e + sl;

-            e = source.indexOf(searchString, s);

-        }

-        e = len;

-        sb.append(source.substring(s, e));

-        return sb.toString();

-    }

-

-    /**

-     * Returns the java String literal for the given String. <p>

-     *  

-     * This is the form of the String that had to be written into source code 

-     * using the unicode escape sequence for special characters. <p> 

-     * 

-     * Example: "�" would be transformed to "\\u00C4".<p>

-     * 

-     * @param s a string that may contain non-ascii characters 

-     * 

-     * @return the java unicode escaped string Literal of the given input string

-     */

-    public static String toUnicodeLiteral(String s) {

-

-        StringBuffer result = new StringBuffer();

-        char[] carr = s.toCharArray();

-

-        String unicode;

-        for (int i = 0; i < carr.length; i++) {

-            result.append("\\u");

-            // append leading zeros

-            unicode = Integer.toHexString(carr[i]).toUpperCase();

-            for (int j = 4 - unicode.length(); j > 0; j--) {

-                result.append("0");

-            }

-            result.append(unicode);

-        }

-        return result.toString();

-    }

-

-    /**

-     * Returns a substring of the source, which is at most length characters long.<p>

-     * 

-     * This is the same as calling {@link #trimToSize(String, int, String)} with the 

-     * parameters <code>(source, length, " ...")</code>.<p>

-     * 

-     * @param source the string to trim

-     * @param length the maximum length of the string to be returned

-     * 

-     * @return a substring of the source, which is at most length characters long

-     */

-    public static String trimToSize(String source, int length) {

-

-        return trimToSize(source, length, length, " ...");

-    }

-

-    /**

-     * Returns a substring of the source, which is at most length characters long.<p>

-     * 

-     * If a char is cut, the given <code>suffix</code> is appended to the result.<p>

-     * 

-     * This is almost the same as calling {@link #trimToSize(String, int, int, String)} with the 

-     * parameters <code>(source, length, length*, suffix)</code>. If <code>length</code>

-     * if larger then 100, then <code>length* = length / 2</code>,

-     * otherwise <code>length* = length</code>.<p>

-     * 

-     * @param source the string to trim

-     * @param length the maximum length of the string to be returned

-     * @param suffix the suffix to append in case the String was trimmed

-     * 

-     * @return a substring of the source, which is at most length characters long

-     */

-    public static String trimToSize(String source, int length, String suffix) {

-

-        int area = (length > 100) ? length / 2 : length;

-        return trimToSize(source, length, area, suffix);

-    }

-

-    /**

-     * Returns a substring of the source, which is at most length characters long, cut 

-     * in the last <code>area</code> chars in the source at a sentence ending char or whitespace.<p>

-     * 

-     * If a char is cut, the given <code>suffix</code> is appended to the result.<p>

-     * 

-     * @param source the string to trim

-     * @param length the maximum length of the string to be returned

-     * @param area the area at the end of the string in which to find a sentence ender or whitespace

-     * @param suffix the suffix to append in case the String was trimmed

-     * 

-     * @return a substring of the source, which is at most length characters long

-     */

-    public static String trimToSize(String source, int length, int area, String suffix) {

-

-        if ((source == null) || (source.length() <= length)) {

-            // no operation is required

-            return source;

-        }

-        if (isEmpty(suffix)) {

-            // we need an empty suffix

-            suffix = "";

-        }

-        // must remove the length from the after sequence chars since these are always added in the end

-        int modLength = length - suffix.length();

-        if (modLength <= 0) {

-            // we are to short, return beginning of the suffix

-            return suffix.substring(0, length);

-        }

-        int modArea = area + suffix.length();

-        if ((modArea > modLength) || (modArea < 0)) {

-            // area must not be longer then max length

-            modArea = modLength;

-        }

-

-        // first reduce the String to the maximum allowed length

-        String findPointSource = source.substring(modLength - modArea, modLength);

-

-        String result;

-        // try to find an "sentence ending" char in the text

-        int pos = lastIndexOf(findPointSource, SENTENCE_ENDING_CHARS);

-        if (pos >= 0) {

-            // found a sentence ender in the lookup area, keep the sentence ender

-            result = source.substring(0, modLength - modArea + pos + 1) + suffix;

-        } else {

-            // no sentence ender was found, try to find a whitespace

-            pos = lastWhitespaceIn(findPointSource);

-            if (pos >= 0) {

-                // found a whitespace, don't keep the whitespace

-                result = source.substring(0, modLength - modArea + pos) + suffix;

-            } else {

-                // not even a whitespace was found, just cut away what's to long

-                result = source.substring(0, modLength) + suffix;

-            }

-        }

-

-        return result;

-    }

+/*******************************************************************************
+ * 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.util;
+
+import java.util.Collection;
+import java.util.Iterator;
+
+/**
+ * Provides String utility functions.<p>
+ * 
+ */
+public final class ReportStringUtil {
+
+    /** Constant for <code>"false"</code>. */
+    public static final String FALSE = Boolean.toString(false);
+
+    /** a convenient shorthand to the line separator constant. */
+    public static final String LINE_SEPARATOR = System.getProperty("line.separator");
+
+    /** Contains all chars that end a sentence in the {@link #trimToSize(String, int, int, String)} method. */
+    public static final char[] SENTENCE_ENDING_CHARS = {'.', '!', '?'};
+
+    /** a convenient shorthand for tabulations.  */
+    public static final String TABULATOR = "  ";
+
+    /** Constant for <code>"true"</code>. */
+    public static final String TRUE = Boolean.toString(true);
+
+    /** Day constant. */
+    private static final long DAYS = 1000 * 60 * 60 * 24;
+
+    /** Hour constant. */
+    private static final long HOURS = 1000 * 60 * 60;
+
+    /** Minute constant. */
+    private static final long MINUTES = 1000 * 60;
+
+    /** Second constant. */
+    private static final long SECONDS = 1000;
+
+    /** 
+     * Default constructor (empty), private because this class has only 
+     * static methods.<p>
+     */
+    private ReportStringUtil() {
+        // empty
+    }
+
+    /**
+     * Changes the filename suffix. 
+     * 
+     * @param filename the filename to be changed
+     * @param suffix the new suffix of the file
+     * 
+     * @return the filename with the replaced suffix
+     */
+    public static String changeFileNameSuffixTo(String filename, String suffix) {
+
+        int dotPos = filename.lastIndexOf('.');
+        if (dotPos != -1) {
+            return filename.substring(0, dotPos + 1) + suffix;
+        } else {
+            // the string has no suffix
+            return filename;
+        }
+    }
+
+    /**
+     * Returns a string representation for the given collection using the given separator.<p>
+     * 
+     * @param collection the collection to print
+     * @param separator the item separator
+     * 
+     * @return the string representation for the given collection
+     */
+    public static String collectionAsString(Collection<String> collection, String separator) {
+
+        StringBuffer string = new StringBuffer(128);
+        Iterator<String> it = collection.iterator();
+        while (it.hasNext()) {
+            string.append(it.next());
+            if (it.hasNext()) {
+                string.append(separator);
+            }
+        }
+        return string.toString();
+    }
+
+    /**
+     * Replaces occurrences of special control characters in the given input with 
+     * a HTML representation.<p>
+     * 
+     * This method currently replaces line breaks to <code>&lt;br/&gt;</code> and special HTML chars 
+     * like <code>&lt; &gt; &amp; &quot;</code> with their HTML entity representation.<p>
+     * 
+     * @param source the String to escape
+     * 
+     * @return the escaped String
+     */
+    public static String escapeHtml(String source) {
+
+        if (source == null) {
+            return null;
+        }
+        source = ReportEncoder.escapeXml(source);
+        source = substitute(source, "\r", "");
+        source = substitute(source, "\n", "<br/>\n");
+        return source;
+    }
+
+    /**
+     * Escapes a String so it may be used in JavaScript String definitions.<p>
+     * 
+     * This method replaces line breaks, quotation marks and \ characters.<p>
+     * 
+     * @param source the String to escape
+     * 
+     * @return the escaped String
+     */
+    public static String escapeJavaScript(String source) {
+
+        source = substitute(source, "\\", "\\\\");
+        source = substitute(source, "\"", "\\\"");
+        source = substitute(source, "\'", "\\\'");
+        source = substitute(source, "\r\n", "\\n");
+        source = substitute(source, "\n", "\\n");
+        return source;
+    }
+
+    /**
+     * Escapes a String so it may be used as a Perl5 regular expression.<p>
+     * 
+     * This method replaces the following characters in a String:<br>
+     * <code>{}[]()\$^.*+/</code><p>
+     * 
+     * @param source the string to escape
+     * 
+     * @return the escaped string
+     */
+    public static String escapePattern(String source) {
+
+        if (source == null) {
+            return null;
+        }
+        StringBuffer result = new StringBuffer(source.length() * 2);
+        for (int i = 0; i < source.length(); ++i) {
+            char ch = source.charAt(i);
+            switch (ch) {
+                case '\\':
+                    result.append("\\\\");
+                    break;
+                case '/':
+                    result.append("\\/");
+                    break;
+                case '$':
+                    result.append("\\$");
+                    break;
+                case '^':
+                    result.append("\\^");
+                    break;
+                case '.':
+                    result.append("\\.");
+                    break;
+                case '*':
+                    result.append("\\*");
+                    break;
+                case '+':
+                    result.append("\\+");
+                    break;
+                case '|':
+                    result.append("\\|");
+                    break;
+                case '?':
+                    result.append("\\?");
+                    break;
+                case '{':
+                    result.append("\\{");
+                    break;
+                case '}':
+                    result.append("\\}");
+                    break;
+                case '[':
+                    result.append("\\[");
+                    break;
+                case ']':
+                    result.append("\\]");
+                    break;
+                case '(':
+                    result.append("\\(");
+                    break;
+                case ')':
+                    result.append("\\)");
+                    break;
+                default:
+                    result.append(ch);
+            }
+        }
+        return new String(result);
+    }
+
+    /**
+     * Formats a runtime in the format hh:mm:ss, to be used e.g. in reports.<p>
+     * 
+     * If the runtime is greater then 24 hours, the format dd:hh:mm:ss is used.<p> 
+     * 
+     * @param runtime the time to format
+     * 
+     * @return the formatted runtime
+     */
+    public static String formatRuntime(long runtime) {
+
+        long seconds = (runtime / SECONDS) % 60;
+        long minutes = (runtime / MINUTES) % 60;
+        long hours = (runtime / HOURS) % 24;
+        long days = runtime / DAYS;
+        StringBuffer strBuf = new StringBuffer();
+
+        if (days > 0) {
+            if (days < 10) {
+                strBuf.append('0');
+            }
+            strBuf.append(days);
+            strBuf.append(':');
+        }
+
+        if (hours < 10) {
+            strBuf.append('0');
+        }
+        strBuf.append(hours);
+        strBuf.append(':');
+
+        if (minutes < 10) {
+            strBuf.append('0');
+        }
+        strBuf.append(minutes);
+        strBuf.append(':');
+
+        if (seconds < 10) {
+            strBuf.append('0');
+        }
+        strBuf.append(seconds);
+
+        return strBuf.toString();
+    }
+
+    /**
+     * Returns <code>true</code> if the provided String is either <code>null</code>
+     * or the empty String <code>""</code>.<p> 
+     * 
+     * @param value the value to check
+     * 
+     * @return true, if the provided value is null or the empty String, false otherwise
+     */
+    public static boolean isEmpty(String value) {
+
+        return (value == null) || (value.length() == 0);
+    }
+
+    /**
+     * Returns <code>true</code> if the provided String is either <code>null</code>
+     * or contains only white spaces.<p> 
+     * 
+     * @param value the value to check
+     * 
+     * @return true, if the provided value is null or contains only white spaces, false otherwise
+     */
+    public static boolean isEmptyOrWhitespaceOnly(String value) {
+
+        return isEmpty(value) || (value.trim().length() == 0);
+    }
+
+    /**
+     * Returns <code>true</code> if the provided Objects are either both <code>null</code> 
+     * or equal according to {@link Object#equals(Object)}.<p>
+     * 
+     * @param value1 the first object to compare
+     * @param value2 the second object to compare
+     * 
+     * @return <code>true</code> if the provided Objects are either both <code>null</code> 
+     *              or equal according to {@link Object#equals(Object)} 
+     */
+    public static boolean isEqual(Object value1, Object value2) {
+
+        if (value1 == null) {
+            return (value2 == null);
+        }
+        return value1.equals(value2);
+    }
+
+    /**
+     * Returns <code>true</code> if the provided String is neither <code>null</code>
+     * nor the empty String <code>""</code>.<p> 
+     * 
+     * @param value the value to check
+     * 
+     * @return true, if the provided value is not null and not the empty String, false otherwise
+     */
+    public static boolean isNotEmpty(String value) {
+
+        return (value != null) && (value.length() != 0);
+    }
+
+    /**
+     * Returns <code>true</code> if the provided String is neither <code>null</code>
+     * nor contains only white spaces.<p> 
+     * 
+     * @param value the value to check
+     * 
+     * @return <code>true</code>, if the provided value is <code>null</code> 
+     *          or contains only white spaces, <code>false</code> otherwise
+     */
+    public static boolean isNotEmptyOrWhitespaceOnly(String value) {
+
+        return (value != null) && (value.trim().length() > 0);
+    }
+
+    /**
+     * Returns the last index of any of the given chars in the given source.<p> 
+     * 
+     * If no char is found, -1 is returned.<p>
+     * 
+     * @param source the source to check
+     * @param chars the chars to find
+     * 
+     * @return the last index of any of the given chars in the given source, or -1
+     */
+    public static int lastIndexOf(String source, char[] chars) {
+
+        // now try to find an "sentence ending" char in the text in the "findPointArea"
+        int result = -1;
+        for (int i = 0; i < chars.length; i++) {
+            int pos = source.lastIndexOf(chars[i]);
+            if (pos > result) {
+                // found new last char
+                result = pos;
+            }
+        }
+        return result;
+    }
+
+    /**
+     * Returns the last index a whitespace char the given source.<p> 
+     * 
+     * If no whitespace char is found, -1 is returned.<p>
+     * 
+     * @param source the source to check
+     * 
+     * @return the last index a whitespace char the given source, or -1
+     */
+    public static int lastWhitespaceIn(String source) {
+
+        if (isEmpty(source)) {
+            return -1;
+        }
+        int pos = -1;
+        for (int i = source.length() - 1; i >= 0; i--) {
+            if (Character.isWhitespace(source.charAt(i))) {
+                pos = i;
+                break;
+            }
+        }
+        return pos;
+    }
+
+    /**
+     * Substitutes <code>searchString</code> in the given source String with <code>replaceString</code>.<p>
+     * 
+     * This is a high-performance implementation which should be used as a replacement for 
+     * <code>{@link String#replaceAll(java.lang.String, java.lang.String)}</code> in case no
+     * regular expression evaluation is required.<p>
+     * 
+     * @param source the content which is scanned
+     * @param searchString the String which is searched in content
+     * @param replaceString the String which replaces <code>searchString</code>
+     * 
+     * @return the substituted String
+     */
+    public static String substitute(String source, String searchString, String replaceString) {
+
+        if (source == null) {
+            return null;
+        }
+
+        if (isEmpty(searchString)) {
+            return source;
+        }
+
+        if (replaceString == null) {
+            replaceString = "";
+        }
+        int len = source.length();
+        int sl = searchString.length();
+        int rl = replaceString.length();
+        int length;
+        if (sl == rl) {
+            length = len;
+        } else {
+            int c = 0;
+            int s = 0;
+            int e;
+            while ((e = source.indexOf(searchString, s)) != -1) {
+                c++;
+                s = e + sl;
+            }
+            if (c == 0) {
+                return source;
+            }
+            length = len - (c * (sl - rl));
+        }
+
+        int s = 0;
+        int e = source.indexOf(searchString, s);
+        if (e == -1) {
+            return source;
+        }
+        StringBuffer sb = new StringBuffer(length);
+        while (e != -1) {
+            sb.append(source.substring(s, e));
+            sb.append(replaceString);
+            s = e + sl;
+            e = source.indexOf(searchString, s);
+        }
+        e = len;
+        sb.append(source.substring(s, e));
+        return sb.toString();
+    }
+
+    /**
+     * Returns the java String literal for the given String. <p>
+     *  
+     * This is the form of the String that had to be written into source code 
+     * using the unicode escape sequence for special characters. <p> 
+     * 
+     * Example: "�" would be transformed to "\\u00C4".<p>
+     * 
+     * @param s a string that may contain non-ascii characters 
+     * 
+     * @return the java unicode escaped string Literal of the given input string
+     */
+    public static String toUnicodeLiteral(String s) {
+
+        StringBuffer result = new StringBuffer();
+        char[] carr = s.toCharArray();
+
+        String unicode;
+        for (int i = 0; i < carr.length; i++) {
+            result.append("\\u");
+            // append leading zeros
+            unicode = Integer.toHexString(carr[i]).toUpperCase();
+            for (int j = 4 - unicode.length(); j > 0; j--) {
+                result.append("0");
+            }
+            result.append(unicode);
+        }
+        return result.toString();
+    }
+
+    /**
+     * Returns a substring of the source, which is at most length characters long.<p>
+     * 
+     * This is the same as calling {@link #trimToSize(String, int, String)} with the 
+     * parameters <code>(source, length, " ...")</code>.<p>
+     * 
+     * @param source the string to trim
+     * @param length the maximum length of the string to be returned
+     * 
+     * @return a substring of the source, which is at most length characters long
+     */
+    public static String trimToSize(String source, int length) {
+
+        return trimToSize(source, length, length, " ...");
+    }
+
+    /**
+     * Returns a substring of the source, which is at most length characters long.<p>
+     * 
+     * If a char is cut, the given <code>suffix</code> is appended to the result.<p>
+     * 
+     * This is almost the same as calling {@link #trimToSize(String, int, int, String)} with the 
+     * parameters <code>(source, length, length*, suffix)</code>. If <code>length</code>
+     * if larger then 100, then <code>length* = length / 2</code>,
+     * otherwise <code>length* = length</code>.<p>
+     * 
+     * @param source the string to trim
+     * @param length the maximum length of the string to be returned
+     * @param suffix the suffix to append in case the String was trimmed
+     * 
+     * @return a substring of the source, which is at most length characters long
+     */
+    public static String trimToSize(String source, int length, String suffix) {
+
+        int area = (length > 100) ? length / 2 : length;
+        return trimToSize(source, length, area, suffix);
+    }
+
+    /**
+     * Returns a substring of the source, which is at most length characters long, cut 
+     * in the last <code>area</code> chars in the source at a sentence ending char or whitespace.<p>
+     * 
+     * If a char is cut, the given <code>suffix</code> is appended to the result.<p>
+     * 
+     * @param source the string to trim
+     * @param length the maximum length of the string to be returned
+     * @param area the area at the end of the string in which to find a sentence ender or whitespace
+     * @param suffix the suffix to append in case the String was trimmed
+     * 
+     * @return a substring of the source, which is at most length characters long
+     */
+    public static String trimToSize(String source, int length, int area, String suffix) {
+
+        if ((source == null) || (source.length() <= length)) {
+            // no operation is required
+            return source;
+        }
+        if (isEmpty(suffix)) {
+            // we need an empty suffix
+            suffix = "";
+        }
+        // must remove the length from the after sequence chars since these are always added in the end
+        int modLength = length - suffix.length();
+        if (modLength <= 0) {
+            // we are to short, return beginning of the suffix
+            return suffix.substring(0, length);
+        }
+        int modArea = area + suffix.length();
+        if ((modArea > modLength) || (modArea < 0)) {
+            // area must not be longer then max length
+            modArea = modLength;
+        }
+
+        // first reduce the String to the maximum allowed length
+        String findPointSource = source.substring(modLength - modArea, modLength);
+
+        String result;
+        // try to find an "sentence ending" char in the text
+        int pos = lastIndexOf(findPointSource, SENTENCE_ENDING_CHARS);
+        if (pos >= 0) {
+            // found a sentence ender in the lookup area, keep the sentence ender
+            result = source.substring(0, modLength - modArea + pos + 1) + suffix;
+        } else {
+            // no sentence ender was found, try to find a whitespace
+            pos = lastWhitespaceIn(findPointSource);
+            if (pos >= 0) {
+                // found a whitespace, don't keep the whitespace
+                result = source.substring(0, modLength - modArea + pos) + suffix;
+            } else {
+                // not even a whitespace was found, just cut away what's to long
+                result = source.substring(0, modLength) + suffix;
+            }
+        }
+
+        return result;
+    }
 }
\ No newline at end of file
diff --git a/specialpurpose/pricat/src/main/java/org/apache/ofbiz/pricat/PricatEvents.java b/specialpurpose/pricat/src/main/java/org/apache/ofbiz/pricat/PricatEvents.java
index f1ad508..4b47931 100644
--- a/specialpurpose/pricat/src/main/java/org/apache/ofbiz/pricat/PricatEvents.java
+++ b/specialpurpose/pricat/src/main/java/org/apache/ofbiz/pricat/PricatEvents.java
@@ -1,193 +1,193 @@
-/*******************************************************************************

- * 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.pricat;

-

-import java.io.File;

-import java.io.IOException;

-import java.net.MalformedURLException;

-import java.net.URLEncoder;

-import java.nio.file.Files;

-import java.nio.file.Path;

-import java.nio.file.Paths;

-

-import javax.servlet.http.HttpServletRequest;

-import javax.servlet.http.HttpServletResponse;

-

-import org.apache.commons.fileupload.servlet.ServletFileUpload;

-import org.jdom.JDOMException;

-import org.apache.ofbiz.base.location.ComponentLocationResolver;

-import org.apache.ofbiz.base.util.Debug;

-import org.apache.ofbiz.base.util.FileUtil;

-import org.apache.ofbiz.base.util.UtilHttp;

-import org.apache.ofbiz.base.util.UtilMisc;

-import org.apache.ofbiz.base.util.UtilProperties;

-import org.apache.ofbiz.base.util.UtilValidate;

-import org.apache.ofbiz.entity.Delegator;

-import org.apache.ofbiz.entity.GenericEntityException;

-import org.apache.ofbiz.entity.GenericValue;

-import org.apache.ofbiz.pricat.AbstractPricatParser;

-import org.apache.ofbiz.pricat.InterfacePricatParser;

-import org.apache.ofbiz.pricat.PricatParseExcelHtmlThread;

-

-public class PricatEvents {

-    

-    public static final String module = PricatEvents.class.getName();

-    

-    public static final String PricatLatestVersion = UtilProperties.getPropertyValue("pricat", "pricat.latest.version", "V1.1");

-    

-    public static final String PricatFileName = "PricatTemplate_" + PricatLatestVersion + ".xlsx";

-    

-    public static final String PricatPath = "component://pricat/webapp/pricat/downloads/";

-    

-    /**

-     * Download excel template.

-     * 

-     * @param request

-     * @param response

-     * @return

-     * @throws IOException

-     * @throws JDOMException

-     */

-    public static String downloadExcelTemplate(HttpServletRequest request, HttpServletResponse response) {

-        String templateType = request.getParameter("templateType");

-        if (UtilValidate.isEmpty(templateType)) {

-            return "error";

-        }

-        try {

-            String path = ComponentLocationResolver.getBaseLocation(PricatPath).toString();

-            String fileName = null;

-            if ("pricatExcelTemplate".equals(templateType)) {

-                fileName = PricatFileName;

-            }

-            if (UtilValidate.isEmpty(fileName)) {

-                return "error";

-            }

-            Path file = Paths.get(path + fileName);

-            byte[] bytes = Files.readAllBytes(file);

-            UtilHttp.streamContentToBrowser(response, bytes, "application/octet-stream", URLEncoder.encode(fileName, "UTF-8"));

-        } catch (MalformedURLException e) {

-            Debug.logError(e.getMessage(), module);

-            return "error";

-        } catch (IOException e) {

-            Debug.logError(e.getMessage(), module);

-            return "error";

-        }

-        return "success";

-    }

-    

-    /**

-     * Upload a pricat.

-     */

-    public static String pricatUpload(HttpServletRequest request, HttpServletResponse response) {

-        boolean isMultiPart = ServletFileUpload.isMultipartContent(request);

-        if (isMultiPart) {

-            return "parse_pricat";

-        } else {

-            String action = request.getParameter("action");

-            if (UtilValidate.isNotEmpty(action) && "downloadPricat".equals(action)) {

-                String sequenceNumString = (String) request.getParameter("sequenceNum");

-                long sequenceNum = -1;

-                if (UtilValidate.isNotEmpty(sequenceNumString)) {

-                    try {

-                        sequenceNum = Long.valueOf(sequenceNumString);

-                    } catch (NumberFormatException e) {

-                        // do nothing

-                    }

-                }

-                String originalPricatFileName = (String) request.getSession().getAttribute(PricatParseExcelHtmlThread.PRICAT_FILE);

-                String pricatFileName = originalPricatFileName;

-                if (sequenceNum > 0 && AbstractPricatParser.isCommentedExcelExists(request, sequenceNum)) {

-                    GenericValue userLogin = (GenericValue) request.getSession().getAttribute("userLogin");

-                    String userLoginId = userLogin.getString("userLoginId");

-                    pricatFileName = InterfacePricatParser.tempFilesFolder + userLoginId + "/" + sequenceNum + ".xlsx";

-                }

-                if (UtilValidate.isNotEmpty(pricatFileName) && UtilValidate.isNotEmpty(originalPricatFileName)) {

-                    try {

-                        Path path = Paths.get(pricatFileName);

-                        byte[] bytes = Files.readAllBytes(path);

-                        path = Paths.get(originalPricatFileName);

-                        UtilHttp.streamContentToBrowser(response, bytes, "application/octet-stream", URLEncoder.encode(path.getName(path.getNameCount() - 1).toString(), "UTF-8"));

-                    } catch (MalformedURLException e) {

-                        Debug.logError(e.getMessage(), module);

-                        return "error";

-                    } catch (IOException e) {

-                        Debug.logError(e.getMessage(), module);

-                        return "error";

-                    }

-                    request.getSession().removeAttribute(PricatParseExcelHtmlThread.PRICAT_FILE);

-                    return "download";

-                }

-            }

-        }

-        return "success";

-    }

-

-    /**

-     * Download commented excel file after it's parsed.

-     * 

-     * @param request

-     * @param response

-     * @return

-     * @throws IOException

-     * @throws JDOMException

-     */

-    public static String downloadCommentedExcel(HttpServletRequest request, HttpServletResponse response) {

-        String sequenceNum = request.getParameter("sequenceNum");

-        GenericValue userLogin = (GenericValue) request.getSession().getAttribute("userLogin");

-        if (UtilValidate.isEmpty(sequenceNum) || UtilValidate.isEmpty(userLogin)) {

-            Debug.logError("sequenceNum[" + sequenceNum + "] or userLogin is empty", module);

-            return "error";

-        }

-        String userLoginId = userLogin.getString("userLoginId");

-        Delegator delegator = (Delegator) request.getAttribute("delegator");

-        GenericValue historyValue = null;

-        try {

-            historyValue = delegator.findOne("ExcelImportHistory", UtilMisc.toMap("userLoginId", userLoginId, "sequenceNum", Long.valueOf(sequenceNum)), false);

-        } catch (NumberFormatException e) {

-            Debug.logError(e.getMessage(), module);

-            return "error";

-        } catch (GenericEntityException e) {

-            Debug.logError(e.getMessage(), module);

-            return "error";

-        }

-        if (UtilValidate.isEmpty(historyValue)) {

-            Debug.logError("No ExcelImportHistory value found by sequenceNum[" + sequenceNum + "] and userLoginId[" + userLoginId + "].", module);

-            return "error";

-        }

-        String fileName = historyValue.getString("fileName");

-        if (UtilValidate.isEmpty(fileName)) {

-            fileName = sequenceNum + ".xlsx";

-        }

-        try {

-            File file = FileUtil.getFile(InterfacePricatParser.tempFilesFolder + userLoginId + "/" + sequenceNum + ".xlsx");

-            if (file.exists()) {

-                Path path = Paths.get(file.getPath());

-                byte[] bytes = Files.readAllBytes(path);

-                UtilHttp.streamContentToBrowser(response, bytes, "application/octet-stream", URLEncoder.encode(fileName, "UTF-8"));

-            }

-        } catch (MalformedURLException e) {

-            Debug.logError(e.getMessage(), module);

-            return "error";

-        } catch (IOException e) {

-            Debug.logError(e.getMessage(), module);

-            return "error";

-        }

-        return "success";

-    }

-}

+/*******************************************************************************
+ * 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.pricat;
+
+import java.io.File;
+import java.io.IOException;
+import java.net.MalformedURLException;
+import java.net.URLEncoder;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.apache.commons.fileupload.servlet.ServletFileUpload;
+import org.jdom.JDOMException;
+import org.apache.ofbiz.base.location.ComponentLocationResolver;
+import org.apache.ofbiz.base.util.Debug;
+import org.apache.ofbiz.base.util.FileUtil;
+import org.apache.ofbiz.base.util.UtilHttp;
+import org.apache.ofbiz.base.util.UtilMisc;
+import org.apache.ofbiz.base.util.UtilProperties;
+import org.apache.ofbiz.base.util.UtilValidate;
+import org.apache.ofbiz.entity.Delegator;
+import org.apache.ofbiz.entity.GenericEntityException;
+import org.apache.ofbiz.entity.GenericValue;
+import org.apache.ofbiz.pricat.AbstractPricatParser;
+import org.apache.ofbiz.pricat.InterfacePricatParser;
+import org.apache.ofbiz.pricat.PricatParseExcelHtmlThread;
+
+public class PricatEvents {
+    
+    public static final String module = PricatEvents.class.getName();
+    
+    public static final String PricatLatestVersion = UtilProperties.getPropertyValue("pricat", "pricat.latest.version", "V1.1");
+    
+    public static final String PricatFileName = "PricatTemplate_" + PricatLatestVersion + ".xlsx";
+    
+    public static final String PricatPath = "component://pricat/webapp/pricat/downloads/";
+    
+    /**
+     * Download excel template.
+     * 
+     * @param request
+     * @param response
+     * @return
+     * @throws IOException
+     * @throws JDOMException
+     */
+    public static String downloadExcelTemplate(HttpServletRequest request, HttpServletResponse response) {
+        String templateType = request.getParameter("templateType");
+        if (UtilValidate.isEmpty(templateType)) {
+            return "error";
+        }
+        try {
+            String path = ComponentLocationResolver.getBaseLocation(PricatPath).toString();
+            String fileName = null;
+            if ("pricatExcelTemplate".equals(templateType)) {
+                fileName = PricatFileName;
+            }
+            if (UtilValidate.isEmpty(fileName)) {
+                return "error";
+            }
+            Path file = Paths.get(path + fileName);
+            byte[] bytes = Files.readAllBytes(file);
+            UtilHttp.streamContentToBrowser(response, bytes, "application/octet-stream", URLEncoder.encode(fileName, "UTF-8"));
+        } catch (MalformedURLException e) {
+            Debug.logError(e.getMessage(), module);
+            return "error";
+        } catch (IOException e) {
+            Debug.logError(e.getMessage(), module);
+            return "error";
+        }
+        return "success";
+    }
+    
+    /**
+     * Upload a pricat.
+     */
+    public static String pricatUpload(HttpServletRequest request, HttpServletResponse response) {
+        boolean isMultiPart = ServletFileUpload.isMultipartContent(request);
+        if (isMultiPart) {
+            return "parse_pricat";
+        } else {
+            String action = request.getParameter("action");
+            if (UtilValidate.isNotEmpty(action) && "downloadPricat".equals(action)) {
+                String sequenceNumString = (String) request.getParameter("sequenceNum");
+                long sequenceNum = -1;
+                if (UtilValidate.isNotEmpty(sequenceNumString)) {
+                    try {
+                        sequenceNum = Long.valueOf(sequenceNumString);
+                    } catch (NumberFormatException e) {
+                        // do nothing
+                    }
+                }
+                String originalPricatFileName = (String) request.getSession().getAttribute(PricatParseExcelHtmlThread.PRICAT_FILE);
+                String pricatFileName = originalPricatFileName;
+                if (sequenceNum > 0 && AbstractPricatParser.isCommentedExcelExists(request, sequenceNum)) {
+                    GenericValue userLogin = (GenericValue) request.getSession().getAttribute("userLogin");
+                    String userLoginId = userLogin.getString("userLoginId");
+                    pricatFileName = InterfacePricatParser.tempFilesFolder + userLoginId + "/" + sequenceNum + ".xlsx";
+                }
+                if (UtilValidate.isNotEmpty(pricatFileName) && UtilValidate.isNotEmpty(originalPricatFileName)) {
+                    try {
+                        Path path = Paths.get(pricatFileName);
+                        byte[] bytes = Files.readAllBytes(path);
+                        path = Paths.get(originalPricatFileName);
+                        UtilHttp.streamContentToBrowser(response, bytes, "application/octet-stream", URLEncoder.encode(path.getName(path.getNameCount() - 1).toString(), "UTF-8"));
+                    } catch (MalformedURLException e) {
+                        Debug.logError(e.getMessage(), module);
+                        return "error";
+                    } catch (IOException e) {
+                        Debug.logError(e.getMessage(), module);
+                        return "error";
+                    }
+                    request.getSession().removeAttribute(PricatParseExcelHtmlThread.PRICAT_FILE);
+                    return "download";
+                }
+            }
+        }
+        return "success";
+    }
+
+    /**
+     * Download commented excel file after it's parsed.
+     * 
+     * @param request
+     * @param response
+     * @return
+     * @throws IOException
+     * @throws JDOMException
+     */
+    public static String downloadCommentedExcel(HttpServletRequest request, HttpServletResponse response) {
+        String sequenceNum = request.getParameter("sequenceNum");
+        GenericValue userLogin = (GenericValue) request.getSession().getAttribute("userLogin");
+        if (UtilValidate.isEmpty(sequenceNum) || UtilValidate.isEmpty(userLogin)) {
+            Debug.logError("sequenceNum[" + sequenceNum + "] or userLogin is empty", module);
+            return "error";
+        }
+        String userLoginId = userLogin.getString("userLoginId");
+        Delegator delegator = (Delegator) request.getAttribute("delegator");
+        GenericValue historyValue = null;
+        try {
+            historyValue = delegator.findOne("ExcelImportHistory", UtilMisc.toMap("userLoginId", userLoginId, "sequenceNum", Long.valueOf(sequenceNum)), false);
+        } catch (NumberFormatException e) {
+            Debug.logError(e.getMessage(), module);
+            return "error";
+        } catch (GenericEntityException e) {
+            Debug.logError(e.getMessage(), module);
+            return "error";
+        }
+        if (UtilValidate.isEmpty(historyValue)) {
+            Debug.logError("No ExcelImportHistory value found by sequenceNum[" + sequenceNum + "] and userLoginId[" + userLoginId + "].", module);
+            return "error";
+        }
+        String fileName = historyValue.getString("fileName");
+        if (UtilValidate.isEmpty(fileName)) {
+            fileName = sequenceNum + ".xlsx";
+        }
+        try {
+            File file = FileUtil.getFile(InterfacePricatParser.tempFilesFolder + userLoginId + "/" + sequenceNum + ".xlsx");
+            if (file.exists()) {
+                Path path = Paths.get(file.getPath());
+                byte[] bytes = Files.readAllBytes(path);
+                UtilHttp.streamContentToBrowser(response, bytes, "application/octet-stream", URLEncoder.encode(fileName, "UTF-8"));
+            }
+        } catch (MalformedURLException e) {
+            Debug.logError(e.getMessage(), module);
+            return "error";
+        } catch (IOException e) {
+            Debug.logError(e.getMessage(), module);
+            return "error";
+        }
+        return "success";
+    }
+}
diff --git a/specialpurpose/pricat/src/main/java/org/apache/ofbiz/pricat/sample/SamplePricatEvents.java b/specialpurpose/pricat/src/main/java/org/apache/ofbiz/pricat/sample/SamplePricatEvents.java
index fc7b43c..721ec50 100644
--- a/specialpurpose/pricat/src/main/java/org/apache/ofbiz/pricat/sample/SamplePricatEvents.java
+++ b/specialpurpose/pricat/src/main/java/org/apache/ofbiz/pricat/sample/SamplePricatEvents.java
@@ -1,84 +1,84 @@
-/*******************************************************************************

- * 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.pricat.sample;

-

-import java.io.IOException;

-import java.net.MalformedURLException;

-import java.net.URLEncoder;

-import java.nio.file.Files;

-import java.nio.file.Path;

-import java.nio.file.Paths;

-

-import javax.servlet.http.HttpServletRequest;

-import javax.servlet.http.HttpServletResponse;

-

-import org.jdom.JDOMException;

-import org.apache.ofbiz.base.location.ComponentLocationResolver;

-import org.apache.ofbiz.base.util.Debug;

-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.pricat.PricatEvents;

-

-public class SamplePricatEvents extends PricatEvents {

-    

-    public static final String module = SamplePricatEvents.class.getName();

-    

-    public static final String PricatLatestVersion = UtilProperties.getPropertyValue("pricat", "pricat.latest.version", "V1.1");

-    

-    public static final String DemoPricatFileName = "SamplePricatTemplate_" + PricatLatestVersion + ".xlsx";

-    

-    public static final String DemoPricatPath = "component://pricat/webapp/pricatdemo/downloads/";

-    

-    /**

-     * Download excel template.

-     * 

-     * @param request

-     * @param response

-     * @return

-     * @throws IOException

-     * @throws JDOMException

-     */

-    public static String downloadExcelTemplate(HttpServletRequest request, HttpServletResponse response) {

-        String templateType = request.getParameter("templateType");

-        if (UtilValidate.isEmpty(templateType)) {

-            return "error";

-        }

-        try {

-            String path = ComponentLocationResolver.getBaseLocation(DemoPricatPath).toString();

-            String fileName = null;

-            if ("pricatExcelTemplate".equals(templateType)) {

-                fileName = DemoPricatFileName;

-            }

-            if (UtilValidate.isEmpty(fileName)) {

-                return "error";

-            }

-            Path file = Paths.get(path + fileName);

-            byte[] bytes = Files.readAllBytes(file);

-            UtilHttp.streamContentToBrowser(response, bytes, "application/octet-stream", URLEncoder.encode(fileName, "UTF-8"));

-        } catch (MalformedURLException e) {

-            Debug.logError(e.getMessage(), module);

-            return "error";

-        } catch (IOException e) {

-            Debug.logError(e.getMessage(), module);

-            return "error";

-        }

-        return "success";

-    }

-}

+/*******************************************************************************
+ * 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.pricat.sample;
+
+import java.io.IOException;
+import java.net.MalformedURLException;
+import java.net.URLEncoder;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.jdom.JDOMException;
+import org.apache.ofbiz.base.location.ComponentLocationResolver;
+import org.apache.ofbiz.base.util.Debug;
+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.pricat.PricatEvents;
+
+public class SamplePricatEvents extends PricatEvents {
+    
+    public static final String module = SamplePricatEvents.class.getName();
+    
+    public static final String PricatLatestVersion = UtilProperties.getPropertyValue("pricat", "pricat.latest.version", "V1.1");
+    
+    public static final String DemoPricatFileName = "SamplePricatTemplate_" + PricatLatestVersion + ".xlsx";
+    
+    public static final String DemoPricatPath = "component://pricat/webapp/pricatdemo/downloads/";
+    
+    /**
+     * Download excel template.
+     * 
+     * @param request
+     * @param response
+     * @return
+     * @throws IOException
+     * @throws JDOMException
+     */
+    public static String downloadExcelTemplate(HttpServletRequest request, HttpServletResponse response) {
+        String templateType = request.getParameter("templateType");
+        if (UtilValidate.isEmpty(templateType)) {
+            return "error";
+        }
+        try {
+            String path = ComponentLocationResolver.getBaseLocation(DemoPricatPath).toString();
+            String fileName = null;
+            if ("pricatExcelTemplate".equals(templateType)) {
+                fileName = DemoPricatFileName;
+            }
+            if (UtilValidate.isEmpty(fileName)) {
+                return "error";
+            }
+            Path file = Paths.get(path + fileName);
+            byte[] bytes = Files.readAllBytes(file);
+            UtilHttp.streamContentToBrowser(response, bytes, "application/octet-stream", URLEncoder.encode(fileName, "UTF-8"));
+        } catch (MalformedURLException e) {
+            Debug.logError(e.getMessage(), module);
+            return "error";
+        } catch (IOException e) {
+            Debug.logError(e.getMessage(), module);
+            return "error";
+        }
+        return "success";
+    }
+}
diff --git a/specialpurpose/pricat/src/main/java/org/apache/poi/xssf/usermodel/OFBizPricatUtil.java b/specialpurpose/pricat/src/main/java/org/apache/poi/xssf/usermodel/OFBizPricatUtil.java
index 3d18c6c..2a10354 100644
--- a/specialpurpose/pricat/src/main/java/org/apache/poi/xssf/usermodel/OFBizPricatUtil.java
+++ b/specialpurpose/pricat/src/main/java/org/apache/poi/xssf/usermodel/OFBizPricatUtil.java
@@ -1,36 +1,36 @@
-/*

- * 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.poi.xssf.usermodel;

-

-import org.apache.poi.ss.util.CellReference;

-import com.microsoft.schemas.vml.CTShape;

-

-public final class OFBizPricatUtil {

-    public static void formatCommentShape(XSSFSheet sheet, CellReference cell) {

-        XSSFVMLDrawing vml = sheet.getVMLDrawing(true);

-        CTShape ctshape = vml.findCommentShape(cell.getRow(), cell.getCol());

-        ctshape.setType("#_x0000_t202");

-    }

-

-    public static void formatCommentShape(XSSFSheet sheet, int rowNum, short colNum) {

-        XSSFVMLDrawing vml = sheet.getVMLDrawing(true);

-        CTShape ctshape = vml.findCommentShape(rowNum, colNum);

-        ctshape.setType("#_x0000_t202");

-    }

-}

+/*
+ * 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.poi.xssf.usermodel;
+
+import org.apache.poi.ss.util.CellReference;
+import com.microsoft.schemas.vml.CTShape;
+
+public final class OFBizPricatUtil {
+    public static void formatCommentShape(XSSFSheet sheet, CellReference cell) {
+        XSSFVMLDrawing vml = sheet.getVMLDrawing(true);
+        CTShape ctshape = vml.findCommentShape(cell.getRow(), cell.getCol());
+        ctshape.setType("#_x0000_t202");
+    }
+
+    public static void formatCommentShape(XSSFSheet sheet, int rowNum, short colNum) {
+        XSSFVMLDrawing vml = sheet.getVMLDrawing(true);
+        CTShape ctshape = vml.findCommentShape(rowNum, colNum);
+        ctshape.setType("#_x0000_t202");
+    }
+}