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 5f658fb7 EMPIREDB-451 Improved FacesUtils and FacesMessage handling
5f658fb7 is described below

commit 5f658fb75f66ae5ecd2b08c75a2312f810dee76d
Author: Rainer Döbele <[email protected]>
AuthorDate: Wed Dec 11 10:43:49 2024 +0100

    EMPIREDB-451
    Improved FacesUtils and FacesMessage handling
---
 .../org/apache/empire/jakarta/app/FacesUtils.java  | 160 ++++++++++++++-------
 .../apache/empire/jakarta/app/WebApplication.java  |  66 +++++++++
 .../empire/jakarta/controls/InputControl.java      |  27 ++--
 .../empire/jakarta/controls/TextInputControl.java  |   4 +-
 .../java/org/apache/empire/jakarta/pages/Page.java |  67 ++++-----
 .../org/apache/empire/jsf2/app/FacesUtils.java     | 132 +++++++++++------
 .../org/apache/empire/jsf2/app/WebApplication.java |  66 +++++++++
 .../apache/empire/jsf2/controls/InputControl.java  |   9 +-
 .../empire/jsf2/controls/TextInputControl.java     |   4 +-
 .../java/org/apache/empire/jsf2/pages/Page.java    |  53 +++----
 10 files changed, 395 insertions(+), 193 deletions(-)

diff --git 
a/empire-db-jakarta-faces/src/main/java/org/apache/empire/jakarta/app/FacesUtils.java
 
b/empire-db-jakarta-faces/src/main/java/org/apache/empire/jakarta/app/FacesUtils.java
index edbd5601..24206695 100644
--- 
a/empire-db-jakarta-faces/src/main/java/org/apache/empire/jakarta/app/FacesUtils.java
+++ 
b/empire-db-jakarta-faces/src/main/java/org/apache/empire/jakarta/app/FacesUtils.java
@@ -23,33 +23,37 @@ import java.io.IOException;
 import java.text.MessageFormat;
 import java.util.HashMap;
 import java.util.Iterator;
+import java.util.Locale;
 import java.util.Map;
 
-import jakarta.el.ValueExpression;
-import jakarta.faces.application.FacesMessage;
-import jakarta.faces.component.UIComponent;
-import jakarta.faces.component.UIInput;
-import jakarta.faces.component.UIViewRoot;
-import jakarta.faces.context.ExternalContext;
-import jakarta.faces.context.FacesContext;
-import jakarta.faces.event.ActionEvent;
-import jakarta.servlet.ServletContext;
-import jakarta.servlet.http.HttpServletRequest;
-
 import org.apache.empire.commons.ObjectUtils;
 import org.apache.empire.commons.StringUtils;
 import org.apache.empire.data.Column;
-import org.apache.empire.exceptions.EmpireException;
 import org.apache.empire.exceptions.InternalException;
+import org.apache.empire.exceptions.InvalidArgumentException;
 import org.apache.empire.exceptions.ItemNotFoundException;
 import org.apache.empire.jakarta.impl.FacesImplementation;
 import org.apache.empire.jakarta.pages.Page;
 import org.apache.empire.jakarta.pages.PageDefinition;
 import org.apache.empire.jakarta.pages.PageOutcome;
+import org.apache.empire.jakarta.utils.HtmlUtils;
 import org.apache.empire.jakarta.utils.ParameterMap;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
+import jakarta.el.ValueExpression;
+import jakarta.faces.application.FacesMessage;
+import jakarta.faces.application.FacesMessage.Severity;
+import jakarta.faces.application.ProjectStage;
+import jakarta.faces.component.UIComponent;
+import jakarta.faces.component.UIInput;
+import jakarta.faces.component.UIViewRoot;
+import jakarta.faces.context.ExternalContext;
+import jakarta.faces.context.FacesContext;
+import jakarta.faces.event.ActionEvent;
+import jakarta.servlet.ServletContext;
+import jakarta.servlet.http.HttpServletRequest;
+
 public class FacesUtils
 {
 
@@ -57,6 +61,12 @@ public class FacesUtils
     
     public static final String SKIP_INPUT_VALIDATION_PARAM = 
"empire.jsf.input.skipValidation";
 
+    /* Develpment stage */
+    public static boolean isDevelopmentStage(final FacesContext fc)
+    {
+        return fc.getApplication().getProjectStage()==ProjectStage.Development;
+    }
+
     /* App */
 
     public static WebApplication getWebApplication()
@@ -73,6 +83,11 @@ public class FacesUtils
     {
         return FacesContext.getCurrentInstance();
     }
+    
+    public static Locale getContextLocale(final FacesContext fc)
+    {
+        return getWebApplication().getContextLocale(fc);
+    }
 
     /* Session */
     
@@ -398,54 +413,50 @@ public class FacesUtils
         return getWebApplication().getTextResolver(fc);
     }
     
-    public static String getMessage(final FacesContext fc, String key)
+    public static String resolveText(final FacesContext fc, String text)
     {
-        return getTextResolver(fc).resolveKey(key);
+        return getTextResolver(fc).resolveText(text);
     }
     
-    public static String getMessage(String messageKey)
+    public static String resolveText(String text)
     {
-        return getMessage(getContext(), messageKey);
+        return getTextResolver(getContext()).resolveText(text);
     }
