Error Handling"

From Documentation
(15 intermediate revisions by 3 users not shown)
Line 14: Line 14:
  
 
'''Note:''' When exceptions are thrown during the ZK UI Lifecycle they are wrapped into a <javadoc  type="class">org.zkoss.zk.ui.UiException</javadoc>. If you want to handle your own exceptions you can implement the <javadoc type="interface">org.zkoss.lang.Expectable</javadoc> on your exception type. Exceptions implementing this interface will not be wrapped and can be handled using the <exception-type> element directly.
 
'''Note:''' When exceptions are thrown during the ZK UI Lifecycle they are wrapped into a <javadoc  type="class">org.zkoss.zk.ui.UiException</javadoc>. If you want to handle your own exceptions you can implement the <javadoc type="interface">org.zkoss.lang.Expectable</javadoc> on your exception type. Exceptions implementing this interface will not be wrapped and can be handled using the <exception-type> element directly.
 +
 +
'''Note:''' If the exception you want to handle is a checked exception, it must extend <tt>ServletException</tt> or <tt>IOException</tt>. So the Web container can handle them directly in <tt>doGet</tt> or <tt>doPost</tt> method.
  
 
<source lang="xml">
 
<source lang="xml">
Line 57: Line 59:
 
'''Tips:'''
 
'''Tips:'''
 
* The error page can be any kind of servlets. In addition to ZUML, you can use JSP or whatever servlet you preferred.
 
* The error page can be any kind of servlets. In addition to ZUML, you can use JSP or whatever servlet you preferred.
 
<blockquote>
 
----
 
<references/>
 
</blockquote>
 
 
* From java code the request attributes are accessible via <javadoc class="true"  method="getAttribute(java.lang.String)">org.zkoss.zk.ui.Execution</javadoc> or from the [https://www.zkoss.org/wiki/ZUML_Reference/EL_Expressions/Implicit_Objects_(Predefined_Variables)/requestScope requestScope (implicit object)].
 
* From java code the request attributes are accessible via <javadoc class="true"  method="getAttribute(java.lang.String)">org.zkoss.zk.ui.Execution</javadoc> or from the [https://www.zkoss.org/wiki/ZUML_Reference/EL_Expressions/Implicit_Objects_(Predefined_Variables)/requestScope requestScope (implicit object)].
  
Line 83: Line 80:
 
}
 
}
 
</source>
 
</source>
 +
 +
<blockquote>
 +
----
 +
<references/>
 +
</blockquote>
 +
 +
== Error Handling when the Client Engine crashes ==
 +
 +
[[File:error_handling_crash_screen.png|300px|right]]
 +
 +
In rare cases the client engine stops working before even the error handling is initialized (e.g. when ZK's core scripts fail to download - zk.wpd). In those cases, the configured error handler can't be called and ZK falls back to a very basic error handling.
 +
 +
If the client engine didn't initialize within a configurable timeout it will display a generic error message like the screenshot to the right. When this occurs the connection to ZK is usually broken so you can't report errors to the server using ZK's Ajax engine. As the error details are usually visible in the browser's console it's useful to instruct users to report the errors manually or automatically extract and send them to an error handling service that is accessible at that time (not part of ZK).
 +
 +
Please check [[ZK_Configuration_Reference/zk.xml/The_client-config_Element/The_init-crash-script_Element|the list of error codes]]. Both the timeout and the way the error is presented to the user can be configured within the <tt><client-config> </tt>.
 +
 +
* [[ZK_Configuration_Reference/zk.xml/The_client-config_Element/The_init-crash-script_Element|<init-crash-script>]]
 +
* [[ZK_Configuration_Reference/zk.xml/The_client-config_Element/The_init-crash-timeout_Element|<init-crash-timeout>]]
  
 
=Error Handling When Serving AU Requests=
 
=Error Handling When Serving AU Requests=
Line 125: Line 140:
 
| javax.servlet.error.exception
 
| javax.servlet.error.exception
 
| java.lang.Throwable
 
| java.lang.Throwable
 +
|-
 +
| javax.servlet.error.status_code
 +
| java.lang.String
 
|}
 
|}
  
Line 131: Line 149:
 
<source lang="xml">
 
<source lang="xml">
 
<window title="Error ${requestScope['javax.servlet.error.status_code']}"
 
<window title="Error ${requestScope['javax.servlet.error.status_code']}"
width="400px" border="normal" mode="modal" closable="true">
+
width="50%" border="normal" mode="modal" closable="true">
<vbox>
+
<vlayout>
 
