You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@empire-db.apache.org by do...@apache.org on 2022/01/20 04:18:23 UTC

[empire-db] branch version3 updated: WebContext test

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

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


The following commit(s) were added to refs/heads/version3 by this push:
     new 6d7f6e0  WebContext test
6d7f6e0 is described below

commit 6d7f6e07fda5a87bfdb69d327da2ea44b5766de1
Author: Rainer Döbele <do...@apache.org>
AuthorDate: Thu Jan 20 05:18:20 2022 +0100

    WebContext test
---
 .../jsf2/websample/web/AppExceptionHandler.java    | 208 +++++++++++++++++++++
 .../websample/web/AppExceptionHandlerFactory.java  |  29 +++
 .../empire/jsf2/websample/web/SampleUser.java      |   2 +-
 .../websample/web/pages/EmployeeDetailPage.java    |  10 +-
 .../jsf2/websample/web/pages/EmployeeListPage.java |   1 -
 .../src/main/webapp/WEB-INF/faces-config.xml       |   4 +
 .../org/apache/empire/jsf2/app/WebApplication.java |  52 ++++--
 .../org/apache/empire/jsf2/app/WebDBContext.java   |  44 ++++-
 .../apache/empire/db/context/DBContextBase.java    |  30 ++-
 9 files changed, 347 insertions(+), 33 deletions(-)