-
-    public static String formatMessage(String msgKey, Object... params)
-    {
-        TextResolver tr = getTextResolver(FacesContext.getCurrentInstance());
-        String pattern = tr.resolveKey(msgKey);
-        return MessageFormat.format(pattern, params);
-    }
-
-    /*
-    public static void addInfoMessage(FacesContext fc, String clientId, String 
msg)
+    
+    public static String getMessage(final FacesContext fc, String key)
     {
-        fc.addMessage(clientId, new FacesMessage(FacesMessage.SEVERITY_INFO, 
msg, msg));
+        if (StringUtils.isEmpty(key))
+            throw new InvalidArgumentException("key", key);
+        TextResolver tr = getTextResolver(fc); 
+        return (key.startsWith(TextResolver.MSG_KEY_INDICATOR) ? 
tr.resolveText(key) : tr.resolveKey(key));
     }
     
-    public static void addInfoMessage(FacesContext fc, String msg)
+    public static String getMessage(String messageKey)
     {
-        addInfoMessage(fc, null, msg);
+        return getMessage(getContext(), messageKey);
     }
 
-    public static void addWarnMessage(FacesContext fc, String clientId, String 
msg)
+    public static String formatMessage(final FacesContext fc, String msgKey, 
Object... params)
     {
-        fc.addMessage(clientId, new FacesMessage(FacesMessage.SEVERITY_WARN, 
msg, msg));
-    }
-    
-    public static void addWarnMessage(FacesContext fc, String msg)
-    {
-        addWarnMessage(fc, null, msg);
+        String pattern = getMessage(fc, msgKey);
+        return MessageFormat.format(pattern, params);
     }
 
-    public static void addErrorMessage(FacesContext fc, String clientId, 
String msg)
+    public static String formatMessage(String msgKey, Object... params)
     {
-        fc.addMessage(clientId, new FacesMessage(FacesMessage.SEVERITY_ERROR, 
msg, msg));
+        return formatMessage(getContext(), msgKey, params);
     }
 
-    public static void addErrorMessage(FacesContext fc, String msg)
+    /**
+     * Escapes Text for Html
+     * Uses HtmlUtils.getInstance() for escaping
+     * @param text the text to escape
+     * @return the escaped text
+     */
+    public static String escapeHtml(String text)
     {
-        addErrorMessage(fc, null, msg);
+        return HtmlUtils.getInstance().escapeText(text);
     }
-    */
 
     /*
      * indicates whether submitted values in InputControl should be cleared or 
preserved.
@@ -463,36 +474,77 @@ public class FacesUtils
         fc.getExternalContext().getRequestMap().put("CLEAR_SUBMITTED_VALUES", 
validate);
     }
     */
+
+    public static void addFacesMessage(FacesContext fc, UIComponent comp, 
FacesMessage facesMsg)
+    {
+        if (facesMsg==null)
+            return;
+        String clientId = (comp!=null ? comp.getClientId() : null);
+        fc.addMessage(clientId, facesMsg);
+    }
+    
+    public static void addFacesMessage(UIComponent comp, Severity severity, 
String message, Object... params)
+    {
+        FacesContext fc = getContext();
+        addFacesMessage(fc, comp, getWebApplication().getFacesMessage(fc, 
severity, message, params));
+    }
+
+    public static void addInfoMessage(String msg, Object... params)
+    {
+        addFacesMessage(null, FacesMessage.SEVERITY_INFO, msg, params);
+    }
+
+    public static void addWarnMessage(String msg, Object... params)
+    {
+        addFacesMessage(null, FacesMessage.SEVERITY_WARN, msg, params);
+    }
+
+    public static void addErrorMessage(String msg, Object... params)
+    {
+        addFacesMessage(null, FacesMessage.SEVERITY_ERROR, msg, params);
+    }
+
+    public static void addErrorMessage(UIComponent comp, Throwable t)
+    {
+        FacesContext fc = getContext();
+        addFacesMessage(fc, comp, getFacesErrorMessage(fc, t));
+    }
+
+    public static void addErrorMessage(Throwable t)
+    {
+        addErrorMessage(null, t);
+    }
     
     public static FacesMessage getFacesErrorMessage(FacesContext fc, Throwable 
t)
     {
-        if (!(t instanceof EmpireException))
-            t = new InternalException(t);
-        // Get Message
-        TextResolver tr = getWebApplication().getTextResolver(fc);
-        String msg = tr.getExceptionMessage((EmpireException)t);
-        // create Faces Message
-        return new FacesMessage(FacesMessage.SEVERITY_ERROR, msg, null);
+        return getWebApplication().getFacesErrorMessage(fc, null, t);
     }
     
