]> git.evergreen-ils.org Git - OpenSRF.git/blob - src/perlmods/OpenSRF/DomainObject/oilsMessage.pm
lots of debuging to find that the zombie loop was broken
[OpenSRF.git] / src / perlmods / OpenSRF / DomainObject / oilsMessage.pm
1 package OpenSRF::DomainObject::oilsMessage;
2 use base 'OpenSRF::DomainObject';
3 use OpenSRF::AppSession;
4 use OpenSRF::DomainObject::oilsResponse qw/:status/;
5 use OpenSRF::Utils::Logger qw/:level/;
6 use warnings; use strict;
7 use OpenSRF::EX qw/:try/;
8
9 =head1 NAME
10
11 OpenSRF::DomainObject::oilsMessage
12
13 =head1
14
15 use OpenSRF::DomainObject::oilsMessage;
16
17 my $msg = OpenSRF::DomainObject::oilsMessage->new( type => 'CONNECT' );
18
19 $msg->payload( $domain_object );
20
21 =head1 ABSTRACT
22
23 OpenSRF::DomainObject::oilsMessage is used internally to wrap data sent
24 between client and server.  It provides the structure needed to authenticate
25 session data, and also provides the logic needed to unwrap session data and 
26 pass this information along to the Application Layer.
27
28 =cut
29
30 my $log = 'OpenSRF::Utils::Logger';
31
32 =head1 METHODS
33
34 =head2 OpenSRF::DomainObject::oilsMessage->type( [$new_type] )
35
36 =over 4
37
38 Used to specify the type of message.  One of
39 B<CONNECT, REQUEST, RESULT, STATUS, ERROR, or DISCONNECT>.
40
41 =back
42
43 =cut
44
45 sub type {
46         my $self = shift;
47         return $self->_attr_get_set( type => shift );
48 }
49
50 =head2 OpenSRF::DomainObject::oilsMessage->api_level( [$new_api_level] )
51
52 =over 4
53
54 Used to specify the api_level of message.  Currently, only api_level C<1> is
55 supported.  This will be used to check that messages are well-formed, and as
56 a hint to the Application as to which version of a method should fulfill a
57 REQUEST message.
58
59 =back
60
61 =cut
62
63 sub api_level {
64         my $self = shift;
65         return $self->_attr_get_set( api_level => shift );
66 }
67
68 =head2 OpenSRF::DomainObject::oilsMessage->threadTrace( [$new_threadTrace] );
69
70 =over 4
71
72 Sets or gets the current message sequence identifier, or thread trace number,
73 for a message.  Useful as a debugging aid, but that's about it.
74
75 =back
76
77 =cut
78
79 sub threadTrace {
80         my $self = shift;
81         return $self->_attr_get_set( threadTrace => shift );
82 }
83
84 =head2 OpenSRF::DomainObject::oilsMessage->update_threadTrace
85
86 =over 4
87
88 Increments the threadTrace component of a message.  This is automatic when
89 using the normal session processing stack.
90
91 =back
92
93 =cut
94
95 sub update_threadTrace {
96         my $self = shift;
97         my $tT = $self->threadTrace;
98
99         $tT ||= 0;
100         $tT++;
101
102         $log->debug("Setting threadTrace to $tT",DEBUG);
103
104         $self->threadTrace($tT);
105
106         return $tT;
107 }
108
109 =head2 OpenSRF::DomainObject::oilsMessage->payload( [$new_payload] )
110
111 =over 4
112
113 Sets or gets the payload of a message.  This should be exactly one object
114 of (sub)type domainObject or domainObjectCollection.
115
116 =back
117
118 =cut
119
120 sub payload {
121         my $self = shift;
122         my $new_pl = shift;
123
124         my ($payload) = $self->getChildrenByTagName('oils:domainObjectCollection') ||
125                                 $self->getChildrenByTagName('oils:domainObject');
126         if ($new_pl) {
127                 $payload = $self->removeChild($payload) if ($payload);
128                 $self->appendChild($new_pl);
129                 return $new_pl unless ($payload);
130         }
131
132         return OpenSRF::DOM::upcast($payload)->upcast if ($payload);
133 }
134
135 =head2 OpenSRF::DomainObject::oilsMessage->handler( $session_id )
136
137 =over 4
138
139 Used by the message processing stack to set session state information from the current
140 message, and then sends control (via the payload) to the Application layer.
141
142 =back
143
144 =cut
145
146 sub handler {
147         my $self = shift;
148         my $session = shift;
149
150         my $mtype = $self->type;
151         my $api_level = $self->api_level || 1;;
152         my $tT = $self->threadTrace;
153
154         $session->last_message_type($mtype);
155         $session->last_message_api_level($api_level);
156         $session->last_threadTrace($tT);
157
158         $log->debug(" Received api_level => [$api_level], MType => [$mtype], ".
159                         "from [".$session->remote_id."], threadTrace[".$self->threadTrace."]", INFO);
160         $log->debug("endpoint => [".$session->endpoint."]", DEBUG);
161         $log->debug("OpenSRF::AppSession->SERVER => [".$session->SERVER()."]", DEBUG);
162
163
164         my $val;
165         if ( $session->endpoint == $session->SERVER() ) {
166                 $val = $self->do_server( $session, $mtype, $api_level, $tT );
167
168         } elsif ($session->endpoint == $session->CLIENT()) {
169                 $val = $self->do_client( $session, $mtype, $api_level, $tT );
170         }
171
172         if( $val ) {
173                 $log->debug("Passing request up to OpenSRF::Application", DEBUG);
174                 return OpenSRF::Application->handler($session, $self->payload);
175         } else {
176                 $log->debug("Request was handled internally", DEBUG);
177         }
178         $log->debug("Returning to ".join('::',(caller)[0,3]), DEBUG);
179
180         return 1;
181
182 }
183
184
185
186 # handle server side message processing
187
188 # !!! Returning 0 means that we don't want to pass ourselves up to the message layer !!!
189 sub do_server {
190         my( $self, $session, $mtype, $api_level, $tT ) = @_;
191
192         # A Server should never receive STATUS messages.  If so, we drop them.
193         # This is to keep STATUS's from dead client sessions from creating new server
194         # sessions which send mangled session exceptions to backends for messages 
195         # that they are not aware of any more.
196         if( $mtype eq 'STATUS' ) { return 0; }
197
198         
199         if ($mtype eq 'DISCONNECT') {
200                 $session->disconnect;
201                 $session->kill_me;
202                 return 0;
203         }
204
205         if ($session->state == $session->CONNECTING()) {
206
207                 # the transport layer thinks this is a new connection. is it?
208                 unless ($mtype eq 'CONNECT') {
209                         $log->error("Connection seems to be mangled: Got $mtype instead of CONNECT");
210
211                         my $res = OpenSRF::DomainObject::oilsBrokenSession->new(
212                                         status => "Connection seems to be mangled: Got $mtype instead of CONNECT",
213                         );
214
215                         $session->status($res);
216                         $session->kill_me;
217                         return 0;
218
219                 }
220                 
221                 my $res = OpenSRF::DomainObject::oilsConnectStatus->new;
222                 $session->status($res);
223                 $session->state( $session->CONNECTED );
224
225                 return 0;
226         }
227
228
229         $log->debug("Passing to Application::handler()", INFO);
230         $log->debug($self->toString(1), DEBUG);
231
232         return 1;
233
234 }
235
236
237 # Handle client side message processing. Return 1 when the the message should be pushed
238 # up to the application layer.  return 0 otherwise.
239 sub do_client {
240
241         my( $self, $session , $mtype, $api_level, $tT) = @_;
242
243
244         if ($mtype eq 'STATUS') {
245
246                 if ($self->payload->statusCode == STATUS_OK) {
247                         $session->state($session->CONNECTED);
248                         $log->debug("We connected successfully to ".$session->app, INFO);
249                         return 0;
250                 }
251
252                 if ($self->payload->statusCode == STATUS_TIMEOUT) {
253                         $session->state( $session->DISCONNECTED );
254                         $session->reset;
255                         $session->push_resend( $session->app_request($self->threadTrace) );
256                         $log->debug("Disconnected because of timeout", WARN);
257                         return 0;
258
259                 } elsif ($self->payload->statusCode == STATUS_REDIRECTED) {
260                         $session->state( $session->DISCONNECTED );
261                         $session->reset;
262                         $session->push_resend( $session->app_request($self->threadTrace) );
263                         $log->debug("Disconnected because of redirect", WARN);
264                         return 0;
265
266                 } elsif ($self->payload->statusCode == STATUS_EXPFAILED) {
267                         $session->state( $session->DISCONNECTED );
268                         $log->debug("Disconnected because of mangled session", WARN);
269                         $session->reset;
270                         $session->push_resend( $session->app_request($self->threadTrace) );
271                         return 0;
272
273                 } elsif ($self->payload->statusCode == STATUS_CONTINUE) {
274                         return 0;
275
276                 } elsif ($self->payload->statusCode == STATUS_COMPLETE) {
277                         my $req = $session->app_request($self->threadTrace);
278                         $req->complete(1) if ($req);
279                         return 0;
280                 }
281
282                 # add more STATUS handling code here (as 'elsif's), for Message layer status stuff
283
284         } elsif ($session->state == $session->CONNECTING()) {
285                 # This should be changed to check the type of response (is it a connectException?, etc.)
286         }
287
288         if( $self->payload and $self->payload->class->isa( "OpenSRF::EX" ) ) { 
289                 $self->payload->throw();
290         }
291
292         if( $self->payload ) {
293                 $log->debug("Passing to OpenSRF::Application::handler()\n" . $self->payload->toString(1), INTERNAL);
294         }
295         $log->debug("oilsMessage passing to Application: " . $self->type." : ".$session->remote_id, INFO );
296
297         return 1;
298
299 }
300
301 1;