]> git.evergreen-ils.org Git - working/Evergreen.git/blob - OpenSRF/src/perlmods/OpenSRF/System.pm
updating to work with the new cvs layout
[working/Evergreen.git] / OpenSRF / src / perlmods / OpenSRF / System.pm
1 package OpenSRF::System;
2 use strict; use warnings;
3 use base 'OpenSRF';
4 use OpenSRF::Utils::Logger qw(:level);
5 use OpenSRF::Transport::Listener;
6 use OpenSRF::Transport;
7 use OpenSRF::UnixServer;
8 use OpenSRF::Utils;
9 use OpenSRF::Utils::LogServer;
10 use OpenSRF::DOM;
11 use OpenSRF::EX qw/:try/;
12 use POSIX ":sys_wait_h";
13 use OpenSRF::Utils::Config;
14 use strict;
15
16 =head2 Name/Description
17
18 OpenSRF::System
19
20 To start the system: OpenSRF::System->bootstrap();
21
22 Simple system process management and automation.  After instantiating the class, simply call
23 bootstrap() to launch the system.  Each launched process is stored as a process-id/method-name
24 pair in a local hash.  When we receive a SIG{CHILD}, we loop through this hash and relaunch
25 any child processes that may have terminated.  
26
27 Currently automated processes include launching the internal Unix Servers, launching the inbound 
28 connections for each application, and starting the system shell.
29
30
31 Note: There should be only one instance of this class
32 alive at any given time.  It is designed as a globel process handler and, hence, will cause much
33 oddness if you call the bootstrap() method twice or attempt to create two of these by trickery.
34 There is a single instance of the class created on the first call to new().  This same instance is 
35 returned on subsequent calls to new().
36
37 =cut
38
39 $| = 1;
40
41 sub APPS { return qw( opac ); } #circ cat storage ); }
42
43 sub DESTROY {}
44
45 # ----------------------------------------------
46
47 $SIG{INT} = sub { instance()->killall(); };
48
49 $SIG{HUP} = sub{ instance()->hupall(); };
50
51 #$SIG{CHLD} = \&process_automation;
52
53
54 # Go ahead and set the config
55
56 set_config();
57
58 # ----------------------------------------------
59 # Set config options
60 sub set_config {
61
62         my $config = OpenSRF::Utils::Config->load( 
63                 config_file => "/pines/conf/opensrf.conf" );
64
65         warn "Setting config " . $config->transport->implementation ."\n";
66
67         if( ! $config ) { throw OpenSRF::EX::Config "System could not load config"; }
68
69         my $tran = $config->transport->implementation;
70
71         eval "use $tran;";
72         if( $@ ) {
73                 throw OpenSRF::EX::PANIC ("Cannot find transport implementation: $@" );
74         }
75
76         OpenSRF::Transport->message_envelope( $tran->get_msg_envelope );
77         OpenSRF::Transport::PeerHandle->set_peer_client( $tran->get_peer_client );
78         OpenSRF::Transport::Listener->set_listener( $tran->get_listener );
79
80
81 }
82
83
84 # ----------------------------------------------
85
86
87         # --- 
88         # put $instance in a closure and return it for requests to new()
89         # since there should only be one System instance running
90         # ----- 
91         my $instance;
92         sub instance { return __PACKAGE__->new(); }
93         sub new {
94                 my( $class ) = @_;
95
96                 if( ! $instance ) {
97                         $class = ref( $class ) || $class;
98                         my $self = {};
99                         $self->{'pid_hash'} = {};
100                         bless( $self, $class );
101                         $instance = $self;
102                 }
103                 return $instance;
104         }
105 }
106
107 # ----------------------------------------------
108 # Commands to execute at system launch
109
110 sub _unixserver {
111         my( $app ) = @_;
112         return "OpenSRF::UnixServer->new( '$app' )->serve()";
113 }
114
115 sub _listener {
116         my( $app ) = @_;
117         return "OpenSRF::Transport::Listener->new( '$app' )->initialize()->listen()";
118 }
119
120 #sub _shell { return "OpenSRF::Shell->listen()"; }
121
122
123 # ----------------------------------------------
124 # Boot up the system
125
126 sub bootstrap {
127
128         my $self = __PACKAGE__->instance();
129
130         my $config = OpenSRF::Utils::Config->current;
131
132         my $apps = $config->system->apps;
133         my $server_type = $config->system->server_type;
134         $server_type ||= "basic";
135
136         if(  $server_type eq "prefork" ) { 
137                 $server_type = "Net::Server::PreForkSimple"; 
138         } else { 
139                 $server_type = "Net::Server::Single"; 
140         }
141
142         _log( " * Server type: $server_type", INTERNAL );
143
144         eval "use $server_type";
145
146         if( $@ ) {
147                 throw OpenSRF::EX::PANIC ("Cannot set $server_type: $@" );
148         }
149
150         push @OpenSRF::UnixServer::ISA, $server_type;
151
152         _log( " * System boostrap" );
153
154         # Start a process group and make me the captain
155         setpgrp( 0, 0 ); 
156
157         $0 = "System";
158         
159         # --- Boot the Unix servers
160         $self->launch_unix($apps);
161
162         _sleep();
163
164         # --- Boot the listeners
165         $self->launch_listener($apps);
166
167         _sleep();
168
169         # --- Start the system shell
170 #if ($config->system->shell) {
171 #               eval " 
172 #                       use OpenSRF::Shell;
173 #                       $self->launch_shell() if ($config->system->shell);
174 #               ";
175 #
176 #               if ($@) {
177 #                       warn "ARRRGGG! Can't start the shell...";
178 #               }
179 #       }
180
181         # --- Now we wait for our brood to perish
182         _log( " * System is ready..." );
183         while( 1 ) { sleep; }
184         exit;
185 }
186
187
188
189 # ----------------------------------------------
190 # Bootstraps a single client connection.  
191
192 sub bootstrap_client {
193
194         my $self = __PACKAGE__->instance();
195         my $config = OpenSRF::Utils::Config->current;
196
197         my $app = "client";
198
199         OpenSRF::Transport::PeerHandle->construct( $app );
200
201 }
202
203 sub bootstrap_logger {
204
205         $0 = "Log Server";
206         OpenSRF::Utils::LogServer->serve();
207
208 }
209
210
211 # ----------------------------------------------
212 # Cycle through the known processes, reap the dead child 
213 # and put a new child in its place. (MMWWAHAHHAHAAAA!)
214
215 sub process_automation {
216
217         my $self = __PACKAGE__->instance();
218
219         foreach my $pid ( keys %{$self->pid_hash} ) {
220
221                 if( waitpid( $pid, WNOHANG ) == $pid ) {
222
223                         my $method = $self->pid_hash->{$pid};
224                         delete $self->pid_hash->{$pid};
225
226                         my $newpid =  OpenSRF::Utils::safe_fork();
227                         _log( "Relaunching => $method" );
228
229                         if( $newpid ) {
230                                 $self->pid_hash( $newpid, $method );
231                         }
232                         else { $0 = $method; eval $method; exit; }
233                 }
234         }
235
236         $SIG{CHLD} = \&process_automation;
237 }
238
239
240 # ----------------------------------------------
241 # Launch the Unix Servers
242
243 sub launch_unix {
244         my( $self, $apps ) = @_;
245
246         foreach my $app ( @$apps ) {
247
248                 _log( " * Starting UnixServer for $app..." );
249
250                 my $pid = OpenSRF::Utils::safe_fork();
251                 if( $pid ) {
252                         $self->pid_hash( $pid , _unixserver( $app ) );
253                 }
254                 else {
255                         my $apname = $app;
256                         $apname =~ tr/[a-z]/[A-Z]/;
257                         $0 = "Unix Server ($apname)";
258                         eval _unixserver( $app );
259                         exit;
260                 }
261         }
262 }
263
264 # ----------------------------------------------
265 # Launch the inbound clients
266
267 sub launch_listener {
268
269         my( $self, $apps ) = @_;
270
271         foreach my $app ( @$apps ) {
272
273                 _log( " * Starting Listener for $app..." );
274
275                 my $pid = OpenSRF::Utils::safe_fork();
276                 if ( $pid ) {
277                         $self->pid_hash( $pid , _listener( $app ) );
278                 }
279                 else {
280                         my $apname = $app;
281                         $apname =~ tr/[a-z]/[A-Z]/;
282                         $0 = "Listener ($apname)";
283                         eval _listener( $app );
284                         exit;
285                 }
286         }
287 }
288
289 # ----------------------------------------------
290
291 =head comment
292 sub launch_shell {
293
294         my $self = shift;
295
296         my $pid = OpenSRF::Utils::safe_fork();
297
298         if( $pid ) { $self->pid_hash( $pid , _shell() ); }
299         else {
300                 $0 = "System Shell";
301                 for( my $x = 0; $x != 10; $x++ ) {
302                         eval _shell();
303                         if( ! $@ ) { last; }
304                 }
305                 exit;
306         }
307 }
308 =cut
309
310
311 # ----------------------------------------------
312
313 sub pid_hash {
314         my( $self, $pid, $method ) = @_;
315         $self->{'pid_hash'}->{$pid} = $method
316                 if( $pid and $method );
317         return $self->{'pid_hash'};
318 }
319
320 # ----------------------------------------------
321 # If requested, the System can shut down.
322
323 sub killall {
324
325         $SIG{CHLD} = 'IGNORE';
326         $SIG{INT} = 'IGNORE';
327         kill( 'INT', -$$ ); #kill all in process group
328         exit;
329
330 }
331
332 # ----------------------------------------------
333 # Handle $SIG{HUP}
334 sub hupall {
335
336         _log( "HUPping brood" );
337         $SIG{CHLD} = 'IGNORE';
338         $SIG{HUP} = 'IGNORE';
339         set_config(); # reload config
340         kill( 'HUP', -$$ );
341 #       $SIG{CHLD} = \&process_automation;
342         $SIG{HUP} = sub{ instance()->hupall(); };
343 }
344
345
346 # ----------------------------------------------
347 # Log to debug, and stdout
348
349 sub _log {
350         my $string = shift;
351         OpenSRF::Utils::Logger->debug( $string );
352         print $string . "\n";
353 }
354
355 # ----------------------------------------------
356
357 sub _sleep {
358         select( undef, undef, undef, 0.3 );
359 }
360
361 1;
362
363