aspose file tools*
The moose likes Java in General and the fly likes Design of Exception Handling in Enterprise System. Big Moose Saloon
  Search | Java FAQ | Recent Topics | Flagged Topics | Hot Topics | Zero Replies
Register / Login
JavaRanch » Java Forums » Java » Java in General
Bookmark "Design of Exception Handling in Enterprise System." Watch "Design of Exception Handling in Enterprise System." New topic
Author

Design of Exception Handling in Enterprise System.

amol deshpande
Ranch Hand

Joined: Sep 05, 2003
Posts: 162
Hi All,
I'm trying to figure out a proper execption handling strategy for a medium to large sized layered system.

Consider that a project has 3 layer architecture, lowest layer handles connections to db, establishes remote connections, and is capable of throwing checked exceptions.

The mid tier has business logic, which will make calls to lower layer. This layer may have its own exceptions.

The higher layer is Business logic caller layer which is like an MVC frame work(struts, presentation).

Now Since the innermost layer throws checked exceptions, each of the caller needs to handle it. Since the app is big, it gives hell of an exception handling code to business and presentation layer.

We have a few options to work over this.

1) If we keep all innermost layer exceptions as those are, it explodes exception handlers all over the system.

2) We can create wrapper check exceptions , ex. AppConnectionException which may denote connection problem to higher layer, and may contain root cause denoting actual problem, viz, SQLException, NamingException, RemoteException, etc.

Even with this approach, the system floods exception handlers all over.

3) Third approach is to define a runtime exception specific for an application, which would wrap the checked exception underneath and at the highest level catch this exception and report to the user or take some action.

Something like
try{
rs.executeQuery(getRemoteQuery());
}catch(SQLException e)
{
throw new ProductQueryException(e); // an unchecked exc.
}catch(RemoteException e)
throw new ProductQueryException(e);
}

As a result of this its callers (which may be too many, as its lowermost layer code) do not need to handle ProductQueryException, only highest layer can put this in try catch and treat in a way.

Now, many people are against approach 3, as its converting a checked to unchecked exception. I think it has its prose and cons and given a situation , you may have to go for it.

Please contribute to tell your views or another even better approach for this.
Stan James
(instanceof Sidekick)
Ranch Hand

Joined: Jan 29, 2003
Posts: 8791
This is surely a controversial area. The checked exceptions in Java were a bit of a language novelty. I'm not sure which other languages have them, but folks who came from Smalltalk and other languages that didn't have them never quite bought into the idea. So you'll find flame wars and other more moderate discussions all over the web. Let's see how this one goes.

A few particular ideas ...

I like the lower levels to throw abstract application exceptions. If the data layer throws SQL exceptions that informs the higher layer that there's a database in use. Why tell them that? Make your own exception that would work for a database, messaging, a web service call, etc. Design the higher layer as if you hadn't quite decided between a database and messaging yet.

I put "throws Exception" on methods all the time. Many people will respond with horror after they recover from the shock enough to type. I've only gone back and made a more specific exception twice, ever. Those were the only two times I ever needed this

and I thought the need for that logic was a flaw, not something I'd do again on purpose.

Resist the urge to catch, log and throw a new exception. It just clutters the log. The exception (!) to this rule is to catch that SQL exception and throw an application exception. For debugging purposes (not for app design or user requirements) use some kind of chained exception that captures the original. A higher layer can log it without ever thinking about what type it is.

I've done one experiment with unchecked exceptions on a non-trivial system and I loved em. I may have gotten lucky with an architecture that let almost all exceptions bubble up to a core request handler, but I was encouraged to try it again.


A good question is never answered. It is not a bolt to be tightened into place but a seed to be planted and to bear more seed toward the hope of greening the landscape of the idea. John Ciardi
Clifton Craig
Ranch Hand

Joined: May 26, 2006
Posts: 103
Not trying to debate but I always favored the rule of thumb where you throw only what your caller can and should handle as checked and everything else as unchecked. Also, it's good to consider frameworks for low level APIs that throw a lot of checked stuff. The advantage here is you upper layers need only concern themselves with exceptions from the next layer down and only with stuff it can handle. What can a swing client do with a low level JDBC exception caused by a socket timout from the app server to the DB? Instead it should handle a more generic service not available exception from the remote server.The other advantage is that it preserves the stack trace where al lot of catching and rethrowing can introduce mutations and dropped frames from the stack trace. exceptions get logged where they occur allowing the problems to be traced better. Frameworks help alot here. Spring has great handling for JDBC and RMI exceptions. Where there is no framework code to handle exceptions properly you must wall off the exception trickle by creating your own framework.


