App::CamelPKI::Error - Camel-PKI Error management


App-CamelPKI documentation Contained in the App-CamelPKI distribution.

Index


Code Index:

NAME

Top

App::CamelPKI::Error - Camel-PKI Error management

SYNOPSIS

Top

  use App::CamelPKI::Error;

  try {
      throw App::CamelPKI::Error::Internal("WRONG_NUMBER_ARGS");
  } catch App::CamelPKI::Error with {
      warn "Oops, I made a boo-boo!";
  };

  package My::Facet;
  use Class::Facet from => "My::Object",
                   on_error => \&App::CamelPKI::Error::Privilege::on_facet_error;

DESCRIPTION

Top

This class leverages the Error module, by the excellent Graham Barr and his buddies, to implement error management in Camel-PKI.

Unlike Error, try, with, finally, except and otherwise symbols are exported by default: no need to say use Error qw(:try); to import these.

App::CamelPKI::Error::Internal

Thrown when a programing issue occurs (for example when not respecting the documented API, using a bad number of arguments, ...).

App::CamelPKI::Error::IO

Thrown when a file issue occurs. The incriminated file name must be passed as the parameter -IOfile, for example.

    throw App::CamelPKI::Error::IO("cannot open file",
                              -IOfile => $file);

The ->{-errorcode} field will be automatically set with the numerical value of $! (see perlvar) when the error is thrown. The ->{-error} field will be automatically set whith the textual value of this same variable; note that this value depends on the active locale and therefore should not be tested by error catching code.

App::CamelPKI::Error::Privilege

Thrown each time the owner of a facet, another object or a class with restricted privileges, try to exceeds those which were granted to it. To this effect, the App::CamelPKI::Error::Privilege also defines a on_facet_error function that can be installed as a Class::Facet error handler, as shown in SYNOPSIS.

App::CamelPKI::Error::Database

Thrown when an Camel-PKI database (typically App::CamelPKI::CADB) detects an error at the SQL level, as an invariant violation tentative or an insert of two values for an unique index.

App::CamelPKI::Error::State

Thrown when a Camel-PKI object or class is in a state which cannot be handled correctly (for example, private key and certificate already present on disk for a non corresponding service), or an asked operation which is no yet or anymore possible to perform (for example when App::CamelPKI::CA ask for a certificate generation when the AC key and certificate are not regulated).

App::CamelPKI::Error::OtherProcess

Thrown in case of an error in the communication with an external process (for example failling to start an instance of App::CamelPKI::SysV::Apache).

App::CamelPKI::Error::User

Thrown when a Camel-PKI mecanism detects an error caused by a bad user action (or a bad usage in a web service client).


App-CamelPKI documentation Contained in the App-CamelPKI distribution.
#!perl -w

package App::CamelPKI::Error;
use strict;
use base "Error";

use Error qw(:try);
use base "Error";
use base "Exporter";
our %EXPORT_TAGS=%Error::subs::EXPORT_TAGS;
our @EXPORT_OK=map { @$_ } (values %EXPORT_TAGS);
our @EXPORT=@{$EXPORT_TAGS{try}};
{
    no warnings "once";
    *import = \&Exporter::import; # Stupid Error.pm redefines its own
                                  # ->import()
}

package App::CamelPKI::Error::Internal;
use vars qw(@ISA); @ISA=qw(App::CamelPKI::Error);

package App::CamelPKI::Error::IO;
use vars qw(@ISA); @ISA=qw(App::CamelPKI::Error);

sub new {
    my $class = shift;
    local $Error::Depth = $Error::Depth + 1;
    return $class->SUPER::new(@_,
                              -errorcode => $! + 0, -error => "$!");
}

package App::CamelPKI::Error::Privilege;
use vars qw(@ISA); @ISA=qw(App::CamelPKI::Error);

sub on_facet_error {
    shift; # Off with the class name
    throw App::CamelPKI::Error::Privilege(-text => "Facet error", @_);
}

package App::CamelPKI::Error::Database;
use vars qw(@ISA); @ISA=qw(App::CamelPKI::Error);

package App::CamelPKI::Error::State;
use vars qw(@ISA); @ISA=qw(App::CamelPKI::Error);

package App::CamelPKI::Error::OtherProcess;
use vars qw(@ISA); @ISA=qw(App::CamelPKI::Error);

package App::CamelPKI::Error::User;
use vars qw(@ISA); @ISA=qw(App::CamelPKI::Error);


package App::CamelPKI::Error;

sub new {
    my $self=shift;
    splice(@_,0,0,"-text") if (@_ % 2);
    my %opts=@_;

    local $Error::Debug = 1;      # activates stack traces...
    local $Carp::MaxEvalLen = 80; # ... but not too long anyway

    local $Error::Depth = $Error::Depth + 1;
    $Error::Depth += $opts{-depth} if (exists $opts{-depth});

    return $self->Error::new(%opts);
}


sub stringify {
    my ($self) = @_;
    my $retval = sprintf("%s=%s\n",
                         ref($self), $self->SUPER::stringify);
    foreach my $k (keys %$self) {
        next if ($k eq "-text" || $k eq "-stacktrace");
        local $@; # if exceptions brakes exceptions... Where do we goes?!
        my $v = eval {
            require Data::Dumper;
            local $Data::Dumper::Indent = $Data::Dumper::Indent = 1;
            local $Data::Dumper::Terse = $Data::Dumper::Terse = 1;
            Data::Dumper::Dumper($self->{$k});
        } || "<huh?>";
        $retval .= "  $k => $v";
    }
    $retval .= $self->stacktrace;
    return $retval;
}



require My::Tests::Below unless caller();
1;

__END__

use Test::More qw(no_plan);
use Test::Group;
use App::CamelPKI::Error;

test "synopsis: basics" => sub {
    my $code = My::Tests::Below->pod_code_snippet("synopsis basic");
    $code =~ s/warn/our \$foo = /g;
    eval $code; die $@ if $@;
    like(our $foo, qr/oops/i);
};

skip_next_test unless eval { require Class::Facet };
test "synopsic: Class::Facet integration" => sub {
    {
        package My::Object;
        sub new { bless {}, shift }
        sub facet { Class::Facet->make("My::Facet", shift) }
        sub nothing { 1 }
    }
    ok(My::Object->new->nothing);

    my $code = My::Tests::Below->pod_code_snippet("synopsis Class::Facet");
    eval $code; die $@ if $@;
    try {
        My::Object->new->facet->nothing;
        fail("should have thrown - Bug in Class::Facet?");
    } catch App::CamelPKI::Error::Privilege with {
        my $E = shift;
        is($E->{-text}, "Facet error");
        is($E->{-method}, "nothing");
    };
};

use Errno qw(ENOENT);
test "App::CamelPKI::Error::IO and automatic decoration" => sub {
    my $file = "/no/such_/file";
    local *BOGON;
    open(BOGON, $file);
    eval My::Tests::Below->pod_code_snippet("App::CamelPKI::Error::IO");
    my $E = $@;
    is($E->{-IOfile}, $file);
    is($E->{-errorcode}, ENOENT);
    like($E->{-error}, qr/no such file|aucun fichier/i);
};

test "stringify" => sub {
    my $less = [];
    my $E = new App::CamelPKI::Error::Internal
        (-text => "strange schmorpz",
         -schmorpz => bless {
                             zoinx => [ "is", $less ],
                             less => $less,
                            }, "Schmorpz");
    my $string = "$E";
    like($E, qr/App::CamelPKI::Error::Internal=strange schmorpz/);
    like($E, qr/strange schmorpz at /);
    like($E, qr/-line => \d+/);
    like($E, qr/bless/);
};