This is an automated email from the ASF dual-hosted git repository.

doebele pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/empire-db.git


The following commit(s) were added to refs/heads/master by this push:
     new 28402921 EMPIREDB-432 Exception message formatting and escaping
28402921 is described below

commit 28402921ae9bd292e8e7bd51896193ac33835e1a
Author: Rainer Döbele <[email protected]>
AuthorDate: Fri Jul 5 14:10:53 2024 +0200

    EMPIREDB-432
    Exception message formatting and escaping
---
 .../empire/jakarta/controls/InputControl.java      |  15 +--
 .../empire/jakarta/impl/ResourceTextResolver.java  |  16 ++-
 .../org/apache/empire/jakarta/utils/HtmlUtils.java |  60 +++++++++
 .../apache/empire/jsf2/controls/InputControl.java  |  15 +--
 .../empire/jsf2/impl/ResourceTextResolver.java     |  16 ++-
 .../org/apache/empire/jsf2/utils/HtmlUtils.java    |  60 +++++++++
 .../apache/empire/exceptions/EmpireException.java  | 136 +++++++++++++--------
 7 files changed, 239 insertions(+), 79 deletions(-)

diff --git 
a/empire-db-jakarta-faces/src/main/java/org/apache/empire/jakarta/controls/InputControl.java
 
b/empire-db-jakarta-faces/src/main/java/org/apache/empire/jakarta/controls/InputControl.java
index 66d4e32d..4b690841 100644
--- 
a/empire-db-jakarta-faces/src/main/java/org/apache/empire/jakarta/controls/InputControl.java
+++ 
b/empire-db-jakarta-faces/src/main/java/org/apache/empire/jakarta/controls/InputControl.java
@@ -43,6 +43,7 @@ import org.apache.empire.exceptions.InvalidArgumentException;
 import org.apache.empire.exceptions.ItemNotFoundException;
 import org.apache.empire.exceptions.UnexpectedReturnValueException;
 import org.apache.empire.jakarta.app.TextResolver;
+import org.apache.empire.jakarta.utils.HtmlUtils;
 import org.apache.empire.jakarta.utils.TagStyleClass;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -799,19 +800,7 @@ public abstract class InputControl
      */
     protected String escapeHTML(String text)
     {
-        if (text==null || text.length()==0)
-            return text;
-        // &amp;
-        if (text.indexOf('&')>=0)
-            text = StringUtils.replaceAll(text, "&", "&amp;");
-        // &lt;
-        if (text.indexOf('<')>=0)
-            text = StringUtils.replaceAll(text, "<", "&lt;");
-        // &gt;
-        if (text.indexOf('>')>=0)
-            text = StringUtils.replaceAll(text, ">", "&gt;");
-        // done
-        return text;
+        return HtmlUtils.getInstance().escapeText(text);
     }
 
     /**
diff --git 
a/empire-db-jakarta-faces/src/main/java/org/apache/empire/jakarta/impl/ResourceTextResolver.java
 
b/empire-db-jakarta-faces/src/main/java/org/apache/empire/jakarta/impl/ResourceTextResolver.java
index 7cea1be7..284be3ed 100644
--- 
a/empire-db-jakarta-faces/src/main/java/org/apache/empire/jakarta/impl/ResourceTextResolver.java
+++ 
b/empire-db-jakarta-faces/src/main/java/org/apache/empire/jakarta/impl/ResourceTextResolver.java
@@ -24,6 +24,7 @@ import java.util.ResourceBundle;
 
 import org.apache.empire.exceptions.EmpireException;
 import org.apache.empire.jakarta.app.TextResolver;
+import org.apache.empire.jakarta.utils.HtmlUtils;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -107,13 +108,13 @@ public class ResourceTextResolver implements TextResolver
             String[] params = ee.getErrorParams();
             if (params!=null)
             {   for (int i=0; i<params.length; i++)
-                    params[i] = resolveText(params[i]);
+                    params[i] = resolveExceptionParam(params[i]);
             }
             // Format message
             return EmpireException.formatErrorMessage(ee.getErrorType(), 
pattern, params);
         }
         else
-        {   // Other exception try to resolve by class name
+        {   // Other exceptions: try to resolve by class name
             String key = "exception."+e.getClass().getName();
             if (resBundle.containsKey(key))
                 return resBundle.getString(key);
@@ -121,4 +122,15 @@ public class ResourceTextResolver implements TextResolver
             return e.getLocalizedMessage();
         }
     }
+    
+    protected String resolveExceptionParam(String param)
+    {
+        if (param==null || param.length()==0)
+            return param;
+        // Translate
+        if (param.startsWith(MSG_KEY_INDICATOR))
+            return resolveText(param);
+        // Encode
+        return HtmlUtils.getInstance().escapeText(param);
+    }
 }
diff --git 
a/empire-db-jakarta-faces/src/main/java/org/apache/empire/jakarta/utils/HtmlUtils.java
 
b/empire-db-jakarta-faces/src/main/java/org/apache/empire/jakarta/utils/HtmlUtils.java
new file mode 100644
index 00000000..ec194bf7
--- /dev/null
+++ 
b/empire-db-jakarta-faces/src/main/java/org/apache/empire/jakarta/utils/HtmlUtils.java
@@ -0,0 +1,60 @@
+/*
+ * 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.empire.jakarta.utils;
+
+import org.apache.empire.commons.StringUtils;
+
+public class HtmlUtils
+{
+    private static HtmlUtils htmlUtils = new HtmlUtils();
+
+    public static HtmlUtils getInstance()
+    {
+        return htmlUtils;
+    }
+
+    public static void setInstance(HtmlUtils htmlUtils)
+    {
+        HtmlUtils.htmlUtils = htmlUtils;
+    }
+    
+    /**
+     * escapes a String for html
+     * 
+     * @param text
+     * @return the escaped html String
+     */
+    public String escapeText(String text)
+    {
+        if (text==null || text.length()==0)
+            return text;
+        // &amp;
+        if (text.indexOf('&')>=0)
+            text = StringUtils.replaceAll(text, "&", "&amp;");
+        // &lt;
+        if (text.indexOf('<')>=0)
+            text = StringUtils.replaceAll(text, "<", "&lt;");
+        // &gt;
+        if (text.indexOf('>')>=0)
+            text = StringUtils.replaceAll(text, ">", "&gt;");
+        // done
+        return text;
+    }
+    
+}
diff --git 
a/empire-db-jsf2/src/main/java/org/apache/empire/jsf2/controls/InputControl.java
 
