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