diff --git a/empire-db-examples/empire-db-example-jsf2/src/main/java/org/apache/empire/jsf2/websample/web/AppExceptionHandler.java b/empire-db-examples/empire-db-example-jsf2/src/main/java/org/apache/empire/jsf2/websample/web/AppExceptionHandler.java
new file mode 100644
index 0000000..c6110bf
--- /dev/null
+++ b/empire-db-examples/empire-db-example-jsf2/src/main/java/org/apache/empire/jsf2/websample/web/AppExceptionHandler.java
@@ -0,0 +1,208 @@
+package org.apache.empire.jsf2.websample.web;
+
+import java.util.Iterator;
+import java.util.Map;
+
+import javax.faces.FacesException;
+import javax.faces.application.FacesMessage;
+import javax.faces.context.ExceptionHandler;
+import javax.faces.context.ExceptionHandlerWrapper;
+import javax.faces.context.FacesContext;
+import javax.faces.event.ExceptionQueuedEvent;
+import javax.faces.event.ExceptionQueuedEventContext;
+
+import org.apache.empire.exceptions.EmpireException;
+import org.apache.empire.exceptions.InternalException;
+import org.apache.empire.jsf2.app.FacesUtils;
+import org.apache.empire.jsf2.app.TextResolver;
+import org.apache.empire.jsf2.app.WebApplication;
+import org.apache.empire.jsf2.websample.web.pages.SamplePages;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class AppExceptionHandler extends ExceptionHandlerWrapper
+{
+
+    private static final Logger    log = LoggerFactory.getLogger(AppExceptionHandler.class);
+
+    private final ExceptionHandler wrapped;
+
+    public AppExceptionHandler(ExceptionHandler delegate)
+    {
+        // super(delegate);
+        this.wrapped = delegate;
+    }
+
+    @Override
+    public javax.faces.context.ExceptionHandler getWrapped()
+    {
+        return this.wrapped;
+    }
+
+    @Override
+    public void handle()
+        throws FacesException
+    {
+        // boolean redirectToErrorPage = false;
+        Throwable rootCause = null;
+        Iterator<ExceptionQueuedEvent> events = getUnhandledExceptionQueuedEvents().iterator();
+
+        // log each error
+        while (events.hasNext())
+        {
+            ExceptionQueuedEvent event = events.next();
+            // handle
+            try {
+            
+                ExceptionQueuedEventContext source = (ExceptionQueuedEventContext) event.getSource();
+                FacesContext context = source.getContext();
+                Throwable t = source.getException();
+                
+                // check t
+                if (t==null)
+                {   log.error("Cannot handle exception. Exception not supplied with context!");
+                    setErrorMessage(context, null);
+                    continue;
+                }    
+
+                // find root
+                rootCause = t.getCause();
+                // second option: getRootCause
+                if (rootCause == null)
+                {   // get cause
+                    rootCause = getRootCause(t);
+                }
+                // third option: use t
+                if (rootCause == null)
+                {
+                    rootCause = t;
+                }
+                
+                // Walk up the tree
+                while (true)
+                {   // if its an empire-exception: game over
+                    if (rootCause instanceof EmpireException)
+                        break;
+                    // has root cause
+                    t = rootCause.getCause();
+                    if (t==null)
+                        break; 
+                    // yes, continue search
+                    rootCause = t;
+                }
+                
+                /*
+                if (rootCause instanceof org.icefaces.application.SessionExpiredException)
+                {   // expired
+                    log.info("Handling SessionExpiredException. No error message is set.");
+                    continue;
+                }
+                */
+
+                // set message
+                String msg = "Handling exception of type "+rootCause.getClass().getSimpleName();
+                // log
+                // msg = appendSessionInfo(context, msg);
+                log.error(msg, rootCause);
+                
+                // set message
+                if (!(rootCause instanceof EmpireException))
+                {   // Wrap as internal exception
+                    rootCause = new InternalException(rootCause);
+                }
+                setErrorMessage(context, rootCause);
+                
+            } catch(Throwable t2) {
+                log.error("Failed to handle exception: "+t2.getMessage(), t2);
+            } finally {
+                events.remove();
+            }
+        }
+
+        // if an error has been found
+        /*
+        if (redirectToErrorPage)
+        {
+            HttpServletResponse response = (HttpServletResponse) FacesContext.getCurrentInstance().getExternalContext().getResponse();
+            try
+            {
+                // put error to session map (will be cleared by ErrorPage)
+                if (rootCause != null)
+                {
+                    FacesUtils.getFin2Session().setError(rootCause);
+                }
+                // redirect to error page
+                String errorPage = FacesUtils.getContextPath() + "/pages/error.iface";
+                Fin2ExceptionHandler.log.debug("Redirecting to error page at '" + errorPage + "'...");
+                FacesUtils.redirectDirectly(errorPage);
+            }
+            catch (Exception e)
+            {
+                Fin2ExceptionHandler.log.error("Error during exception handling.", e);
+                throw new FacesException(e);
+            }
+        }
+        */
+        // let next handler deal
+        getWrapped().handle();
+    }
+    
+    /*
+    private String appendSessionInfo(FacesContext context, String msg)
+    {
+        // Provide session info
+        Fin2Session session = FinUtils.getFin2Session(context, false);
+        Fin2User user = (session!=null ? session.getUser() : null);
+        if (user!=null)
+        {   // Add user information
+            String viewId;
+            if (context.getViewRoot()!=null)
+                viewId = context.getViewRoot().getViewId();
+            else {
+                viewId = "[NO VIEW]";
+                if (context.getExternalContext()!=null)
+                {   // External Context 
+                    Object request = context.getExternalContext().getRequest(); 
+                    if (request instanceof HttpServletRequest) 
+                    {   // The HttpServletRequest Servlet Path
+                        String path = ((HttpServletRequest)request).getServletPath();
+                        viewId += " ("+String.valueOf(path)+")";
+                    }    
+                    else if (request!=null)
+                        viewId += " {"+request.getClass().getName()+"}";
+                }
+            }
+            // Message
+            msg += MessageFormat.format(" for User {0} of DUNS {1} on View {2}.", user.getUserId(), user.getDUNS(), viewId);
+        }
+        return msg;
+    }
+    */
+    
+    private void setErrorMessage(FacesContext fContext, Throwable rootCause)
+    {
+        FacesMessage message = new FacesMessage();
+        message.setSeverity(FacesMessage.SEVERITY_ERROR);
+     
+        Map<String, Object> sm = fContext.getExternalContext().getSessionMap();
+        if (sm.containsKey(SampleSession.MANAGED_BEAN_NAME))
+        {
+            TextResolver resolver = WebApplication.getInstance().getTextResolver(fContext);
+            if (rootCause instanceof Exception)
+            {
+                message.setSummary(resolver.getExceptionMessage((Exception)rootCause));
+            }
+            else
+            {
+                message.setSummary(resolver.resolveKey("global_general_error"));
+            }
+            // Add message
+            fContext.addMessage(null, message);
+        }
+        else
+        {
+            log.error("Unable to handle exception, redirecting to StartPage.", rootCause);
+            FacesUtils.redirectDirectly(fContext, SamplePages.LoginPage);
+        }
+    }
+}
diff --git a/empire-db-examples/empire-db-example-jsf2/src/main/java/org/apache/empire/jsf2/websample/web/AppExceptionHandlerFactory.java b/empire-db-examples/empire-db-example-jsf2/src/main/java/org/apache/empire/jsf2/websample/web/AppExceptionHandlerFactory.java
new file mode 100644
index 0000000..bfd6253
--- /dev/null
+++ b/empire-db-examples/empire-db-example-jsf2/src/main/java/org/apache/empire/jsf2/websample/web/AppExceptionHandlerFactory.java
@@ -0,0 +1,29 @@
+package org.apache.empire.jsf2.websample.web;
+
+import javax.faces.context.ExceptionHandler;
+import javax.faces.context.ExceptionHandlerFactory;
+
+/**
+ * AppExceptionHandlerFactory
+ */
+public class AppExceptionHandlerFactory extends ExceptionHandlerFactory
+{
+    ExceptionHandlerFactory delegateFactory;
+
+    public AppExceptionHandlerFactory(ExceptionHandlerFactory delegateFactory)
+    {
+        this.delegateFactory = delegateFactory;
+    }
+
+    @Override
+    public ExceptionHandlerFactory getWrapped()
+    {
+        return delegateFactory;
+    }
+
+    @Override
+    public ExceptionHandler getExceptionHandler()
+    {
+        return new AppExceptionHandler(getWrapped().getExceptionHandler());
+    }
+}
diff --git a/empire-db-examples/empire-db-example-jsf2/src/main/java/org/apache/empire/jsf2/websample/web/SampleUser.java b/empire-db-examples/empire-db-example-jsf2/src/main/java/org/apache/empire/jsf2/websample/web/SampleUser.java
index 686bb3c..99b2c16 100644
--- a/empire-db-examples/empire-db-example-jsf2/src/main/java/org/apache/empire/jsf2/websample/web/SampleUser.java
+++ b/empire-db-examples/empire-db-example-jsf2/src/main/java/org/apache/empire/jsf2/websample/web/SampleUser.java
@@ -26,7 +26,7 @@ public class SampleUser implements Serializable
     private static final long     serialVersionUID  = 1L;
     protected static final String MANAGED_BEAN_NAME = "sampleUser";
 
