![]() |
|
|
Generated: 8 Jan 2009 |
00001 // $Id: AIDATupleSvc.cpp,v 1.5 2006/11/15 10:45:18 hmd Exp $ 00002 // Include files 00003 #include <cstdlib> 00004 00005 #include "GaudiKernel/DataObject.h" 00006 #include "GaudiKernel/Tokenizer.h" 00007 #include "GaudiKernel/SvcFactory.h" 00008 #include "GaudiKernel/GaudiException.h" 00009 #include "GaudiKernel/ISvcLocator.h" 00010 #include "GaudiKernel/IConversionSvc.h" 00011 #include "GaudiKernel/GenericAddress.h" 00012 #include "GaudiKernel/MsgStream.h" 00013 #include "GaudiKernel/Property.h" 00014 #include "GaudiKernel/IRegistry.h" 00015 00016 #include "AIDATupleSvc.h" 00017 00018 //------------------------------------- 00019 //For myTest(). REMOVE: 00020 #include "CLHEP/Random/RandGauss.h" 00021 #include "CLHEP/Random/DRand48Engine.h" 00022 #include <math.h> 00023 //------------------------------------- 00024 00031 // Instantiation of a static factory class used by clients to create 00032 // instances of this service 00033 00034 DECLARE_SERVICE_FACTORY(AIDATupleSvc) 00035 00036 00037 StatusCode AIDATupleSvc::myTest() 00038 { 00039 MsgStream log ( msgSvc(), name() ); 00040 log << MSG::INFO << "Wellcome to myTest!" << endreq; 00041 00042 // Defining the description of the tuple columns 00043 std::string description = "float px; float py; float pz; float mass"; 00044 00045 pi_aida::Proxy_Store* store = new pi_aida::Proxy_Store("ntuple.root","POOL",0,"CAT=xmlcatalog_file:anotherCatalog.xml,SUB=POOL_ROOTTREE"); 00046 pi_aida::Tuple tuple(*store, "1", "tuple1", description); 00047 //AIDATuple tuple( store, "1", "example tuple", description ); 00048 00049 DRand48Engine randomEngine; 00050 RandGauss rBeamEnergy( randomEngine, 90, 5 ); 00051 RandGauss rTracksSpread( randomEngine, 0, 2 ); 00052 RandGauss rMomentum( randomEngine, 0, 3 ); 00053 RandGauss rMass( randomEngine, 1, 0.1 ); 00054 00055 std::cout << "Tuple created ... starting to fill " << std::endl; 00056 00057 int i_px = tuple.findColumn( "px" ); 00058 int i_py = tuple.findColumn( "py" ); 00059 int i_pz = tuple.findColumn( "pz" ); 00060 int i_mass = tuple.findColumn( "mass" ); 00061 00062 for ( unsigned int i = 0; i < 1000; i++ ) { 00063 00064 tuple.fill( i_px, rMomentum.fire() ); 00065 tuple.fill( i_py, rMomentum.fire() ); 00066 tuple.fill( i_pz, rMomentum.fire() ); 00067 tuple.fill( i_mass, rMass.fire() ); 00068 tuple.addRow(); 00069 } 00070 std::cout << "Filled the tuple with " << tuple.rows() << " rows" << std::endl; 00071 store->close(); 00072 delete store; 00073 00074 pi_aida::Proxy_Store* store1 = new pi_aida::Proxy_Store("ntuple.root","POOL",3,"CAT=xmlcatalog_file:anotherCatalog.xml,SUB=POOL_ROOTTREE"); 00075 pi_aida::Tuple tuple1 = store1->retrieveTuple("1"); 00076 00077 //AIDATuple tuple1 = store1->retrieveTuple("1"); 00078 //AIDATuple tuple = static_cast<AIDATuple>(tmp); 00079 00080 std::cout << "FOUND TUPLE WITH " << tuple1.rows() << " ROWS" << std::endl; 00081 00082 tuple1.start(); 00083 int i = 0; 00084 while( tuple1.next() ) { 00085 i++; 00086 std::cout << "ROW " << i << std::endl; 00087 std::cout << "px: " << tuple1.getFloat(i_px) << std::endl; 00088 std::cout << "py: " << tuple1.getFloat(i_py) << std::endl; 00089 std::cout << "pz: " << tuple1.getFloat(i_pz) << std::endl; 00090 std::cout << "mass: " << tuple1.getFloat(i_mass) << std::endl; 00091 } 00092 store1->close(); 00093 delete store1; 00094 return StatusCode::SUCCESS; 00095 } 00096 00097 00098 // ============================================== 00099 // Methods to book a tuple in the transient store 00100 // ============================================== 00101 AIDA::ITuple* AIDATupleSvc::book( const std::string& fullPath, 00102 const std::string& title, 00103 const std::string& columns ) 00104 { 00105 std::string dirPath, objPath, storePath, storeObj; 00106 parsePath( fullPath, dirPath, objPath, storePath, storeObj); 00107 00108 Connections::iterator i = m_connections.find(storePath); 00109 if( i != m_connections.end() ) { 00110 pi_aida::Tuple* tmp = new pi_aida::Tuple( *(*i).second, storeObj, title, columns ); 00111 AIDA::ITuple* tuple = tmp; 00112 00113 if( registerObject(dirPath, objPath, tuple).isSuccess() ) 00114 return tuple; 00115 else { 00116 delete tuple; 00117 throw GaudiException("Cannot book tuple " + title,"AIDATupleSvc", StatusCode::FAILURE); 00118 } 00119 } 00120 else 00121 throw GaudiException("Cannot find store " + storePath, "AIDATupleSvc", StatusCode::FAILURE); 00122 } 00123 00124 00125 AIDA::ITuple* AIDATupleSvc::book( const std::string& parentPath, 00126 const std::string& objPath, 00127 const std::string& title, 00128 const std::string& columns ) 00129 { 00130 std::string fullPath = parentPath+"/"+objPath; 00131 return book( fullPath, title, columns ); 00132 } 00133 00134 00135 AIDA::ITuple* AIDATupleSvc::book( const std::string& parentPath, 00136 int tupleID, 00137 const std::string& title, 00138 const std::string& columns ) 00139 { 00140 char objPath[32]; 00141 ::_itoa(tupleID, objPath, 10); 00142 std::string fullPath = parentPath+"/"+objPath; 00143 return book( fullPath, title, columns ); 00144 } 00145 00146 00147 AIDA::ITuple* AIDATupleSvc::book( DataObject* pParent, 00148 const std::string& objPath, 00149 const std::string& title, 00150 const std::string& columns ) 00151 { 00152 IRegistry* tmp = pParent->registry(); 00153 std::string fullPath, parentPath; 00154 parentPath = tmp->identifier(); 00155 fullPath = fullPath = parentPath+"/"+objPath; 00156 return book( fullPath, title, columns ); 00157 } 00158 00159 00160 AIDA::ITuple* AIDATupleSvc::book( DataObject* pParent, 00161 int tupleID, 00162 const std::string& title, 00163 const std::string& columns ) 00164 { 00165 char txt[32]; 00166 return book( pParent, ::_itoa(tupleID, txt, 10), title, columns ); 00167 } 00168 00169 00170 // ================================================== 00171 // Methods to register a tuple in the transient store 00172 // ================================================== 00173 StatusCode AIDATupleSvc::registerObject( const std::string& dirPath, 00174 const std::string& objPath, 00175 AIDA::ITuple* tObj ) 00176 { 00177 DataObject* pParent = 0; 00178 pParent = createPath( dirPath ); 00179 return registerObject( pParent, objPath, tObj ); 00180 00181 } 00182 00183 StatusCode AIDATupleSvc::registerObject( DataObject* pParent, 00184 const std::string& objPath, 00185 AIDA::ITuple* tObj ) 00186 { 00187 // Set the tuple id 00188 if ( objPath[0] == SEPARATOR ) { 00189 if ( !tObj->annotation().addItem( "id", objPath.substr(1) ) ) 00190 tObj->annotation().setValue( "id", objPath.substr(1) ); 00191 } 00192 else { 00193 if ( !tObj->annotation().addItem( "id", objPath ) ) 00194 tObj->annotation().setValue( "id", objPath ); 00195 } 00196 00197 // Register the tuple in the tuple data store 00198 StatusCode status = DataSvc::registerObject( pParent, 00199 objPath, 00200 dynamic_cast<DataObject*>(tObj) ); 00201 return status; 00202 } 00203 00204 00205 // ==================================================== 00206 // Methods to unregister a tuple in the transient store 00207 // ==================================================== 00208 StatusCode AIDATupleSvc::unregisterObject( AIDA::ITuple* tObj ) 00209 { 00210 StatusCode status = DataSvc::unregisterObject( dynamic_cast<DataObject*>(tObj) ); 00211 return status; 00212 } 00213 00214 00215 StatusCode AIDATupleSvc::unregisterObject( AIDA::ITuple* tObj, 00216 const std::string& objPath ) 00217 { 00218 StatusCode status = DataSvc::unregisterObject( dynamic_cast<DataObject*>(tObj), 00219 objPath ); 00220 return status; 00221 } 00222 00223 00224 // =============================================== 00225 // Methods to retrieve a tuple from the data store 00226 // =============================================== 00227 StatusCode AIDATupleSvc::retrieveObject( const std::string& fullPath, 00228 AIDA::ITuple*& tObj ) 00229 { 00230 MsgStream log ( msgSvc(), name() ); 00231 StatusCode status; 00232 status = findObject(fullPath, tObj); 00233 00234 // Tuple already in the transient store 00235 if( status.isSuccess() ) 00236 return status; 00237 00238 std::string dirPath, objPath, storePath, storeObj; 00239 parsePath( fullPath, dirPath, objPath, storePath, storeObj); 00240 00241 // Load tuple from persistency 00242 Connections::iterator i = m_connections.find(storePath); 00243 if( i != m_connections.end() ) { 00244 pi_aida::Tuple* tmp = new pi_aida::Tuple(((*i).second)->retrieveTuple(storeObj)); 00245 00246 tObj = dynamic_cast<AIDA::ITuple*>(tmp); 00247 return StatusCode::SUCCESS; 00248 } 00249 log << MSG::ERROR << "Could not retrieve tuple " << fullPath << endreq; 00250 return StatusCode::FAILURE; 00251 } 00252 00253 00254 StatusCode AIDATupleSvc::retrieveObject( const std::string& parentPath, 00255 const std::string& objPath, 00256 AIDA::ITuple*& tObj ) 00257 { 00258 std::string fullPath = parentPath+'/'+objPath; 00259 return retrieveObject( fullPath, tObj ); 00260 } 00261 00262 00263 StatusCode AIDATupleSvc::retrieveObject( DataObject* pParent, 00264 const std::string& objPath, 00265 AIDA::ITuple*& tObj ) 00266 { 00267 IRegistry* tmpReg = pParent->registry(); 00268 std::string parentPath = tmpReg->identifier(); 00269 std::string fullPath = parentPath+'/'+objPath; 00270 00271 return retrieveObject( fullPath, tObj ); 00272 } 00273 00274 00275 // ========================================= 00276 // Methods to find a tuple in the data store 00277 // ========================================= 00278 StatusCode AIDATupleSvc::findObject( const std::string& fullPath, 00279 AIDA::ITuple*& tObj ) 00280 { 00281 DataObject* pObject = 0; 00282 StatusCode sc = DataSvc::findObject( fullPath, pObject ); 00283 tObj = dynamic_cast<AIDA::ITuple*>(pObject); 00284 return sc; 00285 } 00286 00287 00288 StatusCode AIDATupleSvc::findObject( IRegistry* pRegistry, 00289 const std::string& path, 00290 AIDA::ITuple*& tObj ) 00291 { 00292 DataObject* pObject = 0; 00293 StatusCode sc = DataSvc::findObject( pRegistry, path, pObject ); 00294 tObj = dynamic_cast<AIDA::ITuple*>(pObject); 00295 return sc; 00296 } 00297 00298 00299 StatusCode AIDATupleSvc::findObject( const std::string& parentPath, 00300 const std::string& objPath, 00301 AIDA::ITuple*& tObj ) 00302 { 00303 DataObject* pObject = 0; 00304 StatusCode sc = DataSvc::findObject( parentPath, objPath, pObject ); 00305 tObj = dynamic_cast<AIDA::ITuple*>(pObject); 00306 return sc; 00307 } 00308 00309 00310 StatusCode AIDATupleSvc::findObject( DataObject* parentObj, 00311 const std::string& objPath, 00312 AIDA::ITuple*& tObj ) 00313 { 00314 DataObject* pObject = 0; 00315 StatusCode sc = DataSvc::findObject( parentObj, objPath, pObject ); 00316 tObj = dynamic_cast<AIDA::ITuple*>(pObject); 00317 return sc; 00318 } 00319 00320 00321 void AIDATupleSvc::setCriteria( AIDA::ITuple*& tObj, 00322 const std::string& criteria ) 00323 { 00324 pi_aida::Tuple* t = dynamic_cast<pi_aida::Tuple*>(tObj); 00325 t->setCriteria(criteria); 00326 } 00327 00328 00329 // ============== 00330 // Helper methods 00331 // ============== 00332 00333 // std::string AIDATupleSvc::storeName(AIDA::ITuple*& tObj) 00334 // { 00335 // pi_aida::Tuple* t = dynamic_cast<pi_aida::Tuple*>(tObj); 00336 // std::cout << "NAME: " << t->storeName() << std::endl; 00337 // return t->storeName(); 00338 // } 00339 00340 00341 StatusCode AIDATupleSvc::connect( const std::string& ident, 00342 int mode ) 00343 { 00344 MsgStream log ( msgSvc(), name() ); 00345 DataObject* p0 = 0; 00346 StatusCode status = DataSvc::findObject(m_rootName, p0); 00347 if (status.isSuccess() ) { 00348 Tokenizer tok(true); 00349 long loc = ident.find(" "); 00350 int open_mode = 0; // Default is AUTO mode 00351 std::string file, typ = "", tmp_typ = "", opt = ""; 00352 std::string logname = ident.substr(0,loc); 00353 tok.analyse(ident.substr(loc+1,ident.length()), " ", "", "", "=", "'", "'"); 00354 for ( Tokenizer::Items::iterator i = tok.items().begin(); i != tok.items().end(); i++) { 00355 const std::string& tag = (*i).tag(); 00356 switch( ::toupper(tag[0]) ) { 00357 case 'F': // FILE='<file name>' 00358 case 'D': // DATAFILE='<file name>' 00359 file = (*i).value(); 00360 break; 00361 case 'O': // OPT='<AUTO, OVERWRITE, CREATE, READONLY, UPDATE>' 00362 switch( ::toupper((*i).value()[0]) ) { 00363 case 'A': // AUTO 00364 if( mode == 0 ) 00365 open_mode = 3; // READONLY 00366 else 00367 open_mode = 1; // CREATE 00368 break; 00369 case 'O': // OVERWRITE 00370 if( mode == 0 ) 00371 throw GaudiException("Input file " + file + " with improper option (OVERWRITE)", "AIDATupleSvc", StatusCode::FAILURE); 00372 else 00373 open_mode = 1; 00374 break; 00375 case 'C': // CREATE 00376 if( mode == 0 ) 00377 throw GaudiException("Input file " + file + " with improper option (CREATE)", "AIDATupleSvc", StatusCode::FAILURE); 00378 else 00379 open_mode = 2; 00380 break; 00381 case 'R': // READONLY 00382 if( mode == 1 ) 00383 throw GaudiException("Output file " + file + " with improper option (READONLY)", "AIDATupleSvc", StatusCode::FAILURE); 00384 else 00385 open_mode = 3; 00386 break; 00387 case 'U': // UPDATE 00388 if( mode == 0 ) 00389 throw GaudiException("Input file " + file + " with improper option (UPDATE)", "AIDATupleSvc", StatusCode::FAILURE); 00390 else 00391 open_mode = 4; 00392 break; 00393 } 00394 break; 00395 case 'T': // TYP='<HBOOK,ROOT,XML,POOL>' 00396 typ = (*i).value(); 00397 break; 00398 default: 00399 opt += (*i).tag() + "=" + (*i).value() + ","; 00400 break; 00401 } 00402 } 00403 00404 // Check if persistency type has been specified at job options 00405 if (typ == "") { 00406 log << MSG::WARNING << "File type not specified at job options." 00407 << " Setting 'HistogramPersistency' type as default" 00408 << endreq; 00409 // Get the value of the Stat persistancy mechanism from the AppMgr 00410 IProperty* appPropMgr = 0; 00411 status = serviceLocator()->queryInterface(IID_IProperty,(void **)&appPropMgr ); 00412 if( !status.isSuccess() ) { 00413 // Report an error and return the FAILURE status code 00414 log << MSG::ERROR << "Could not get PropMgr" << endreq; 00415 return status; 00416 } 00417 StringProperty sp("HistogramPersistency",""); 00418 status = appPropMgr->getProperty( &sp ); 00419 if ( !status.isSuccess() ) { 00420 log << MSG::ERROR << "Could not get NTuple Persistency format" 00421 << " from ApplicationMgr properties" << endreq; 00422 return status; 00423 } 00424 tmp_typ = sp.value(); 00425 if (tmp_typ == "ROOT" || tmp_typ == "XML" || tmp_typ == "HBOOK" || tmp_typ == "POOL") 00426 typ = tmp_typ; 00427 else { 00428 log << MSG::ERROR << "Unknown persistency format at 'HistogramPersistency' option" 00429 << endreq; 00430 return StatusCode::FAILURE; 00431 } 00432 } 00433 00434 // Create a new pi_aida::Proxy_Store 00435 pi_aida::Proxy_Store* storePtr = new pi_aida::Proxy_Store( file, typ, open_mode, opt ); 00436 m_connections.insert(Connections::value_type(m_rootName+'/'+logname, storePtr)); 00437 00438 return StatusCode::SUCCESS; 00439 } 00440 log << MSG::ERROR << "Cannot add " << ident << " invalid filename!" << endreq; 00441 return StatusCode::FAILURE; 00442 00443 } 00444 00445 00446 StatusCode AIDATupleSvc::closeAIDAStores() 00447 { 00448 for( Connections::iterator k = m_connections.begin(); k != m_connections.end(); k++ ) { 00449 if ( (*k).second->isOpen()) { 00450 (*k).second->close(); 00451 (*k).second = 0; 00452 } 00453 } 00454 00455 m_connections.erase(m_connections.begin(), m_connections.end()); 00456 return StatusCode::SUCCESS; 00457 } 00458 00459 00460 void AIDATupleSvc::parsePath( const std::string& fullPath, 00461 std::string& dirPath, 00462 std::string& objPath, 00463 std::string& storePath, 00464 std::string& storeObj ) 00465 { 00466 std::string tmpPath = fullPath; 00467 if ( tmpPath[0] != SEPARATOR ) { 00468 // Insert the top level name of the store (/NTUPLES) 00469 tmpPath.insert(tmpPath.begin(), SEPARATOR); 00470 tmpPath.insert(tmpPath.begin(), m_rootName.begin(), m_rootName.end()); 00471 } 00472 // Remove trailing "/" from tmpPath if it exists 00473 if (tmpPath.rfind(SEPARATOR) == tmpPath.length()-1) { 00474 tmpPath.erase(tmpPath.rfind(SEPARATOR),1); 00475 } 00476 int sep = tmpPath.rfind(SEPARATOR); 00477 dirPath = tmpPath.substr(0, sep); 00478 objPath = tmpPath.substr(sep, tmpPath.length()-sep ); 00479 sep = tmpPath.find(SEPARATOR, m_rootName.length()+1); 00480 storePath = tmpPath.substr(0, sep); 00481 storeObj = tmpPath.substr(sep+1, tmpPath.length()-sep ); 00482 } 00483 00484 00485 DataObject* AIDATupleSvc::createPath( const std::string& newPath ) 00486 { 00487 std::string tmpPath = newPath; 00488 if ( tmpPath[0] != SEPARATOR ) { 00489 tmpPath.insert(tmpPath.begin(), SEPARATOR); 00490 tmpPath.insert(tmpPath.begin(), m_rootName.begin(), m_rootName.end()); 00491 } 00492 // Remove trailing "/" from newPath if it exists 00493 if (tmpPath.rfind(SEPARATOR) == tmpPath.length()-1) { 00494 tmpPath.erase(tmpPath.rfind(SEPARATOR),1); 00495 } 00496 00497 DataObject* pObject = 0; 00498 StatusCode sc = DataSvc::findObject( tmpPath, pObject ); 00499 if( sc.isSuccess() ) { 00500 return pObject; 00501 } 00502 00503 int sep = tmpPath.rfind(SEPARATOR); 00504 std::string rest( tmpPath, sep+1, tmpPath.length()-sep ); 00505 std::string subPath( tmpPath, 0, sep ); 00506 if( 0 != sep ) { 00507 createPath( subPath ); 00508 } 00509 else { 00510 MsgStream log( msgSvc(), name() ); 00511 log << MSG::ERROR << "Unable to create the tuple path" << endreq; 00512 return 0; 00513 } 00514 00515 pObject = createDirectory( subPath, rest ); 00516 return pObject; 00517 } 00518 00519 00520 DataObject* AIDATupleSvc::createDirectory( const std::string& parentDir, 00521 const std::string& subDir ) 00522 { 00523 00524 StatusCode status = StatusCode::FAILURE; 00525 DataObject* directory = new DataObject(); 00526 00527 if ( 0 != directory ) { 00528 DataObject* pnode; 00529 status = DataSvc::findObject( parentDir, pnode ); 00530 if( status.isSuccess() ) { 00531 status = DataSvc::registerObject( pnode, subDir, directory ); 00532 if ( !status.isSuccess() ) { 00533 MsgStream log( msgSvc(), name() ); 00534 log << MSG::ERROR << "Unable to create the directory: " 00535 << parentDir << "/" << subDir << endreq; 00536 delete directory; 00537 return 0; 00538 } 00539 } 00540 else { 00541 MsgStream log( msgSvc(), name() ); 00542 log << MSG::ERROR << "Unable to create the directory: " 00543 << parentDir << "/" << subDir << endreq; 00544 delete directory; 00545 return 0; 00546 } 00547 } 00548 return directory; 00549 } 00550 00551 // ======================================== 00552 // Constructor, destructor and main methods 00553 // ======================================== 00554 AIDATupleSvc::AIDATupleSvc( const std::string& name, ISvcLocator* svc ) 00555 : DataSvc( name, svc ) 00556 { 00557 // Properties can be declared here 00558 m_rootName = "/NTUPLES"; 00559 m_rootCLID = CLID_DataObject; 00560 declareProperty("Input", m_input); 00561 declareProperty("Output", m_output); 00562 } 00563 00564 00565 AIDATupleSvc::~AIDATupleSvc() 00566 { 00567 clearStore().ignore(); 00568 } 00569 00570 00571 StatusCode AIDATupleSvc::initialize() 00572 { 00573 MsgStream log( msgSvc(), name() ); 00574 StatusCode status = DataSvc::initialize(); 00575 00576 if( status.isSuccess() ){ 00577 DataObject* rootObj = new DataObject(); 00578 status = setRoot( m_rootName, rootObj ); 00579 if( !status.isSuccess() ) { 00580 log << MSG::ERROR << "Unable to set NTuple data store root." << endreq; 00581 delete rootObj; 00582 return status; 00583 } 00584 00585 //Connect inputs (MODE = 0) 00586 for( DBaseEntries::iterator i = m_input.begin(); i != m_input.end(); i++ ) { 00587 status = connect(*i, 0); 00588 if( !status.isSuccess() ) 00589 return status; 00590 } 00591 //Connect outputs (MODE = 1) 00592 for( DBaseEntries::iterator j = m_output.begin(); j != m_output.end(); j++ ) { 00593 status = connect(*j, 1); 00594 if( !status.isSuccess() ) 00595 return status; 00596 } 00597 } 00598 return status; 00599 } 00600 00601 00602 StatusCode AIDATupleSvc::reinitialize() 00603 { 00604 return StatusCode::SUCCESS; 00605 } 00606 00607 00608 StatusCode AIDATupleSvc::finalize() 00609 { 00610 MsgStream log( msgSvc(), name() ); 00611 StatusCode status = DataSvc::finalize(); 00612 if( status.isSuccess() ) { 00613 status = closeAIDAStores(); 00614 if( status.isSuccess() ) 00615 return status; 00616 } 00617 log << MSG::ERROR << "Error finalizing AIDATupleSvc." << endreq; 00618 return status; 00619 } 00620 00621 00622 StatusCode AIDATupleSvc::queryInterface( const InterfaceID& riid, 00623 void** ppvInterface ) 00624 { 00625 if( riid == IID_IAIDATupleSvc ) { 00626 *ppvInterface = static_cast<IAIDATupleSvc*>(this); 00627 } 00628 else { 00629 // Interface is not directly availible: try out a base class 00630 return DataSvc::queryInterface( riid, ppvInterface ); 00631 } 00632 addRef(); 00633 return StatusCode::SUCCESS; 00634 }