The idea here is to isolate the ugly code behind interfaces that describe the concept or overall task being performed. Clients use the MyStragey interface that declares myJob. The MyObject implementation calls (rather dives) into ugly exception throwing code and gets the job done reporting back a more general exception containing the actual exception. The general exception should normally be unchecked unless the caller can actually do something about it. For example, if the exception is something like "drive not available" then it reflects a setup problem that the caller cannot control. In this case the exception should trickle all the way to the top and cause the app to abend if necessary where the stack trace could be examined.

It really depends on the steps that my strategy must take. If these steps reflect a sequence of actions that should not fail under normal setup then myJob() should thrown unchecked. If its a series of steps that could be retried then maybe myJob() can throw checked allowing the caller to trap and retry. For example a postOrder() method might hide a bunch of low level network issues behind a OrderDidNotPostException. The caller could be a servlet that redirects to an error page allowing the user to retry the post order operation. That's really a bad example and I'm really babbling now. I'll cool out...


Holla at me...<br /><a href="http://codeforfun.wordpress.com" target="_blank" rel="nofollow">http://codeforfun.wordpress.com</a>
Mr. C Lamont Gilbert
Ranch Hand

Joined: Oct 05, 2001
Posts: 1170

I'm one of those horrified by the masking of checked exceptions to avoid catching them. I think its a idea pushed for political reasons and not coding reasons. People want the illusive Data access object that acts like a POJO so they bury their heads in the sand and act like because its throwing runtime exceptions that somehow its no longer throwing exceptions...

Originally posted by amol deshpande:
...

We have a few options to work over this.

1) If we keep all innermost layer exceptions as those are, it explodes exception handlers all over the system.

You only have to handle the exception where you call the method. You don't complain about having to call the method so why complain about having to catch the exception? This is just code, its not complexity. it may be monotonous, but its not dangerous or hard to manage.

Originally posted by amol deshpande:

2) We can create wrapper check exceptions , ex. AppConnectionException which may denote connection problem to higher layer, and may contain root cause denoting actual problem, viz, SQLException, NamingException, RemoteException, etc.

Even with this approach, the system floods exception handlers all over.

You should not design it so it is merely a wrapper. Often it may be thrown as a result of an exception on the lower level, but the reason is not directly because of the lower level. Furthermore, it may be thrown on its own sometimes. You need to start viewing your layers as independent. If the lower layer does not provide the thing that the upper level requested, then the upper layer can't do its thing so thats what the upper layer reports. The upper layer does not report that the lower layer had a problem, it reports that itself was unable to conduct its business.

Originally posted by amol deshpande:

3) Third approach is to define a runtime exception specific for an application, which would wrap the checked exception underneath and at the highest level catch this exception and report to the user or take some action.

Something like
try{
rs.executeQuery(getRemoteQuery());
}catch(SQLException e)
{
throw new ProductQueryException(e); // an unchecked exc.
}catch(RemoteException e)
throw new ProductQueryException(e);
}

As a result of this its callers (which may be too many, as its lowermost layer code) do not need to handle ProductQueryException, only highest layer can put this in try catch and treat in a way.


Ok, I have to take a minute to calm down again

The callers do need to be aware of it even if they choose to ignore it. You would Hate for a caller to create some new resource, then have a runtime exception thrown, exiting the method, and not cleaning up this resource. Normally Runtime exceptions are cause for shutting down the program. If you shutdown on runtime exceptions then ok. If you do not, then you have no way to properly isolate your layers.

There are NO pros to masking an exception because you don't feel like catching it. If there is nothing that you can do with the exception on a certain layer, then let that layer decide to ignore it. But don't change the lower layer to not throw an exception just because the upper layer does not feel like catching exceptions!?!

Whether you should catch an exception or not has nothing to do with whether it should have been thrown in the first place. It has only to do with what you are able or not able to do with the knowledge of the exception.

On the other hand, if you are forwarding the exception in the form of RuntimeException because you have created for yourself an architecture that handles your exceptions on a high layer as runtime exceptions, then that is ok. Just be sure your not doing this because you don't want to type a few lines of code.
amol deshpande
Ranch Hand

