You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@struts.apache.org by Laine Donlan <ld...@elogex.com> on 2001/11/01 04:06:06 UTC

Declarative exception handling for Action classes

Wanted to submit the following code for comment from the Struts dev
group.  Being faced with a pretty large development project and a
development environment that oftentimes had one developer working on the
Web tier code (Struts) and another developer working at the middle tier
level (EJB's),  an attempt was made to alleviate the need to update
action code and workflow to accommodate changes in the web tier/middle
tier contract.  

Specifically this related to how business logic exceptions were defined
and handled.  We have found that within our Struts actions we often see
large amounts of business logic exception handling which usually does
nothing more then configure a message and forward the user to some kind
or error url or back to the previous page with a validation type error
message.  Not only is this verbose and repetitious, but it is fragile to
changes in the middle tier since every time a new exception is added, a
struts-knowledgeable person needs go into all the struts code and add
exception handling for it.  As with other repitious and tedious code,
our feeling was that the best way to handle this was to allow for
exception handling to be declarative and configurable through the
struts-config.xml.  We have therefore created a scheme where exceptions
are treated much the same as forwards in the current Struts code-line.
Each action mapping can define any number of exceptions that may occur
and how they should be handled.  The handling of the exceptions consists
of the definition of a key value (error message, etc) , and a path
(optional - input of the action would be the default).  When an
exception occurs that can be handled the ActionException (consisting of
key, and path) is placed into the user's session under a key constant -
org.apache.struts.action.ACTION_EXCEPTION.  It can then be handled
however is necessary by an app.

Exception hierarchies are supported just as they would be in a typically
try{}catch code block through an optional mapping parameter to determine
whether or not to support the hierarchy.  When attempting to match and
handle an exception first a specific match would be sought, if one could
not be found, then a search for any assignable exception would be made.
The first match would end the search.

The following would be an example of an action mapping:

<action path="/handleSomething" 
	name="someForm"
	validate="false"
	input="/someUri.....">

	<forward ...just like always/>
	<exception key="some.key" 
		     type="some.package.business.logic.Exception"/>
	<exception key="some.other.key"
	                 type="some.package.business.logic.Exception2"
		     path="/someotherUri..."/>
	<exception key="general"
		     type="java.lang.Exception"/>
	<exception key="ejb"
		     type="javax.ejb.EjbException"
		     hierarchachal="false"/>
</action>

The following outlines how each of the exceptions would be handled:

1) If an some.package.business.logic.Exception is throw from the Action
perform method, the client will be dispatched to the input of the form
with an ActionException placed into the session under a specific key.

2) If an some.package.business.logic.Exception2 is thrown, the client
will be dispatched to the path specified in that mapping with the
ActionException placed in the session.

3) If anything other than the previous 2 exception or an EjbException is
thrown, the client would be re-directed to the input of the form, again
with the ActionException placed into the session.

4) If an EjbException is thrown (it's children would not be handled by
this) then the client would be dispatched with that ActionException in
the session under a defined constant value.

The changes to the code base consisted of:

1) Addition of ActionException and ActionExceptions classes.  Very much
like the existing mapping classes.
2) Change of the perform() method signature to throw Exception rather
than IOException and ServletException
3) Update the processActionPerform() method of the ActionServlet perform
the try{}cactch{} and to map resultant exceptions.
4) Add the digesting into the ActionServlet init()
5) Add the ActionExceptions reference into the ActionMapping.

I have attached the code:
 <<changes.zip>> 

As well as diffs of the changes to the ActionServlet and Action classes
 <<Action-diff.txt>>  <<ActionServlet-diff.txt>> 

A couple of major @todo's in the code would be the implementation of
global-exceptions, and a currently hard-coded exception message in any
unhandled exception that is wrapped into a ServletException.  I wanted
to see if there was interest for this type of feature, if so I can
easily put the rest of it together and submit it.

Thanks, any comments or feedback would be appreciated.

Re: Declarative exception handling for Action classes

Posted by Ted Husted <hu...@apache.org>.
I haven't tried the code, but assuming it works, I think I'm on board
here. 

The part about perform() throwing Exception gives me pause though. 

Does perform need to throw Exception, or does ActionController simply
need to catch Exception?

Why are EjbExceptions handled differently?

