SFrame 3.6
core/src/SCycleOutput.cxx
Go to the documentation of this file.
00001 // $Id: SCycleOutput.cxx 191 2010-08-04 08:00:45Z krasznaa $
00002 /***************************************************************************
00003  * @Project: SFrame - ROOT-based analysis framework for ATLAS
00004  * @Package: Core
00005  *
00006  * @author Stefan Ask       <Stefan.Ask@cern.ch>           - Manchester
00007  * @author David Berge      <David.Berge@cern.ch>          - CERN
00008  * @author Johannes Haller  <Johannes.Haller@cern.ch>      - Hamburg
00009  * @author A. Krasznahorkay <Attila.Krasznahorkay@cern.ch> - CERN/Debrecen
00010  *
00011  ***************************************************************************/
00012 
00013 // System include(s):
00014 #include <string.h>
00015 
00016 // STL include(s):
00017 #include <vector>
00018 
00019 // ROOT include(s):
00020 #include <TCollection.h>
00021 #include <TList.h>
00022 #include <TMethodCall.h>
00023 #include <TDirectory.h>
00024 #include <TTree.h>
00025 #include <TKey.h>
00026 #include <TObjArray.h>
00027 #include <TObjString.h>
00028 
00029 // Local include(s):
00030 #include "../include/SCycleOutput.h"
00031 #include "../include/SLogger.h"
00032 
00033 #ifndef DOXYGEN_IGNORE
00034 ClassImp( SCycleOutput );
00035 #endif // DOXYGEN_IGNORE
00036 
00045 SCycleOutput::SCycleOutput( TObject* object, const char* name,
00046                             const char* path )
00047    : TNamed( name, "SFrame cycle output object" ), m_object( object ),
00048      m_path( path ), m_logger( "SCycleOutput" ) {
00049 
00050 }
00051 
00056 SCycleOutput::~SCycleOutput() {
00057 
00058    if( m_object ) delete m_object;
00059 }
00060 
00064 TObject* SCycleOutput::GetObject() const {
00065 
00066    return m_object;
00067 }
00068 
00072 void SCycleOutput::SetObject( TObject* object ) {
00073 
00074    m_object = object;
00075    return;
00076 }
00077 
00078 const TString& SCycleOutput::GetPath() const {
00079 
00080    return m_path;
00081 }
00082 
00083 void SCycleOutput::SetPath( const TString& path ) {
00084 
00085    m_path = path;
00086    return;
00087 }
00088 
00099 Int_t SCycleOutput::Merge( TCollection* coll ) {
00100 
00101    //
00102    // Return right away if the input is flawed:
00103    //
00104    if( ! coll ) return 0;
00105    if( coll->IsEmpty() ) return 0;
00106 
00107    //
00108    // Select the elements from the collection that can actually be merged:
00109    //
00110    TList list;
00111    TIter next( coll );
00112    TObject* obj = 0;
00113    while( ( obj = next() ) ) {
00114 
00115       //
00116       // See if it is an SCycleOutput object itself:
00117       //
00118       SCycleOutput* sobj = dynamic_cast< SCycleOutput* >( obj );
00119       if( ! sobj ) {
00120          REPORT_ERROR( "Trying to merge \"" << obj->ClassName()
00121                        << "\" object into \"" << this->ClassName() << "\"" );
00122          continue;
00123       }
00124 
00125       //
00126       // See if it holds the same kind of object as this output object:
00127       //
00128       TObject* mobj = sobj->GetObject();
00129       if( ! mobj ) continue;
00130       if( strcmp( mobj->ClassName(), this->GetObject()->ClassName() ) ) {
00131          REPORT_ERROR( "Trying to merge \"" << mobj->ClassName()
00132                        << "\" object into \"" << this->GetObject()->ClassName() );
00133          continue;
00134       }
00135 
00136       //
00137       // If everything is fine, add it to the list of objects to merge:
00138       //
00139       list.Add( mobj );
00140 
00141    }
00142 
00143    //
00144    // Stop if the list is empty:
00145    //
00146    if( list.IsEmpty() ) {
00147       m_logger << WARNING << "No suitable object found for merging" << SLogger::endmsg;
00148       return 0;
00149    }
00150 
00151    //
00152    // Make sure that my object supports merging:
00153    //
00154    TMethodCall mergeMethod;
00155    mergeMethod.InitWithPrototype( this->GetObject()->IsA(), "Merge", "TCollection*" );
00156    if( ! mergeMethod.IsValid() ) {
00157       REPORT_ERROR( "Object type \"" << this->GetObject()->ClassName()
00158                     << "\" doesn't support merging" );
00159       return 0;
00160    }
00161 
00162    //
00163    // Execute the merging:
00164    //
00165    mergeMethod.SetParam( ( Long_t ) &list );
00166    mergeMethod.Execute( this->GetObject() );
00167 
00168    //
00169    // A little feedback of what we've done:
00170    //
00171    m_logger << DEBUG << "Merged objects of type \"" << this->GetObject()->ClassName()
00172             << "\"" << SLogger::endmsg;
00173 
00174    return 1;
00175 
00176 }
00177 
00188 Int_t SCycleOutput::Write( const char* name, Int_t option,
00189                            Int_t bufsize ) const {
00190 
00191    // Nothing to be done with no object:
00192    if( ! m_object ) return -1;
00193 
00194    //
00195    // Remember both the current directory, and create the directory for the
00196    // output object:
00197    //
00198    TDirectory* origDir = gDirectory;
00199    TDirectory* outDir = MakeDirectory( m_path );
00200 
00201    //
00202    // Check if the output directory already holds such an object:
00203    //
00204    TObject* original_obj;
00205    if( ( original_obj = outDir->Get( m_object->GetName() ) ) ) {
00206 
00207       m_logger << DEBUG << "Merging object \"" << m_object->GetName() << "\" under \""
00208                << m_path << "\" with already existing object..." << SLogger::endmsg;
00209 
00210       //
00211       // Check that it's the same type as the object that we want to save:
00212       //
00213       if( strcmp( original_obj->ClassName(), m_object->ClassName() ) ) {
00214          REPORT_ERROR( "Object in file (\"" << original_obj->ClassName()
00215                        << "\") is not the same type as the object in memory (\""
00216                        << m_object->ClassName() << "\")" );
00217          return 0;
00218       }
00219 
00220       //
00221       // Try to merge the new object into the old one:
00222       //
00223       TMethodCall mergeMethod;
00224       mergeMethod.InitWithPrototype( original_obj->IsA(), "Merge", "TCollection*" );
00225       if( ! mergeMethod.IsValid() ) {
00226          REPORT_ERROR( "Object type \"" << original_obj->ClassName()
00227                        << "\" doesn't support merging" );
00228          return 0;
00229       }
00230 
00231       //
00232       // Remember the key of this object, to be able to remove it after the merging:
00233       //
00234       TKey* oldKey = outDir->GetKey( m_object->GetName() );
00235 
00236       //
00237       // Execute the merging:
00238       //
00239       TList list;
00240       list.Add( m_object );
00241       mergeMethod.SetParam( ( Long_t ) &list );
00242       mergeMethod.Execute( original_obj );
00243 
00244       //
00245       // Remove the old object from the file:
00246       //
00247       oldKey->Delete();
00248       delete oldKey;
00249 
00250       // Return gracefully:
00251       return 1;
00252 
00253    }
00254 
00255    //
00256    // TTree-s have to be handled in a special way:
00257    //
00258    TTree* tobject = dynamic_cast< TTree* >( m_object );
00259    if( tobject ) tobject->SetDirectory( outDir );
00260 
00261    //
00262    // Write out the object:
00263    //
00264    outDir->cd();
00265    Int_t ret = m_object->Write( name, option, bufsize );
00266    if( tobject ) tobject->AutoSave();
00267    origDir->cd();
00268 
00269    // Remove the memory-resident TTree from the directory:
00270    if( tobject ) tobject->SetDirectory( 0 );
00271 
00272    REPORT_VERBOSE( "Written object \"" << m_object->GetName()
00273                    <<"\" to: " << outDir->GetPath() );
00274 
00275    return ret;
00276 
00277 }
00278 
00279 Int_t SCycleOutput::Write( const char* name, Int_t option,
00280                            Int_t bufsize ) {
00281 
00282    return const_cast< const SCycleOutput* >( this )->Write( name, option, bufsize );
00283 }
00284 
00291 TDirectory* SCycleOutput::MakeDirectory( const TString& path ) const throw( SError ) {
00292 
00293    if( ! path.Length() ) return gDirectory;
00294 
00295    TDirectory* dir = 0;
00296    if( ! ( dir = gDirectory->GetDirectory( path ) ) ) {
00297 
00298       REPORT_VERBOSE( "Creating directory: "
00299                       << gDirectory->GetPath() << "/" << path );
00300 
00301       //
00302       // Break up the path name at the slashes:
00303       //
00304       TObjArray* directories = path.Tokenize( "/" );
00305 
00306       //
00307       // Create each necessary directory:
00308       //
00309       dir = gDirectory;
00310       TDirectory* tempDir = 0;
00311       for( Int_t i = 0; i < directories->GetSize(); ++i ) {
00312 
00313          TObjString* path_element = dynamic_cast< TObjString* >( directories->At( i ) );
00314          if( ! path_element ) continue;
00315          if( path_element->GetString() == "" ) continue;
00316 
00317          REPORT_VERBOSE( "Accessing directory: " << path_element->GetString() );
00318          if( ! ( tempDir = dir->GetDirectory( path_element->GetString() ) ) ) {
00319             REPORT_VERBOSE( "Directory doesn't exist, creating it..." );
00320             if( ! ( tempDir = dir->mkdir( path_element->GetString(), "dummy title" ) ) ) {
00321                SError error( SError::SkipInputData );
00322                error << "Couldn't create directory: " << path
00323                      << " in the output file!";
00324                throw error;
00325             }
00326          }
00327          dir = tempDir;
00328 
00329       }
00330 
00331       // Delete the object created by TString::Tokenize(...):
00332       delete directories;
00333 
00334    }
00335 
00336    return dir;
00337 
00338 }