-    private String                userName          = "";
+    private String                userName          = "test";
     private String                password          = "";
     private Locale                language          = SampleApplication.DEFAULT_LOCALE;
 
diff --git a/empire-db-examples/empire-db-example-jsf2/src/main/java/org/apache/empire/jsf2/websample/web/pages/EmployeeDetailPage.java b/empire-db-examples/empire-db-example-jsf2/src/main/java/org/apache/empire/jsf2/websample/web/pages/EmployeeDetailPage.java
index 7f91052..bdc1cb7 100644
--- a/empire-db-examples/empire-db-example-jsf2/src/main/java/org/apache/empire/jsf2/websample/web/pages/EmployeeDetailPage.java
+++ b/empire-db-examples/empire-db-example-jsf2/src/main/java/org/apache/empire/jsf2/websample/web/pages/EmployeeDetailPage.java
@@ -18,8 +18,6 @@
  */
 package org.apache.empire.jsf2.websample.web.pages;
 
-import java.sql.Connection;
-
 import org.apache.empire.jsf2.pageelements.RecordPageElement;
 import org.apache.empire.jsf2.pages.PageOutcome;
 import org.apache.empire.jsf2.websample.db.SampleDB;
@@ -102,7 +100,15 @@ public class EmployeeDetailPage extends SamplePage
     
     public PageOutcome doSave()
     {
+
         getEmployeeRecord().update();
+        
+        /* test transaction
+        SampleDB db = this.getDatabase();
+        if (getEmployeeRecord().isNull(db.T_EMPLOYEES.PHONE_NUMBER))
+            throw new MiscellaneousErrorException("Phone number must not be empty!");
+         */
+        
         return getParentOutcome(true);
     }
 
