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 //---------------------------------------------------------------------------