File Coverage

blib/lib/Data/Conveyor/Exception/Container.pm
Criterion Covered Total %
statement 31 46 67.3
branch 0 2 0.0
condition 0 12 0.0
subroutine 10 12 83.3
pod 6 6 100.0
total 47 78 60.2


line stmt bran cond sub pod time code
1 1     1   909 use 5.008;
  1         6  
  1         103  
2 1     1   9 use strict;
  1         4  
  1         43  
3 1     1   8 use warnings;
  1         2  
  1         57  
4              
5             package Data::Conveyor::Exception::Container;
6             BEGIN {
7 1     1   34 $Data::Conveyor::Exception::Container::VERSION = '1.103130';
8             }
9             # ABSTRACT: Stage-based conveyor-belt-like ticket handling system
10              
11             # implements a container object.
12 1     1   6 use Data::Miscellany qw/set_push flex_grep/;
  1         9  
  1         66  
13 1     1   6 use parent 'Class::Scaffold::Exception::Container';
  1         2  
  1         9  
14              
15             sub get_disruptive_items {
16 11     11 1 17 my ($self, $ticket) = @_;
17             return
18 11   0     40 grep { !$ticket->ignores_exception($_) && !$_->is_optional } $self->items;
  0         0  
19             }
20              
21             # determines the overall rc of the item's exceptions
22             sub rc {
23 5     5 1 322 my ($self, $ticket, $payload_item) = @_;
24 5         33 my $handler = $self->delegate->make_obj('exception_handler');
25 5         2826 my $rc =
26             $self->delegate->make_obj('value_ticket_rc', $self->delegate->RC_OK);
27             $rc += $handler->rc_for_exception_class($_, $payload_item)
28 5         520 for $self->get_disruptive_items($ticket);
29 5         1048 $rc;
30             }
31              
32             # determines the overall status of the item's exceptions
33             sub status {
34 6     6 1 63 my ($self, $ticket, $payload_item) = @_;
35 6         17 my $handler = $self->delegate->make_obj('exception_handler');
36 6         447 my $status =
37             $self->delegate->make_obj('value_ticket_status',
38             $self->delegate->TS_RUNNING);
39              
40             # Add the status only for exceptions that have an rc that's equal to the
41             # ticket's rc -- assuming the ticket's rc has been calculated before, of
42             # course. For an explanation, assume the following situation:
43             #
44             # A ticket has recorded two exceptions: One with RC_OK and TS_HOLD, the
45             # other with RC_ERROR and TS_RUNNING. If we just added rc's and stati
46             # independently of each other, we'd end up with RC_ERROR and TS_HOLD. This
47             # is not what we want. The ticket should go on hold -- for manual
48             # inspection -- only if there weren't more serious issues. After all, we
49             # don't want to waste a person's time only to later declare that the
50             # ticket has serious problems anyway and to abort processing.
51             #
52             # What we want to end up with in the above situation is RC_ERROR and
53             # TS_RUNNING so that the ticket is aborted. We do this by applying the
54             # stati of only those exceptions that caused the ticket's overall rc.
55             #
56             # In our example, that's the exception that caused the RC_ERROR. Since
57             # that exception has TS_RUNNING, that's the status we end up with. Which
58             # is nice.
59             $status += $handler->status_for_exception_class($_, $payload_item)
60 6         631 for $self->filter_exceptions_by_rc($ticket, $ticket->rc);
61 6         82 $status;
62             }
63              
64             sub filter_exceptions_by_rc {
65 6     6 1 189 my ($self, $ticket, @filter) = @_;
66 6         19 my $handler = $self->delegate->make_obj('exception_handler');
67 6         420 grep { flex_grep($handler->rc_for_exception_class($_), @filter) }
  0            
68             $self->get_disruptive_items($ticket);
69             }
70              
71             sub filter_exceptions_by_status {
72 0     0 1   my ($self, $ticket, @filter) = @_;
73 0           my $handler = $self->delegate->make_obj('exception_handler');
74 0           grep { flex_grep($handler->status_for_exception_class($_), @filter) }
  0            
75             $self->get_disruptive_items($ticket);
76             }
77              
78             # Transactions ask their item (which asks their exception container) whether
79             # it has problematic exceptions that should cause the transaction's status to
80             # be set to $self->delegate->TXS_ERROR. See Data::Conveyor::Ticket::Transaction.
81             #
82             # Ordinarily, exceptions with an rc of RC_ERROR or RC_INTERNAL_ERROR are
83             # considered problematic. The exception's status can also have an effect on
84             # the tx's status. For example, in NICAT, an ::Onwait exception will have
85             # RC_OK and TS_HOLD, which should leave the tx on TXS_RUNNING in non-mass
86             # tickets (i.e., the legal department will decide whether to shift the ticket
87             # to the delegation stage). Same for RC_MANUAL. I.e., set the tx status only
88             # to TXS_ERROR if the exception indicates an RC_ERROR or an RC_INTERNAL_ERROR.
89             # In mass tickets, we don't want to hold up the ticket - just set the
90             # corresponding exception to TXS_ERROR - but only for optional exceptions.
91             sub has_problematic_exceptions {
92 0     0 1   my ($self, $ticket, $payload_item) = @_;
93 0           my $handler = $self->delegate->make_obj('exception_handler');
94              
95             # Don't use get_disruptive_items() because that would weed out exceptions
96             # marked with is_optional() as well. But even optional exceptions should
97             # cause a TXS_ERROR, if they aren't RC_OK.
98 0           my @exceptions =
99 0           grep { !$ticket->ignores_exception($_) } $self->items;
100 0           for my $exception (@exceptions) {
101 0           my $rc = $handler->rc_for_exception_class($exception, $payload_item);
102 0           my $status = $handler->status_for_exception_class($exception);
103 0 0 0       return 1
      0        
      0        
104             if $rc eq $self->delegate->RC_ERROR
105             || $rc eq $self->delegate->RC_INTERNAL_ERROR
106             || !(
107             $status eq $self->delegate->TS_RUNNING
108             || $status eq $self->delegate->TS_HOLD
109             || $status eq $self->delegate->TS_PENDING
110             );
111             }
112 0           return 0;
113             }
114             1;
115              
116              
117             __END__