Main Page   Class Hierarchy   Compound List   File List   Compound Members   File Members  

modulebase.cpp

Go to the documentation of this file.
00001 //---------------------------------------------------------------------------
00002 #pragma hdrstop
00003 
00004 #if defined(_WINNT) || defined(_Windows)
00005 
00006 #include <windows.h>  // SetCurrentDirectory
00007 
00008 #elif defined(SOLARIS)
00009 
00010 #include <unistd.h>  // chdir()
00011 
00012 #else
00013 #error modulemase.cpp not completed for this O/S
00014 #endif
00015 
00016 
00017 #include "modulebase.h"
00018 #include <worm_environ.h>
00019 #include <worm_exceptions.h>
00020 #include <logger.h>
00021 #include <timefuncs.h>
00022 #include <comfile.h>
00023 
00024 
00025 
00026 //---------------------------------------------------------------------------
00027 TModuleBase::TModuleBase( char * p_programname
00028                         , char * p_configfilename
00029                         )
00030                         : TConfigurable()
00031                         , ThreadableObject()
00032 {
00033 
00034    Running = false;
00035    LastBeat = 0;
00036 
00037    LoopSleepMS = DEF_LOOP_SLEEP_MS;
00038 
00039    CommandRingKey = WORM_RING_INVALID;
00040    CommandRing    = NULL;
00041 
00042    MyGlobalUtils = NULL;
00043 
00044    HeartbeatMsg = NULL;
00045    ErrorMsg     = NULL;
00046 
00047    try
00048    {
00049       if ( p_configfilename == NULL )
00050       {
00051          strcpy ( ConfigFileName, "" );
00052       }
00053       else
00054       {
00055          strcpy ( ConfigFileName, p_configfilename );
00056       }
00057 
00058 
00059       // ----- Get the global utilites and parse the command file -----------
00060 
00061       if ( (MyGlobalUtils = new TGlobalUtils(p_programname)) == NULL )
00062       {
00063          throw worm_exception("failed creating global utilities object");
00064       }
00065 
00066 
00067       // Change working directory to environment variable EW_PARAMS value
00068       char * runPath;
00069 
00070       bool _isEW = false;
00071 
00072       if ( (runPath = TGlobalUtils::GetEnvironmentValue( WORM_CONFIG_DIR )) == NULL )
00073       {
00074          _isEW = true;
00075          runPath = TGlobalUtils::GetEnvironmentValue( EW_CONFIG_DIR );
00076       }
00077 
00078       if ( runPath == NULL )
00079       {
00080          worm_exception _expt( "Neither environment variable <" );
00081          _expt += WORM_CONFIG_DIR;
00082          _expt += "> nor <";
00083          _expt += EW_CONFIG_DIR;
00084          _expt += "> is defined";
00085          throw _expt;
00086       }
00087 
00088       if ( *runPath == '\0' )
00089       {
00090          worm_exception _expt( "Environment variable " );
00091          _expt += (_isEW ? EW_CONFIG_DIR : WORM_CONFIG_DIR);
00092          _expt += " defined, but has no value";
00093          throw _expt;
00094       }
00095 
00096 #if defined(_WINNT) || defined(_Windows)
00097       if ( ! SetCurrentDirectory( runPath ) )
00098 #elif defined(SOLARIS)
00099       if ( chdir( runPath ) == -1 )
00100 #else
00101 #error TModuleBase() changing directory not implemented for this O/S
00102 #endif
00103       {
00104          worm_exception _expt( "Params directory not found: " );
00105          _expt += runPath;
00106          _expt += "\nPlease set environment variable ";
00107          _expt += WORM_CONFIG_DIR;
00108          throw _expt;
00109       }
00110 
00111    }
00112    catch( worm_exception & _we )
00113    {
00114       TLogger::Logit( WORM_LOG_TOFILE|WORM_LOG_TOSTDERR
00115                     , "TModuleBase() ERROR:  %s\n"
00116                     , _we.what()
00117                     );
00118       throw _we;
00119    }
00120    catch( ... )
00121    {
00122       TLogger::Logit( WORM_LOG_TOFILE|WORM_LOG_TOSTDERR|WORM_LOG_TIMESTAMP
00123                     , "TModuleBase(): Unidentifed Exception\n"
00124                     );
00125       throw worm_exception("TModuleBase(): unidentified exception");
00126    }
00127 }
00128 //---------------------------------------------------------------------------
00129 TModuleBase::~TModuleBase()
00130 {
00131    if ( CommandRing != NULL )
00132    {
00133       delete( CommandRing );
00134       CommandRing = NULL;
00135    }
00136    if ( MyGlobalUtils != NULL )
00137    {
00138       delete( MyGlobalUtils );
00139       MyGlobalUtils = NULL;
00140    }
00141    if ( HeartbeatMsg != NULL )
00142    {
00143       delete( HeartbeatMsg );
00144       HeartbeatMsg = NULL;
00145    }
00146    if ( ErrorMsg != NULL )
00147    {
00148       delete( ErrorMsg );
00149       ErrorMsg = NULL;
00150    }
00151 }
00152 //---------------------------------------------------------------------------
00153 HANDLE_STATUS TModuleBase::HandleConfigLine( ConfigSource * p_parser )
00154 {
00155    // Do not manipulate ConfigState herein.
00156 
00157    HANDLE_STATUS r_handled = MyGlobalUtils->HandleConfigLine(p_parser);
00158 
00159    if ( r_handled == HANDLER_UNUSED )
00160    {
00161       try
00162       {
00163          char * _token;
00164 
00165          r_handled = HANDLER_USED;
00166 
00167          do
00168          {
00169 
00170             if ( p_parser->Its("CmdRingName") )
00171             {
00172                _token = p_parser->String();
00173                if ( strlen(_token) == 0 )
00174                {
00175                   throw worm_exception("missing <CmdRingName> value");
00176                }
00177 
00178                if ( (CommandRingKey = TGlobalUtils::LookupRingKey(_token)) == WORM_RING_INVALID )
00179                {
00180                   throw worm_exception("invalid <CmdRingName> value");
00181                }
00182 
00183                continue;
00184             }
00185 
00186             if ( p_parser->Its("LoopSleepMS") )
00187             {
00188                if ( (LoopSleepMS = p_parser->Int()) == ConfigSource::INVALID_INT )
00189                {
00190                   LoopSleepMS = DEF_LOOP_SLEEP_MS;
00191                   throw worm_exception("invalid <LoopSleepMS> value");
00192                }
00193                continue;
00194             }
00195 
00196             r_handled = HANDLER_UNUSED;
00197 
00198          } while ( false );
00199       }
00200       catch( worm_exception _we )
00201       {
00202          r_handled = HANDLER_INVALID;
00203          TLogger::Logit( WORM_LOG_TOFILE|WORM_LOG_TOSTDERR
00204                       , "TModuleBase::HandleConfigLine(): configuration error: %s\nin line: %s\n"                      , _we.what()
00205                       , p_parser->GetCurrentLine()
00206                       );
00207       }
00208    }
00209 
00210    return r_handled;
00211 }
00212 //---------------------------------------------------------------------------
00213 void TModuleBase::CheckConfig()
00214 {
00215 
00216    if ( MyGlobalUtils == NULL )
00217    {
00218       TLogger::Logit( WORM_LOG_TOFILE|WORM_LOG_TOSTDERR
00219                     , "TModuleBase::CheckConfig(): Global Configurations object not created\n"
00220                     );
00221       ConfigState = WORM_STAT_BADSTATE;
00222    }
00223    else if ( ! MyGlobalUtils->IsReady() )
00224    {
00225       TLogger::Logit( WORM_LOG_TOFILE|WORM_LOG_TOSTDERR
00226                     , "TModuleBase::CheckConfig(): Global Configurations object not configured\n"
00227                     );
00228       ConfigState = WORM_STAT_BADSTATE;
00229    }
00230 
00231    if ( TGlobalUtils::GetHeartbeatInt() == ConfigSource::INVALID_INT )
00232    {
00233       TLogger::Logit( WORM_LOG_TOFILE|WORM_LOG_TOSTDERR
00234                     , "TModuleBase::CheckConfig(): No <HeartBeatInt> value from the config file\n"
00235                     );
00236       ConfigState = WORM_STAT_BADSTATE;
00237    }
00238 
00239    if ( CommandRingKey == WORM_RING_INVALID )
00240    {
00241       TLogger::Logit( WORM_LOG_TOFILE|WORM_LOG_TOSTDERR
00242                     , "TModuleBase::CheckConfig(): No <CmdRingName> value from the config file\n"
00243                     );
00244       ConfigState = WORM_STAT_BADSTATE;
00245    }
00246 
00247    if ( LoopSleepMS < 10 || 30000 < LoopSleepMS )
00248    {
00249       TLogger::Logit( WORM_LOG_TOFILE|WORM_LOG_TOSTDERR
00250                     , "TModuleBase::CheckConfig(): <LoopSleepMS> value (%d) must be in range 10 - 30000\n"
00251                     , LoopSleepMS
00252                     );
00253       ConfigState = WORM_STAT_BADSTATE;
00254    }
00255 
00256    if ( (TYPE_ERROR = TGlobalUtils::LookupMessageTypeId("TYPE_ERROR")) == WORM_MSGTYPE_INVALID )
00257    {
00258       TLogger::Logit( WORM_LOG_TOFILE|WORM_LOG_TOSTDERR
00259                     , "TModuleBase::CheckConfig(): TYPE_ERROR not found in config files\n"
00260                     , LoopSleepMS
00261                     );
00262       ConfigState = WORM_STAT_BADSTATE;
00263    }
00264 
00265    if ( (TYPE_HEARTBEAT = TGlobalUtils::LookupMessageTypeId("TYPE_HEARTBEAT")) == WORM_MSGTYPE_INVALID )
00266    {
00267       TLogger::Logit( WORM_LOG_TOFILE|WORM_LOG_TOSTDERR
00268                     , "TModuleBase::CheckConfig(): TYPE_HEARTBEAT not found in config files\n"
00269                     , LoopSleepMS
00270                     );
00271       ConfigState = WORM_STAT_BADSTATE;
00272    }
00273 }
00274 //---------------------------------------------------------------------------
00275 void TModuleBase::SendStatus( WORM_MSGTYPE_ID   p_type
00276                             , short             p_ierr
00277                             , const char      * p_text
00278                             )
00279 {
00280    TMessageBase * _msg = NULL;
00281 
00282    try
00283    {
00284       if ( CommandRing == NULL )
00285       {
00286          throw worm_exception("Command Ring is NULL");
00287       }
00288 
00289       if      ( p_type == TYPE_HEARTBEAT )
00290       {
00291          HeartbeatMsg->SetTime();
00292          _msg = HeartbeatMsg;
00293       }
00294       else if ( p_type == TYPE_ERROR )
00295       {
00296          ErrorMsg->SetTime();
00297          ErrorMsg->SetErrorCode(p_ierr);
00298          ErrorMsg->SetText(p_text);
00299          _msg = ErrorMsg;
00300       }
00301       else
00302       {
00303          worm_exception _expt("invalid message type "):
00304                         _expt += (int)p_type;
00305          throw _expt;
00306       }
00307 
00308       if ( _msg != NULL )
00309       {
00310          if ( CommandRing->PutMessage(*_msg) != WORM_STAT_SUCCESS )
00311          {
00312             if( p_type == TYPE_HEARTBEAT )
00313             {
00314                throw worm_exception("Error sending heartbeat." );
00315             }
00316             else // if( p_type == TYPE_ERROR )
00317             {
00318                worm_exception _expt("Error sending error: "); 
00319                               _expt += (int)p_ierr;
00320                throw _expt;
00321             }
00322          }
00323       }
00324    }
00325    catch( worm_exception & _we )
00326    {
00327       TLogger::Logit( WORM_LOG_TOFILE|WORM_LOG_TOSTDERR
00328                     , "TModuleBase::SendStatus() Error: %s\n"
00329                     , _we.what()
00330                     );
00331    }
00332    catch( ... )
00333    {
00334       TLogger::Logit( WORM_LOG_TOFILE|WORM_LOG_TOSTDERR
00335                     , "TModuleBase::SendStatus() Error\n"
00336                     );
00337       Running = false;
00338    }
00339 }
00340 //---------------------------------------------------------------------------
00341 void TModuleBase::Heartbeat()
00342 {
00343    static long _interval = TGlobalUtils::GetHeartbeatInt();
00344 
00345    if ( 0 < _interval )
00346    {
00347       if ( (LastBeat + _interval) < time(NULL) )
00348       {
00349          SendStatus(TYPE_HEARTBEAT);
00350          LastBeat = time(NULL);
00351       }
00352    }
00353 }
00354 //---------------------------------------------------------------------------
00355 int TModuleBase::Run()
00356 {
00357    int r_status = 0;
00358 
00359    TComFileParser * _parser = NULL;
00360 
00361    try
00362    {
00363 
00364       // check for this module's configuration file
00365       if ( (_parser = new TComFileParser()) == NULL )
00366       {
00367          throw worm_exception("failed creating parser for configuration file");
00368       }
00369 
00370 
00371       if ( strlen(ConfigFileName) == 0 )
00372       {
00373          TLogger::Logit( WORM_LOG_TOFILE|WORM_LOG_TOSTDERR
00374                        , "%s.main(): using default configuration file %s\n"
00375                        , TGlobalUtils::GetProgramName()
00376                        , GetDefaultConfigFile()
00377                        );
00378          strcpy ( ConfigFileName, GetDefaultConfigFile() );
00379       }
00380 
00381 
00382       if ( ! _parser->Open(ConfigFileName) )
00383       {
00384          worm_exception _expt("failed opening configuration file: ");
00385          _expt += ConfigFileName;
00386          throw _expt;
00387       }
00388 
00389 
00390       bool _parsing = true;
00391 
00392       do
00393       {
00394          switch ( _parser->ReadLine() )
00395          {
00396            case COMFILE_ERROR:
00397                 {
00398                    char * _errortxt;
00399                    _parser->Error( &_errortxt );
00400                    worm_exception _expt( "Error while parsing config file " );
00401                    _expt += ConfigFileName;
00402                    _expt += "\n";
00403                    _expt += _errortxt;
00404                    throw _expt;
00405                 }
00406 
00407            case COMFILE_EOF:
00408                 _parsing = false;
00409                 break;
00410 
00411            default:
00412 
00413                 (void *)_parser->NextToken();
00414 
00415                 // check if the derivative class uses the configuration line
00416                 if ( HandleConfigLine(_parser) == HANDLER_UNUSED )
00417                 {
00418                    TLogger::Logit( WORM_LOG_TOFILE|WORM_LOG_TOSTDOUT
00419                                  , "unrecognized command in line:\n%s\n%s\n%s\n"
00420                                  , _parser->GetCurrentLine()
00421                                  , "while parsing config file:"
00422                                  , ConfigFileName
00423                                  );
00424                 }
00425                 
00426                 break;
00427 
00428          } // switch()
00429 
00430       } while(_parsing);
00431 
00432 
00433       delete( _parser );
00434       _parser = NULL;
00435 
00436 
00437       if ( (HeartbeatMsg = new THeartbeatMessage( TGlobalUtils::GetThisInstallationId()
00438                                                 , TGlobalUtils::GetThisModuleId()
00439                                                 ) ) == NULL )
00440       {
00441          throw worm_exception("failed creating heartbeat message object");
00442       }
00443 
00444 
00445       if ( (ErrorMsg = new TErrorMessage( TGlobalUtils::GetThisInstallationId()
00446                                         , TGlobalUtils::GetThisModuleId()
00447                                         ) ) == NULL )
00448       {
00449          throw worm_exception("failed creating error message object");
00450       }
00451 
00452       if ( ! IsReady() )
00453       {
00454          throw worm_exception( "Module is not configured, must exit");
00455       }
00456 
00457       // global logging level might have been overriden in config file
00458       //
00459       LoggingLevel = TGlobalUtils::GetLoggingLevel();
00460 
00461 #ifdef SOLARIS
00462       // Set our "nice" value back to the default value.
00463       // This does nothing if you started at the default.
00464       // Requested by D. Chavez, University of Utah.
00465       //
00466       nice( -nice( 0 ) );
00467 
00468       // Catch process termination signals
00469       //
00470       sigignore( SIGINT );             /* Control-c */
00471       sigignore( SIGQUIT );            /* Control-\ */
00472       sigset( SIGTERM, SigtermHandler );
00473 
00474       // Catch tty input signal, in case we are in background
00475       sigignore( SIGTTIN );
00476 #endif
00477 
00478 
00479       if ( (Running = PrepareToRun()) == true )
00480       {
00481          if ( (CommandRing = new TRingWriter(CommandRingKey)) == NULL )
00482          {
00483             throw worm_exception( "Failed creating command ring writer, must exit");
00484          }
00485       }
00486 
00487       int _flag;
00488 
00489       while( Running )
00490       {
00491          if ( CheckForFatal() )
00492          {
00493             if ( TGlobalUtils::GetLoggingLevel() == WORM_LOG_DEBUG )
00494             {
00495                TLogger::Logit( WORM_LOG_TOFILE|WORM_LOG_TOSTDERR|WORM_LOG_TIMESTAMP
00496                              , "TModuleBase::Run(): Worker thread reported fatal error\n"
00497                              );
00498             }
00499             Running = false;
00500          }
00501          else
00502          {
00503             _flag = CommandRing->GetFlag();
00504 
00505             if (   _flag == WORM_STOP_ALL_MODULES
00506                 || _flag == TGlobalUtils::GetThisModuleId()
00507                )
00508             {
00509                if ( WORM_LOG_STATUS <= TGlobalUtils::GetLoggingLevel() )
00510                {
00511                   TLogger::Logit( WORM_LOG_TOFILE|WORM_LOG_TOSTDOUT|WORM_LOG_TIMESTAMP
00512                                 , "TModuleBase::Run(): Shutting down\n"
00513                                 );
00514                }
00515                Running = false;
00516             }
00517             else
00518             {
00519                Heartbeat();
00520 
00521                switch ( MainThreadActions() )
00522                {
00523                  case WORM_STAT_NOMATCH:
00524                       // No actions to take at this time, sleep for a bit
00525                       // waiting for the situation to change.
00526                       TTimeFuncs::MSecSleep(LoopSleepMS);
00527 
00528                  case WORM_STAT_SUCCESS:
00529                       // Commonly, successful processing indicates that an
00530                       // incoming message was handled.  Since there might
00531                       // be other messages pending, don't sleep, return to
00532                       // look for another one.
00533                       break;
00534 
00535                  case WORM_STAT_FAILURE:
00536                       if ( TGlobalUtils::GetLoggingLevel() == WORM_LOG_DEBUG )
00537                       {
00538                          TLogger::Logit( WORM_LOG_TOFILE|WORM_LOG_TOSTDERR|WORM_LOG_TIMESTAMP
00539                                        , "TModuleBase::Run(): Main thread reported fatal error\n"
00540                                        );
00541                       }
00542                       r_status = -1;
00543                       Running = false;
00544                       break;
00545                }
00546             }
00547          }
00548 
00549       }
00550 
00551       FinishedRunning();
00552 
00553    }
00554    catch( worm_exception & _we )
00555    {
00556       if ( WORM_LOG_ERRORS <= TGlobalUtils::GetLoggingLevel() )
00557       {
00558          TLogger::Logit( WORM_LOG_TOFILE|WORM_LOG_TOSTDERR
00559                        , "TModuleBase::Run() Error: %s\n"
00560                        , _we.what()
00561                        );
00562       }
00563       r_status = -1;
00564       // Some lower-level exceptions might end up here without
00565       // adjusting Running state
00566       if ( Running )
00567       {
00568          Running = false;
00569          TTimeFuncs::MSecSleep(750);
00570          FinishedRunning();
00571       }
00572    }
00573 
00574    if ( _parser != NULL )
00575    {
00576       delete( _parser );
00577       _parser = NULL;
00578    }
00579 
00580    return r_status;
00581 }
00582 //---------------------------------------------------------------------------

Generated on Tue May 6 09:16:05 2003 for Earthworm Libs by doxygen1.3-rc3