views:

169

answers:

3

Hi,

I have service object (Service A), that has some specific repetitive asynchronous task . This service object also has a supervising object (Service B). I want to handle most of the errors concerning the specific task in Service A and only inform Service B if it needs to take any additional measures (e.g. when Service A does not know how to handle the error).

Since Service A depends on external resources (e.g. network availabilty) there are many different exceptions, that can be thrown and I do not know all of them right now.

Because of that I would also like to have a pluggable eror-handling strategy inside Service A so that it can handle different exceptions differently. I would like to plug in those stratgies using my IoC container.

Example A: Service A is suppsoed to download something every 30 sec. (polling), but the URL is malformed so a MalformedURLException is thrown. A looks up the error handling strategy for MalformedURLExcpetion and in this case the strategy will mean canceling the download and informing Service B (the supervisor) via a callback.

Example B: Service A is supposed to download something, but the hostname cannot be resolved. Again an Exception is thrown (sorry don't know exacpt type now) and the corresponding strategy will be looked up: in this case the download should be stalled and retried at another time until a certain threshold is hit.

My problem now: How should I implement this dynamic lookup of error handling strategies and the strategies themselves? Is there a pattern for that?

(Sorry for this lengthy post)

A: 

Try Observer pattern. In general, your ServiceA should have methods like addFirstTypeExceptionsListener (ServiceListener l) addSecondTypeExceptionsListener (ServiceListener l)

or addExceptionListener (ServiceListener l, ExceptionTypeEnum type).

Your ServiceB then should implement ServiceListener interface which will probably have method like handleException (Exception e);


If we abstract away from your question then it's a bad practice to use exceptions for flow control.

Roman
You mean, that each ExceptionHandler is an Observer of my Service A and gets notified when the Exception it registered on is thrown?
er4z0r
Yes. Look also at Nils Schmidt approach based on decorator pattern. My approach gives your lower coupling but it's a matter of taste what to use in your situation.
Roman
+1  A: 

Well, the easiest and straight forward solution would be tu use plain java try catchs, not that flexible, but often useful enough as error handling strategies does not change that often. Those exceptions you can not catch are declared on the method to may be thrown, and may be handled by your Object B.

If you wanna be more flexible. Create an interface for your service A with all the possible exceptions declared. Implement that interface with logic but without any error handling. Then you could create ErrorStrategy objects that implement the interface as well and delegate incoming calls to another implementation of that interface, BUT and this is the interesting part append some error handling strategy for one or more particular exceptions. Here is an example to make it more understandable.

public interface A {
    void someMethod() throws IOException, MalformedURLException;
}

class AImpl implements A {
    @Override
    public void someMethod() throws IOException, MalformedURLException {
        // here goes your business logic
    }
}

class ErrorHandlerOne implements A {

    @Override
    public void someMethod() throws IOException {
        try {
            delegate.someMethod();
        } catch (MalformedURLException e) {
            // handle the exception
        }
    }
}

If you wanna be even more flexible, I would recommend to use AOP mechanisms instead of the simple delegation chain, that way you can easily plug-in and exchange your error handling strategies. If you use Spring and your Service A is a Spring-Bean you could easily use Springs build in AOP support. In that case the after throwing advice is what you looking for.

After throwing advice: Advice to be executed if a method exits by throwing an exception.

import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.AfterThrowing;

@Aspect
public class AfterThrowingExample {

  @AfterThrowing(
     pointcut="com.xyz.myapp.A.someOperation()"
     throwing="ex")
  public void doRecoveryActions(IOException ex) {
    // ...
  }
}
Nils Schmidt
Thank you nils. In fact being able to plug in and exchange the strategies is my core point. Background the the taks of the service depends on external resources and as such can throw a quite a variety of different exceptions. Since I don't assume that I know all of these at design time and will come up with new exceptions later, I would like to be able to inject the error handling via my IoC Container (Spring in this case)
er4z0r
When you say that you dont know all the exceptions, that means we are talking about RuntimeExceptions, right. That way you dont need to define them on the interfaces anyway.If you are using Spring everything becomes even more easy :-)If your service A is a Spring Bean, I would totally suggest to use Springs AOP mechanisms to plug-in error handlers. Full flexible, easy to configure and prbly. in line with your application/framework.
Nils Schmidt
Hi Nils. That sounds well. I'll have a look at it.
er4z0r
A: 

Keep it simple and use plain exceptions.

They are already meant to implement different error handling strategies: you can catch different exception and act accordingly. You can implement your own error handling scheme as long as exceptions remain, well, exceptional. Otherwise if it's really control flow, you should think about it differently.

Here is one in pseudo-code:

  • CannotDownloadException. When the download is realy not possible. Fatal error.
  • RetryDownlaodException. When the download is momentary not possible. Can implement retry logic.

The names are not so good, but it illustrates the principle.

class ServiceB {

  private serviceA serviceA;

  public download( URL url ) throws CannotDownloadException
  {
       try
       {
               serviceA.download( url );
       }
       catch( RetryDownloadException ex )
       {
             // you could have here something more elaborated that would
             // perform a retry strategy based on a configuration (e.g. the number of retry, 
             // or the interval between retry)
             try
             {
                  sleep( 10 sec );
                  serviceA.download( url );
             }
             catch( RetryDownloadException ex )
             {
                  throw new CannotDownloadException();
             }
       }

  }
}

class ServiceA {

  public download( URL url ) throws DownloadException
  {
       try
       {
               if( ! url.isValid() )
                   throws new CannotDownloadException();

               serviceA.download( url );
       }
       catch( ConnectionException ex )
       {
             throw new RetryDownloadException();
       }
   }
}
ewernli
O.K. Forgot to mention another constraint: The tasks performed by ServiceA are asynchronous by nature. That means simply doing a serviceA.download(URL url) and catching the exceptions won't work since that would mean that the call to needs to be a blocking call, which I can not afford.
er4z0r
Hmm...That can still be adapted for asynchronous scenario. Instead of a blocking call you have two callbacks `onSuccess`, and `onError`. In `onError` you can select and implement a retry logic. The point is that you can use `Exception` to define the class or errors that you can handle -- that's their initial purpose. The exact error handling logic for each class can be selected dynamically.
ewernli
Yeah that is more like it. Currntly I have a Callback interface with exactlly those methods where each of the methods is passed the task that failed/succeeded and the onError also an Exception which caused the failure. This Interface is implemented by ServiceA as well as ServiceB so ServiceA can delegate every exception it cannot handle alone. My problem is now how to implement the internal lookup of Exception <-> ExceptionHandlerStrategy.
er4z0r
Why don't you simply map one strategy to each exception type?
ewernli
That was the plan. Using a HashMap<Throwable,ErrorHandlingStrategy>. I just wanted to hear if there is a well known solution for this.
er4z0r
As I said, I would use catch blocks to dispatch the exception type to the error handling strategy. Each catch blocks then looks up the strategy, e.g. `lookupRetryStrategy()`. If I understand right, there is a fixed number of Exception, and a fixed number of `lookupXxxxStrategy()`. Using a HashMap means you re-do what catch block do naturally.
ewernli