If this is a convenience for your project, can it arranged as a standard
alternative rather than the default?


-- Ted Husted, Husted dot Com, Fairport NY USA.
-- Custom Software ~ Technical Services.
-- Tel +1 716 737-3463
-- http://www.husted.com/struts/

--
To unsubscribe, e-mail:   <ma...@jakarta.apache.org>
For additional commands, e-mail: <ma...@jakarta.apache.org>


Re: Declarative exception handling for Action classes

Posted by Joe Faith <fa...@runtime-collective.com>.
I was presuming that the default behaviour would be for the ActionServlet to
send the user back to the 'input' page on error; but these would be useful
optional
parameters.

Laine: would you consider incorporating this, or should I have a go myself?

"Deadman, Hal" wrote:

> Wouldn't Joe Faith's example have to support a forward or path attribute so
> the action servlet would know where to forward to?
>
> <action ....>
>         <exception error="some.error.key" type="package.Exception"
> forward="failure" />
> </action>
> or
> <action ....>
>         <exception error="some.error.key" type="package.Exception"
> path="/error.jsp" />
> </action>

Joe Faith

Runtime Collective, Ltd
T: (+44) 01273 234294
www.runtime-collective.com

RE: Declarative exception handling for Action classes

Posted by "Deadman, Hal" <ha...@tallan.com>.
I think this is a good idea. I also have similar repetative exception
handling in all of my action classes. Having global exceptions to handle
general system errors would be helpful. I might prefer to handle some
"expected" exceptions in my action class just to make the code easier to
read but I could do without having to trap Exception in every action class
and forwarding to a system error page.

Wouldn't Joe Faith's example have to support a forward or path attribute so
the action servlet would know where to forward to?

<action ....>
	<exception error="some.error.key" type="package.Exception"
forward="failure" />
</action>
or
<action ....>
	<exception error="some.error.key" type="package.Exception"
path="/error.jsp" />
</action>

-----Original Message-----
From: faith [mailto:faith]On Behalf Of Joe Faith
Sent: Thursday, November 01, 2001 5:44 AM
To: Struts Developers List
Subject: Re: Declarative exception handling for Action classes


This looks useful, but would be even more so if you could include the
following type
of exception mapping:

    <action ....>
        <exception error="some.error.key"
                   type="package.Exception" />
     </action>

The action servlet would then generate an ActionError and add it to the
request.
This would save a lot of code of the following type:

    } catch (package.Exception e) {
     errors.add(ActionErrors.GLOBAL_ERROR, new
ActionError("some.error.key"));
     saveErrors(request, errors);
     return (mapping.findForward("failure"));
   }

which seems to take up half of my actions at the moment.

Laine Donlan wrote:

