diff --git a/imixs-office-workflow-app/src/main/webapp/WEB-INF/faces-config.xml b/imixs-office-workflow-app/src/main/webapp/WEB-INF/faces-config.xml index 222165e9..986d60c5 100644 --- a/imixs-office-workflow-app/src/main/webapp/WEB-INF/faces-config.xml +++ b/imixs-office-workflow-app/src/main/webapp/WEB-INF/faces-config.xml @@ -4,6 +4,11 @@ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="https://jakarta.ee/xml/ns/jakartaee https://jakarta.ee/xml/ns/jakartaee/web-facesconfig_3_0.xsd"> + + + org.imixs.workflow.office.util.ImixsExceptionHandlerFactory + + diff --git a/imixs-office-workflow-app/src/main/webapp/errorhandler.xhtml b/imixs-office-workflow-app/src/main/webapp/errorhandler.xhtml index 01a07149..dca1432d 100644 --- a/imixs-office-workflow-app/src/main/webapp/errorhandler.xhtml +++ b/imixs-office-workflow-app/src/main/webapp/errorhandler.xhtml @@ -20,7 +20,7 @@ + test="#{flash.keep.type eq 'ModelException'}">

@@ -31,7 +31,7 @@ + test="#{flash.keep.type eq 'PluginException'}">

#{message['plugin_exception_title']} @@ -40,7 +40,7 @@ + test="#{flash.keep.type eq 'ConversationException'}">

#{message['login.conversation_expired_title']} @@ -49,7 +49,7 @@ + test="#{flash.keep.type eq 'OptimisticLockException'}">

#{message['login.optimisticlock_exception_title']} @@ -58,7 +58,7 @@ + test="#{flash.keep.type eq 'RolledbackException'}">

#{message.error_message_rollback_title} @@ -76,13 +76,11 @@ -

#{errorHandlerData.exceptionType}: #{errorHandlerData.message}

+

#{flash.keep.type}: #{flash.keep.message}

+
+ Exception:#{flash.keep.exception}
- Exception: #{errorHandlerData.exception} -
- Error Code:#{errorHandlerData.statusCode} -
- URI:#{errorHandlerData.uri} + URI:#{flash.keep.uri}