-    public static void redirectFromError(Page page, Throwable t)
+    public static void redirectFromError(Page page, FacesMessage errorMsg)
     {
         PageOutcome pageTarget = page.getPageDefinition().getOutcome();
         // throw new InternalException(e);
         FacesContext fc = FacesUtils.getContext();
         boolean committed = fc.getExternalContext().isResponseCommitted();
         if (committed)
-        {   log.warn("Cannot redirect to {} from an already committed 
response! Error is {}.", pageTarget, t.getMessage());
+        {   log.warn("Cannot redirect to {} from an already committed 
response! Error is {}.", pageTarget, errorMsg.getSummary());
             return;
         }
         // redirect to target page
-        FacesMessage facesMsg = getFacesErrorMessage(fc, t);
-        ExternalContext ec = fc.getExternalContext();
-        ec.getSessionMap().put(Page.SESSION_MESSAGE, facesMsg);
+        if (errorMsg!=null) {
+            ExternalContext ec = fc.getExternalContext();
+            ec.getSessionMap().put(Page.SESSION_MESSAGE, errorMsg);
+        }
         // redirect
         FacesUtils.redirectDirectly(fc, pageTarget);
     }
-    
+
+    public static void redirectFromError(Page page, Throwable t)
+    {
+        FacesContext fc = FacesUtils.getContext();
+        FacesMessage facesMsg = getFacesErrorMessage(fc, t);
+        redirectFromError(page, facesMsg);
+    }
     
     /* Component search */
     public static UIInput findInputComponent(UIComponent parent, Column column)
diff --git 
a/empire-db-jakarta-faces/src/main/java/org/apache/empire/jakarta/app/WebApplication.java
 
b/empire-db-jakarta-faces/src/main/java/org/apache/empire/jakarta/app/WebApplication.java
index c40ecf84..ac6b8293 100644
--- 
a/empire-db-jakarta-faces/src/main/java/org/apache/empire/jakarta/app/WebApplication.java
+++ 
b/empire-db-jakarta-faces/src/main/java/org/apache/empire/jakarta/app/WebApplication.java
@@ -20,6 +20,7 @@ package org.apache.empire.jakarta.app;
 
 import java.sql.Connection;
 import java.sql.SQLException;
+import java.text.MessageFormat;
 import java.util.HashMap;
 import java.util.Iterator;
 import java.util.Locale;
@@ -33,6 +34,7 @@ import org.apache.empire.data.DataType;
 import org.apache.empire.db.DBDatabase;
 import org.apache.empire.db.context.DBRollbackManager;
 import org.apache.empire.db.context.DBRollbackManager.ReleaseAction;
+import org.apache.empire.exceptions.EmpireException;
 import org.apache.empire.exceptions.InternalException;
 import org.apache.empire.exceptions.InvalidArgumentException;
 import org.apache.empire.exceptions.NotSupportedException;
@@ -252,6 +254,70 @@ public abstract class WebApplication
         return getTextResolver(getContextLocale(ctx));
     }
 
+    /**
+     * Returns a FacesMessage 
+     * @param ctx the FacesContext
+     * @param severity the message severity
+     * @param msg the message or message key
+     * @param params the message params
+     * @return the FacesMessage or null to ignore
+     */
+    public FacesMessage getFacesMessage(FacesContext ctx, Severity severity, 
String msg, Object... params)
+    {
+        TextResolver resolver = getTextResolver(getContextLocale(ctx));
+        msg = resolver.resolveText(msg);
+        if (params.length>0)
+        {   // translate params
+            for (int i=0; i<params.length; i++)
+                if (params[i] instanceof String)
+                    params[i] = resolver.resolveText((String)params[i]);
+                else if ((params[i] instanceof Integer) || (params[i] 
instanceof Long))
+                    params[i] = String.valueOf(params[i]); // avoid group 
separator
+            // format
+            msg = MessageFormat.format(msg, params);
+        }
+        return new FacesMessage(severity, msg, null);
+    }
+    
+    /**
+     * Returns a FacesMessage for an Exception 
+     * @param ctx the FacesContext
+     * @param errorContext the error context (optional)
+     * @param t the exception
+     * @return the FacesMessage or null to ignore
+     */
+    public FacesMessage getFacesErrorMessage(FacesContext ctx, String 
errorContext, Throwable t)
+    {
+        // Wrap exception if necessary
+        EmpireException e = (t instanceof EmpireException) ? 
((EmpireException)t) : new InternalException(t); 
+        // Get Message
+        TextResolver tr = getTextResolver(ctx);
+        String msg = tr.getExceptionMessage(e);
+        String msgDetail = extractErrorMessageDetail(errorContext, t, 3);
+        // create Faces Message
+        return new FacesMessage(FacesMessage.SEVERITY_ERROR, msg, msgDetail);
+    }
+    
+    protected String extractErrorMessageDetail(String errorContext, Throwable 
e, int stackTraceElements)
+    {
+        StringBuilder b = new StringBuilder();
+        if (errorContext!=null)
+        {   // Append context String
+            b.append(errorContext);
+            b.append(": ");
+        }
+        b.append(e.toString());
+        b.append("\r\nat:");
+        StackTraceElement[] stack = e.getStackTrace();
+        int len = (stack.length>stackTraceElements) ? stackTraceElements : 
stack.length; 
+        for (int i=0; i<len; i++)
+        {
+            b.append(stack[i].toString());
+            b.append("\r\n");
+        }
+        return b.toString();
+    }
+
     /**
      * checks if the current context contains an error
      * @param fc the FacesContext
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 e5eaed45..b1641425 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
@@ -432,7 +432,7 @@ public abstract class InputControl
         {   // Null
             styleClass += " eValNull";
         }
-        else if (dataType.isNumeric())
+        else if (dataType.isNumeric() && value instanceof Number)
         {   // Check negative
             if (ObjectUtils.getLong(value)<0)
                 styleClass += " eValNeg";
@@ -524,13 +524,19 @@ public abstract class InputControl
     {
         // UIInput
         if (comp instanceof UIInput)
-        {
+        {   // Check LocalValue set 
             UIInput input = (UIInput)comp; 
-            if (input.isLocalValueSet())
-            {   input.setValue(null);
-                input.setLocalValueSet(false);
-                // log.debug("clearLocalValues performed for {}", 
input.getClass().getName());
+            if (input.isValid() && input.isLocalValueSet())
+            {   // Check ValueExpression
+                // @see: UIInput:updateModel(FacesContext context)
+                ValueExpression expression = input.getValueExpression("value");
+                if (expression != null)
+                {   // Reset localValue if ValueExpression is set
+                    input.resetValue();
+                }
             }
+            // we're done here
+            return;
         }
         // clearLocalValues of all facets and children of this UIComponent
         if (comp.getFacetCount() > 0)
@@ -785,7 +791,7 @@ public abstract class InputControl
         if (hasFormatOption(vi, "noencode"))
             return s;
         // Encode Html
-        return escapeHTML(s);
+        return escapeHtml(s);
     }
 
     /**
@@ -825,12 +831,11 @@ public abstract class InputControl
     */
 
     /**
-     * escapes a String for html
-     * 
-     * @param text
+     * Escapes a String for html
+     * @param text the text to escape
      * @return the escaped html String
      */
-    protected String escapeHTML(String text)
+    protected String escapeHtml(String text)
     {
         return HtmlUtils.getInstance().escapeText(text);
     }
diff --git 
a/empire-db-jakarta-faces/src/main/java/org/apache/empire/jakarta/controls/TextInputControl.java
 
b/empire-db-jakarta-faces/src/main/java/org/apache/empire/jakarta/controls/TextInputControl.java
index d7896487..24889175 100644
--- 
a/empire-db-jakarta-faces/src/main/java/org/apache/empire/jakarta/controls/TextInputControl.java
+++ 
b/empire-db-jakarta-faces/src/main/java/org/apache/empire/jakarta/controls/TextInputControl.java
@@ -287,7 +287,7 @@ public class TextInputControl extends InputControl
                 return s;
             // Encoded text
             if (escapeHTML)
-                s = escapeHTML(s);
+                s = escapeHtml(s);
             return s;
         }
         if (dataType == DataType.INTEGER || dataType == DataType.AUTOINC)
@@ -316,7 +316,7 @@ public class TextInputControl extends InputControl
         // Convert to String
         if (escapeHTML)
         {
-            return escapeHTML(String.valueOf(value));
+            return escapeHtml(String.valueOf(value));
         }
         return String.valueOf(value);
     }