Joined: Sep 05, 2003
Posts: 162
Wow so many of fruitful posts here!

I like the way C. Gilbert is drilling down into the things. Its sure getting a nice shape.

You only have to handle the exception where you call the method. You don't complain about having to call the method so whycomplain about having to catch the exception?


Yeah thats for sure. I need to care only a stuff I call upon. Imagine an architecture with no good exception handling mechanish and you would like to make things better.

void m1()
{ a.m2(); } // same layer another class call
void m2()
{ b.m3() ; } // innerlayer call
void m3()
{ c.m4() ; } // inner layer call
void m4()
{ // some connectivity, naming, remote(not business) exception } // throws a checked exception.

Here now since m4 in innermost layer has a generic service to offer, it will be called by lot many classes in layer higher up and this cycle goes up. Ultimately at the higher most layer, through the chained calles I'm referring to services exposed by inner classes so in the way I'm calling inner methods (m4()), so I need to care for its exception.

Here the higher layer is abstract and this abstraction gets reduced to more specific operations going below. As long as I'm catching BalanceNotEnough exception its fine to know and bring this to the knowledge of higher layer to make it do something about it.
There are NO pros to masking an exception because you don't feel like catching it. If there is nothing that you can do with the exception on a certain layer, then let that layer decide to ignore it. But don't change the lower layer to not >throw an exception just because the upper layer does not feel like catching exceptions!?!


A point behind not designing and catching(only a few set of checked exceptions) is many systems do not do anything with it other than just log it and tell the user for a specific problem. One cant just catch them log and do nothing as code afterwords would expect that things have gone right when infact they have not.

The checked exceptions denote some kind of error you can do something with. I like Stan's point here that if this denotes a business exception( SQLException ), you give it more specific meaning and take follow up with it by propagating it. However, what does one do with inner layer saying ConnectException kinda stuff? If i choose to propagate this kind of exceptions which basically denote a setup or config or out of programming environment problem I sure dont have a step to take. Rather app may like to log it and present it to the user.

Yes when we mask a Checked exception into a Unchecked one, we've to be careful to make sure that at highest layer we do tackle it and deal with it (or app will shutdown) .This is risky because system wont mandate this.A framework may be of use here.
A guideline out of this may be..dont make exceptions unchecked which denote business issue, an issue on which some action can be taken by caller. But if its nothing that caller can do with it, and given that higher the layer, more the callers, one might want to mask this and handle it higher up the layer to provide navigation path...obviously by denoting app specific exception. Otherwise in a typical application which I have in mind, one may end up a mesh like call note diagram for a use case and make it very difficult to understand how the system flow works in case exception is thrown.
Stan James
(instanceof Sidekick)
Ranch Hand

Joined: Jan 29, 2003
Posts: 8791
Mr. Gilbert's posts accurately reflect the Java designers intentions. But we don't have to eat everything Sun serves up. Look around for all points of view. Here is a good essay from Bruce Eckell. His opinions have shifted over time and experience, starting from being on the C++ committee when exceptions were introduced there. A brief quote:


Checked exceptions seem like a really good idea at first. But it's all based on our unchallenged assumption that static type checking detects your problems and is always best. Java is the first language (that I know of) that uses checked exceptions and is thus the first experiment. However, the kind of code you must write around these things and the common phenomenon of "swallowed" exceptions begins to suggest there's a problem. In Python, exceptions are unchecked, and you can catch them and do something if you want, but you aren't forced. And it seems to work just fine.


I think he has links to more of both sides of the debate.
Mr. C Lamont Gilbert
Ranch Hand

Joined: Oct 05, 2001
Posts: 1170

It does have a lot to do with typing. For instance, I have a business layer that uses a DAO layer of sorts. One implementation of the DAO layer uses JDBC, another implementation uses JDO. JDBC throws checked exceptions, JDO throws unchecked exceptions.

There is never a case that I do not catch and properly deal with the exceptions thrown by JDBC within the JDBC implementation. This is obvious because I have no choice. However, on occasion I have missed exceptions thrown by the JDO layer and they have sprung up at the highest levels of my application causing problems for things I otherwise can deal with. The only way to ensure I am catching all of the JDO exceptions is with Unit testing or something.
 
I agree. Here's the link: http://aspose.com/file-tools
 
subject: Design of Exception Handling in Enterprise System.