diff --git a/empire-db-examples/empire-db-example-jsf2/src/main/java/org/apache/empire/jsf2/websample/web/pages/EmployeeListPage.java b/empire-db-examples/empire-db-example-jsf2/src/main/java/org/apache/empire/jsf2/websample/web/pages/EmployeeListPage.java
index 18af8d8..dcdf356 100644
--- a/empire-db-examples/empire-db-example-jsf2/src/main/java/org/apache/empire/jsf2/websample/web/pages/EmployeeListPage.java
+++ b/empire-db-examples/empire-db-example-jsf2/src/main/java/org/apache/empire/jsf2/websample/web/pages/EmployeeListPage.java
@@ -26,7 +26,6 @@ import java.util.Date;
 import org.apache.commons.beanutils.PropertyUtils;
 import org.apache.empire.commons.ObjectUtils;
 import org.apache.empire.commons.Options;
-import org.apache.empire.data.DataType;
 import org.apache.empire.db.DBColumn;
 import org.apache.empire.db.DBColumnExpr;
 import org.apache.empire.db.DBCommand;
diff --git a/empire-db-examples/empire-db-example-jsf2/src/main/webapp/WEB-INF/faces-config.xml b/empire-db-examples/empire-db-example-jsf2/src/main/webapp/WEB-INF/faces-config.xml
index 6e43a4e..2d6d4cc 100644
--- a/empire-db-examples/empire-db-example-jsf2/src/main/webapp/WEB-INF/faces-config.xml
+++ b/empire-db-examples/empire-db-example-jsf2/src/main/webapp/WEB-INF/faces-config.xml
@@ -14,6 +14,10 @@
 	xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-facesconfig_2_0.xsd"
 	version="2.0">
 
+	<factory>
+		<exception-handler-factory>org.apache.empire.jsf2.websample.web.AppExceptionHandlerFactory</exception-handler-factory>
+	</factory>
+
 	<application>
 	    <!-- System event listener --> 
 	    <system-event-listener>
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 4607a4d..d9948a3 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
@@ -45,6 +45,7 @@ import org.apache.empire.db.DBDatabase;
 import org.apache.empire.exceptions.InternalException;
 import org.apache.empire.exceptions.InvalidArgumentException;
 import org.apache.empire.exceptions.NotSupportedException;
+import org.apache.empire.exceptions.UnexpectedReturnValueException;
 import org.apache.empire.jsf2.controls.TextAreaInputControl;
 import org.apache.empire.jsf2.controls.TextInputControl;
 import org.apache.empire.jsf2.impl.FacesImplementation;
@@ -58,6 +59,8 @@ public abstract class WebApplication
 
     private static final String CONNECTION_ATTRIBUTE  = "dbConnections";
 
+    private static final String DB_CONTEXT_MAP        = "dbContextMap";
+    
     public static String        APPLICATION_BEAN_NAME = "webApplication";
 
     protected TextResolver[]    textResolvers         = null;
@@ -453,28 +456,38 @@ public abstract class WebApplication
     /**
      * returns a connection for the current Request
      */