diff --git 
a/empire-db-jakarta-faces/src/main/java/org/apache/empire/jakarta/pages/Page.java
 
b/empire-db-jakarta-faces/src/main/java/org/apache/empire/jakarta/pages/Page.java
index 4810d53f..9ce53cf4 100644
--- 
a/empire-db-jakarta-faces/src/main/java/org/apache/empire/jakarta/pages/Page.java
+++ 
b/empire-db-jakarta-faces/src/main/java/org/apache/empire/jakarta/pages/Page.java
@@ -19,32 +19,29 @@
 package org.apache.empire.jakarta.pages;
 
 import java.lang.reflect.Method;
-import java.text.MessageFormat;
 import java.util.ArrayList;
 import java.util.Iterator;
 import java.util.List;
 import java.util.Map;
 
-import jakarta.faces.application.FacesMessage;
-import jakarta.faces.application.FacesMessage.Severity;
-import jakarta.faces.application.NavigationHandler;
-import jakarta.faces.context.ExternalContext;
-import jakarta.faces.context.FacesContext;
-
 import org.apache.empire.commons.StringUtils;
 import org.apache.empire.db.DBRowSet;
-import org.apache.empire.exceptions.EmpireException;
-import org.apache.empire.exceptions.InternalException;
+import org.apache.empire.exceptions.InvalidOperationException;
 import org.apache.empire.exceptions.ItemNotFoundException;
 import org.apache.empire.jakarta.app.FacesUtils;
 import org.apache.empire.jakarta.app.TextResolver;
 import org.apache.empire.jakarta.app.WebApplication;
 import org.apache.empire.jakarta.utils.ParameterMap;
 import org.apache.empire.jakarta.utils.ParameterObject;
-import org.apache.empire.exceptions.InvalidOperationException;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
+import jakarta.faces.application.FacesMessage;
+import jakarta.faces.application.FacesMessage.Severity;
+import jakarta.faces.application.NavigationHandler;
+import jakarta.faces.context.ExternalContext;
+import jakarta.faces.context.FacesContext;
+
 public abstract class Page // *Deprecated* implements Serializable
 {
     // *Deprecated* private static final long serialVersionUID = 1L;
@@ -289,25 +286,22 @@ public abstract class Page // *Deprecated* implements 
Serializable
         ec.getSessionMap().put(SESSION_MESSAGE, facesMsg);
     }
     
-    protected void setSessionError(Throwable e)
+    protected void setSessionError(Throwable t)
     {
         // Set Session Message
-        String msg = extractErrorMessage(e);
-        String detail = extractErrorMessageDetail(action, e, 1);
-        if (log.isDebugEnabled())
-            log.debug(msg + "\r\n" + detail, e);
-        FacesMessage facesMsg = new FacesMessage(FacesMessage.SEVERITY_ERROR, 
msg, detail);
+        FacesContext fc = FacesContext.getCurrentInstance(); 
+        FacesMessage facesMsg = FacesUtils.getFacesErrorMessage(fc, t);
         setSessionMessage(facesMsg);
     }
 
-    protected boolean handleActionError(String action, Throwable e)
+    protected boolean handleActionError(String action, Throwable t)
     {
-        // Set Faces Message
-        String msg = extractErrorMessage(e);
-        String detail = extractErrorMessageDetail(action, e, 1);
-        // log.error(msg + "\r\n" + detail);
-        FacesMessage facesMsg = new FacesMessage(FacesMessage.SEVERITY_ERROR, 
msg, detail);
-        setSessionMessage(facesMsg);
+        // the error context
+        String errorContext = StringUtils.concat(getPageName(), ":", action);
+        // get Message
+        WebApplication app = FacesUtils.getWebApplication();
+        FacesContext fc = FacesContext.getCurrentInstance(); 
+        FacesMessage facesMsg = app.getFacesErrorMessage(fc, errorContext, t);
         // Return to parent page
         PageDefinition parentPage = getParentPage();
         if (parentPage == null)
@@ -315,24 +309,14 @@ public abstract class Page // *Deprecated* implements 
Serializable
             return false;
         }
         // redirect