> Each action mapping can define any number of exceptions that may occur
> and how they should be handled.  The handling of the exceptions
consists
> of the definition of a key value (error message, etc) , and a path
> (optional - input of the action would be the default).  When an
> exception occurs that can be handled the ActionException (consisting
of
> key, and path) is placed into the user's session under a key constant
-
> org.apache.struts.action.ACTION_EXCEPTION.  It can then be handled
> however is necessary by an app.
> The following would be an example of an action mapping:
>
> <action path="/handleSomething"
>         name="someForm"
>         validate="false"
>         input="/someUri.....">
>
>         <forward ...just like always/>
>         <exception key="some.key"
>                      type="some.package.business.logic.Exception"/>
>         <exception key="some.other.key"
>                          type="some.package.business.logic.Exception2"
>                      path="/someotherUri..."/>
>         <exception key="general"
>                      type="java.lang.Exception"/>
>         <exception key="ejb"
>                      type="javax.ejb.EjbException"
>                      hierarchachal="false"/>
> </action>
>
> The following outlines how each of the exceptions would be handled:
>
> 1) If an some.package.business.logic.Exception is throw from the
Action
> perform method, the client will be dispatched to the input of the form
> with an ActionException placed into the session under a specific key.
>
> 2) If an some.package.business.logic.Exception2 is thrown, the client
> will be dispatched to the path specified in that mapping with the
> ActionException placed in the session.
>
> 3) If anything other than the previous 2 exception or an EjbException
is
> thrown, the client would be re-directed to the input of the form,
again
> with the ActionException placed into the session.
>
> 4) If an EjbException is thrown (it's children would not be handled by
> this) then the client would be dispatched with that ActionException in
> the session under a defined constant value.
>
> The changes to the code base consisted of:
>
> 1) Addition of ActionException and ActionExceptions classes.  Very
much
> like the existing mapping classes.
> 2) Change of the perform() method signature to throw Exception rather
> than IOException and ServletException
> 3) Update the processActionPerform() method of the ActionServlet
perform
> the try{}cactch{} and to map resultant exceptions.
> 4) Add the digesting into the ActionServlet init()
> 5) Add the ActionExceptions reference into the ActionMapping.
>
> I have attached the code:
>  <<changes.zip>>
>
> As well as diffs of the changes to the ActionServlet and Action
classes
>  <<Action-diff.txt>>  <<ActionServlet-diff.txt>>
>
> A couple of major @todo's in the code would be the implementation of
> global-exceptions, and a currently hard-coded exception message in any
> unhandled exception that is wrapped into a ServletException.  I wanted
> to see if there was interest for this type of feature, if so I can
> easily put the rest of it together and submit it.
>
> Thanks, any comments or feedback would be appreciated.
>
>
------------------------------------------------------------------------
>                          Name: changes.zip
>                          Type: Zip Compressed Data
(application/x-zip-compressed)
>    changes.zip       Encoding: base64
>                   Description: changes.zip
>               Download Status: Not downloaded with message
>
>                          Name: Action-diff.txt
>    Action-diff.txt       Type: Plain Text (text/plain)
>                      Encoding: base64
>                   Description: Action-diff.txt
>
>                                 Name: ActionServlet-diff.txt
>    ActionServlet-diff.txt       Type: Plain Text (text/plain)
>                             Encoding: base64
>                          Description: ActionServlet-diff.txt
>
>
------------------------------------------------------------------------
> --
> To unsubscribe, e-mail:
<ma...@jakarta.apache.org>
> For additional commands, e-mail:
<ma...@jakarta.apache.org>

--

Joe Faith

Runtime Collective, Ltd
T: (+44) 01273 234294


--
To unsubscribe, e-mail:   <ma...@jakarta.apache.org>
For additional commands, e-mail: <ma...@jakarta.apache.org>


Re: Declarative exception handling for Action classes

Posted by Joe Faith <fa...@runtime-collective.com>.
This looks useful, but would be even more so if you could include the following type
of exception mapping:

    <action ....>
        <exception error="some.error.key"
                   type="package.Exception" />
     </action>

The action servlet would then generate an ActionError and add it to the request.
This would save a lot of code of the following type:

    } catch (package.Exception e) {
     errors.add(ActionErrors.GLOBAL_ERROR, new ActionError("some.error.key"));
     saveErrors(request, errors);
     return (mapping.findForward("failure"));
   }

which seems to take up half of my actions at the moment.

Laine Donlan wrote:

