File Coverage

blib/lib/Connector/Tee.pm
Criterion Covered Total %
statement 64 70 91.4
branch 11 14 78.5
condition 4 5 80.0
subroutine 9 9 100.0
pod 3 3 100.0
total 91 101 90.1


line stmt bran cond sub pod time code
1             package Connector::Tee;
2              
3 1     1   7 use strict;
  1         2  
  1         29  
4 1     1   5 use warnings;
  1         2  
  1         25  
5 1     1   7 use English;
  1         2  
  1         7  
6 1     1   353 use Moose;
  1         3  
  1         9  
7 1     1   6016 use Data::Dumper;
  1         2  
  1         638  
8              
9             extends 'Connector::Proxy';
10              
11             # Location must not be used
12             has '+LOCATION' => ( required => 0, 'isa' => 'Undef' );
13              
14             has branches => (
15             is => 'rw',
16             isa => 'ArrayRef',
17             );
18              
19             has accept => (
20             is => 'rw',
21             isa => 'Str',
22             default => '',
23             );
24              
25             sub get {
26              
27 4     4 1 7 my $self = shift;
28 4         7 my $location = shift;
29 4         6 my @args = @_;
30              
31 4         82 my $accept = $self->accept();
32 4         77 $self->log()->trace('initialize tee');
33              
34 4         24 foreach my $child ( @{$self->branches()} ) {
  4         80  
35              
36 8         154 $self->log()->debug('query child ' . $child );
37              
38 8         219 my @prefix = $self->conn()->_build_path([ 'nodes', $child, @{$location}] );
  8         26  
39              
40 8         205 my $result = $self->conn()->get( \@prefix , \@args );
41              
42 8   100     149 $self->log()->trace('raw result ' . ($result // 'undef'));
43              
44 8 100       149 if (!defined $result) {
    100          
    100          
45             } elsif (!$accept) {
46 2         14 return $result;
47             } elsif ($result =~ qr/$accept/) {
48 2         36 $self->log()->debug('result accepted (scalar)');
49 2         59 return $result;
50             } else {
51 3         58 $self->log()->debug('result mismatches pattern (scalar)');
52 3         63 $self->log()->trace($accept . ' - ' . $result);
53             }
54             }
55              
56 0         0 return $self->_node_not_exists( $location );
57              
58             }
59              
60             sub get_hash {
61              
62 1     1 1 3 my $self = shift;
63 1         2 my $location = shift;
64 1         2 my @args = @_;
65              
66 1         22 my $accept = $self->accept();
67 1         18 $self->log()->trace('initialize tee');
68              
69 1         6 foreach my $child ( @{$self->branches()} ) {
  1         26  
70              
71 2         51 $self->log()->debug('query child ' . $child );
72              
73 2         59 my @prefix = $self->conn()->_build_path([ 'nodes', $child, @{$location}] );
  2         20  
74              
75 2         53 my $result = $self->conn()->get_hash( \@prefix , \@args );
76              
77 2   66     45 $self->log()->trace('raw result ' . ($result // Dumper $result));
78              
79 2 100       51 if (!defined $result) {
    50          
    0          
80              
81             } elsif (!$accept) {
82 1         7 return $result;
83 0         0 } elsif (keys %{$result}) {
84 0         0 $self->log()->debug('result accepted (hash)');
85 0         0 return $result;
86             }
87             }
88              
89 0         0 return $self->_node_not_exists( $location );
90             }
91              
92             sub get_list {
93              
94              
95 1     1 1 2 my $self = shift;
96 1         2 my $location = shift;
97 1         2 my @args = @_;
98              
99 1         18 $self->log()->trace('initialize tee');
100              
101 1         6 foreach my $child ( @{$self->branches()} ) {
  1         23  
102              
103 2         38 $self->log()->debug('query child ' . $child );
104              
105 2         63 my @prefix = $self->conn()->_build_path([ 'nodes', $child, @{$location}] );
  2         8  
106              
107 2         51 my @result = $self->conn()->get_list( \@prefix , \@args );
108              
109 2         39 $self->log()->trace('raw result ' . (Dumper \@result));
110              
111 2 100       120 if (@result) {
112 1         24 $self->log()->debug('result accepted (list)');
113 1         16 return @result;
114             }
115             }
116              
117 0           return $self->_node_not_exists( $location );
118              
119             }
120              
121              
122 1     1   7 no Moose;
  1         2  
  1         4  
123             __PACKAGE__->meta->make_immutable;
124              
125             1;
126             __END__
127              
128             =head1 Name
129              
130             Connector::Tee
131              
132             =head1 Description
133              
134             This connector can be used to search for a value over multiple branches
135             in a way that is transparent to the caller.
136              
137             =head1 Configurarion Example
138              
139             class: Connector::Tee
140             accept: "\\A[a-zA-Z]+\\z"
141             branches:
142             - static
143             - conn1
144             - conn2
145              
146             nodes:
147             static:
148             test1: NO
149             test2: YES
150             test3: 0
151             conn1@: connector:connectors.conn1
152             conn2@: connector:connectors.conn2
153              
154             If the connector with the above configuration is called with I<get('test1')>,
155             the request is dispatched to nodes.static.test1 which evaluates to I<NO>
156             and is returned as the overall result.
157              
158             If you call I<get('test3')>, the result is NOT I<0> as this does not match
159             the regex given as accept pattern! The request is therefore resend to
160             nodes.conn1.test3 which is revolved to another connector call. In case
161             the result of this connector does also not match the pattern (or is empty),
162             the same request is send to nodes.conn2.test3.
163              
164             For the scalar I<get> call, the value given to accept is evaluated as a
165             case-sensitive regex pattern using qr// internally. If you set accept to
166             the empty string, any defined value is accepted.
167              
168             For I<get_hash>, an empty value for accept will let the empty hash pass,
169             if accept is set to any true value, only non-empty hashes are accepted.
170              
171             For I<get_list>, accept is ignored and only non-empty lists are accepted.
172