@@ -98,7 +96,7 @@ + onclick="document.location='#{flash.keep.uri}'" /> diff --git a/imixs-office-workflow-util/src/main/java/org/imixs/workflow/office/util/ErrorController.java b/imixs-office-workflow-util/src/main/java/org/imixs/workflow/office/util/ErrorController.java deleted file mode 100644 index a2a47983..00000000 --- a/imixs-office-workflow-util/src/main/java/org/imixs/workflow/office/util/ErrorController.java +++ /dev/null @@ -1,88 +0,0 @@ -/******************************************************************************* - * Imixs Workflow - * Copyright (C) 2001, 2011 Imixs Software Solutions GmbH, - * http://www.imixs.com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You can receive a copy of the GNU General Public - * License at http://www.gnu.org/licenses/gpl.html - * - * Project: - * http://www.imixs.org - * http://java.net/projects/imixs-workflow - * - * Contributors: - * Imixs Software Solutions GmbH - initial API and implementation - * Ralph Soika - Software Developer - *******************************************************************************/ - -package org.imixs.workflow.office.util; - -import java.io.Serializable; -import java.util.logging.Logger; - -import jakarta.enterprise.context.RequestScoped; -import jakarta.inject.Named; - -/** - * The ErrorController provides methods to analyse a exception stack trace. - * The controller is used in the errorhandler.xhtml page to redirect the user to a corresponding error page. - * - * @author rsoika - */ -@Named -@RequestScoped -public class ErrorController implements Serializable { - - private static final long serialVersionUID = 1L; - - private static Logger logger = Logger.getLogger(ErrorController.class.getName()); - - private String message=null; - - public ErrorController() { - super(); - } - - /** - * Returns true if the exception is caused by a specific Exception type - * @param e - * @return - */ - public boolean isCausedBy(Exception e, String excpetionType) { - if (e==null) { - return false; - } - - // iterate over the full exception stack trace - Throwable cause = e.getCause(); - while (cause!=null) { - if (cause.toString().contains(excpetionType)) { - logger.warning("...exception caused by " + excpetionType ); - setMessage(cause.getMessage()); - return true; - } - // take next cause from stack - cause=cause.getCause(); - } - return false; - } - - public String getMessage() { - return message; - } - - public void setMessage(String message) { - this.message = message; - } - -} diff --git a/imixs-office-workflow-util/src/main/java/org/imixs/workflow/office/util/ErrorHandlerData.java b/imixs-office-workflow-util/src/main/java/org/imixs/workflow/office/util/ErrorHandlerData.java deleted file mode 100644 index a1a56c7a..00000000 --- a/imixs-office-workflow-util/src/main/java/org/imixs/workflow/office/util/ErrorHandlerData.java +++ /dev/null @@ -1,97 +0,0 @@ -/******************************************************************************* - * Imixs Workflow - * Copyright (C) 2001, 2011 Imixs Software Solutions GmbH, - * http://www.imixs.com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You can receive a copy of the GNU General Public - * License at http://www.gnu.org/licenses/gpl.html - * - * Project: - * http://www.imixs.org - * http://java.net/projects/imixs-workflow - * - * Contributors: - * Imixs Software Solutions GmbH - initial API and implementation - * Ralph Soika - Software Developer - *******************************************************************************/ - -package org.imixs.workflow.office.util; - -import java.io.Serializable; - -import jakarta.enterprise.context.SessionScoped; -import jakarta.inject.Named; - -/** - * The ErrorHandlerData provides data about the cause of an exception. - * The ErrorHanlderData object is used by the ErrorHandlerServlet. - * - * @author rsoika - */ -@Named -@SessionScoped -public class ErrorHandlerData implements Serializable { - - private static final long serialVersionUID = 1L; - - private String message = null; - private String exception = null; - private String exceptionType = null; - - public String getExceptionType() { - return exceptionType; - } - - private String uri = null; - private int statusCode = 500; - - public String getException() { - return exception; - } - - public void setException(String exception) { - this.exception = exception; - if (exception.contains(".")) { - exceptionType = exception.substring(exception.lastIndexOf(".") + 1); - } - } - - public String getUri() { - return uri; - } - - public void setUri(String uri) { - this.uri = uri; - } - - public int getStatusCode() { - return statusCode; - } - - public void setStatusCode(int statusCode) { - this.statusCode = statusCode; - } - - public ErrorHandlerData() { - super(); - } - - public String getMessage() { - return message; - } - - public void setMessage(String message) { - this.message = message; - } - -} diff --git a/imixs-office-workflow-util/src/main/java/org/imixs/workflow/office/util/ErrorHandlerServlet.java b/imixs-office-workflow-util/src/main/java/org/imixs/workflow/office/util/ErrorHandlerServlet.java deleted file mode 100644 index 26e38cdf..00000000 --- a/imixs-office-workflow-util/src/main/java/org/imixs/workflow/office/util/ErrorHandlerServlet.java +++ /dev/null @@ -1,83 +0,0 @@ -package org.imixs.workflow.office.util; - -import java.io.IOException; - -import jakarta.inject.Inject; -import jakarta.servlet.ServletException; -import jakarta.servlet.annotation.WebServlet; -import jakarta.servlet.http.HttpServlet; -import jakarta.servlet.http.HttpServletRequest; -import jakarta.servlet.http.HttpServletResponse; - -/** - * This Servlet is used to catch servlet exceptions and redirect the user to - * user-friendly page showing the exception details. The servlet simply fills - * the ErrorHandlerData object and redirects to the errorhandler.xhtml page. - * - * The servlet is mapped in the web.xml file: - * - *
{@code
- *  
- *       java.lang.Exception 
- *       /errorHandler 
- * 
- * }
- * - * - * - * See also: https://www.baeldung.com/servlet-exceptions - * https://www.digitalocean.com/community/tutorials/servlet-exception-and-error-handling-example-tutorial - * - */ -@WebServlet(urlPatterns = "/errorHandler") -public class ErrorHandlerServlet extends HttpServlet { - - @Inject - private ErrorHandlerData errorHandlerData; - - @Override - protected void doGet(HttpServletRequest request, - HttpServletResponse response) throws ServletException, IOException { - processError(request, response); - } - - @Override - protected void doPost(HttpServletRequest request, - HttpServletResponse response) throws ServletException, IOException { - processError(request, response); - } - - private void processError(HttpServletRequest request, - HttpServletResponse response) throws IOException { - // Analyze the servlet exception - Throwable throwable = (Throwable) request - .getAttribute("jakarta.servlet.error.exception"); - Integer statusCode = (Integer) request - .getAttribute("jakarta.servlet.error.status_code"); - String servletName = (String) request - .getAttribute("jakarta.servlet.error.servlet_name"); - if (servletName == null) { - servletName = "Unknown"; - } - String requestUri = (String) request - .getAttribute("jakarta.servlet.error.request_uri"); - if (requestUri == null) { - requestUri = "Unknown"; - } - - // try { - if (throwable != null) { - errorHandlerData.setMessage(throwable.getMessage()); - errorHandlerData.setException(throwable.getClass().getName()); - } else { - errorHandlerData.setMessage("Unknown"); - - } - errorHandlerData.setUri(requestUri); - errorHandlerData.setStatusCode(statusCode); - - response.sendRedirect(request.getContextPath() + "/errorhandler.xhtml"); - - } - -} \ No newline at end of file diff --git a/imixs-office-workflow-util/src/main/java/org/imixs/workflow/office/util/ImixsExceptionHandler.java b/imixs-office-workflow-util/src/main/java/org/imixs/workflow/office/util/ImixsExceptionHandler.java new file mode 100644 index 00000000..f0f2810b --- /dev/null +++ b/imixs-office-workflow-util/src/main/java/org/imixs/workflow/office/util/ImixsExceptionHandler.java @@ -0,0 +1,82 @@ +package org.imixs.workflow.office.util; + +import java.util.Iterator; +import java.util.Objects; + +import jakarta.faces.FacesException; +import jakarta.faces.application.NavigationHandler; +import jakarta.faces.context.ExceptionHandler; +import jakarta.faces.context.ExceptionHandlerWrapper; +import jakarta.faces.context.ExternalContext; +import jakarta.faces.context.FacesContext; +import jakarta.faces.context.Flash; +import jakarta.faces.event.ExceptionQueuedEvent; +import jakarta.faces.event.ExceptionQueuedEventContext; +import jakarta.servlet.http.HttpServletRequest; + +public class ImixsExceptionHandler extends ExceptionHandlerWrapper { + + public ImixsExceptionHandler(ExceptionHandler wrapped) { + super(wrapped); + } + + @Override + public void handle() throws FacesException { + Iterator iterator = getUnhandledExceptionQueuedEvents().iterator(); + + while (iterator.hasNext()) { + ExceptionQueuedEvent event = (ExceptionQueuedEvent) iterator.next(); + ExceptionQueuedEventContext context = (ExceptionQueuedEventContext) event.getSource(); + + Throwable throwable = context.getException(); + + throwable = findCauseUsingPlainJava(throwable); + + FacesContext fc = FacesContext.getCurrentInstance(); + + try { + Flash flash = fc.getExternalContext().getFlash(); + + // Put the exception in the flash scope to be displayed in the error + // page if necessary ... + flash.put("message", throwable.getMessage()); + + ExternalContext externalContext = fc.getExternalContext(); + + flash.put("type", throwable.getClass().getSimpleName()); + flash.put("exception", throwable.getClass().getName()); + if (externalContext != null) { + HttpServletRequest hrequest = (HttpServletRequest) FacesContext.getCurrentInstance().getExternalContext() + .getRequest(); + String uri = hrequest.getRequestURI(); + flash.put("uri", uri); + } + + NavigationHandler navigationHandler = fc.getApplication().getNavigationHandler(); + navigationHandler.handleNavigation(fc, null, "/errorhandler.xhtml?faces-redirect=true"); + fc.renderResponse(); + } finally { + iterator.remove(); + } + } + + // Let the parent handle the rest + getWrapped().handle(); + } + + /** + * Helper method to find the exception root cause. + * + * See: https://www.baeldung.com/java-exception-root-cause + */ + public static Throwable findCauseUsingPlainJava(Throwable throwable) { + Objects.requireNonNull(throwable); + Throwable rootCause = throwable; + while (rootCause.getCause() != null && rootCause.getCause() != rootCause) { + System.out.println("cause: " + rootCause.getCause().getMessage()); + rootCause = rootCause.getCause(); + } + return rootCause; + } + +} \ No newline at end of file diff --git a/imixs-office-workflow-util/src/main/java/org/imixs/workflow/office/util/ImixsExceptionHandlerFactory.java b/imixs-office-workflow-util/src/main/java/org/imixs/workflow/office/util/ImixsExceptionHandlerFactory.java new file mode 100644 index 00000000..174086b1 --- /dev/null +++ b/imixs-office-workflow-util/src/main/java/org/imixs/workflow/office/util/ImixsExceptionHandlerFactory.java @@ -0,0 +1,32 @@ +package org.imixs.workflow.office.util; + +import jakarta.faces.context.ExceptionHandler; +import jakarta.faces.context.ExceptionHandlerFactory; + +/** + * This is the custom exception handler factory class that is responsible for + * creating the instances of the ImixsExceptionHandler class. + * + * The factory need to be declared in the faces-config.xml file + * + *
{@code
+ *   
+      
+        org.imixs.workflow.office.util.ImixsExceptionHandlerFactory
+      
+    
+ * }
+ */ +public class ImixsExceptionHandlerFactory extends ExceptionHandlerFactory { + + public ImixsExceptionHandlerFactory(ExceptionHandlerFactory wrapped) { + super(wrapped); + } + + @Override + public ExceptionHandler getExceptionHandler() { + ExceptionHandler parentHandler = getWrapped().getExceptionHandler(); + return new ImixsExceptionHandler(parentHandler); + } + +} \ No newline at end of file