+        setSessionMessage(facesMsg);
         navigateTo(parentPage.getRedirect());
         return true;
     }
 
     protected void addFacesMessage(Severity severity, String msg, Object... 
params)
     {
-        TextResolver resolver = getTextResolver();
-        msg = resolver.resolveText(msg);
-        if (params.length>0)
-        {   // translate params
-            for (int i=0; i<params.length; i++)
-                if (params[i] instanceof String)
-                    params[i] = resolver.resolveText((String)params[i]);
-            // format
-            msg = MessageFormat.format(msg, params);
-        }
-        FacesMessage facesMsg = new FacesMessage(severity, msg, msg);
-        FacesContext.getCurrentInstance().addMessage(getPageName(), facesMsg);
+        FacesUtils.addFacesMessage(null, severity, msg, params);
     }
 
     public final void addInfoMessage(String msg, Object... params)
@@ -350,16 +334,14 @@ public abstract class Page // *Deprecated* implements 
Serializable
         addFacesMessage(FacesMessage.SEVERITY_ERROR, msg, params);
     }
 
-    public void setErrorMessage(Throwable e)
+    public void setErrorMessage(Throwable t)
     {
-        String msg = extractErrorMessage(e);
-        String detail = extractErrorMessageDetail(action, e, 1);
-        if (log.isDebugEnabled())
-            log.debug(msg + "\r\n" + detail, e);
-        FacesMessage facesMsg = new FacesMessage(FacesMessage.SEVERITY_ERROR, 
msg, detail);
-        FacesContext.getCurrentInstance().addMessage(getPageName(), facesMsg);
+        FacesUtils.addErrorMessage(t);
     }
 
+    /* 
+     * obsolete, now in WebApplication
+     * 
     protected String extractErrorMessage(Throwable e)
     {   // Wrap Exception
         if (!(e instanceof EmpireException))
@@ -387,6 +369,7 @@ public abstract class Page // *Deprecated* implements 
Serializable
         }
         return b.toString();
     }
+    */
 
     /**
      * navigates to the desired page. Depending on the page outcome provided 
this is either a forward or a redirect.
diff --git 
a/empire-db-jsf2/src/main/java/org/apache/empire/jsf2/app/FacesUtils.java 
b/empire-db-jsf2/src/main/java/org/apache/empire/jsf2/app/FacesUtils.java
index f5b89fee..3b1c37f3 100644
--- a/empire-db-jsf2/src/main/java/org/apache/empire/jsf2/app/FacesUtils.java
+++ b/empire-db-jsf2/src/main/java/org/apache/empire/jsf2/app/FacesUtils.java
@@ -23,10 +23,13 @@ import java.io.IOException;
 import java.text.MessageFormat;
 import java.util.HashMap;
 import java.util.Iterator;
+import java.util.Locale;
 import java.util.Map;
 
 import javax.el.ValueExpression;
 import javax.faces.application.FacesMessage;
+import javax.faces.application.FacesMessage.Severity;
+import javax.faces.application.ProjectStage;
 import javax.faces.component.UIComponent;
 import javax.faces.component.UIInput;
 import javax.faces.component.UIViewRoot;
@@ -39,7 +42,6 @@ import javax.servlet.http.HttpServletRequest;
 import org.apache.empire.commons.ObjectUtils;
 import org.apache.empire.commons.StringUtils;
 import org.apache.empire.data.Column;
-import org.apache.empire.exceptions.EmpireException;
 import org.apache.empire.exceptions.InternalException;
 import org.apache.empire.exceptions.InvalidArgumentException;
 import org.apache.empire.exceptions.ItemNotFoundException;
@@ -47,6 +49,7 @@ import org.apache.empire.jsf2.impl.FacesImplementation;
 import org.apache.empire.jsf2.pages.Page;
 import org.apache.empire.jsf2.pages.PageDefinition;
 import org.apache.empire.jsf2.pages.PageOutcome;
+import org.apache.empire.jsf2.utils.HtmlUtils;
 import org.apache.empire.jsf2.utils.ParameterMap;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -58,6 +61,12 @@ public class FacesUtils
     
     public static final String SKIP_INPUT_VALIDATION_PARAM = 
"empire.jsf.input.skipValidation";
 
+    /* Develpment stage */
+    public static boolean isDevelopmentStage(final FacesContext fc)
+    {
+        return fc.getApplication().getProjectStage()==ProjectStage.Development;
+    }
+
     /* App */
 
     public static WebApplication getWebApplication()
@@ -74,6 +83,11 @@ public class FacesUtils
     {
         return FacesContext.getCurrentInstance();
     }
+    
+    public static Locale getContextLocale(final FacesContext fc)
+    {
+        return getWebApplication().getContextLocale(fc);
+    }
 
     /* Session */
     
@@ -399,6 +413,16 @@ public class FacesUtils
         return getWebApplication().getTextResolver(fc);
     }
     
+    public static String resolveText(final FacesContext fc, String text)
+    {
+        return getTextResolver(fc).resolveText(text);
+    }
+    
+    public static String resolveText(String text)
+    {
+        return getTextResolver(getContext()).resolveText(text);
+    }
+    
     public static String getMessage(final FacesContext fc, String key)
     {
         if (StringUtils.isEmpty(key))
@@ -412,91 +436,115 @@ public class FacesUtils
         return getMessage(getContext(), messageKey);
     }
 
-    public static String formatMessage(String msgKey, Object... params)
+    public static String formatMessage(final FacesContext fc, String msgKey, 
Object... params)
     {
-        TextResolver tr = getTextResolver(FacesContext.getCurrentInstance());
-        String pattern = tr.resolveKey(msgKey);
+        String pattern = getMessage(fc, msgKey);
         return MessageFormat.format(pattern, params);
     }
 
