Christophe Nowicki

January 12, 2006

Gestion des exceptions SOAP en Perl avec les module SOAP::Lite et Error

Après une longue journée de travail, j’ai enfin réussi à faire fonctionner correctement le système de gestion d’exception de SOAP::Lite avec le module Error. Tout d’abord quelques explications.

Système de gestion d’exception

Tout programme en exécution peut être sujet à des erreurs, pour lesquels des stratégies de détection et de réparation sont possibles. Ces erreurs ne sont donc pas des bogues des programmes, mais des conditions particulières, on parle aussi de conditions exceptionnelles ou exceptions dans le déroulement normal d’une partie d’un programme.

Module Perl Error

Le module CPAN Error permet de gérér les exceptions en Perl. Il propose une interface objet semblable à celle disponible dans des langages comme Java ou bien C#. Le module repose sur la fonction die du langage.

SOAP::Lite

Le projet SOAP::Lite permet de prendre en charge l’ensemble des protocoles lier aux Web Services (SOAP, WSDL et UDDI). L’ensemble des fonctionnalitées offertes sont extrèment riches et puissantes. Vous pouvez aussi bien faire un serveur qu’un client en Perl et vous interfacer avec des Service écrit dans de nombreaux autres langages.

Entre la théorie et la pratique …

L’ensemble des interactions sont décrites dans les spécifications des protocoles de Web Services. Mais comme présque toujours en informatique, chaque constructeur, langage ou implémentation apporte son lot de spécificitées.

Dans le cas du langage Perl, les deux principaux sont l’absence :

  • de typage
  • d’un système de gestion d’exception

Le permier problème se controurne à l’aide de la déclaration des type dans un fichier WSDL.
Pour le second, j’ai eu un peu plus de mal avant de trouver la solution.

A propos du code source de SOAP::Lite

Ce n’est vraiment pas un exemple à suivre :

  • très peu de commentaires dans le code
  • seul fichier de 5000 lignes
  • le mode de debug trace n’est pas assez verbeux
  • on se demande souvent si l’auteur du module n’a pas coder sous l’imfluence de certaines drogues

L’anomalie de fonctionnement

Lorsqu’une exception est levée à l’aide de la fonction throw dans un module Perl elle créer un objet pour indiquer des informations sur le contexte de l’erreur. L’objet le plus simple est Error::Simple

sub foo {
   throw Error::Simple( "A simple error");
}

Il est possible de créer vos propres objets en utilisant l’héritage en utilisant l’objet Error comme base.

La framework SOAP::Lite détourne la fonction die et renvoie une exception SOAP qui contiens un objet. La problème est que cela ne fonctionne pas correctement :

 SOAP Fault :
        Fault String : Application error
        Fault Detail :  {
          'Error__Simple' => {
                             '-file' => 'Demo.pm',
                             '-text' => 'A simple error',
                             '-package' => 'Demo',
                             '-line' => '9'
                           }
        };

        Fault Actor  : http://localhost:4242/

Le contenu de Fault Detail n’est pas un objet MAIS une table de HASH.
De plus un message d’erreur du côte du serveur vous indique qu’il y’a visiblement un problème avec la serialisation :

 Use of uninitialized value in sprintf at /usr/share/perl5/SOAP/Lite.pm line 814.
Cannot encode 'namesp1:something' element as 'hash'. Will be encoded as 'map' in  stead

Après quelques heures de tatonnement et de recherche dans le code source de SOAP::Lite, j’ai trouver la source du problème.

Les attributs du module Error contiennent tous un préfixe qui fait échouer la serialization :

$VAR1 =  bless( {
        '-file' => '...',
        '-text' => '...',
        '-package' => '...',
        '-line' => '...'
        }, 'BadError')

La fonction résponsable de ce bug est SOAP::Serializer::encode_hash.
Une expression régulier empeche la serialisation d’un caractère ‘-‘ dans le flux XML.

J’ai donc déciser de supprimer le caractère ‘-‘ dans le nom des attributs à l’aide du boût de code suivant :

sub encode_hash {

my($self, $hash, $name, $type, $attr) = @_;

  while(my ($k, $v) = each (%$hash))
  {
    if ($k =~ m/^-/)
    {
        $k =~ s/^-//;
        $hash->{$k} = $v;
        delete $hash->{'-'.$k};
    }
  }

  if ($self->autotype && grep {!/$SOAP::Constants::ELMASK/o} keys %$hash) {

Et Voilà !

Cela fonctionne enfin correctement :

 SOAP Fault :
        Fault String : Application error
        Fault Detail :  {
                             'detail' => bless ( {
                             '-file' => 'Demo.pm',
                             '-text' => 'A simple error',
                             '-package' => 'Demo',
                             '-line' => '9'
                           }, 'Error::Simple')
        };

        Fault Actor  : http://localhost:4242/

Je vais contacter l’auteur du module pour trouver une solution plus propore ;0)
Mais en attendant celle-ci fonctionne correctement.

Filed under: Programming — Tags:, , — cscm @ 21:20

Comments are closed.

Powered by WordPress