back to API     back to index     prev     next  

Handling Non-Functional Exceptions in ProActive

 What are Non-Functional Exceptions ?

A few years ago, Aspect-oriented Programming first defined non-functional properties (security, persistence, transaction...) to produce separation of concerns (for information and more, see AspectJ website). Distribution is considered as a non-functional property, especially in ProActive where distributed mechanisms are transparent. Unfortunately, exceptions related to distribution are often raised from non-functional levels (i.e. network, Java RMI or JVM) and propagated to functional one (application code). But users do not have to deal with exceptions not related to the application. Such exceptions, raised from non-functional properties, are called non-functional exceptions and should not be propagated to the application. The handlers mechanism of ProActive is the result of intensive work presentes in a EHOOS'03 (ECOOP Workshop) article here.

Non-functional exceptions signal abnormal behaviour of non-functional properties (ie. distribution). They are gathered into a hierarchy based on inheritance. This classification is used by the handling mechanism (look forward).

Figure 1 : Hierarchy of Non-Functional Exceptions for Distribution

Distributed exceptions can be found in the following packages :

  • Communication exceptions : org.objectweb.proactive.core.exceptions.communication
  • Creation exceptions : org.objectweb.proactive.core.exceptions.creation
  • Group exceptions : org.objectweb.proactive.core.exceptions.group
  • Migration exceptions : org.objectweb.proactive.core.exceptions.migration
  • Security exceptions : org.objectweb.proactive.core.exceptions.security
  • Service exceptions : org.objectweb.proactive.core.exceptions.service
  •  The Handlers Mechanism

    Handlers are exception managers dedicated to non-functional exceptions. Every handler implements the following Handler interface.

    public Interface Handler implements java.io.Serializable {
         // Is the exception managed by the current handler ?
      public boolean isHandling(NonFunctionalException e);
    
         // Provide a treatment for handled exception(s)
      public void handle(NonFunctionalException e);
    }
    

    Then, handlers are gathered into static and dynamic structures providing different levels of handling. The following levels are ordered from lower to higher priority :

  • Default : This static level is initialized in the core code and provides a basic handling behaviour for every distributed exception.
  • Virtual Machine : The first dynamic level allow configuration of general handling behaviour for every VM.
  • Body / Proxy / Future : The different components of active object are protected with specific handlers.
  • Code : Handlers can be set temporarily from functional or non functional code.
  • The default level avoid intensive use of dynamic levels. It must handle every single non functional exception to provide soundness for distributed applications. This level is also useful to create different strategies according to the version of the distributed middleware (Peer to Peer, Client/Server or Desktop/Mobile applications). Higher levels (VM, body, proxy, future or temporarily code) use dynamic handlers (created at runtime) to improve fault tolerance strategies defined at default level. A standard strategy, common to every distributed application, is defined in default level while more specific strategies are achieved in dynamic levels. Dynamic handlers, modified or exchanged according to the context of environment, offers obviously much more possibilities than the static ones.

     A few words about the API

    The API consists of three static functions, accessible from any point of the distributed application (from functional or non functional code) :

      public static void setExceptionHandler(HandlerClass, ExceptionClass, level, HandlerizableObject);
      public static Handler unsetExceptionHandler(ExceptionClass, level, HandlerizableObject);
      public static Handler searchExceptionHandler(NonFunctionalException, HandlerizableObject);
    

    setExceptionHandler binds a class of handler with a class of exception in a specific level.
    unsetExceptionHandler removes the class of handler associated to the given class of exception.
    searchExceptionHandler searches and return the right handler for a non functional exception.

     Dealing with Exceptions in ProActive Contributions : Creation and Configuration of Handlers

    Default handlers are statically created during ProActive initialization. They should not be removed nor overloaded because they are essentiel for the safety of the application built over the library. As described before, dynamic handlers from higher level should be used to improve the overall fault tolerance behaviour. Default level gives a basic and safe exception handling behaviour while VM and higher level specializate it. However, when different versions of ProActive are planed, default level can be specialized (ex : Peer to Peer application, Client/Server or Desktop/Mobile require different basic handling behaviour). This exception to the rule avoid large configuration during runtime.

    Configure Default Level :

    The following code show the initialization of the mechanism.

         // Levels of exception handling
      static public HashMap defaultLevel = null;
      static public HashMap VMLevel = null;
      static public HashMap codeLevel = null;
    
     
         // Static initialization of ProActive
      static {
    	
           // Creation of the default level
        defaultLevel = new HashMap();	
    	
           // We set default handlers to use at default level
           // VM and higher level are still set to null as long as they remain empty from any handler
        setExceptionHandler(HandlerNonFunctionalException.class, NonFunctionalException.class, Handler.ID_Default, null);
        setExceptionHandler(HandlerCommunicationException.class, CommunicationException.class, Handler.ID_Default, null);
    
        // Other initializations follow...
      }
    

    Configure Active Object Level(s) :

    The next lines associate handlers with active objects. This mobile object is then protected during any migration.

         // Creation of an active object
      RO remote = (RO) org.objectweb.proactive.ProActive.newActive(RO.getClass().getName(), null, remoteNode);
    
         // Get the remote body associated to the object (body is a meta-object, look forward MOP documentation)
      UniversalBody ro_body = ((BodyProxy) ((org.objectweb.proactive.core.mop.StubObject) remote).getProxy()).getBody();
    
         // If the configuration is made by the remote object itself, reference to the body must be obtained with
      UniversalBody ro_body = ProActive.getBodyOnThis();
    
         // Set exception handler to the body of the remote object
         // Remote object can now migrate safely
      ProActive.setExceptionHandler(HandlerMigrationException.class, MigrationException.class, Handler.ID_Body, ro_body);
      remote.moveTo(destinationNode);
    

    Search a Handler for Non-Functional Exception :

    The last thing to know is how to search the right handler for a given exception. Keep in mind that the research starts from higher priority levels.

      try {
     
         // Reified method call as founded in the core of ProActive 
         sendRequest(methodCall, null);
    
      catch (ProActiveException e) {
    
           // Create a non functional exception encapsulating the network exception
        Context context = new ContextOfExecution();
        NonFunctionalException nfe = new CommunicationException(e, context);
    
           // Research of the right handler for the given exception
           // Give reference to any active object structure to use active object levels
        Handler handler = searchExceptionHandler(nfe, null);
        handler.handle(nfe);
      }
    

    To summarize :

    here are the most important points to customize handlers mechanism :

  • Define a Distributed Exception within the hierarchy of non-functional exceptions.
  • Create a handler from scratch or use an existing one.
  • Register handler during initialization or execution with setExceptionHandler.
  • Adapt try/catch construction with searchExceptionHandler.
  •  Performances

    We made several tests showing that the mechanism remains light for the application. Overall performance are not affected by the configuration of hundred handlers or less. And that number of handlers is huge ! Moreover, configuration is a punctual operation. Mobility is not really affected until the migration of an object with hundred handlers. Both results show that every handlerizable object supports a few dozen of handlers with no other problem than a limitation to hundred handlers.

    Figure 2 : Performances of mechanism configuration

    Figure 3 : Performances of mechanism during migration

     Example of a Complete Strategy within a ProActive Application

    Coming soon...



    Copyright © October 2002 INRIA All Rights Reserved.