+    public static String formatMessage(String msgKey, Object... params)
+    {
+        return formatMessage(getContext(), msgKey, params);
+    }
+
+    /**
+     * Escapes Text for Html
+     * Uses HtmlUtils.getInstance() for escaping
+     * @param text the text to escape
+     * @return the escaped text
+     */
+    public static String escapeHtml(String text)
+    {
+        return HtmlUtils.getInstance().escapeText(text);
+    }
+
     /*
-    public static void addInfoMessage(FacesContext fc, String clientId, String 
msg)
+     * indicates whether submitted values in InputControl should be cleared or 
preserved.
+     * Default is true.   
+     * @param fc the faces context
+     * @return true if the submitted values should be cleared or false if they 
shold be preserved
+    public static boolean isClearSubmittedValues(FacesContext fc)
     {
-        fc.addMessage(clientId, new FacesMessage(FacesMessage.SEVERITY_INFO, 
msg, msg));
+        Object validate = 
fc.getExternalContext().getRequestMap().get("CLEAR_SUBMITTED_VALUES");
+        return (validate!=null ? ObjectUtils.getBoolean(validate) : false);
     }
-    
-    public static void addInfoMessage(FacesContext fc, String msg)
+
+    public static void setClearSubmittedValues(FacesContext fc, boolean 
validate)
     {
-        addInfoMessage(fc, null, msg);
+        fc.getExternalContext().getRequestMap().put("CLEAR_SUBMITTED_VALUES", 
validate);
     }
+    */
 
-    public static void addWarnMessage(FacesContext fc, String clientId, String 
msg)
+    public static void addFacesMessage(FacesContext fc, UIComponent comp, 
FacesMessage facesMsg)
     {
-        fc.addMessage(clientId, new FacesMessage(FacesMessage.SEVERITY_WARN, 
msg, msg));
+        if (facesMsg==null)
+            return;
+        String clientId = (comp!=null ? comp.getClientId() : null);
+        fc.addMessage(clientId, facesMsg);
     }
     
-    public static void addWarnMessage(FacesContext fc, String msg)
+    public static void addFacesMessage(UIComponent comp, Severity severity, 
String message, Object... params)
     {
-        addWarnMessage(fc, null, msg);
+        FacesContext fc = getContext();
+        addFacesMessage(fc, comp, getWebApplication().getFacesMessage(fc, 
severity, message, params));
     }
 
-    public static void addErrorMessage(FacesContext fc, String clientId, 
String msg)
+    public static void addInfoMessage(String msg, Object... params)
     {
-        fc.addMessage(clientId, new FacesMessage(FacesMessage.SEVERITY_ERROR, 
msg, msg));
+        addFacesMessage(null, FacesMessage.SEVERITY_INFO, msg, params);
     }
 
-    public static void addErrorMessage(FacesContext fc, String msg)
+    public static void addWarnMessage(String msg, Object... params)
     {
-        addErrorMessage(fc, null, msg);
+        addFacesMessage(null, FacesMessage.SEVERITY_WARN, msg, params);
     }
-    */
 
-    /*
-     * indicates whether submitted values in InputControl should be cleared or 
preserved.
-     * Default is true.   
-     * @param fc the faces context
-     * @return true if the submitted values should be cleared or false if they 
shold be preserved
-    public static boolean isClearSubmittedValues(FacesContext fc)
+    public static void addErrorMessage(String msg, Object... params)
     {
-        Object validate = 
fc.getExternalContext().getRequestMap().get("CLEAR_SUBMITTED_VALUES");
-        return (validate!=null ? ObjectUtils.getBoolean(validate) : false);
+        addFacesMessage(null, FacesMessage.SEVERITY_ERROR, msg, params);
     }
 
-    public static void setClearSubmittedValues(FacesContext fc, boolean 
validate)
+    public static void addErrorMessage(UIComponent comp, Throwable t)
     {
-        fc.getExternalContext().getRequestMap().put("CLEAR_SUBMITTED_VALUES", 
validate);
+        FacesContext fc = getContext();
+        addFacesMessage(fc, comp, getFacesErrorMessage(fc, t));
+    }
+
+    public static void addErrorMessage(Throwable t)
+    {
+        addErrorMessage(null, t);
     }
-    */
     
     public static FacesMessage getFacesErrorMessage(FacesContext fc, Throwable 
t)
     {
-        if (!(t instanceof EmpireException))
-            t = new InternalException(t);
-        // Get Message
-        TextResolver tr = getWebApplication().getTextResolver(fc);
-        String msg = tr.getExceptionMessage((EmpireException)t);
-        // create Faces Message
-        return new FacesMessage(FacesMessage.SEVERITY_ERROR, msg, null);
+        return getWebApplication().getFacesErrorMessage(fc, null, t);
     }
     
