]> git.evergreen-ils.org Git - OpenSRF.git/blob - src/perlmods/OpenSRF/Application.pm
1adc67d8ab8fb599f02f88ef591fb79d658aba76
[OpenSRF.git] / src / perlmods / OpenSRF / Application.pm
1 package OpenSRF::Application;
2 use base qw/OpenSRF/;
3 use OpenSRF::AppSession;
4 use OpenSRF::DomainObject::oilsMethod;
5 use OpenSRF::DomainObject::oilsResponse qw/:status/;
6 use OpenSRF::Utils::Logger qw/:level/;
7 use Time::HiRes qw/time/;
8 use vars qw/$_app $log %_METHODS/;
9 use OpenSRF::EX qw/:try/;
10 use strict;
11 use warnings;
12
13 $log = 'OpenSRF::Utils::Logger';
14
15 our $in_request = 0;
16 our @pending_requests;
17
18 sub application_implementation {
19         my $self = shift;
20         my $app = shift;
21
22         if (defined $app) {
23                 $_app = $app;
24                 eval "use $_app;";
25                 if( $@ ) {
26                         $log->error( "Error loading application_implementation: $app -> $@", ERROR);
27                 }
28
29         }
30
31         return $_app;
32 }
33
34 sub handler {
35         my ($self, $session, $app_msg) = @_;
36
37         if( ! $app_msg ) {
38                 return 0;  # error?
39         }
40
41         $log->debug( "In Application::handler()", DEBUG );
42
43         my $app = $self->application_implementation;
44
45         if( $app ) {
46                 $log->debug( "Application is $app", DEBUG);
47         }
48         $log->debug( "Message is ".$app_msg->toString(1), INTERNAL);
49
50
51         if ($session->last_message_type eq 'REQUEST') {
52                 $log->debug( "We got a REQUEST: ". $app_msg->method, INFO );
53
54                 my $method_name = $app_msg->method;
55                 $log->debug( " * Looking up $method_name inside $app", DEBUG);
56
57                 my $method_proto = $session->last_message_protocol;
58                 $log->debug( " * Method API Level [$method_proto]", DEBUG);
59
60                 my $coderef = $app->method_lookup( $method_name, $method_proto );
61
62                 unless ($coderef) {
63                         $session->status( OpenSRF::DomainObject::oilsMethodException->new() );
64                         return 1;
65                 }
66
67                 $log->debug( " (we got coderef $coderef", DEBUG);
68
69                 unless ($session->continue_request) {
70                         $session->status(
71                                 OpenSRF::DomainObject::oilsConnectStatus->new(
72                                                 statusCode => STATUS_REDIRECTED(),
73                                                 status => 'Disconnect on max requests' ) );
74                         $session->kill_me;
75                         return 1;
76                 }
77
78                 if (ref $coderef) {
79                         my @args = $app_msg->params;
80                         my $appreq = OpenSRF::AppRequest->new( $session );
81
82                         $log->debug( "in_request = $in_request : [" . $appreq->threadTrace."]", DEBUG );
83                         if( $in_request ) {
84                                 $log->debug( "Pushing onto pending requests: " . $appreq->threadTrace, DEBUG );
85                                 push @pending_requests, [ $appreq, \@args, $coderef ]; 
86                                 return 1;
87                         }
88
89
90                         $in_request++;
91
92                         $log->debug( "Executing coderef for {$method_name -> ".join(', ', @args)."}", INTERNAL );
93
94                         my $resp;
95                         try {
96                                 my $start = time();
97                                 $resp = $coderef->run( $appreq, @args); 
98                                 my $time = sprintf '%.3f', time() - $start;
99                                 $log->debug( "Method duration for {$method_name -> ".join(', ', @args)."}:  ". $time, DEBUG );
100                                 if( ref( $resp ) ) {
101                                         $log->debug( "Calling respond_complete: ". $resp->toString(), INTERNAL );
102                                         $appreq->respond_complete( $resp );
103                                 } else {
104                                         $appreq->status( OpenSRF::DomainObject::oilsConnectStatus->new(
105                                                                 statusCode => STATUS_COMPLETE(),
106                                                                 status => 'Request Complete' ) );
107                                 }
108                         } catch Error with {
109                                 my $e = shift;
110                                 $e = $e->{-text} || $e->message if (ref $e);
111                                 my $sess_id = $session->session_id;
112                                 $session->status(
113                                         OpenSRF::DomainObject::oilsMethodException->new(
114                                                         statusCode      => STATUS_INTERNALSERVERERROR(),
115                                                         status          => " *** Call to [$method_name] failed for session ".
116                                                                            "[$sess_id], thread trace [".$appreq->threadTrace."]:\n".$e
117                                         )
118                                 );
119                         };
120
121
122
123                         # ----------------------------------------------
124
125
126                         # XXX may need this later
127                         # $_->[1] = 1 for (@OpenSRF::AppSession::_CLIENT_CACHE);
128
129                         $in_request--;
130
131                         $log->debug( "Pending Requests: " . scalar(@pending_requests), INTERNAL );
132
133                         # cycle through queued requests
134                         while( my $aref = shift @pending_requests ) {
135                                 $in_request++;
136                                 my $resp;
137                                 try {
138                                         my $start = time;
139                                         my $response = $aref->[2]->run( $aref->[0], @{$aref->[1]} );
140                                         my $time = sprintf '%.3f', time - $start;
141                                         $log->debug( "Method duration for {[".$aref->[2]->name." -> ".join(', ',@{$aref->[1]}).'}:  '.$time, DEBUG );
142
143                                         $appreq = $aref->[0];   
144                                         if( ref( $response ) ) {
145                                                 $log->debug( "Calling respond_complete: ". $response->toString(), INTERNAL );
146                                                 $appreq->respond_complete( $response );
147                                         } else {
148                                                 $appreq->status( OpenSRF::DomainObject::oilsConnectStatus->new(
149                                                                         statusCode => STATUS_COMPLETE(),
150                                                                         status => 'Request Complete' ) );
151                                         }
152                                         $log->debug( "Executed: " . $appreq->threadTrace, DEBUG );
153                                 } catch Error with {
154                                         my $e = shift;
155                                         $session->status(
156                                                 OpenSRF::DomainObject::oilsMethodException->new(
157                                                                 statusCode => STATUS_INTERNALSERVERERROR(),
158                                                                 status => "Call to [".$aref->[2]->name."] faild:  ".$e->{-text}
159                                                 )
160                                         );
161                                 };
162                                 $in_request--;
163                         }
164
165                         return 1;
166                 } 
167                 my $res = OpenSRF::DomainObject::oilsMethodException->new;
168                 $session->send('ERROR', $res);
169                 $session->kill_me;
170                 return 1;
171
172         } else {
173                 $log->debug( "Pushing ". $app_msg->toString ." onto queue", INTERNAL );
174                 $session->push_queue([ $app_msg, $session->last_threadTrace ]);
175         }
176
177         $session->last_message_type('');
178         $session->last_message_protocol('');
179
180         return 1;
181 }
182
183 sub register_method {
184         my $self = shift;
185         my $app = ref($self) || $self;
186         my %args = @_;
187
188         throw OpenSRF::DomainObject::oilsMethodException unless ($args{method});
189         
190         $args{protocol} ||= 1;
191         $args{api_name} ||= $app . '.' . $args{method};
192         $args{code} ||= \&{$app . '::' . $args{method}};
193         
194         $_METHODS{$args{api_name}} = bless \%args => $app;
195 }
196
197
198 sub method_lookup {             
199         my $self = shift;
200         my $method = shift;
201         my $proto = shift;
202
203         my $class = ref($self) || $self;
204
205         $log->debug("Specialized lookup of [$method] in [$class]", INTERNAL);
206
207         if (exists $_METHODS{$method}) {
208                 return $_METHODS{$method} if ($_METHODS{$method}{protocol} == $proto);
209         }               
210
211         return undef; 
212 }
213
214 sub run {
215         my $self = shift;
216         $self->{code}->($self, @_);
217 }
218
219 1;