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/;
9 OpenSRF::Utils::JSON->register_class_hint(hint => 'osrfMessage', name => 'OpenSRF::DomainObject::oilsMessage', type => 'hash');
13 return OpenSRF::Utils::JSON->perl2JSON($self);
18 my $class = ref($self) || $self;
20 return bless \%args => $class;
26 OpenSRF::DomainObject::oilsMessage
30 use OpenSRF::DomainObject::oilsMessage;
32 my $msg = OpenSRF::DomainObject::oilsMessage->new( type => 'CONNECT' );
34 $msg->payload( $domain_object );
38 OpenSRF::DomainObject::oilsMessage is used internally to wrap data sent
39 between client and server. It provides the structure needed to authenticate
40 session data, and also provides the logic needed to unwrap session data and
41 pass this information along to the Application Layer.
45 my $log = 'OpenSRF::Utils::Logger';
49 =head2 OpenSRF::DomainObject::oilsMessage->type( [$new_type] )
53 Used to specify the type of message. One of
54 B<CONNECT, REQUEST, RESULT, STATUS, ERROR, or DISCONNECT>.
63 $self->{type} = $val if (defined $val);
67 =head2 OpenSRF::DomainObject::oilsMessage->api_level( [$new_api_level] )
71 Used to specify the api_level of message. Currently, only api_level C<1> is
72 supported. This will be used to check that messages are well-formed, and as
73 a hint to the Application as to which version of a method should fulfill a
83 $self->{api_level} = $val if (defined $val);
84 return $self->{api_level};
87 =head2 OpenSRF::DomainObject::oilsMessage->sender_locale( [$locale] );
91 Sets or gets the current message locale hint. Useful for telling the
92 server how you see the world.
101 $self->{locale} = $val if (defined $val);
102 return $self->{locale};
105 =head2 OpenSRF::DomainObject::oilsMessage->sender_ingress( [$ingress] );
109 Sets or gets the current message ingress. Useful for telling the
110 server how you entered the opensrf network.
119 $self->{ingress} = $val if $val;
120 return $self->{ingress};
123 =head2 OpenSRF::DomainObject::oilsMessage->threadTrace( [$new_threadTrace] );
127 Sets or gets the current message sequence identifier, or thread trace number,
128 for a message. Useful as a debugging aid, but that's about it.
137 $self->{threadTrace} = $val if (defined $val);
138 return $self->{threadTrace};
141 =head2 OpenSRF::DomainObject::oilsMessage->update_threadTrace
145 Increments the threadTrace component of a message. This is automatic when
146 using the normal session processing stack.
152 sub update_threadTrace {
154 my $tT = $self->threadTrace;
159 $log->debug("Setting threadTrace to $tT",DEBUG);
161 $self->threadTrace($tT);
166 =head2 OpenSRF::DomainObject::oilsMessage->payload( [$new_payload] )
170 Sets or gets the payload of a message. This should be exactly one object
171 of (sub)type domainObject or domainObjectCollection.
180 $self->{payload} = $val if (defined $val);
181 return $self->{payload};
184 =head2 OpenSRF::DomainObject::oilsMessage->handler( $session_id )
188 Used by the message processing stack to set session state information from the current
189 message, and then sends control (via the payload) to the Application layer.
199 my $mtype = $self->type;
200 my $locale = $self->sender_locale || '';
201 my $ingress = $self->sender_ingress || '';
202 my $api_level = $self->api_level || 1;
203 my $tT = $self->threadTrace;
205 $log->debug("Message locale is $locale; ingress = $ingress", DEBUG);
207 $session->last_message_type($mtype);
208 $session->last_message_api_level($api_level);
209 $session->last_threadTrace($tT);
210 $session->session_locale($locale);
212 $log->debug(" Received api_level => [$api_level], MType => [$mtype], ".
213 "from [".$session->remote_id."], threadTrace[".$self->threadTrace."]");
216 if ( $session->endpoint == $session->SERVER() ) {
217 $val = $self->do_server( $session, $mtype, $api_level, $tT );
219 } elsif ($session->endpoint == $session->CLIENT()) {
220 $val = $self->do_client( $session, $mtype, $api_level, $tT );
224 return OpenSRF::Application->handler($session, $self->payload);
226 $log->debug("Request was handled internally", DEBUG);
235 # handle server side message processing
237 # !!! Returning 0 means that we don't want to pass ourselves up to the message layer !!!
239 my( $self, $session, $mtype, $api_level, $tT ) = @_;
241 # A Server should never receive STATUS or RESULT messages. If so, we drop them.
242 # This is to keep STATUS/RESULT's from dead client sessions from creating new server
243 # sessions which send mangled session exceptions to backends for messages
244 # that they are not aware of any more.
245 if( $mtype eq 'STATUS' or $mtype eq 'RESULT' ) { return 0; }
248 if ($mtype eq 'DISCONNECT') {
249 $session->disconnect;
254 if ($session->state == $session->CONNECTING()) {
256 if($mtype ne "CONNECT" and $session->stateless) {
257 return 1; #pass the message up the stack
260 # the transport layer thinks this is a new connection. is it?
261 unless ($mtype eq 'CONNECT') {
262 $log->error("Connection seems to be mangled: Got $mtype instead of CONNECT");
264 my $res = OpenSRF::DomainObject::oilsBrokenSession->new(
265 status => "Connection seems to be mangled: Got $mtype instead of CONNECT",
268 $session->status($res);
274 my $res = OpenSRF::DomainObject::oilsConnectStatus->new;
275 $session->status($res);
276 $session->state( $session->CONNECTED );
287 # Handle client side message processing. Return 1 when the the message should be pushed
288 # up to the application layer. return 0 otherwise.
291 my( $self, $session , $mtype, $api_level, $tT) = @_;
294 if ($mtype eq 'STATUS') {
296 if ($self->payload->statusCode == STATUS_OK) {
297 $session->state($session->CONNECTED);
298 $log->debug("We connected successfully to ".$session->app);
302 if ($self->payload->statusCode == STATUS_TIMEOUT) {
303 $session->state( $session->DISCONNECTED );
306 $session->push_resend( $session->app_request($self->threadTrace) );
307 $log->debug("Disconnected because of timeout");
310 } elsif ($self->payload->statusCode == STATUS_REDIRECTED) {
311 $session->state( $session->DISCONNECTED );
314 $session->push_resend( $session->app_request($self->threadTrace) );
315 $log->debug("Disconnected because of redirect", WARN);
318 } elsif ($self->payload->statusCode == STATUS_EXPFAILED) {
319 $session->state( $session->DISCONNECTED );
320 $log->debug("Disconnected because of mangled session", WARN);
322 $session->push_resend( $session->app_request($self->threadTrace) );
325 } elsif ($self->payload->statusCode == STATUS_CONTINUE) {
326 $session->reset_request_timeout($self->threadTrace);
329 } elsif ($self->payload->statusCode == STATUS_COMPLETE) {
330 my $req = $session->app_request($self->threadTrace);
331 $req->complete(1) if ($req);
335 # add more STATUS handling code here (as 'elsif's), for Message layer status stuff
337 #$session->state( $session->DISCONNECTED() );
340 } elsif ($session->state == $session->CONNECTING()) {
341 # This should be changed to check the type of response (is it a connectException?, etc.)
344 if( $self->payload and $self->payload->isa( "ERROR" ) ) {
345 if ($session->raise_remote_errors) {
346 $self->payload->throw();
350 $log->debug("oilsMessage passing to Application: " . $self->type." : ".$session->remote_id );