]> git.evergreen-ils.org Git - OpenSRF.git/blob - src/perlmods/OpenSRF/Transport.pm
bfc25d17243b16173a8966b73d7908df20d2c3a4
[OpenSRF.git] / src / perlmods / OpenSRF / Transport.pm
1 package OpenSRF::Transport;
2 use strict; use warnings;
3 use base 'OpenSRF';
4 use Time::HiRes qw/time/;
5 use OpenSRF::AppSession;
6 use OpenSRF::Utils::Logger qw(:level);
7 use OpenSRF::DomainObject::oilsResponse qw/:status/;
8 use OpenSRF::EX qw/:try/;
9 use OpenSRF::Transport::SlimJabber::MessageWrapper;
10
11 #------------------ 
12 # --- These must be implemented by all Transport subclasses
13 # -------------------------------------------
14
15 =head2 get_listener
16
17 Returns the package name of the package the system will use to 
18 gather incoming requests
19
20 =cut
21
22 sub get_listener { shift()->alert_abstract(); }
23
24 =head2 get_peer_client
25
26 Returns the name of the package responsible for client communication
27
28 =cut
29
30 sub get_peer_client { shift()->alert_abstract(); } 
31
32 =head2 get_msg_envelope
33
34 Returns the name of the package responsible for parsing incoming messages
35
36 =cut
37
38 sub get_msg_envelope { shift()->alert_abstract(); } 
39
40 # -------------------------------------------
41
42 our $message_envelope;
43 my $logger = "OpenSRF::Utils::Logger"; 
44
45
46
47 =head2 message_envelope( [$envelope] );
48
49 Sets the message envelope class that will allow us to extract
50 information from the messages we receive from the low 
51 level transport
52
53 =cut
54
55 sub message_envelope {
56         my( $class, $envelope ) = @_;
57         if( $envelope ) {
58                 $message_envelope = $envelope;
59                 $envelope->use;
60                 if( $@ ) {
61                         $logger->error( 
62                                         "Error loading message_envelope: $envelope -> $@", ERROR);
63                 }
64         }
65         return $message_envelope;
66 }
67
68 =head2 handler( $data )
69
70 Creates a new MessageWrapper, extracts the remote_id, session_id, and message body
71 from the message.  Then, creates or retrieves the AppSession object with the session_id and remote_id. 
72 Finally, creates the message document from the body of the message and calls
73 the handler method on the message document.
74
75 =cut
76
77 sub handler {
78         my $start_time = time();
79         my( $class, $service, $data ) = @_;
80
81         $logger->transport( "Transport handler() received $data", INTERNAL );
82
83         # pass data to the message envelope 
84         my $helper = OpenSRF::Transport::SlimJabber::MessageWrapper->new( $data );
85
86         # Extract message information
87         my $remote_id   = $helper->get_remote_id();
88         my $sess_id     = $helper->get_sess_id();
89         my $body        = $helper->get_body();
90         my $type        = $helper->get_msg_type();
91
92
93         if (defined($type) and $type eq 'error') {
94                 throw OpenSRF::EX::Session ("$remote_id IS NOT CONNECTED TO THE NETWORK!!!");
95
96         }
97
98         # See if the app_session already exists.  If so, make 
99         # sure the sender hasn't changed if we're a server
100         my $app_session = OpenSRF::AppSession->find( $sess_id );
101         if( $app_session and $app_session->endpoint == $app_session->SERVER() and
102                         $app_session->remote_id ne $remote_id ) {
103                 $logger->transport( "Backend Gone or invalid sender", INTERNAL );
104                 my $res = OpenSRF::DomainObject::oilsBrokenSession->new();
105                 $res->status( "Backend Gone or invalid sender, Reconnect" );
106                 $app_session->status( $res );
107                 return 1;
108         } 
109
110         # Retrieve or build the app_session as appropriate (server_build decides which to do)
111         $logger->transport( "AppSession is valid or does not exist yet", INTERNAL );
112         $app_session = OpenSRF::AppSession->server_build( $sess_id, $remote_id, $service );
113
114         if( ! $app_session ) {
115                 throw OpenSRF::EX::Session ("Transport::handler(): No AppSession object returned from server_build()");
116         }
117
118         # Create a document from the JSON contained within the message 
119         my $doc; 
120         eval { $doc = JSON->JSON2perl($body); };
121         if( $@ ) {
122
123                 $logger->transport( "Received bogus JSON: $@", INFO );
124                 $logger->transport( "Bogus JSON data: \n $body \n", INTERNAL );
125                 my $res = OpenSRF::DomainObject::oilsXMLParseError->new( status => "JSON Parse Error --- $body\n\n$@" );
126
127                 $app_session->status($res);
128                 #$app_session->kill_me;
129                 return 1;
130         }
131
132         $logger->transport( "Transport::handler() creating \n$body", INTERNAL );
133
134         # We need to disconnect the session if we got a jabber error on the client side.  For
135         # server side, we'll just tear down the session and go away.
136         if (defined($type) and $type eq 'error') {
137                 # If we're a server
138                 if( $app_session->endpoint == $app_session->SERVER() ) {
139                         $app_session->kill_me;
140                         return 1;
141                 } else {
142                         $app_session->reset;
143                         $app_session->state( $app_session->DISCONNECTED );
144                         # below will lead to infinite looping, should return an exception
145                         #$app_session->push_resend( $app_session->app_request( 
146                         #               $doc->documentElement->firstChild->threadTrace ) );
147                         $logger->debug(
148                                 "Got Jabber error on client connection $remote_id, nothing we can do..", ERROR );
149                         return 1;
150                 }
151         }
152
153
154         # cycle through and pass each oilsMessage contained in the message
155         # up to the message layer for processing.
156         for my $msg (@$doc) {
157
158                 next unless (   $msg && UNIVERSAL::isa($msg => 'OpenSRF::DomainObject::oilsMessage'));
159
160                 if( $app_session->endpoint == $app_session->SERVER() ) {
161
162                         try {  
163
164                                 if( ! $msg->handler( $app_session ) ) { return 0; }
165
166                                 $logger->debug("Successfully handled message", DEBUG);
167
168                         } catch Error with {
169
170                                 my $e = shift;
171                                 my $res = OpenSRF::DomainObject::oilsServerError->new();
172                                 $res->status( $res->status . "\n$e");
173                                 $app_session->status($res) if $res;
174                                 $app_session->kill_me;
175                                 return 0;
176
177                         };
178
179                 } else { 
180
181                         if( ! $msg->handler( $app_session ) ) { return 0; } 
182                         $logger->info("Successfully handled message", DEBUG);
183
184                 }
185
186         }
187
188         $logger->debug(sprintf("Message processing duration: %.3fs",(time() - $start_time)), DEBUG);
189
190         return $app_session;
191 }
192
193 1;