Exceptions

N

nukleus

I have some old java code i am working with right now.
All AWT stuff, no javax.
It is a network related application.

There are some issues with Events and Exceptions:

Exceptions:

The program is quite complex and there are all sorts of things
that may go wrong. At any time, the sockets may be lost, the
servers may get close their end of the wire, bad data may arrive
and so on. The error may happen several levels deep, and it
all has to be handle in such a way, that user can comprehend
what logially happens in any situation.

So, the strategy chosen, is to create custom Exceptions,
derived from standard exceptions, such as socket exceptions,
invalid numbers, etc.

Several levels up, the routines that perform logically complete
operations, catch those custom exceptions and can display the
the information to the user in a command history text area.

There is a tradeoff here. On one hand, it is easier to use
exceptions as you don't have to worry about the return codes
by routines that are several levels deep, analyze those results,
and create extra code that would be nice not to have.

On the other hand, some classes of errors, are not critical.
They simply mean that user provided incorrect configuration
parameters and the server issued an error code, which is
perfectly valid. In this case, it doe seem to be preferrable
to use the ResultCode class object, automatically parsing
the network server standard results, such as NNTP, SMTP
or other standard protocol return codes.
Creating a different exception for some of those codes
simply creates too much of extra code and, finally, may
confuse the issues to the point where you no longer grasp
what is going on.

So, there is a fine balance between the return codes and
exceptions. For example, in case of NNTP protocol, in
article download operation, there is a sequence of commands
exchanged by the program and server. First, you have to
connect to server, then you have to issue group command,
then download article headers, necessary to perform a
specific operation, then issue ARTICLE command, and,
finally, load the article and save it in archive file.
Depending on response of server, the ResultCode object,
may contain either a standard NNTP error code plus the
body of actual server response, or, it may contain some
custom codes and text of their error messages.

For example, if socket is timed out, stream is lost, etc.,
we should be able to catch those situations and covert them
into our custom codes. Several levels above,
the caller of logically complete operation may use the switch
statement and act upon various standard or custom errors
differently depending on type of operation. It things time out
in the middle of header download, the server has to be
reconnected to, the GROUP command is to be issued,
and then the broken headers are to be downloaded
instead of redoing the whole operation from the top.
This way, you recover in the middle of ANY situation,
and recover in the most effective and logical way.
If you have error while downloading article itself,
it means you are already connected to the server,
issued group command, downloaded all the headers,
and are now doing the actual work of article downloading.
Any errors at this point, should simply redo the last article
and keep going. After each article is downloaded, the
article number is saved in a group file. So, no matter what
happends, you know exactly where to restart. Even if the
program crashes, you still recover exactly what you need to.

To make a long story short, question:

Does it make sense?
Is it the way to go or is there any other alternative?

To summarize: the custom exceptions are used to bring up
some fine graining into error handling structure. Instead of
using the standard exceptions, such as IOException, socket,
or Exception itself, we use those custom exceptions
and catch them in various places above to precisely affect
the recovery code. In the main routines, various exceptions
are caught starting from the mist fine grained level, and
going down to the Exception level, if we did not catch
the any lower level custom exceptions.

Thanks for your opinion on this.
 
L

Lew

nukleus said:
To summarize: the custom exceptions are used to bring up
some fine graining into error handling structure. Instead of
using the standard exceptions, such as IOException, socket,
or Exception itself, we use those custom exceptions
and catch them in various places above to precisely affect
the recovery code. In the main routines, various exceptions
are caught starting from the mist fine grained level, and
going down to the Exception level, if we did not catch
the any lower level custom exceptions.

I will not treat your points in detail here, but instead speak to the
strategies for using exceptions.

Generally, what you describe is viable, perhaps not best practice but not so
terrible on the face of it. The danger, almost a certainty in the real world,
especially given your descriptions in other threads of the coding style that
you inherited, is that the implementation of the strategy is flawed in the
details.

Here are Lew's Laws for the use of exceptions (not guaranteed to be clever or
correct, but presented as a starting point). This post runs a little lengthy.

1.
Exceptions, as the name implies, are for exceptional circumstances. Use
regular logic for things you expect.

instead of
public void act( Entity entity )
{
try
{
System.out.println( entity.name );
}
catch ( NullPointerException e )
{
System.out.println( "null entity" );
}
}

use
public void act( Entity entity )
{
if ( entity == null )
{
System.out.println( "null entity" );
}
else
{
System.out.println( entity.name );
}
}

2.
Return codes are better than throws, when either the result makes sense within
the problem domain or a reasonable default exists.

public boolean storeData( Entity entity )
{
// Set up a PreparedStatement with an INSERT ...
try
{
ps.execute();
}
catch ( SQLException se )
{
logger.error( e );
return false; // clearly the exception means that the store failed
}
finally
{
ps.close();
}
// more logic and cleanup ...
return true;
}

3.
Log your exceptions.
Corollaries: Have a logging strategy. Include in it a standard logging format.

4.
Do something with received exceptions at the first point of reception.

Even if an exception will be rethrown, you should at least log it at the point
of first capture. You will have available the fullest possible context at that
moment. Then either rethrow, convert to a custom or convert to a
problem-domain value.

5.
An application should define a custom exception, possibly two, the first
extending Exception and the other RuntimeException.

You probably do not need any more than these two. Use constructors that take
the causal exception as a parameter. (Roll your own in J 1.3, use the
corresponding super() calls in J 1.4+.) Your custom exceptions should expose
all four constructors.

6.
Analyze each potential exception situation individually. Does it make sense to
"eat the exception" and convert to a default value or action? Should you throw
an exception? Should it be a standard exception or a custom one? (I typically
throw standard Java RuntimeExceptions like IllegalArgumentException, but use a
custom checked exception.)

7.
Exceptions are essentially value objects. They shouldn't log, and they damn
sure shouldn't do anything within the problem domain. (By which I mean that an
Exception should sport no methods that do these things.)

To apply these "laws" to your problem, I'd say to make sure that the code logs
exceptions at first contact, that throws occur only when necessary, not for
"in the domain" occurrences, and that the recovery actions make sense.

- Lew
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,764
Messages
2,569,566
Members
45,041
Latest member
RomeoFarnh

Latest Threads

Top