> Each action mapping can define any number of exceptions that may occur
> and how they should be handled.  The handling of the exceptions consists
> of the definition of a key value (error message, etc) , and a path
> (optional - input of the action would be the default).  When an
> exception occurs that can be handled the ActionException (consisting of
> key, and path) is placed into the user's session under a key constant -
> org.apache.struts.action.ACTION_EXCEPTION.  It can then be handled
> however is necessary by an app.
> The following would be an example of an action mapping:
>
> <action path="/handleSomething"
>         name="someForm"
>         validate="false"
>         input="/someUri.....">
>
>         <forward ...just like always/>
>         <exception key="some.key"
>                      type="some.package.business.logic.Exception"/>
>         <exception key="some.other.key"
>                          type="some.package.business.logic.Exception2"
>                      path="/someotherUri..."/>
>         <exception key="general"
>                      type="java.lang.Exception"/>
>         <exception key="ejb"
>                      type="javax.ejb.EjbException"
>                      hierarchachal="false"/>
> </action>
>
> The following outlines how each of the exceptions would be handled:
>
> 1) If an some.package.business.logic.Exception is throw from the Action
> perform method, the client will be dispatched to the input of the form
> with an ActionException placed into the session under a specific key.
>
> 2) If an some.package.business.logic.Exception2 is thrown, the client
> will be dispatched to the path specified in that mapping with the
> ActionException placed in the session.
>
> 3) If anything other than the previous 2 exception or an EjbException is
> thrown, the client would be re-directed to the input of the form, again
> with the ActionException placed into the session.
>
> 4) If an EjbException is thrown (it's children would not be handled by
> this) then the client would be dispatched with that ActionException in
> the session under a defined constant value.
>
> The changes to the code base consisted of:
>
> 1) Addition of ActionException and ActionExceptions classes.  Very much
> like the existing mapping classes.
> 2) Change of the perform() method signature to throw Exception rather
> than IOException and ServletException
> 3) Update the processActionPerform() method of the ActionServlet perform
> the try{}cactch{} and to map resultant exceptions.
> 4) Add the digesting into the ActionServlet init()
> 5) Add the ActionExceptions reference into the ActionMapping.
>
> I have attached the code:
>  <<changes.zip>>
>
> As well as diffs of the changes to the ActionServlet and Action classes
>  <<Action-diff.txt>>  <<ActionServlet-diff.txt>>
>
> A couple of major @todo's in the code would be the implementation of
> global-exceptions, and a currently hard-coded exception message in any
> unhandled exception that is wrapped into a ServletException.  I wanted
> to see if there was interest for this type of feature, if so I can
> easily put the rest of it together and submit it.
>
> Thanks, any comments or feedback would be appreciated.
>
>   ------------------------------------------------------------------------
>                          Name: changes.zip
>                          Type: Zip Compressed Data (application/x-zip-compressed)
>    changes.zip       Encoding: base64
>                   Description: changes.zip
>               Download Status: Not downloaded with message
>
>                          Name: Action-diff.txt
>    Action-diff.txt       Type: Plain Text (text/plain)
>                      Encoding: base64
>                   Description: Action-diff.txt
>
>                                 Name: ActionServlet-diff.txt
>    ActionServlet-diff.txt       Type: Plain Text (text/plain)
>                             Encoding: base64
>                          Description: ActionServlet-diff.txt
>
>   ------------------------------------------------------------------------
> --
> To unsubscribe, e-mail:   <ma...@jakarta.apache.org>
> For additional commands, e-mail: <ma...@jakarta.apache.org>

--

Joe Faith

Runtime Collective, Ltd
T: (+44) 01273 234294


Re: Declarative exception handling for Action classes

Posted by "Craig R. McClanahan" <cr...@apache.org>.

On Thu, 1 Nov 2001, Simon Sadedin wrote:

> Date: Thu, 1 Nov 2001 15:59:28 -0500
> From: Simon Sadedin <ss...@bigpond.net.au>
> Reply-To: Struts Developers List <st...@jakarta.apache.org>
> To: Struts Developers List <st...@jakarta.apache.org>
> Subject: Re: Declarative exception handling for Action classes
>
> > - If we pass the actual exception as attributes, I would suggest
> >   using request scope rather than session scope.  This will allow
> >   the technique to work even in apps that don't use sessions, and
> >   will also avoid problems when there are multiple simultaneous
> >   requests for a particular session.
>
> Maybe a "scope" type attribute like we use elsewhere?  Since our application
> makes heavy use of frames, putting stuff in the request doesn't always work
> (at least, not easily).

That makes sense.  I would still lobby for request scope as the default.

One thing I didn't comment on before -- do we really need more than one
key, or can we just use a single well-know key name?

