File Coverage

lib/UR/Service/RPC/Executer.pm
Criterion Covered Total %
statement 54 70 77.1
branch 14 24 58.3
condition 1 3 33.3
subroutine 9 12 75.0
pod 4 4 100.0
total 82 113 72.5


line stmt bran cond sub pod time code
1             package UR::Service::RPC::Executer;
2              
3 1     1   39 use UR;
  1         1  
  1         12  
4              
5 1     1   4 use strict;
  1         1  
  1         20  
6 1     1   3 use warnings;
  1         2  
  1         299  
7             our $VERSION = "0.46"; # UR $VERSION;
8              
9             class UR::Service::RPC::Executer {
10             has => [
11             fh => { is => 'IO::Handle', doc => 'handle we will send and receive messages across' },
12             ],
13             has_optional => [
14             use_sigio => { is => 'Boolean', default_value => 0 },
15             ],
16             is_transactional => 0,
17             };
18              
19              
20             sub create {
21 1     1 1 583 my $class = shift;
22              
23 1         9 my $obj = $class->SUPER::create(@_);
24 1 50       4 return unless $obj;
25              
26 1 50       8 if ($obj->use_sigio) {
27 0         0 UR::Service::RPC->enable_sigio_processing($obj);
28             }
29              
30             $obj->create_subscription(method => 'use_sigio',
31             callback => sub {
32 0     0   0 my ($changed_object, $changed_property, $old_value, $new_value) = @_;
33 0 0       0 return 1 if ($old_value == $new_value);
34              
35 0 0       0 if ($new_value) {
36 0         0 UR::Service::RPC->enable_sigio_processing($obj);
37             } else {
38 0         0 UR::Service::RPC->disable_sigio_processing($obj);
39             }
40 1         12 });
41 1         4 return $obj;
42             }
43              
44              
45             # sub classes can override this
46             # If they're going to reject the request, $msg should be modified in place
47             # with a return value and exception, because we're going to return it right back
48             # to the requester
49             sub authenticate {
50             # my($self,$msg) = @_;
51 0     0 1 0 return 1;
52             }
53              
54             # Process one message off of the file handle
55             sub execute {
56 5     5 1 6 my $self = shift;
57            
58 5         23 my $msg = UR::Service::RPC::Message->recv($self->fh);
59 5 50       29 unless ($msg) {
60             # The other end probably closed the socket
61 0         0 $self->close_connection();
62 0         0 return 1;
63             }
64              
65 5         13 my $response;
66              
67 5 100       27 if ($self->authenticate($msg)) {
68              
69 4   33     35 my $target_class = $msg->target_class || ref($self);
70 4         9 my $method = $msg->method_name;
71 4         16 my @arglist = $msg->param_list;
72 4         14 my $wantarray = $msg->wantarray;
73 4         15 my %resp_msg_args = ( target_class => $target_class,
74             method_name => $method,
75             params => \@arglist,
76             'wantarray' => $wantarray,
77             fh => $self->fh );
78              
79              
80 4         10 my $method_name = join('::',$target_class, $method);
81 4 100       16 if ($wantarray) {
    50          
82 1         1 my @retval;
83 1     1   4 eval { no strict 'refs'; @retval = &{$method_name}(@arglist); };
  1         1  
  1         58  
  1         2  
  1         2  
  1         6  
84 1 50       17 $resp_msg_args{'return_values'} = \@retval unless ($@);
85             } elsif (defined $wantarray) {
86 3         3 my $retval;
87 1     1   3 eval { no strict 'refs'; no warnings; $retval = &{$method_name}(@arglist); };
  1     1   1  
  1         40  
  1         4  
  1         1  
  1         59  
  3         5  
  3         4  
  3         28  
88 3 100       30 $resp_msg_args{'return_values'} = [$retval] unless ($@);
89             } else {
90 1     1   4 eval { no strict 'refs'; &{$method_name}(@arglist); };
  1         1  
  1         163  
  0         0  
  0         0  
  0         0  
91             }
92 4 100       13 $resp_msg_args{'exception'} = $@ if $@;
93 4         21 $response = UR::Service::RPC::Message->create(%resp_msg_args);
94              
95             } else {
96             # didn't authenticate.
97 1         5 $response = $msg;
98             }
99              
100 5 50       28 unless ($response->send()) {
101 0         0 $self->fh->close();
102             }
103              
104 5         34 return 1;
105             }
106              
107              
108              
109             sub close_connection {
110 0     0 1   my $self = shift;
111            
112 0           $self->use_sigio(0);
113              
114 0           $self->fh->close();
115             }
116              
117            
118             1;
119              
120              
121             =pod
122              
123             =head1 NAME
124              
125             UR::Service::RPC::Executer - Base class for modules implementing RPC executers
126              
127             =head1 DESCRIPTION
128              
129             This class is an abstract base class used to implement RPC executers. That
130             is, modules meant to have their methods called from another process, and have
131             the results passed back to the original caller. The communication happens
132             over a read-write filehandle such as a socket by passing L
133             objects back and forth.
134              
135             Executors are subordinate to a L object which
136             handles decoding the message passed over the socket, calling the method
137             on the correct executor in the right context, and returning the result
138             back through the file handle.
139              
140             =head1 PROPERTIES
141              
142             =over 4
143              
144             =item fh => IO::Handle
145              
146             File handle messages are received on and responses are sent to
147              
148             =item use_sigio => Boolean
149              
150             If true, the Server will set up a callback on the IO signal to handle
151             execution, so the Server does not need to block in loop().
152              
153             =back
154              
155             =head1 METHODS
156              
157             =over 4
158              
159             =item authenticate
160              
161             $bool = $exec->authenticate($msg);
162              
163             This is called by execute() after the message object is deserialized from the
164             filehandle. The default implementation just returns true. Subclasses can
165             override this to examine the UR::Service::RPC::Message object and return
166             true or fale whether it should allow or disallow execution. If authentication
167             fails, the Executor should modify the Message object in-place with a proper
168             return value and exception.
169              
170             =item execute
171              
172             $exec->execute();
173              
174             Called when the Server detects data is available to read on its file handle.
175             It deserializes the message and calls authenticate. If authentication fails,
176             it immediately passes the message object back to the caller.
177              
178             If authentication succeeds, it calls the appropriate method in the Executor
179             package, and creates a new Message object with the return value to pass back
180             to the caller.
181              
182             =item close_connection
183              
184             $exec->close_connection();
185              
186             Called by execute() when it detects that the file handle has closed.
187              
188             =back
189              
190             Derived classes should define additional methods that then become callable
191             by execute().
192              
193             =head1 SEE ALSO
194              
195             UR::Service::RPC::Server, UR::Service::RPC::Message
196              
197             =cut
198