b/empire-db-jsf2/src/main/java/org/apache/empire/jsf2/controls/InputControl.java
index 84bdfda1..8f4452bf 100644
--- 
a/empire-db-jsf2/src/main/java/org/apache/empire/jsf2/controls/InputControl.java
+++ 
b/empire-db-jsf2/src/main/java/org/apache/empire/jsf2/controls/InputControl.java
@@ -43,6 +43,7 @@ import org.apache.empire.exceptions.InvalidArgumentException;
 import org.apache.empire.exceptions.ItemNotFoundException;
 import org.apache.empire.exceptions.UnexpectedReturnValueException;
 import org.apache.empire.jsf2.app.TextResolver;
+import org.apache.empire.jsf2.utils.HtmlUtils;
 import org.apache.empire.jsf2.utils.TagStyleClass;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -799,19 +800,7 @@ public abstract class InputControl
      */
     protected String escapeHTML(String text)
     {
-        if (text==null || text.length()==0)
-            return text;
-        // &amp;
-        if (text.indexOf('&')>=0)
-            text = StringUtils.replaceAll(text, "&", "&amp;");
-        // &lt;
-        if (text.indexOf('<')>=0)
-            text = StringUtils.replaceAll(text, "<", "&lt;");
-        // &gt;
-        if (text.indexOf('>')>=0)
-            text = StringUtils.replaceAll(text, ">", "&gt;");
-        // done
-        return text;
+        return HtmlUtils.getInstance().escapeText(text);
     }
 
     /**
diff --git 
a/empire-db-jsf2/src/main/java/org/apache/empire/jsf2/impl/ResourceTextResolver.java
 
b/empire-db-jsf2/src/main/java/org/apache/empire/jsf2/impl/ResourceTextResolver.java
index a32e40d4..0a0ba465 100644
--- 
a/empire-db-jsf2/src/main/java/org/apache/empire/jsf2/impl/ResourceTextResolver.java
+++ 
b/empire-db-jsf2/src/main/java/org/apache/empire/jsf2/impl/ResourceTextResolver.java
@@ -24,6 +24,7 @@ import java.util.ResourceBundle;
 
 import org.apache.empire.exceptions.EmpireException;
 import org.apache.empire.jsf2.app.TextResolver;
+import org.apache.empire.jsf2.utils.HtmlUtils;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -107,13 +108,13 @@ public class ResourceTextResolver implements TextResolver
             String[] params = ee.getErrorParams();
             if (params!=null)
             {   for (int i=0; i<params.length; i++)
-                    params[i] = resolveText(params[i]);
+                    params[i] = resolveExceptionParam(params[i]);
             }
             // Format message
             return EmpireException.formatErrorMessage(ee.getErrorType(), 
pattern, params);
         }
         else
-        {   // Other exception try to resolve by class name
+        {   // Other exceptions: try to resolve by class name
             String key = "exception."+e.getClass().getName();
             if (resBundle.containsKey(key))
                 return resBundle.getString(key);
@@ -121,4 +122,15 @@ public class ResourceTextResolver implements TextResolver
             return e.getLocalizedMessage();
         }
     }
+    
+    protected String resolveExceptionParam(String param)
+    {
+        if (param==null || param.length()==0)
+            return param;
+        // Translate
+        if (param.startsWith(MSG_KEY_INDICATOR))
+            return resolveText(param);
+        // Encode
+        return HtmlUtils.getInstance().escapeText(param);
+    }
 }
diff --git 
a/empire-db-jsf2/src/main/java/org/apache/empire/jsf2/utils/HtmlUtils.java 
b/empire-db-jsf2/src/main/java/org/apache/empire/jsf2/utils/HtmlUtils.java
new file mode 100644
index 00000000..07d622d1
--- /dev/null
+++ b/empire-db-jsf2/src/main/java/org/apache/empire/jsf2/utils/HtmlUtils.java
@@ -0,0 +1,60 @@
+/*
+ * 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.empire.jsf2.utils;
+
+import org.apache.empire.commons.StringUtils;
+
+public class HtmlUtils
+{
+    private static HtmlUtils htmlUtils = new HtmlUtils();
+
+    public static HtmlUtils getInstance()
+    {
+        return htmlUtils;
+    }
+
+    public static void setInstance(HtmlUtils htmlUtils)
+    {
+        HtmlUtils.htmlUtils = htmlUtils;
+    }
+    
+    /**
+     * escapes a String for html
+     * 
+     * @param text
+     * @return the escaped html String
+     */
+    public String escapeText(String text)
+    {
+        if (text==null || text.length()==0)
+            return text;
+        // &amp;
+        if (text.indexOf('&')>=0)
+            text = StringUtils.replaceAll(text, "&", "&amp;");
+        // &lt;
+        if (text.indexOf('<')>=0)
+            text = StringUtils.replaceAll(text, "<", "&lt;");
+        // &gt;
+        if (text.indexOf('>')>=0)
+            text = StringUtils.replaceAll(text, ">", "&gt;");
+        // done
+        return text;
+    }
+    
+}
diff --git 
a/empire-db/src/main/java/org/apache/empire/exceptions/EmpireException.java 
b/empire-db/src/main/java/org/apache/empire/exceptions/EmpireException.java
index 8ccda191..9ad3aee7 100644
--- a/empire-db/src/main/java/org/apache/empire/exceptions/EmpireException.java
+++ b/empire-db/src/main/java/org/apache/empire/exceptions/EmpireException.java
@@ -30,66 +30,104 @@ import org.slf4j.LoggerFactory;
 public class EmpireException extends RuntimeException
 {
     private static final long serialVersionUID = 1L;
-
+    
     // Logger
     private static final Logger log = 
LoggerFactory.getLogger(EmpireException.class);
-    
-    private final ErrorType errorType;
-    private final String[]  errorParams;
-    // private final String errorSourceClassname;
-    
-    public static String formatErrorMessage(final ErrorType errType, String 
pattern, final String[] params)
+
+    /**
+     * ExceptionMessageFormatter
+     * returns a message text for an Exception from a given pattern and 
parameters 
+     */
+    public static class ExceptionMessageFormatter
     {
-        // Log Error
-        try {
-            // the pattern
-            if (pattern==null)
-                pattern=errType.getMessagePattern();
-            // init format args
-            Object[] formatArgs = params;
-            // Check parameter count
-            int patParamCount = errType.getNumParams();
-            int paramCount = (params!=null) ? params.length : 0;            
-            if (paramCount < patParamCount)
-            {   // Number of parameters does not match
-                log.warn("Invalid Number of arguments supplied for error " + 
errType.getKey() 
-                       + "\nArguments supplied= " + String.valueOf(paramCount) 
+ "; Arguments expected= " + String.valueOf(errType.getNumParams()));
-                // Return the pattern
-                return pattern;
-            }
-            // more params than expected
-            else if (paramCount>patParamCount)
-            {   // check for wildcard
+        protected String missingArgument = "?";
+        
+        public String format(final ErrorType errType, String pattern, String[] 
params)
+        {
+            // format error message
+            try {
+                // the pattern
+                if (pattern==null)
+                    pattern=errType.getMessagePattern();
+                // Check parameter count
+                int patParamCount = errType.getNumParams();
+                int extraParamIndex = -1;
+                // wildcard
                 if (pattern.contains("{*}")) 
                 {   pattern = pattern.replace("{*}", 
"{"+String.valueOf(patParamCount)+"}");
+                    extraParamIndex = patParamCount;
                     patParamCount++;
                 }
-                // Build new array
-                if (patParamCount>0)
-                {      // reduce number of arguments
-                       formatArgs = new String[patParamCount];
-                       int i=0;
-                       for (; i<patParamCount-1; i++)
-                           formatArgs[i]=params[i];
-                       // Build a array for the rest
-                       StringBuilder b = new StringBuilder();
-                       for (;i<paramCount;i++)
-                       {   if (b.length()>0)
-                               b.append(", ");
-                           b.append(String.valueOf(params[i]));
-                       }
-                       formatArgs[patParamCount-1]=b.toString();
+                // check params
+                int paramCount = (params!=null) ? params.length : 0;           
 
+                if (paramCount < patParamCount)
+                {   // Missing arguments
+                    log.warn("Invalid Number of arguments supplied for error 
{}: Arguments expected={} / Arguments supplied={}.", errType.getKey(), 
patParamCount, paramCount);
                 }
+                // more params than expected
+                else if (paramCount>patParamCount && extraParamIndex<0)
+                {   // Too many arguments
+                    log.info("Additional arguments supplied for error {}: 
Arguments expected={} / Arguments supplied={}.", errType.getKey(), 
patParamCount, paramCount);
+                }
+                // Build format list
+                Object[] messageArgs = new String[patParamCount];
+                for (int i=0; i<messageArgs.length; i++)
+                {
+                    if (i==extraParamIndex) {
+                        // summary of remaining params
+                        StringBuilder b = new StringBuilder();
+                        for (int j=extraParamIndex;j<paramCount;j++)
+                        {   if (b.length()>0)
+                                b.append(", ");
+                            b.append(formatParam(errType, i, params[j]));
+                        }
+                        messageArgs[i] = b.toString();
+                    }
+                    else if (i<paramCount)
+                        messageArgs[i] = formatParam(errType, i, params[i]);
+                    else
+                        messageArgs[i] = missingArgument;
+                }
+                // format now
+                String msg = MessageFormat.format(pattern, messageArgs);
+                return msg;
+            } catch(Exception e) {
+                log.error("Unable to format error message: "+pattern, e);
+                return pattern;
             }
-            // format now
-            String msg = MessageFormat.format(pattern, formatArgs);
-            return msg;
-        } catch(Exception e) {
-            log.error("Unable to format error message: "+pattern, e);
-            return pattern;
+        }
+        
+        protected Object formatParam(final ErrorType errType, int index, 
String param)
+        {
+            return param;
         }
     }
     
+    private static ExceptionMessageFormatter messageFormatter = new 
ExceptionMessageFormatter();
+    
+    public static ExceptionMessageFormatter getMessageFormatter()
+    {
+        return messageFormatter;
+    }
+
+    public static void setMessageFormatter(ExceptionMessageFormatter 
messageFormatter)
+    {
+        if (messageFormatter==null)
+            throw new InvalidArgumentException("messageFormatter", 
messageFormatter);
+        // set formatter
+        EmpireException.messageFormatter = messageFormatter;
+    }
+
+    public static String formatErrorMessage(final ErrorType errType, String 
pattern, final String[] params)
+    {
+        return messageFormatter.format(errType, pattern, params);
+    }
+    
+    private final ErrorType errorType;
+    private final String[]  errorParams;
+    // private final String errorSourceClassname;
+    
+    
     /**
      * Constructor for derived classes
      * @param errType
@@ -98,7 +136,7 @@ public class EmpireException extends RuntimeException
      */
     protected EmpireException(final ErrorType errType, final String[] params, 
final Throwable cause)
     {
-        super(formatErrorMessage(errType, null, params), cause);
+        super(messageFormatter.format(errType, null, params), cause);
         // save type and params for custom message formatting
         this.errorType = errType;
         this.errorParams = params;

Reply via email to