>
> > - As an alternative to passing the exception you are throwing under
> >   a particular request or session scope key, how about having your
> >   Action simply wrap the business logic exception inside a
> >   ServletException (as the root cause) and throw that?  The perform
> >   method already declares "throws ServletException", and we could
> >   enhance the controller servlet to simply do its exception mapping
> >   trick on any exception thrown by the perform method.
>
> This seems like a good idea to me.  People who want the "throws Exception"
> semantics can easily achieve it by subclassing Action and doing a try{}
> catch{} in there, and then having all their actions extend the subclass.
>
> > But, given all of the above, if you have your actions throw a business
> > logic exception wrapped in a servlet exception, is there something needed
> > that the standard <error-page> mechanism does not handle for you?  The
> > only thing I can think of would be the global/local mapping option (which
> > is probably a good enough reason to do this), but the standard mechanism
> > seems to be pretty complete.
>
> I guess the difference would be that it can't be configured "per action"
> (right?) and its not integrated with struts style error messages from
> resources files (correct me if I'm wrong!).

Being able to do mapings per-Action would definitely be a reason to do
this inside of Struts (container managed exception pages are global to the
app).  I would suggest we support the "global and local" mappings for
this, just like we do with ActionForwards.

With regards to integration, the container-managed approach would easily
integrate, because it does create a request-scope attribute containing the
actual exception for you.  So it would be possible to integrate either
way.

>
> Cheers,
>
> Simon Sadedin.
>
>

Craig


--
To unsubscribe, e-mail:   <ma...@jakarta.apache.org>
For additional commands, e-mail: <ma...@jakarta.apache.org>


Re: Declarative exception handling for Action classes

Posted by Simon Sadedin <ss...@bigpond.net.au>.
> - If we pass the actual exception as attributes, I would suggest
>   using request scope rather than session scope.  This will allow
>   the technique to work even in apps that don't use sessions, and
>   will also avoid problems when there are multiple simultaneous
>   requests for a particular session.

Maybe a "scope" type attribute like we use elsewhere?  Since our application
makes heavy use of frames, putting stuff in the request doesn't always work
(at least, not easily).

> - As an alternative to passing the exception you are throwing under
>   a particular request or session scope key, how about having your
>   Action simply wrap the business logic exception inside a
>   ServletException (as the root cause) and throw that?  The perform
>   method already declares "throws ServletException", and we could
>   enhance the controller servlet to simply do its exception mapping
>   trick on any exception thrown by the perform method.

This seems like a good idea to me.  People who want the "throws Exception"
semantics can easily achieve it by subclassing Action and doing a try{}
catch{} in there, and then having all their actions extend the subclass.

> But, given all of the above, if you have your actions throw a business
> logic exception wrapped in a servlet exception, is there something needed
> that the standard <error-page> mechanism does not handle for you?  The
> only thing I can think of would be the global/local mapping option (which
> is probably a good enough reason to do this), but the standard mechanism
> seems to be pretty complete.

I guess the difference would be that it can't be configured "per action"
(right?) and its not integrated with struts style error messages from
resources files (correct me if I'm wrong!).

Cheers,

Simon Sadedin.




--
To unsubscribe, e-mail:   <ma...@jakarta.apache.org>
For additional commands, e-mail: <ma...@jakarta.apache.org>


Re: Declarative exception handling for Action classes

Posted by "Craig R. McClanahan" <cr...@apache.org>.
I haven't played directly with this code yet, but the general concept
sounds very cool.  A couple of thoughts:

- If we pass the actual exception as attributes, I would suggest
  using request scope rather than session scope.  This will allow
  the technique to work even in apps that don't use sessions, and
  will also avoid problems when there are multiple simultaneous
  requests for a particular session.

- As an alternative to passing the exception you are throwing under
  a particular request or session scope key, how about having your
  Action simply wrap the business logic exception inside a
  ServletException (as the root cause) and throw that?  The perform
  method already declares "throws ServletException", and we could
  enhance the controller servlet to simply do its exception mapping
  trick on any exception thrown by the perform method.

- Matching exceptions to handlers should check the inheritance
  hierarchy of the actual exception, but trying to match on the
  exact class first.  This is how the servlet container (at least
  for version 2.3 and beyond) match up exceptions when you define
  an <error-page> for a particular exception.

- Given the change to just having your action throw the exception,
  defining global exception handlers with local overrides can be
  done in a manner similar to the way global forwards are defined
  with local overrides.

But, given all of the above, if you have your actions throw a business
logic exception wrapped in a servlet exception, is there something needed
that the standard <error-page> mechanism does not handle for you?  The
only thing I can think of would be the global/local mapping option (which
is probably a good enough reason to do this), but the standard mechanism
seems to be pretty complete.

Craig McClanahan



On Wed, 31 Oct 2001, Laine Donlan wrote:

> Date: Wed, 31 Oct 2001 22:06:06 -0500
> From: Laine Donlan <ld...@elogex.com>
> Reply-To: Struts Developers List <st...@jakarta.apache.org>
> To: struts-dev@jakarta.apache.org
> Subject: Declarative exception handling for Action classes
>
>
> Wanted to submit the following code for comment from the Struts dev
> group.  Being faced with a pretty large development project and a
> development environment that oftentimes had one developer working on the
> Web tier code (Struts) and another developer working at the middle tier
> level (EJB's),  an attempt was made to alleviate the need to update
> action code and workflow to accommodate changes in the web tier/middle
> tier contract.
>
> Specifically this related to how business logic exceptions were defined
> and handled.  We have found that within our Struts actions we often see
> large amounts of business logic exception handling which usually does
> nothing more then configure a message and forward the user to some kind
> or error url or back to the previous page with a validation type error
> message.  Not only is this verbose and repetitious, but it is fragile to
> changes in the middle tier since every time a new exception is added, a
> struts-knowledgeable person needs go into all the struts code and add
> exception handling for it.  As with other repitious and tedious code,
> our feeling was that the best way to handle this was to allow for
> exception handling to be declarative and configurable through the
> struts-config.xml.  We have therefore created a scheme where exceptions
> are treated much the same as forwards in the current Struts code-line.
> Each action mapping can define any number of exceptions that may occur
> and how they should be handled.  The handling of the exceptions consists
> of the definition of a key value (error message, etc) , and a path
> (optional - input of the action would be the default).  When an
> exception occurs that can be handled the ActionException (consisting of
> key, and path) is placed into the user's session under a key constant -
> org.apache.struts.action.ACTION_EXCEPTION.  It can then be handled
> however is necessary by an app.
>
> Exception hierarchies are supported just as they would be in a typically
> try{}catch code block through an optional mapping parameter to determine
> whether or not to support the hierarchy.  When attempting to match and
> handle an exception first a specific match would be sought, if one could
> not be found, then a search for any assignable exception would be made.
> The first match would end the search.
>
> The following would be an example of an action mapping:
>
> <action path="/handleSomething"
> 	name="someForm"
> 	validate="false"
> 	input="/someUri.....">
>
> 	<forward ...just like always/>
> 	<exception key="some.key"
> 		     type="some.package.business.logic.Exception"/>
> 	<exception key="some.other.key"
> 	                 type="some.package.business.logic.Exception2"
> 		     path="/someotherUri..."/>
> 	<exception key="general"
> 		     type="java.lang.Exception"/>
> 	<exception key="ejb"
> 		     type="javax.ejb.EjbException"
> 		     hierarchachal="false"/>
> </action>
>
> The following outlines how each of the exceptions would be handled:
>
> 1) If an some.package.business.logic.Exception is throw from the Action
> perform method, the client will be dispatched to the input of the form
> with an ActionException placed into the session under a specific key.
>
> 2) If an some.package.business.logic.Exception2 is thrown, the client
> will be dispatched to the path specified in that mapping with the
> ActionException placed in the session.
>
> 3) If anything other than the previous 2 exception or an EjbException is
> thrown, the client would be re-directed to the input of the form, again
> with the ActionException placed into the session.
>
> 4) If an EjbException is thrown (it's children would not be handled by
> this) then the client would be dispatched with that ActionException in
> the session under a defined constant value.
>
> The changes to the code base consisted of:
>
> 1) Addition of ActionException and ActionExceptions classes.  Very much
> like the existing mapping classes.
> 2) Change of the perform() method signature to throw Exception rather
> than IOException and ServletException
> 3) Update the processActionPerform() method of the ActionServlet perform
> the try{}cactch{} and to map resultant exceptions.
> 4) Add the digesting into the ActionServlet init()
> 5) Add the ActionExceptions reference into the ActionMapping.
>
> I have attached the code:
>  <<changes.zip>>
>
> As well as diffs of the changes to the ActionServlet and Action classes
>  <<Action-diff.txt>>  <<ActionServlet-diff.txt>>
>
> A couple of major @todo's in the code would be the implementation of
> global-exceptions, and a currently hard-coded exception message in any
> unhandled exception that is wrapped into a ServletException.  I wanted
> to see if there was interest for this type of feature, if so I can
> easily put the rest of it together and submit it.
>
> Thanks, any comments or feedback would be appreciated.
>


--
To unsubscribe, e-mail:   <ma...@jakarta.apache.org>
For additional commands, e-mail: <ma...@jakarta.apache.org>