-    public static void redirectFromError(Page page, Throwable t)
+    public static void redirectFromError(Page page, FacesMessage errorMsg)
     {
         PageOutcome pageTarget = page.getPageDefinition().getOutcome();
         // throw new InternalException(e);
         FacesContext fc = FacesUtils.getContext();
         boolean committed = fc.getExternalContext().isResponseCommitted();
         if (committed)
-        {   log.warn("Cannot redirect to {} from an already committed 
response! Error is {}.", pageTarget, t.getMessage());
+        {   log.warn("Cannot redirect to {} from an already committed 
response! Error is {}.", pageTarget, errorMsg.getSummary());
             return;
         }
         // redirect to target page
-        FacesMessage facesMsg = getFacesErrorMessage(fc, t);
-        ExternalContext ec = fc.getExternalContext();
-        ec.getSessionMap().put(Page.SESSION_MESSAGE, facesMsg);
+        if (errorMsg!=null) {
+            ExternalContext ec = fc.getExternalContext();
+            ec.getSessionMap().put(Page.SESSION_MESSAGE, errorMsg);
+        }
         // redirect
         FacesUtils.redirectDirectly(fc, pageTarget);
     }
-    
+
+    public static void redirectFromError(Page page, Throwable t)
+    {
+        FacesContext fc = FacesUtils.getContext();
+        FacesMessage facesMsg = getFacesErrorMessage(fc, t);
+        redirectFromError(page, facesMsg);
+    }
     
     /* Component search */
     public static UIInput findInputComponent(UIComponent parent, Column column)
diff --git 
a/empire-db-jsf2/src/main/java/org/apache/empire/jsf2/app/WebApplication.java 
b/empire-db-jsf2/src/main/java/org/apache/empire/jsf2/app/WebApplication.java
index 694015ec..cb85d295 100644
--- 
a/empire-db-jsf2/src/main/java/org/apache/empire/jsf2/app/WebApplication.java
+++ 
b/empire-db-jsf2/src/main/java/org/apache/empire/jsf2/app/WebApplication.java
@@ -20,6 +20,7 @@ package org.apache.empire.jsf2.app;
 
 import java.sql.Connection;
 import java.sql.SQLException;
+import java.text.MessageFormat;
 import java.util.HashMap;
 import java.util.Iterator;
 import java.util.Locale;
@@ -44,6 +45,7 @@ import org.apache.empire.data.DataType;
 import org.apache.empire.db.DBDatabase;
 import org.apache.empire.db.context.DBRollbackManager;
 import org.apache.empire.db.context.DBRollbackManager.ReleaseAction;
+import org.apache.empire.exceptions.EmpireException;
 import org.apache.empire.exceptions.InternalException;
 import org.apache.empire.exceptions.InvalidArgumentException;
 import org.apache.empire.exceptions.NotSupportedException;
@@ -251,6 +253,70 @@ public abstract class WebApplication
         return getTextResolver(getContextLocale(ctx));
     }
 
+    /**
+     * Returns a FacesMessage 
+     * @param ctx the FacesContext
+     * @param severity the message severity
+     * @param msg the message or message key
+     * @param params the message params
+     * @return the FacesMessage or null to ignore
+     */
+    public FacesMessage getFacesMessage(FacesContext ctx, Severity severity, 
String msg, Object... params)
+    {
+        TextResolver resolver = getTextResolver(getContextLocale(ctx));
+        msg = resolver.resolveText(msg);
+        if (params.length>0)
+        {   // translate params
+            for (int i=0; i<params.length; i++)
+                if (params[i] instanceof String)
+                    params[i] = resolver.resolveText((String)params[i]);
+                else if ((params[i] instanceof Integer) || (params[i] 
instanceof Long))
+                    params[i] = String.valueOf(params[i]); // avoid group 
separator
+            // format
+            msg = MessageFormat.format(msg, params);
+        }
+        return new FacesMessage(severity, msg, null);
+    }
+    
+    /**
+     * Returns a FacesMessage for an Exception 
+     * @param ctx the FacesContext
+     * @param errorContext the error context (optional)
+     * @param t the exception
+     * @return the FacesMessage or null to ignore
+     */
+    public FacesMessage getFacesErrorMessage(FacesContext ctx, String 
errorContext, Throwable t)
+    {
+        // Wrap exception if necessary
+        EmpireException e = (t instanceof EmpireException) ? 
((EmpireException)t) : new InternalException(t); 
+        // Get Message
+        TextResolver tr = getTextResolver(ctx);
+        String msg = tr.getExceptionMessage(e);
+        String msgDetail = extractErrorMessageDetail(errorContext, t, 3);
+        // create Faces Message
+        return new FacesMessage(FacesMessage.SEVERITY_ERROR, msg, msgDetail);
+    }
+    
+    protected String extractErrorMessageDetail(String errorContext, Throwable 
e, int stackTraceElements)
+    {
+        StringBuilder b = new StringBuilder();
+        if (errorContext!=null)
+        {   // Append context String
+            b.append(errorContext);
+            b.append(": ");
+        }
+        b.append(e.toString());
+        b.append("\r\nat:");
+        StackTraceElement[] stack = e.getStackTrace();
+        int len = (stack.length>stackTraceElements) ? stackTraceElements : 
stack.length; 
+        for (int i=0; i<len; i++)
+        {
+            b.append(stack[i].toString());
+            b.append("\r\n");
+        }
+        return b.toString();
+    }
+
     /**
      * checks if the current context contains an error
      * @param fc the FacesContext
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 aa9da2b8..c72ce4f8 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
@@ -791,7 +791,7 @@ public abstract class InputControl
         if (hasFormatOption(vi, "noencode"))
             return s;
         // Encode Html
-        return escapeHTML(s);
+        return escapeHtml(s);
     }
 
     /**
@@ -831,12 +831,11 @@ public abstract class InputControl
     */
 
     /**
-     * escapes a String for html
-     * 
-     * @param text
+     * Escapes a String for html
+     * @param text the text to escape
      * @return the escaped html String
      */
-    protected String escapeHTML(String text)
+    protected String escapeHtml(String text)
     {
         return HtmlUtils.getInstance().escapeText(text);
     }
diff --git 
a/empire-db-jsf2/src/main/java/org/apache/empire/jsf2/controls/TextInputControl.java
 
b/empire-db-jsf2/src/main/java/org/apache/empire/jsf2/controls/TextInputControl.java
index 96f4e0cd..af084acc 100644
--- 
a/empire-db-jsf2/src/main/java/org/apache/empire/jsf2/controls/TextInputControl.java
+++ 
b/empire-db-jsf2/src/main/java/org/apache/empire/jsf2/controls/TextInputControl.java
@@ -287,7 +287,7 @@ public class TextInputControl extends InputControl
                 return s;
             // Encoded text
             if (escapeHTML)
-                s = escapeHTML(s);
+                s = escapeHtml(s);
             return s;
         }
         if (dataType == DataType.INTEGER || dataType == DataType.AUTOINC)
@@ -316,7 +316,7 @@ public class TextInputControl extends InputControl
         // Convert to String
         if (escapeHTML)
         {
-            return escapeHTML(String.valueOf(value));
+            return escapeHtml(String.valueOf(value));
         }
         return String.valueOf(value);
     }