KillerApp encounters an error: ${requestScope['javax.servlet.error.message']}
 
KillerApp encounters an error: ${requestScope['javax.servlet.error.message']}
<hbox style="margin-left:auto; margin-right:auto">
+
<hlayout style="margin-left:auto; margin-right:auto">
 
<button label="Continue" onClick="spaceOwner.detach()"/>
 
<button label="Continue" onClick="spaceOwner.detach()"/>
 
<button label="Reload" onClick="Executions.sendRedirect(null)"/>
 
<button label="Reload" onClick="Executions.sendRedirect(null)"/>
</hbox>
+
</hlayout>
</vbox>
+
</vlayout>
  
 
<!-- optional: record the error for improving the app -->
 
<!-- optional: record the error for improving the app -->
Line 155: Line 173:
 
* The error page is created at the same desktop that causes the error, so you can retrieve the relevant information from the desktop.
 
* The error page is created at the same desktop that causes the error, so you can retrieve the relevant information from the desktop.
 
* '''The order to handle the thrown exception according to it's type is based on the <error-page>'s declaration sequence in zk.xml'''.
 
* '''The order to handle the thrown exception according to it's type is based on the <error-page>'s declaration sequence in zk.xml'''.
 +
 +
= Handling a Custom Exception =
 +
By default, ZK will wrap your custom exception with <tt>UiException</tt> or <tt>OperationException</tt>. If you want to handle you custom exception, <tt>YourException</tt>, specifically on a specific error page upon its type. Your custom exception class needs to extend specific classes to avoid being wrapped:
 +
 +
* For unchecked:<ref>http://tracker.zkoss.org/browse/ZK-2638</ref>
 +
<source lang='java'>
 +
public class YourException extends java.lang.RuntimeException{...}
 +
</source>
 +
 +
* For checked:<ref>http://tracker.zkoss.org/browse/ZK-3679</ref>
 +
<source lang='java'>
 +
public class YourException extends javax.servlet.ServletException{...}
 +
</source>
 +
or
 +
<source lang='java'>
 +
public class YourException extends java.io.IOException{...}
 +
</source>
 +
 +
