1 package OpenSRF::DomainObject::oilsMessage;
2 use OpenSRF::Utils::JSON;
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/;
10 OpenSRF::Utils::JSON->register_class_hint(hint => 'osrfMessage', name => 'OpenSRF::DomainObject::oilsMessage', type => 'hash');
14 return OpenSRF::Utils::JSON->perl2JSON($self);
19 my $class = ref($self) || $self;
22 return bless \%args => $class;
28 OpenSRF::DomainObject::oilsMessage
32 use OpenSRF::DomainObject::oilsMessage;
34 my $msg = OpenSRF::DomainObject::oilsMessage->new( type => 'CONNECT' );
36 $msg->payload( $domain_object );
40 OpenSRF::DomainObject::oilsMessage is used internally to wrap data sent
41 between client and server. It provides the structure needed to authenticate
42 session data, and also provides the logic needed to unwrap session data and
43 pass this information along to the Application Layer.
47 my $log = 'OpenSRF::Utils::Logger';
51 =head2 OpenSRF::DomainObject::oilsMessage->type( [$new_type] )
55 Used to specify the type of message. One of
56 B<CONNECT, REQUEST, RESULT, STATUS, ERROR, or DISCONNECT>.
65 $self->{type} = $val if (defined $val);
69 =head2 OpenSRF::DomainObject::oilsMessage->api_level( [$new_api_level] )
73 Used to specify the api_level of message. Currently, only api_level C<1> is
74 supported. This will be used to check that messages are well-formed, and as
75 a hint to the Application as to which version of a method should fulfill a
85 $self->{api_level} = $val if (defined $val);
86 return $self->{api_level};
89 =head2 OpenSRF::DomainObject::oilsMessage->sender_locale( [$locale] );
93 Sets or gets the current message locale hint. Useful for telling the
94 server how you see the world.
103 $self->{locale} = $val if (defined $val);
104 return $self->{locale};
107 =head2 OpenSRF::DomainObject::oilsMessage->sender_tz( [$tz] );
111 Sets or gets the current message tz. Useful for telling the
112 server how you see the world.
121 $self->{tz} = $val if (defined $val);
125 =head2 OpenSRF::DomainObject::oilsMessage->sender_ingress( [$ingress] );
129 Sets or gets the current message ingress. Useful for telling the
130 server how you entered the opensrf network.
139 $self->{ingress} = $val if $val;
140 return $self->{ingress};
143 =head2 OpenSRF::DomainObject::oilsMessage->threadTrace( [$new_threadTrace] );
147 Sets or gets the current message sequence identifier, or thread trace number,
148 for a message. Useful as a debugging aid, but that's about it.
157 $self->{threadTrace} = $val if (defined $val);
158 return $self->{threadTrace};
161 =head2 OpenSRF::DomainObject::oilsMessage->update_threadTrace
165 Increments the threadTrace component of a message. This is automatic when
166 using the normal session processing stack.
172 sub update_threadTrace {
174 my $tT = $self->threadTrace;
179 $log->debug("Setting threadTrace to $tT",DEBUG);
181 $self->threadTrace($tT);
186 =head2 OpenSRF::DomainObject::oilsMessage->payload( [$new_payload] )
190 Sets or gets the payload of a message. This should be exactly one object
191 of (sub)type domainObject or domainObjectCollection.
200 $self->{payload} = $val if (defined $val);
201 return $self->{payload};
204 =head2 OpenSRF::DomainObject::oilsMessage->handler( $session_id )
208 Used by the message processing stack to set session state information from the current
209 message, and then sends control (via the payload) to the Application layer.
219 my $mtype = $self->type;
220 my $tz = $self->sender_tz || '';
221 my $locale = $self->sender_locale || '';
222 my $ingress = $self->sender_ingress || '';
223 my $api_level = $self->api_level || 1;
224 my $tT = $self->threadTrace;
226 $log->debug("Message locale is $locale; ingress = $ingress; tz = $tz", DEBUG);
228 $session->last_message_type($mtype);
229 $session->last_message_api_level($api_level);
230 $session->last_threadTrace($tT);
231 $session->session_locale($locale);
233 $log->debug(" Received api_level => [$api_level], MType => [$mtype], ".
234 "from [".$session->remote_id."], threadTrace[".$self->threadTrace."]");
237 if ( $session->endpoint == $session->SERVER() ) {
238 $val = $self->do_server( $session, $mtype, $api_level, $tT );
240 } elsif ($session->endpoint == $session->CLIENT()) {
241 $tz = undef; # Client should not adopt the TZ of the server
242 $val = $self->do_client( $session, $mtype, $api_level, $tT );
246 local $ENV{TZ} = $tz || $ENV{TZ}; # automatic revert at the end of this scope
248 return OpenSRF::Application->handler($session, $self->payload);
250 $log->debug("Request was handled internally", DEBUG);
259 # handle server side message processing
261 # !!! Returning 0 means that we don't want to pass ourselves up to the message layer !!!
263 my( $self, $session, $mtype, $api_level, $tT ) = @_;
265 # A Server should never receive STATUS or RESULT messages. If so, we drop them.
266 # This is to keep STATUS/RESULT's from dead client sessions from creating new server
267 # sessions which send mangled session exceptions to backends for messages
268 # that they are not aware of any more.
269 if( $mtype eq 'STATUS' or $mtype eq 'RESULT' ) { return 0; }
272 if ($mtype eq 'DISCONNECT') {
273 $session->disconnect;
278 if ($session->state == $session->CONNECTING()) {
280 if($mtype ne "CONNECT" and $session->stateless) {
281 return 1; #pass the message up the stack
284 # the transport layer thinks this is a new connection. is it?
285 unless ($mtype eq 'CONNECT') {
286 $log->error("Connection seems to be mangled: Got $mtype instead of CONNECT");
288 my $res = OpenSRF::DomainObject::oilsBrokenSession->new(
289 status => "Connection seems to be mangled: Got $mtype instead of CONNECT",
292 $session->status($res);
298 my $res = OpenSRF::DomainObject::oilsConnectStatus->new;
299 $session->status($res);
300 $session->state( $session->CONNECTED );
311 # Handle client side message processing. Return 1 when the the message should be pushed
312 # up to the application layer. return 0 otherwise.
315 my( $self, $session , $mtype, $api_level, $tT) = @_;
318 if ($mtype eq 'STATUS') {
320 if ($self->payload->statusCode == STATUS_OK) {
321 $session->state($session->CONNECTED);
322 $log->debug("We connected successfully to ".$session->app);
326 if ($self->payload->statusCode == STATUS_TIMEOUT) {
327 $session->state( $session->DISCONNECTED );
330 $session->push_resend( $session->app_request($self->threadTrace) );
331 $log->debug("Disconnected because of timeout");
334 } elsif ($self->payload->statusCode == STATUS_REDIRECTED) {
335 $session->state( $session->DISCONNECTED );
338 $session->push_resend( $session->app_request($self->threadTrace) );
339 $log->debug("Disconnected because of redirect", WARN);
342 } elsif ($self->payload->statusCode == STATUS_EXPFAILED) {
343 $session->state( $session->DISCONNECTED );
344 $log->debug("Disconnected because of mangled session", WARN);
346 $session->push_resend( $session->app_request($self->threadTrace) );
349 } elsif ($self->payload->statusCode == STATUS_CONTINUE) {
350 $session->reset_request_timeout($self->threadTrace);
353 } elsif ($self->payload->statusCode == STATUS_COMPLETE) {
354 my $req = $session->app_request($self->threadTrace);
355 $req->complete(1) if ($req);
359 # add more STATUS handling code here (as 'elsif's), for Message layer status stuff
361 #$session->state( $session->DISCONNECTED() );
364 } elsif ($session->state == $session->CONNECTING()) {
365 # This should be changed to check the type of response (is it a connectException?, etc.)
368 if( $self->payload and $self->payload->isa( "ERROR" ) ) {
369 if ($session->raise_remote_errors) {
370 $self->payload->throw();
374 $log->debug("oilsMessage passing to Application: " . $self->type." : ".$session->remote_id );