-    public Connection getConnectionForRequest(FacesContext fc, DBDatabase db)
+    public Connection getConnectionForRequest(FacesContext fc, WebDBContext<? extends DBDatabase> context)
     {
         if (fc == null)
             throw new InvalidArgumentException("FacesContext", fc);
-        if (db == null)
-            throw new InvalidArgumentException("DBDatabase", db);
+        if (context == null)
+            throw new InvalidArgumentException("context", context);
         // Get Conneciton map
+        DBDatabase db = context.getDatabase();
         @SuppressWarnings("unchecked")
         Map<DBDatabase, Connection> connMap = (Map<DBDatabase, Connection>) FacesUtils.getRequestAttribute(fc, CONNECTION_ATTRIBUTE);
-        if (connMap != null && connMap.containsKey(db))
-            return connMap.get(db);
-        // Pooled Connection
-        Connection conn = getConnection(db);
-        if (conn == null)
-            return null;
-        // Add to map
-        if (connMap == null)
-        {
-            connMap = new HashMap<DBDatabase, Connection>();
+        if (connMap== null)
+        {   connMap = new HashMap<DBDatabase, Connection>();
             FacesUtils.setRequestAttribute(fc, CONNECTION_ATTRIBUTE, connMap);
         }
-        connMap.put(db, conn);
+        Connection conn = connMap.get(db);
+        if (conn==null)
+        {   // Get Pooled Connection
+            conn = getConnection(db);
+            if (conn== null)
+                throw new UnexpectedReturnValueException(this, "getConnection"); 
+            // Add to map
+            connMap.put(db, conn);
+        }
+        // Store Context
+        @SuppressWarnings("unchecked")
+        Map<Integer, WebDBContext<? extends DBDatabase>> ctxMap = (Map<Integer, WebDBContext<? extends DBDatabase>>) FacesUtils.getRequestAttribute(fc, DB_CONTEXT_MAP);
+        if (ctxMap== null)
+        {   ctxMap = new HashMap<Integer, WebDBContext<? extends DBDatabase>>();
+            FacesUtils.setRequestAttribute(fc, DB_CONTEXT_MAP, ctxMap);
+        }
+        ctxMap.put(conn.hashCode(), context);
+        // done
         return conn;
     }
 
@@ -487,14 +500,21 @@ public abstract class WebApplication
     {
         @SuppressWarnings("unchecked")
         Map<DBDatabase, Connection> connMap = (Map<DBDatabase, Connection>) FacesUtils.getRequestAttribute(fc, CONNECTION_ATTRIBUTE);
+        @SuppressWarnings("unchecked")
+        Map<Integer, WebDBContext<? extends DBDatabase>> ctxMap = (Map<Integer, WebDBContext<? extends DBDatabase>>) FacesUtils.getRequestAttribute(fc, DB_CONTEXT_MAP);
         if (connMap != null)
-        { // Walk the connection map
+        {   // Walk the connection map
             for (Map.Entry<DBDatabase, Connection> e : connMap.entrySet())
             {
-                releaseConnection(e.getKey(), e.getValue(), commit);
+                Connection conn = e.getValue();
+                releaseConnection(e.getKey(), conn, commit);
+                // release connection
+                WebDBContext<? extends DBDatabase> ctx = ctxMap.get(conn.hashCode());
+                ctx.releaseConnection(commit);
             }
             // remove from request map
             FacesUtils.setRequestAttribute(fc, CONNECTION_ATTRIBUTE, null);
+            FacesUtils.setRequestAttribute(fc, DB_CONTEXT_MAP, null);
         }
     }
 
diff --git a/empire-db-jsf2/src/main/java/org/apache/empire/jsf2/app/WebDBContext.java b/empire-db-jsf2/src/main/java/org/apache/empire/jsf2/app/WebDBContext.java
index e4c4394..da70293 100644
--- a/empire-db-jsf2/src/main/java/org/apache/empire/jsf2/app/WebDBContext.java
+++ b/empire-db-jsf2/src/main/java/org/apache/empire/jsf2/app/WebDBContext.java
@@ -1,12 +1,15 @@
 package org.apache.empire.jsf2.app;
 
 import java.sql.Connection;
+import java.sql.SQLException;
 
 import javax.faces.context.FacesContext;
 
 import org.apache.empire.db.DBDatabase;
 import org.apache.empire.db.DBDatabaseDriver;
 import org.apache.empire.db.context.DBContextBase;
+import org.apache.empire.db.exceptions.EmpireSQLException;
+import org.apache.empire.exceptions.InvalidArgumentException;
 import org.apache.empire.exceptions.NotSupportedException;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -26,6 +29,9 @@ public class WebDBContext<DB extends DBDatabase> extends DBContextBase
     private final WebApplication app;
     private final DB             database;
 
+    // Held for request only
+    private Connection           conn;
+
     public WebDBContext(WebApplication app, DB db)
     {
         this.app = app;
@@ -51,10 +57,42 @@ public class WebDBContext<DB extends DBDatabase> extends DBContextBase
      * IMPORTANT: Do not hold the connection!
      */
     @Override
-    public Connection getConnection()
+    public synchronized Connection getConnection()
     {
-        FacesContext fc = FacesContext.getCurrentInstance();
-        return this.app.getConnectionForRequest(fc, database);
+        if (conn==null)
+        {   // get a new connection
+            FacesContext fc = FacesContext.getCurrentInstance();
+            conn = this.app.getConnectionForRequest(fc, this);
+        }
+        return conn;
+    }
+
+    @Override
+    public void commit()
+    {
+        if (conn!=null)
+            super.commit();
+        else
+            log.warn("No Connection to commmit");
+    }
+
+    @Override
+    public synchronized void rollback()
+    {
+        if (conn!=null)
+            super.commit();
+        else
+            log.warn("No Connection to rollbakc");
+    }
+    
+    public synchronized void releaseConnection(boolean commitPerformed)
+    {
+        this.conn = null;
+        // commit or rollback?
+        if (commitPerformed)
+            discardAllHandlers();
+        else
+            rollbackAllHandlers();
     }
 
     /**
diff --git a/empire-db/src/main/java/org/apache/empire/db/context/DBContextBase.java b/empire-db/src/main/java/org/apache/empire/db/context/DBContextBase.java
index 59933ff..2490bc4 100644
--- a/empire-db/src/main/java/org/apache/empire/db/context/DBContextBase.java
+++ b/empire-db/src/main/java/org/apache/empire/db/context/DBContextBase.java
@@ -35,16 +35,12 @@ public abstract class DBContextBase implements DBContext
             if (conn.getAutoCommit()==false)
                 conn.commit();
             // discard rollbacks
-            if (rollbackHandler!=null)
-                for (DBRollbackHandler handler : rollbackHandler.values())
-                    handler.discard();
+            discardAllHandlers();
             // Done
             return;
         } catch (SQLException sqle) { 
             // Commit failed!
             throw new EmpireSQLException(getDriver(), sqle);
-        } finally {
-            rollbackHandler=null;
         }
     }
 
@@ -67,16 +63,12 @@ public abstract class DBContextBase implements DBContext
             log.info("Database rollback issued!");
             conn.rollback();
             // rollback
-            if (rollbackHandler!=null)
-                for (DBRollbackHandler handler : rollbackHandler.values())
-                    handler.rollback();
+            rollbackAllHandlers();
             // Done
             return;
         } catch (SQLException sqle) { 
             // Commit failed!
             throw new EmpireSQLException(getDriver(), sqle);
-        } finally {
-            rollbackHandler=null;
         }
     }
     
@@ -110,6 +102,24 @@ public abstract class DBContextBase implements DBContext
     public void discard()
     {
         /* don't close connection! */
+        discardAllHandlers();
+    }
+    
+    protected void discardAllHandlers()
+    {   // rollback
+        if (rollbackHandler==null)
+            return;
+        for (DBRollbackHandler handler : rollbackHandler.values())
+            handler.discard();
+        rollbackHandler=null;
+    }
+    
+    protected void rollbackAllHandlers()
+    {   // rollback
+        if (rollbackHandler==null)
+            return;
+        for (DBRollbackHandler handler : rollbackHandler.values())
+            handler.rollback();
         rollbackHandler=null;
     }