1 package OpenSRF::Transport;
2 use strict; use warnings;
4 use Time::HiRes qw/time/;
5 use OpenSRF::AppSession;
6 use OpenSRF::Utils::JSON;
7 use OpenSRF::Utils::Logger qw(:level);
8 use OpenSRF::DomainObject::oilsResponse qw/:status/;
9 use OpenSRF::EX qw/:try/;
10 use OpenSRF::Transport::SlimJabber::MessageWrapper;
13 # --- These must be implemented by all Transport subclasses
14 # -------------------------------------------
18 Returns the package name of the package the system will use to
19 gather incoming requests
23 sub get_listener { shift()->alert_abstract(); }
25 =head2 get_peer_client
27 Returns the name of the package responsible for client communication
31 sub get_peer_client { shift()->alert_abstract(); }
33 =head2 get_msg_envelope
35 Returns the name of the package responsible for parsing incoming messages
39 sub get_msg_envelope { shift()->alert_abstract(); }
41 # -------------------------------------------
43 our $message_envelope;
44 my $logger = "OpenSRF::Utils::Logger";
48 =head2 message_envelope( [$envelope] );
50 Sets the message envelope class that will allow us to extract
51 information from the messages we receive from the low
56 sub message_envelope {
57 my( $class, $envelope ) = @_;
59 $message_envelope = $envelope;
63 "Error loading message_envelope: $envelope -> $@", ERROR);
66 return $message_envelope;
69 =head2 handler( $data )
71 Creates a new MessageWrapper, extracts the remote_id, session_id, and message body
72 from the message. Then, creates or retrieves the AppSession object with the session_id and remote_id.
73 Finally, creates the message document from the body of the message and calls
74 the handler method on the message document.
79 my $start_time = time();
80 my( $class, $service, $data ) = @_;
82 $logger->transport( "Transport handler() received $data", INTERNAL );
84 my $remote_id = $data->from;
85 my $sess_id = $data->thread;
86 my $body = $data->body;
87 my $type = $data->type;
89 $logger->set_osrf_xid($data->osrf_xid);
92 if (defined($type) and $type eq 'error') {
93 throw OpenSRF::EX::Session ("$remote_id IS NOT CONNECTED TO THE NETWORK!!!");
97 # See if the app_session already exists. If so, make
98 # sure the sender hasn't changed if we're a server
99 my $app_session = OpenSRF::AppSession->find( $sess_id );
100 if( $app_session and $app_session->endpoint == $app_session->SERVER() and
101 $app_session->remote_id ne $remote_id ) {
103 my $c = OpenSRF::Utils::SettingsClient->new();
104 if($c->config_value("apps", $app_session->service, "migratable")) {
105 $logger->debug("service is migratable, new client is $remote_id");
108 $logger->warn("Backend Gone or invalid sender");
109 my $res = OpenSRF::DomainObject::oilsBrokenSession->new();
110 $res->status( "Backend Gone or invalid sender, Reconnect" );
111 $app_session->status( $res );
116 # Retrieve or build the app_session as appropriate (server_build decides which to do)
117 $logger->transport( "AppSession is valid or does not exist yet", INTERNAL );
118 $app_session = OpenSRF::AppSession->server_build( $sess_id, $remote_id, $service );
120 if( ! $app_session ) {
121 throw OpenSRF::EX::Session ("Transport::handler(): No AppSession object returned from server_build()");
124 # Create a document from the JSON contained within the message
126 eval { $doc = OpenSRF::Utils::JSON->JSON2perl($body); };
129 $logger->warn("Received bogus JSON: $@");
130 $logger->warn("Bogus JSON data: $body");
131 my $res = OpenSRF::DomainObject::oilsXMLParseError->new( status => "JSON Parse Error --- $body\n\n$@" );
133 $app_session->status($res);
134 #$app_session->kill_me;
138 $logger->transport( "Transport::handler() creating \n$body", INTERNAL );
140 # We need to disconnect the session if we got a jabber error on the client side. For
141 # server side, we'll just tear down the session and go away.
142 if (defined($type) and $type eq 'error') {
144 if( $app_session->endpoint == $app_session->SERVER() ) {
145 $app_session->kill_me;
149 $app_session->state( $app_session->DISCONNECTED );
150 # below will lead to infinite looping, should return an exception
151 #$app_session->push_resend( $app_session->app_request(
152 # $doc->documentElement->firstChild->threadTrace ) );
154 "Got Jabber error on client connection $remote_id, nothing we can do..", ERROR );
159 # cycle through and pass each oilsMessage contained in the message
160 # up to the message layer for processing.
161 for my $msg (@$doc) {
163 next unless ( $msg && UNIVERSAL::isa($msg => 'OpenSRF::DomainObject::oilsMessage'));
165 if( $app_session->endpoint == $app_session->SERVER() ) {
169 if( ! $msg->handler( $app_session ) ) { return 0; }
171 $logger->debug("Successfully handled message", DEBUG);
176 my $res = OpenSRF::DomainObject::oilsServerError->new();
177 $res->status( $res->status . "\n$e");
178 $app_session->status($res) if $res;
179 $app_session->kill_me;
186 if( ! $msg->handler( $app_session ) ) { return 0; }
187 $logger->info("Successfully handled message", DEBUG);
193 $logger->debug(sprintf("Message processing duration: %.3fs",(time() - $start_time)), DEBUG);