Because <tt>HttpServlet</tt> only [https://docs.oracle.com/javaee/7/api/javax/servlet/http/HttpServlet.html#doGet-javax.servlet.http.HttpServletRequest-javax.servlet.http.HttpServletResponse- throws these 2 exceptions].
 +
 +
 +
<references/>
  
 
=Version History=
 
=Version History=

Revision as of 07:15, 7 September 2021

Here we describe how to handle errors. An error is caused by an exception that is not caught by the application. An exception might be thrown in two situations: when loading a ZUML document or when serving an AU request (aka, an Ajax request).

Error Handling When Loading ZUML Documents

If an un-caught exception is thrown when loading a ZUML document, it is handled directly by the Web server. In other words, the handling is no different from other servlets.

By default, the Web server displays an error page showing the error message and stack trace. For example,

Exception.png

You can customize the error handling by specifying the error page in WEB-INF/web.xml as follows[1].

Note: When exceptions are thrown during the ZK UI Lifecycle they are wrapped into a UiException. If you want to handle your own exceptions you can implement the Expectable on your exception type. Exceptions implementing this interface will not be wrapped and can be handled using the <exception-type> element directly.

Note: If the exception you want to handle is a checked exception, it must extend ServletException or IOException. So the Web container can handle them directly in doGet or doPost method.

<!-- WEB-INF/web.xml -->
<error-page>
    <exception-type>java.lang.Throwable</exception-type>    
    <location>/WEB-INF/sys/error.zul</location>    
</error-page>

Then, when an error occurs on loading a page, the Web server forwards the error page you specified, /error/error.zul. Upon forwarding, the Web server passes a set of request attributes to the error page to describe what happens. These attributes are as follows.

Request Attribute Type
javax.servlet.error.status_code java.lang.Integer
javax.servlet.error.exception_type java.lang.Class
javax.servlet.error.message java.lang.String
javax.servlet.error.exception java.lang.Throwable
javax.servlet.error.request_uri java.lang.String
javax.servlet.error.servlet_name java.lang.String

Then, in the error page, you can display your custom information by the use of these attributes. For example,

<window title="Error ${requestScope['javax.servlet.error.status_code']}">
    Cause: ${requestScope['javax.servlet.error.message']}    
</window>

Tips:

public class ErrorHandlingComposer extends SelectorComposer<Component> {

	@WireVariable
	private Map<String, Object> requestScope;

	@Override
	public void doAfterCompose(Component comp) throws Exception {

		//via execution.getAttribute()
		Execution execution = Executions.getCurrent();
		Exception ex1 = (Exception) execution.getAttribute("javax.servlet.error.exception");

		//via requestScope map
		Exception ex2 = (Exception) requestScope.get("javax.servlet.error.exception");
	}
}

  1. Please refer to Chapter 10.9 of Java Servlet Specification for more details.

Error Handling when the Client Engine crashes

Error handling crash screen.png

In rare cases the client engine stops working before even the error handling is initialized (e.g. when ZK's core scripts fail to download - zk.wpd). In those cases, the configured error handler can't be called and ZK falls back to a very basic error handling.

If the client engine didn't initialize within a configurable timeout it will display a generic error message like the screenshot to the right. When this occurs the connection to ZK is usually broken so you can't report errors to the server using ZK's Ajax engine. As the error details are usually visible in the browser's console it's useful to instruct users to report the errors manually or automatically extract and send them to an error handling service that is accessible at that time (not part of ZK).

Please check the list of error codes. Both the timeout and the way the error is presented to the user can be configured within the <client-config> .

Error Handling When Serving AU Requests

If an uncaught exception is thrown when serving an AU request (aka., an Ajax request; such as caused by an event listener), it is handled by the ZK Update Engine. By default, it simply shows up an error message to indicate the error.

For example, suppose we have the following code:

<button label="Cause Error" onClick='throw new NullPointerException("Unknown Value")'/>

Then, if you click the button, the following error message will be shown.

Exception-au.png

You can customize the error handling by specifying the error page in WEB-INF/zk.xml as described in ZK Configuration Reference. For example,

<!-- zk.xml -->
<error-page>
    <exception-type>java.lang.Throwable</exception-type>    
    <location>/WEB-INF/sys/error.zul</location>    
</error-page>

Then, when an error occurs in an event listener, the ZK Update Engine will create a dialog by the use of the error page you specified, /error/error.zul.

Like error handling in loading a ZUML page, you can specify multiple <error-page> elements. Each of them is associated with a different exception type (the value of <exception-type> element). When an error occurs, ZK will search the error pages one-by-one until the exception type matches.

In addition, ZK passes a set of request attributes to the error page to describe what happens. These attribute are as follows.

Request Attribute Type
javax.servlet.error.exception_type java.lang.Class
javax.servlet.error.message java.lang.String
javax.servlet.error.exception java.lang.Throwable
javax.servlet.error.status_code java.lang.String

For example, you can specify the following content as the error page.

<window title="Error ${requestScope['javax.servlet.error.status_code']}"
width="50%" border="normal" mode="modal" closable="true">
	<vlayout>
KillerApp encounters an error: ${requestScope['javax.servlet.error.message']}
		<hlayout style="margin-left:auto; margin-right:auto">
			<button label="Continue" onClick="spaceOwner.detach()"/>
			<button label="Reload" onClick="Executions.sendRedirect(null)"/>
		</hlayout>
	</vlayout>

	<!-- optional: record the error for improving the app -->
	<zscript>
	org.zkoss.util.logging.Log.lookup("Fatal").error(
		requestScope.get("javax.servlet.error.exception"));
	</zscript>
</window>

Then, when the button is clicked, the following will be shown.

Exception-au2.png

Tips:

  • The error page is created at the same desktop that causes the error, so you can retrieve the relevant information from the desktop.
  • The order to handle the thrown exception according to it's type is based on the <error-page>'s declaration sequence in zk.xml.

Handling a Custom Exception

By default, ZK will wrap your custom exception with UiException or OperationException. If you want to handle you custom exception, YourException, specifically on a specific error page upon its type. Your custom exception class needs to extend specific classes to avoid being wrapped:

  • For unchecked:[1]
public class YourException extends java.lang.RuntimeException{...}
  • For checked:[2]
public class YourException extends javax.servlet.ServletException{...}

or

public class YourException extends java.io.IOException{...}

Because HttpServlet only throws these 2 exceptions.


Version History

Last Update : 2021/09/07


Version Date Content
     



Last Update : 2021/09/07

Copyright © Potix Corporation. This article is licensed under GNU Free Documentation License.