diff --git 
a/empire-db-jsf2/src/main/java/org/apache/empire/jsf2/pages/Page.java 
b/empire-db-jsf2/src/main/java/org/apache/empire/jsf2/pages/Page.java
index 31fa7cb7..a3cac649 100644
--- a/empire-db-jsf2/src/main/java/org/apache/empire/jsf2/pages/Page.java
+++ b/empire-db-jsf2/src/main/java/org/apache/empire/jsf2/pages/Page.java
@@ -19,7 +19,6 @@
 package org.apache.empire.jsf2.pages;
 
 import java.lang.reflect.Method;
-import java.text.MessageFormat;
 import java.util.ArrayList;
 import java.util.Iterator;
 import java.util.List;
@@ -33,8 +32,6 @@ import javax.faces.context.FacesContext;
 
 import org.apache.empire.commons.StringUtils;
 import org.apache.empire.db.DBRowSet;
-import org.apache.empire.exceptions.EmpireException;
-import org.apache.empire.exceptions.InternalException;
 import org.apache.empire.exceptions.InvalidOperationException;
 import org.apache.empire.exceptions.ItemNotFoundException;
 import org.apache.empire.jsf2.app.FacesUtils;
@@ -289,25 +286,22 @@ public abstract class Page // *Deprecated* implements 
Serializable
         ec.getSessionMap().put(SESSION_MESSAGE, facesMsg);
     }
     
-    protected void setSessionError(Throwable e)
+    protected void setSessionError(Throwable t)
     {
         // Set Session Message
-        String msg = extractErrorMessage(e);
-        String detail = extractErrorMessageDetail(action, e, 1);
-        if (log.isDebugEnabled())
-            log.debug(msg + "\r\n" + detail, e);
-        FacesMessage facesMsg = new FacesMessage(FacesMessage.SEVERITY_ERROR, 
msg, detail);
+        FacesContext fc = FacesContext.getCurrentInstance(); 
+        FacesMessage facesMsg = FacesUtils.getFacesErrorMessage(fc, t);
         setSessionMessage(facesMsg);
     }
 
-    protected boolean handleActionError(String action, Throwable e)
+    protected boolean handleActionError(String action, Throwable t)
     {
-        // Set Faces Message
-        String msg = extractErrorMessage(e);
-        String detail = extractErrorMessageDetail(action, e, 1);
-        // log.error(msg + "\r\n" + detail);
-        FacesMessage facesMsg = new FacesMessage(FacesMessage.SEVERITY_ERROR, 
msg, detail);
-        setSessionMessage(facesMsg);
+        // the error context
+        String errorContext = StringUtils.concat(getPageName(), ":", action);
+        // get Message
+        WebApplication app = FacesUtils.getWebApplication();
+        FacesContext fc = FacesContext.getCurrentInstance(); 
+        FacesMessage facesMsg = app.getFacesErrorMessage(fc, errorContext, t);
         // Return to parent page
         PageDefinition parentPage = getParentPage();
         if (parentPage == null)
@@ -315,24 +309,14 @@ public abstract class Page // *Deprecated* implements 
Serializable
             return false;
         }
         // redirect
+        setSessionMessage(facesMsg);
         navigateTo(parentPage.getRedirect());
         return true;
     }
 
     protected void addFacesMessage(Severity severity, String msg, Object... 
params)
     {
-        TextResolver resolver = getTextResolver();
-        msg = resolver.resolveText(msg);
-        if (params.length>0)
-        {   // translate params
-            for (int i=0; i<params.length; i++)
-                if (params[i] instanceof String)
-                    params[i] = resolver.resolveText((String)params[i]);
-            // format
-            msg = MessageFormat.format(msg, params);
-        }
-        FacesMessage facesMsg = new FacesMessage(severity, msg, msg);
-        FacesContext.getCurrentInstance().addMessage(getPageName(), facesMsg);
+        FacesUtils.addFacesMessage(null, severity, msg, params);
     }
 
     public final void addInfoMessage(String msg, Object... params)
@@ -350,16 +334,14 @@ public abstract class Page // *Deprecated* implements 
Serializable
         addFacesMessage(FacesMessage.SEVERITY_ERROR, msg, params);
     }
 
-    public void setErrorMessage(Throwable e)
+    public void setErrorMessage(Throwable t)
     {
-        String msg = extractErrorMessage(e);
-        String detail = extractErrorMessageDetail(action, e, 1);
-        if (log.isDebugEnabled())
-            log.debug(msg + "\r\n" + detail, e);
-        FacesMessage facesMsg = new FacesMessage(FacesMessage.SEVERITY_ERROR, 
msg, detail);
-        FacesContext.getCurrentInstance().addMessage(getPageName(), facesMsg);
+        FacesUtils.addErrorMessage(t);
     }
 
+    /* 
+     * obsolete, now in WebApplication
+     * 
     protected String extractErrorMessage(Throwable e)
     {   // Wrap Exception
         if (!(e instanceof EmpireException))
@@ -387,6 +369,7 @@ public abstract class Page // *Deprecated* implements 
Serializable
         }
         return b.toString();
     }
+    */
 
     /**
      * navigates to the desired page. Depending on the page outcome provided 
this is either a forward or a redirect.


Reply via email to