Logging_Strategy.cpp

Go to the documentation of this file.
00001 // $Id: Logging_Strategy.cpp 81696 2008-05-14 18:15:31Z johnnyw $
00002 
00003 #include "ace/Logging_Strategy.h"
00004 #include "ace/Service_Config.h"
00005 #include "ace/ACE.h"
00006 #include "ace/Get_Opt.h"
00007 
00008 // FUZZ: disable check_for_streams_include
00009 #include "ace/streams.h"
00010 
00011 #include "ace/Lib_Find.h"
00012 #include "ace/Log_Msg.h"
00013 #include "ace/Reactor.h"
00014 #include "ace/OS_NS_string.h"
00015 #include "ace/OS_NS_stdio.h"
00016 #include "ace/OS_NS_unistd.h"
00017 
00018 ACE_RCSID (ace,
00019            Logging_Strategy,
00020            "$Id: Logging_Strategy.cpp 81696 2008-05-14 18:15:31Z johnnyw $")
00021 
00022 ACE_BEGIN_VERSIONED_NAMESPACE_DECL
00023 
00024 // Parse the string containing (thread) priorities and set them
00025 // accordingly.
00026 
00027 void
00028 ACE_Logging_Strategy::priorities (ACE_TCHAR *priority_string,
00029                                   ACE_Log_Msg::MASK_TYPE mask)
00030 {
00031   u_long priority_mask = 0;
00032 
00033   // Choose priority mask to change.
00034 
00035   if (mask == ACE_Log_Msg::PROCESS)
00036     priority_mask = process_priority_mask_;
00037   else
00038     priority_mask = thread_priority_mask_;
00039 
00040   ACE_TCHAR *strtokp = 0;
00041 
00042   // Parse string and alternate priority mask.
00043 
00044   for (ACE_TCHAR *priority = ACE_OS::strtok_r (priority_string,
00045                                                ACE_TEXT ("|"),
00046                                                &strtokp);
00047        priority != 0;
00048        priority = ACE_OS::strtok_r (0,
00049                                     ACE_TEXT ("|"),
00050                                     &strtokp))
00051     {
00052       if (ACE_OS::strcmp (priority, ACE_TEXT ("SHUTDOWN")) == 0)
00053         ACE_SET_BITS (priority_mask, LM_SHUTDOWN);
00054       else if (ACE_OS::strcmp (priority, ACE_TEXT ("~SHUTDOWN")) == 0)
00055         ACE_CLR_BITS (priority_mask, LM_SHUTDOWN);
00056       else if (ACE_OS::strcmp (priority, ACE_TEXT ("TRACE")) == 0)
00057         ACE_SET_BITS (priority_mask, LM_TRACE);
00058       else if (ACE_OS::strcmp (priority, ACE_TEXT ("~TRACE")) == 0)
00059         ACE_CLR_BITS (priority_mask, LM_TRACE);
00060       else if (ACE_OS::strcmp (priority, ACE_TEXT ("DEBUG")) == 0)
00061         ACE_SET_BITS (priority_mask, LM_DEBUG);
00062       else if (ACE_OS::strcmp (priority, ACE_TEXT ("~DEBUG")) == 0)
00063         ACE_CLR_BITS (priority_mask, LM_DEBUG);
00064       else if (ACE_OS::strcmp (priority, ACE_TEXT ("INFO")) == 0)
00065         ACE_SET_BITS (priority_mask, LM_INFO);
00066       else if (ACE_OS::strcmp (priority, ACE_TEXT ("~INFO")) == 0)
00067         ACE_CLR_BITS (priority_mask, LM_INFO);
00068       else if (ACE_OS::strcmp (priority, ACE_TEXT ("NOTICE")) == 0)
00069         ACE_SET_BITS (priority_mask, LM_NOTICE);
00070       else if (ACE_OS::strcmp (priority, ACE_TEXT ("~NOTICE")) == 0)
00071         ACE_CLR_BITS (priority_mask, LM_NOTICE);
00072       else if (ACE_OS::strcmp (priority, ACE_TEXT ("WARNING")) == 0)
00073         ACE_SET_BITS (priority_mask, LM_WARNING);
00074       else if (ACE_OS::strcmp (priority, ACE_TEXT ("~WARNING")) == 0)
00075         ACE_CLR_BITS (priority_mask, LM_WARNING);
00076       else if (ACE_OS::strcmp (priority, ACE_TEXT ("STARTUP")) == 0)
00077         ACE_SET_BITS (priority_mask, LM_STARTUP);
00078       else if (ACE_OS::strcmp (priority, ACE_TEXT ("~STARTUP")) == 0)
00079         ACE_CLR_BITS (priority_mask, LM_STARTUP);
00080       else if (ACE_OS::strcmp (priority, ACE_TEXT ("ERROR")) == 0)
00081         ACE_SET_BITS (priority_mask, LM_ERROR);
00082       else if (ACE_OS::strcmp (priority, ACE_TEXT ("~ERROR")) == 0)
00083         ACE_CLR_BITS (priority_mask, LM_ERROR);
00084       else if (ACE_OS::strcmp (priority, ACE_TEXT ("CRITICAL")) == 0)
00085         ACE_SET_BITS (priority_mask, LM_CRITICAL);
00086       else if (ACE_OS::strcmp (priority, ACE_TEXT ("~CRITICAL")) == 0)
00087         ACE_CLR_BITS (priority_mask, LM_CRITICAL);
00088       else if (ACE_OS::strcmp (priority, ACE_TEXT ("ALERT")) == 0)
00089         ACE_SET_BITS (priority_mask, LM_ALERT);
00090       else if (ACE_OS::strcmp (priority, ACE_TEXT ("~ALERT")) == 0)
00091         ACE_CLR_BITS (priority_mask, LM_ALERT);
00092       else if (ACE_OS::strcmp (priority, ACE_TEXT ("EMERGENCY")) == 0)
00093         ACE_SET_BITS (priority_mask, LM_EMERGENCY);
00094       else if (ACE_OS::strcmp (priority, ACE_TEXT ("~EMERGENCY")) == 0)
00095         ACE_CLR_BITS (priority_mask, LM_EMERGENCY);
00096     }
00097 
00098   // Affect right priority mask.
00099 
00100   if (mask == ACE_Log_Msg::PROCESS)
00101     process_priority_mask_ = priority_mask;
00102   else
00103     thread_priority_mask_ = priority_mask;
00104 }
00105 
00106 // Parse the string containing all the flags and set the flags
00107 // accordingly.
00108 
00109 void
00110 ACE_Logging_Strategy::tokenize (ACE_TCHAR *flag_string)
00111 {
00112   ACE_TCHAR *strtokp;
00113 
00114   for (ACE_TCHAR *flag = ACE_OS::strtok_r (flag_string,
00115                                            ACE_TEXT ("|"),
00116                                            &strtokp);
00117        flag != 0;
00118        flag = ACE_OS::strtok_r (0, ACE_TEXT ("|"), &strtokp))
00119     {
00120       if (ACE_OS::strcmp (flag, ACE_TEXT ("STDERR")) == 0)
00121         ACE_SET_BITS (this->flags_, ACE_Log_Msg::STDERR);
00122       else if (ACE_OS::strcmp (flag, ACE_TEXT ("LOGGER")) == 0)
00123         ACE_SET_BITS (this->flags_, ACE_Log_Msg::LOGGER);
00124       else if (ACE_OS::strcmp (flag, ACE_TEXT ("OSTREAM")) == 0)
00125         ACE_SET_BITS (this->flags_, ACE_Log_Msg::OSTREAM);
00126       else if (ACE_OS::strcmp (flag, ACE_TEXT ("VERBOSE")) == 0)
00127         ACE_SET_BITS (this->flags_, ACE_Log_Msg::VERBOSE);
00128       else if (ACE_OS::strcmp (flag, ACE_TEXT ("VERBOSE_LITE")) == 0)
00129         ACE_SET_BITS (this->flags_, ACE_Log_Msg::VERBOSE_LITE);
00130       else if (ACE_OS::strcmp (flag, ACE_TEXT ("SILENT")) == 0)
00131         ACE_SET_BITS (this->flags_, ACE_Log_Msg::SILENT);
00132       else if (ACE_OS::strcmp (flag, ACE_TEXT ("SYSLOG")) == 0)
00133         ACE_SET_BITS (this->flags_, ACE_Log_Msg::SYSLOG);
00134     }
00135 }
00136 
00137 int
00138 ACE_Logging_Strategy::parse_args (int argc, ACE_TCHAR *argv[])
00139 {
00140   ACE_TRACE ("ACE_Logging_Strategy::parse_args");
00141   ACE_TCHAR *temp;
00142 
00143   // Perform data member initializations.  BTW, do *not* initialize
00144   // <thread_priority_mask_> or <process_priority_mask_> here to avoid
00145   // unduing the behavior in <init>, where these are set by
00146   // <ACE_Log_Msg::instance>.
00147   this->flags_ = 0;
00148   this->wipeout_logfile_ = false;
00149   this->count_ = 0;
00150   this->fixed_number_ = false;
00151   this->order_files_ = false;
00152   this->max_file_number_ = 1;
00153   this->interval_ = ACE_DEFAULT_LOGFILE_POLL_INTERVAL;
00154   this->max_size_ = 0;
00155 
00156   ACE_Get_Opt get_opt (argc, argv,
00157                        ACE_TEXT ("f:i:k:m:n:N:op:s:t:w"), 0);
00158 
00159   for (int c; (c = get_opt ()) != -1; )
00160     {
00161       switch (c)
00162         {
00163         case 'f':
00164           temp = get_opt.opt_arg ();
00165           // Now tokenize the string to get all the flags
00166           this->tokenize (temp);
00167           // If LOGGER was specified, set up the default logger key.
00168           // The key can be changed by the -k option also, so if it's
00169           // been set already, don't set it.
00170           if (ACE_BIT_ENABLED (this->flags_, ACE_Log_Msg::LOGGER) &&
00171               this->logger_key_ == 0)
00172             this->logger_key_ = ACE::strnew (ACE_DEFAULT_LOGGER_KEY);
00173           break;
00174         case 'i':
00175           // Interval (in secs) at which logfile size is sampled.
00176           this->interval_ = ACE_OS::strtoul (get_opt.opt_arg (), 0, 10);
00177           break;
00178         case 'k':
00179           // Ensure that the LOGGER flag is set
00180           ACE_SET_BITS (this->flags_, ACE_Log_Msg::LOGGER);
00181           delete [] this->logger_key_;
00182           this->logger_key_ = ACE::strnew (get_opt.opt_arg ());
00183           break;
00184         case 'm':
00185           // Maximum logfile size (in KB).  Must be a non-zero value.
00186           this->max_size_ = ACE_OS::strtoul (get_opt.opt_arg (), 0, 10);
00187           this->max_size_ <<= 10;       // convert from KB to bytes.
00188           break;
00189         case 'n':
00190           delete [] this->program_name_;
00191           this->program_name_ = ACE::strnew (get_opt.opt_arg ());
00192           break;
00193         case 'N':
00194           // The max number for the log_file being created
00195           this->max_file_number_ = ACE_OS::atoi (get_opt.opt_arg ()) - 1;
00196           this->fixed_number_ = true;
00197           break;
00198         case 'o':
00199           // Log_files generation order
00200           this->order_files_ = true;
00201           break;
00202         case 'p':
00203           temp = get_opt.opt_arg ();
00204           // Now tokenize the string to setup process log priority
00205           this->priorities (temp, ACE_Log_Msg::PROCESS);
00206           break;
00207         case 's':
00208           // Ensure that the OSTREAM flag is set
00209           ACE_SET_BITS (this->flags_, ACE_Log_Msg::OSTREAM);
00210           delete [] this->filename_;
00211           this->filename_ = ACE::strnew (get_opt.opt_arg ());
00212           break;
00213         case 't':
00214           temp = get_opt.opt_arg ();
00215           // Now tokenize the string to setup thread log priority
00216           this->priorities (temp, ACE_Log_Msg::THREAD);
00217           break;
00218         case 'w':
00219           // Cause the logfile to be wiped out, both on startup and on
00220           // reconfigure.
00221           this->wipeout_logfile_ = true;
00222           break;
00223         default:
00224           break;
00225         }
00226     }
00227   return 0;
00228 }
00229 
00230 ACE_Logging_Strategy::ACE_Logging_Strategy (void)
00231   : thread_priority_mask_ (0),
00232     process_priority_mask_ (0),
00233     flags_ (0),
00234     filename_ (0),
00235     logger_key_ (0),
00236     program_name_ (0),
00237     wipeout_logfile_ (false),
00238     fixed_number_ (false),
00239     order_files_ (false),
00240     count_ (0),
00241     max_file_number_ (1), // 2 files by default (max file number + 1)
00242     interval_ (ACE_DEFAULT_LOGFILE_POLL_INTERVAL),
00243     max_size_ (0),
00244     log_msg_ (ACE_Log_Msg::instance ())
00245 {
00246 #if defined (ACE_DEFAULT_LOGFILE)
00247   this->filename_ = ACE::strnew (ACE_DEFAULT_LOGFILE);
00248 #else /* ACE_DEFAULT_LOGFILE */
00249   ACE_NEW (this->filename_,
00250            ACE_TCHAR[MAXPATHLEN + 1]);
00251 
00252   // Get the temporary directory
00253   if (ACE::get_temp_dir
00254       (this->filename_,
00255        MAXPATHLEN - 7) == -1) // 7 for "logfile"
00256     {
00257       ACE_ERROR ((LM_ERROR,
00258                   ACE_TEXT ("Temporary path too long, ")
00259                   ACE_TEXT ("defaulting to current directory\n")));
00260       this->filename_[0] = 0;
00261     }
00262 
00263   // Add the filename to the end
00264   ACE_OS::strcat (this->filename_,
00265                   ACE_TEXT ("logfile"));
00266 #endif /* ACE_DEFAULT_LOGFILE */
00267 }
00268 
00269 ACE_Logging_Strategy::~ACE_Logging_Strategy (void)
00270 {
00271   // This is allocated in constructor, so it must be deallocated in
00272   // the destructor!
00273   delete [] this->filename_;
00274 }
00275 
00276 int
00277 ACE_Logging_Strategy::fini (void)
00278 {
00279   delete [] this->filename_;
00280   this->filename_ = 0; // Avoid double deletions.
00281 
00282   delete [] this->logger_key_;
00283   delete [] this->program_name_;
00284 
00285   if (this->reactor ()
00286       && this->interval_ > 0 && this->max_size_ > 0)
00287     this->reactor ()->cancel_timer (this);
00288 
00289   return 0;
00290 }
00291 
00292 int
00293 ACE_Logging_Strategy::init (int argc, ACE_TCHAR *argv[])
00294 {
00295   ACE_TRACE ("ACE_Logging_Strategy::init");
00296 
00297   // Store current priority masks for changes in <parse_args>.
00298 
00299   this->process_priority_mask_ =
00300     this->log_msg_->priority_mask (ACE_Log_Msg::PROCESS);
00301 
00302   this->thread_priority_mask_ =
00303     this->log_msg_->priority_mask (ACE_Log_Msg::THREAD);
00304 
00305   // Use the options hook to parse the command line arguments.
00306   this->parse_args (argc, argv);
00307 
00308   // Setup priorities (to original if not specified on command line)
00309 
00310   this->log_msg_->priority_mask (thread_priority_mask_,
00311                                  ACE_Log_Msg::THREAD);
00312 
00313   this->log_msg_->priority_mask (process_priority_mask_,
00314                                  ACE_Log_Msg::PROCESS);
00315 
00316   // Check if any flags were specified. If none were specified, let
00317   // the default behavior take effect.
00318   if (this->flags_ != 0)
00319     {
00320       // Clear all flags
00321       this->log_msg_->clr_flags (ACE_Log_Msg::STDERR
00322                                  | ACE_Log_Msg::LOGGER
00323                                  | ACE_Log_Msg::OSTREAM
00324                                  | ACE_Log_Msg::VERBOSE
00325                                  | ACE_Log_Msg::VERBOSE_LITE
00326                                  | ACE_Log_Msg::SILENT
00327                                  | ACE_Log_Msg::SYSLOG);
00328       // Check if OSTREAM bit is set
00329       if (ACE_BIT_ENABLED (this->flags_,
00330                            ACE_Log_Msg::OSTREAM))
00331         {
00332           int delete_ostream = 0;
00333 #if defined (ACE_LACKS_IOSTREAM_TOTALLY)
00334           FILE *output_file = this->log_msg_->msg_ostream ();
00335           if (wipeout_logfile_)
00336             {
00337               // close and re-open a stream if such exits
00338               if (output_file &&
00339                   ACE_OS::fclose (output_file) == -1)
00340                 return -1;
00341               output_file = ACE_OS::fopen (this->filename_, ACE_TEXT ("wt"));
00342             }
00343           // open a stream only if such doesn't exists
00344           else if (output_file == 0)
00345             output_file = ACE_OS::fopen (this->filename_,
00346                                          ACE_TEXT ("at"));
00347 
00348           if (output_file == 0)
00349             return -1;
00350 #else
00351           ostream *output_file = this->log_msg_->msg_ostream ();
00352           // Create a new ofstream to direct output to the file.
00353           if (wipeout_logfile_)
00354             {
00355               ACE_NEW_RETURN
00356                 (output_file,
00357                  ofstream (ACE_TEXT_ALWAYS_CHAR (this->filename_)),
00358                  -1);
00359               delete_ostream = 1;
00360             }
00361           else if (output_file == 0)
00362             {
00363               ACE_NEW_RETURN
00364                 (output_file,
00365                  ofstream (ACE_TEXT_ALWAYS_CHAR (this->filename_),
00366                            ios::app | ios::out),
00367                  -1);
00368               delete_ostream = 1;
00369             }
00370 
00371           if (output_file->rdstate () != ios::goodbit)
00372             {
00373               if (delete_ostream)
00374                 delete output_file;
00375               return -1;
00376             }
00377 #endif /* ACE_LACKS_IOSTREAM_TOTALLY */
00378           // Set the <output_file> that'll be used by the rest of the
00379           // code.
00380           this->log_msg_->msg_ostream (output_file, delete_ostream);
00381 
00382           // Setup a timeout handler to perform the maximum file size
00383           // check (if required).
00384           if (this->interval_ > 0 && this->max_size_ > 0)
00385             {
00386               if (this->reactor () == 0)
00387                 // Use singleton.
00388                 this->reactor (ACE_Reactor::instance ());
00389 
00390               this->reactor ()->schedule_timer
00391                 (this, 0,
00392                  ACE_Time_Value (this->interval_),
00393                  ACE_Time_Value (this->interval_));
00394             }
00395         }
00396       // Now set the flags for Log_Msg
00397       this->log_msg_->set_flags (this->flags_);
00398     }
00399 
00400   return this->log_msg_->open (this->program_name_,
00401                                this->log_msg_->flags (),
00402                                this->logger_key_);
00403 }
00404 
00405 int
00406 ACE_Logging_Strategy::handle_timeout (const ACE_Time_Value &,
00407                                       const void *)
00408 {
00409 #if defined (ACE_LACKS_IOSTREAM_TOTALLY)
00410   if ((size_t) ACE_OS::ftell (this->log_msg_->msg_ostream ()) > this->max_size_)
00411 #else
00412   if ((size_t) this->log_msg_->msg_ostream ()->tellp () > this->max_size_)
00413 #endif /* ACE_LACKS_IOSTREAM_TOTALLY */
00414     {
00415       // Lock out any other logging.
00416       if (this->log_msg_->acquire ())
00417         ACE_ERROR_RETURN ((LM_ERROR,
00418                            ACE_TEXT ("Cannot acquire lock!\n")),
00419                           -1);
00420 
00421       // Close the current ostream.
00422 #if defined (ACE_LACKS_IOSTREAM_TOTALLY)
00423       FILE *output_file = (FILE *) this->log_msg_->msg_ostream ();
00424       ACE_OS::fclose (output_file);
00425       // We'll call msg_ostream() modifier later.
00426 #else
00427       ofstream *output_file =
00428         (ofstream *) this->log_msg_->msg_ostream ();
00429       output_file->close ();
00430 #endif /* ACE_LACKS_IOSTREAM_TOTALLY */
00431       // Save current logfile to logfile.old analyze if it was set any
00432       // fixed number for the log_files.
00433       if (fixed_number_)
00434         {
00435           if (max_file_number_ < 1) //we only want one file
00436             {
00437               // Just unlink the file.
00438               ACE_OS::unlink (this->filename_);
00439 
00440               // Open a new log file with the same name.
00441 #if defined (ACE_LACKS_IOSTREAM_TOTALLY)
00442               output_file = ACE_OS::fopen (this->filename_,
00443                                            ACE_TEXT ("wt"));
00444 
00445               if (output_file == 0)
00446                 return -1;
00447 
00448               this->log_msg_->msg_ostream (output_file);
00449 #else
00450               output_file->open (ACE_TEXT_ALWAYS_CHAR (this->filename_),
00451                                  ios::out);
00452 #endif /* ACE_LACKS_IOSTREAM_TOTALLY */
00453 
00454               // Release the lock previously acquired.
00455               this->log_msg_->release ();
00456               return 0;
00457             }
00458         }
00459       count_++;
00460 
00461       // Set the number of digits of the log_files labels.
00462       int digits = 1, res = count_;
00463       while((res = (res / 10))>0)
00464         digits++;
00465 
00466       if (ACE_OS::strlen (this->filename_) + digits <= MAXPATHLEN)
00467         {
00468           ACE_TCHAR backup[MAXPATHLEN+1];
00469 
00470           // analyse if it was chosen the mode which will order the
00471           // log_files
00472           if (order_files_)
00473             {
00474               ACE_TCHAR to_backup[MAXPATHLEN+1];
00475 
00476               // reorder the logs starting at the oldest (the biggest
00477               // number) watch if we reached max_file_number_.
00478               int max_num;
00479               if (fixed_number_ && count_ > max_file_number_)
00480                 // count_ will always be bigger than max_file_number_,
00481                 // so do nothing so to always reorder files from
00482                 // max_file_number_.
00483                 max_num = max_file_number_;
00484               else
00485                 max_num = count_;
00486 
00487               for (int i = max_num ; i > 1 ;i--)
00488                 {
00489                   ACE_OS::sprintf (backup,
00490                                    ACE_TEXT ("%s.%d"),
00491                                    this->filename_,
00492                                    i);
00493                   ACE_OS::sprintf (to_backup,
00494                                    ACE_TEXT ("%s.%d"),
00495                                    this->filename_,
00496                                    i - 1);
00497 
00498                   // Remove any existing old file; ignore error as
00499                   // file may not exist.
00500                   ACE_OS::unlink (backup);
00501 
00502                   // Rename the current log file to the name of the
00503                   // backup log file.
00504                   ACE_OS::rename (to_backup, backup);
00505                 }
00506               ACE_OS::sprintf (backup,
00507                                ACE_TEXT ("%s.1"),
00508                                this->filename_);
00509             }
00510           else
00511             {
00512               if (fixed_number_ && count_>max_file_number_)
00513                 count_ = 1; // start over from 1
00514 
00515               ACE_OS::sprintf (backup,
00516                                ACE_TEXT ("%s.%d"),
00517                                this->filename_,
00518                                count_);
00519             }
00520 
00521           // Remove any existing old file; ignore error as file may
00522           // not exist.
00523           ACE_OS::unlink (backup);
00524 
00525           // Rename the current log file to the name of the backup log
00526           // file.
00527           ACE_OS::rename (this->filename_, backup);
00528         }
00529       else
00530         ACE_ERROR ((LM_ERROR,
00531                     ACE_TEXT ("Backup file name too long; ")
00532                     ACE_TEXT ("backup logfile not saved.\n")));
00533 
00534       // Open a new log file by the same name
00535 #if defined (ACE_LACKS_IOSTREAM_TOTALLY)
00536       output_file = ACE_OS::fopen (this->filename_, ACE_TEXT ("wt"));
00537 
00538       if (output_file == 0)
00539         return -1;
00540 
00541       this->log_msg_->msg_ostream (output_file);
00542 #else
00543       output_file->open (ACE_TEXT_ALWAYS_CHAR (this->filename_),
00544                          ios::out);
00545 #endif /* ACE_LACKS_IOSTREAM_TOTALLY */
00546 
00547       // Release the lock previously acquired.
00548       this->log_msg_->release ();
00549     }
00550 
00551   return 0;
00552 }
00553 
00554 void
00555 ACE_Logging_Strategy::log_msg (ACE_Log_Msg *log_msg)
00556 {
00557   this->log_msg_  = log_msg;
00558 }
00559 
00560 ACE_END_VERSIONED_NAMESPACE_DECL
00561 
00562 // The following is a "Factory" used by the ACE_Service_Config and
00563 // svc.conf file to dynamically initialize the state of the
00564 // Logging_Strategy.
00565 
00566 ACE_FACTORY_DEFINE (ACE, ACE_Logging_Strategy)

Generated on Tue Feb 2 17:18:40 2010 for ACE by  doxygen 1.4.7