00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022 #define GAUDISVC_NTUPLESVC_CPP
00023
00024
00025 #include "GaudiKernel/xtoa.h"
00026 #include "GaudiKernel/SmartIF.h"
00027 #include "GaudiKernel/Tokenizer.h"
00028 #include "GaudiKernel/SvcFactory.h"
00029 #include "GaudiKernel/DataObject.h"
00030 #include "GaudiKernel/ObjectFactory.h"
00031 #include "GaudiKernel/GenericAddress.h"
00032
00033 #include "GaudiKernel/IProperty.h"
00034 #include "GaudiKernel/ISvcLocator.h"
00035 #include "GaudiKernel/IDataSelector.h"
00036
00037 #include "GaudiKernel/Property.h"
00038 #include "GaudiKernel/Selector.h"
00039 #include "GaudiKernel/MsgStream.h"
00040 #include "GaudiKernel/ConversionSvc.h"
00041 #include "GaudiKernel/DataSelectionAgent.h"
00042 #include "GaudiKernel/NTupleImplementation.h"
00043
00044 #include "NTupleSvc.h"
00045
00046
00047
00048 DECLARE_SERVICE_FACTORY(NTupleSvc)
00049
00050
00051 DECLARE_NAMESPACE_OBJECT_FACTORY(NTuple,Selector)
00052
00054 NTupleSvc::NTupleSvc(const std::string& name, ISvcLocator* svc)
00055 : base_class(name, svc)
00056 {
00057 declareProperty("Input", m_input);
00058 declareProperty("Output", m_output);
00059 m_rootName = "/NTUPLES";
00060 m_rootCLID = CLID_DataObject;
00061 }
00062
00064 NTupleSvc::~NTupleSvc() {
00065 }
00066
00068 StatusCode NTupleSvc::initialize() {
00069 StatusCode status = DataSvc::initialize();
00070 if ( status.isSuccess() ) {
00071 status = setProperties();
00072 if ( status.isSuccess() ) {
00073 StatusCode iret(StatusCode::SUCCESS,true);
00074 DataObject* root = new NTuple::Directory();
00075 status = setRoot(m_rootName, root);
00076 for ( DBaseEntries::iterator i = m_output.begin(); i != m_output.end(); ++i ) {
00077 iret = connect(*i);
00078 if ( !iret.isSuccess() ) {
00079 status = iret;
00080 }
00081 }
00082 for ( DBaseEntries::iterator j = m_input.begin(); j != m_input.end(); ++j ) {
00083 iret = connect(*j);
00084 if ( !iret.isSuccess() ) {
00085 status = iret;
00086 }
00087 }
00088 }
00089 }
00090 return status;
00091 }
00092
00094 StatusCode NTupleSvc::reinitialize() {
00095 return StatusCode::SUCCESS;
00096 }
00097
00098
00099 bool NTupleSvc::isConnected(const std::string& identifier) const {
00100 Connections::const_iterator i = m_connections.find(identifier);
00101 return !(i==m_connections.end());
00102 }
00103
00105 IConversionSvc* NTupleSvc::getDataLoader(IRegistry* pRegistry) {
00106 if ( 0 != pRegistry ) {
00107 std::string full = pRegistry->identifier();
00108 size_t len = m_rootName.length();
00109 size_t idx = full.find(SEPARATOR,len+1);
00110 std::string path = (idx==std::string::npos) ? full : full.substr(0, idx);
00111 Connections::iterator i = m_connections.find(path);
00112 if ( i != m_connections.end() ) {
00113 return (*i).second.service;
00114 }
00115 }
00116 return 0;
00117 }
00118
00119 StatusCode NTupleSvc::updateDirectories() {
00120 typedef std::vector<IRegistry*> Leaves;
00121 long need_update = 0;
00122 DataObject* pO = 0;
00123 StatusCode iret = findObject(m_rootName, pO);
00124 MsgStream log ( msgSvc(), name() );
00125
00126 if ( iret.isSuccess() ) {
00127 Leaves leaves;
00128 iret = objectLeaves(pO, leaves);
00129 if ( iret.isSuccess() ) {
00130
00131 for ( Leaves::iterator d = leaves.begin(); d != leaves.end(); d++ ) {
00132 if ( (*d)->object() ) {
00133 IOpaqueAddress* pA = (*d)->address();
00134 if ( pA ) {
00135 unsigned long typ = pA->ipar()[1];
00136 if ( typ == 'R' || typ == 'N' || typ == 'U' ) {
00137
00138 IConversionSvc* svc = getDataLoader(*d);
00139 if ( 0 != svc ) {
00140 StatusCode status;
00141 DataSelectionAgent agent;
00142 IDataSelector* sel = agent.selectedObjects();
00143 traverseSubTree ( (*d)->object(), &agent ).ignore();
00144 for(int i = sel->size()-1; i >= 0; i-- ) {
00145 DataObject* o = (*sel)[i];
00146 IRegistry* r = o->registry();
00147 status = svc->updateRep(r->address(), o);
00148 if ( !status.isSuccess() ) {
00149 iret = status;
00150 }
00151 }
00152 for(int j = sel->size()-1; j >= 0; j-- ) {
00153 DataObject* o = (*sel)[j];
00154 IRegistry* r = o->registry();
00155 status = svc->updateRepRefs(r->address(), o);
00156 if ( !status.isSuccess() ) {
00157 iret = status;
00158 }
00159 }
00160 if ( iret.isSuccess() ) need_update += sel->size();
00161 }
00162 }
00163 }
00164 }
00165 }
00166 }
00167 }
00168 if ( !iret.isSuccess() ) {
00169 log << MSG::ERROR << "ERROR while saving NTuples" << endmsg;
00170 return iret;
00171 }
00172 else if ( need_update > 0 ) {
00173 log << MSG::INFO << "NTuples saved successfully" << endmsg;
00174 }
00175 return iret;
00176 }
00177
00178
00179 void NTupleSvc::releaseConnection(Connection& c) {
00180 SmartIF<IService> isvc( c.service );
00181 if ( isvc.isValid( ) ) {
00182 isvc->finalize().ignore();
00183 }
00184 c.service->release();
00185 c.service = 0;
00186 }
00187
00188
00189 StatusCode NTupleSvc::disconnect(const std::string& nam) {
00190 Connections::iterator i = m_connections.find(nam);
00191 if ( i != m_connections.end() ) {
00192 releaseConnection((*i).second);
00193 m_connections.erase(i);
00194 return StatusCode::SUCCESS;
00195 }
00196 return StatusCode::FAILURE;
00197 }
00198
00199
00200 StatusCode NTupleSvc::disconnectAll() {
00201 for(Connections::iterator i = m_connections.begin(); i != m_connections.end(); ++i) {
00202 releaseConnection((*i).second);
00203 }
00204 m_connections.erase(m_connections.begin(), m_connections.end());
00205 return StatusCode::SUCCESS;
00206 }
00207
00209 StatusCode NTupleSvc::finalize() {
00210 StatusCode status = updateDirectories();
00211 status = clearStore();
00212 status = DataSvc::finalize();
00213 status = disconnectAll();
00214 return status;
00215 }
00216
00217 StatusCode NTupleSvc::connect(const std::string& ident) {
00218 std::string logName;
00219 return connect(ident, logName);
00220 }
00221
00222 StatusCode NTupleSvc::connect(const std::string& ident, std::string& logname) {
00223 MsgStream log ( msgSvc(), name() );
00224 DataObject* pO = 0;
00225 StatusCode status = findObject(m_rootName, pO);
00226 if ( status.isSuccess() ) {
00227 char typ=0;
00228 Tokenizer tok(true);
00229 std::vector<Prop> props;
00230 long loc = ident.find(" ");
00231 std::string filename, auth, svc = "", db_typ = "";
00232 logname = ident.substr(0,loc);
00233 tok.analyse(ident.substr(loc+1,ident.length()), " ", "", "", "=", "'", "'");
00234 for ( Tokenizer::Items::iterator i = tok.items().begin(); i != tok.items().end(); ++i) {
00235 const std::string& tag = (*i).tag();
00236 switch( ::toupper(tag[0]) ) {
00237 case 'A':
00238 break;
00239 case 'F':
00240 case 'D':
00241 filename = (*i).value();
00242 break;
00243 case 'O':
00244 switch( ::toupper((*i).value()[0]) ) {
00245 case 'C':
00246 case 'N':
00247 case 'W':
00248 typ = 'N';
00249 break;
00250 case 'U':
00251 typ = 'U';
00252 break;
00253 case 'O':
00254 case 'R':
00255 typ = 'O';
00256 break;
00257 default:
00258 typ = 0;
00259 break;
00260 }
00261 break;
00262 case 'T':
00263 db_typ = (*i).value();
00264 break;
00265 default:
00266 props.push_back( Prop((*i).tag(), (*i).value()));
00267 break;
00268 }
00269 }
00270 if ( 0 != typ ) {
00271 IConversionSvc* pSvc = 0;
00272 status = createService(name()+'.'+logname, db_typ, props, pSvc);
00273 if ( status.isSuccess() ) {
00274 status = attachTuple(filename, logname, typ, pSvc->repSvcType());
00275 if ( status.isSuccess() ) {
00276 m_connections.insert(Connections::value_type(m_rootName+'/'+logname,Connection(pSvc)));
00277 return StatusCode::SUCCESS;
00278 }
00279 }
00280 }
00281 }
00282 log << MSG::ERROR << "Cannot add " << ident << " invalid filename!" << endmsg;
00283 return StatusCode::FAILURE;
00284 }
00285
00286 StatusCode NTupleSvc::createService(const std::string& ,
00287 const std::string& typ,
00288 const std::vector<Prop>& ,
00289 IConversionSvc*& pSvc)
00290 {
00291 MsgStream log ( msgSvc(), name() );
00293
00294 IProperty* appPropMgr = 0;
00295 StatusCode sts = serviceLocator()->queryInterface(IProperty::interfaceID(), pp_cast<void>(&appPropMgr) );
00296 if( !sts.isSuccess() ) {
00297
00298 log << MSG::ERROR << "Could not get PropMgr" << endmsg;
00299 return sts;
00300 }
00301
00302 StringProperty sp("HistogramPersistency","");
00303 sts = appPropMgr->getProperty( &sp );
00304 if ( !sts.isSuccess() ) {
00305 log << MSG::ERROR << "Could not get NTuple Persistency format"
00306 << " from ApplicationMgr properties" << endmsg;
00307 return sts;
00308 }
00309
00310 long storage_typ = TEST_StorageType;
00311 if ( sp.value() == "HBOOK" ) {
00312 storage_typ = HBOOK_StorageType;
00313 }
00314 else if ( sp.value() == "ROOT" ) {
00315 storage_typ = ROOT_StorageType;
00316 }
00317 else {
00318 appPropMgr->release();
00319 log << MSG::ERROR << "Unknown NTuple Persistency format: " << sp.value() << endmsg;
00320 return StatusCode::FAILURE;
00321 }
00322
00323 appPropMgr->release();
00324
00325 if ( typ.length() > 0 && typ != sp.value() ) {
00326 log << MSG::WARNING << "NTuple persistency type is "
00327 << sp.value() << "." << endmsg
00328 << "Type given by job option "
00329 << "NTupleSvc.Input/Output ignored!" << endmsg;
00330 }
00331
00332
00333
00334
00335 IService* pService = 0;
00336 IInterface* iface = new ConversionSvc(name()+"Conversions", serviceLocator(), storage_typ);
00337 StatusCode status = iface->queryInterface(IService::interfaceID(), pp_cast<void>(&pService));
00338 if ( status.isSuccess() ) {
00339 status = iface->queryInterface(IConversionSvc::interfaceID(), pp_cast<void>(&pSvc));
00340 if ( !status.isSuccess() ) {
00341 pService->release();
00342 return status;
00343 }
00344 }
00345 status = pService->sysInitialize();
00346 if ( !status.isSuccess() ) {
00347 return status;
00348 }
00349 pService->release();
00350 status = pSvc->setDataProvider(this);
00351 if ( !status.isSuccess() ) {
00352 return status;
00353 }
00354 return status;
00355 }
00356
00358 StatusCode NTupleSvc::create(const CLID& typ, const std::string& title, NTuple::Tuple*& refpTuple) {
00359 NTuple::TupleImp* pTuple = 0;
00360 StatusCode status = StatusCode::FAILURE;
00361 if ( typ == CLID_ColumnWiseTuple ) {
00362 pTuple = new NTuple::ColumnWiseTuple( title );
00363 }
00364 else if ( typ == CLID_RowWiseTuple ) {
00365 pTuple = new NTuple::RowWiseTuple( title );
00366 }
00367 else {
00369 }
00370 if ( 0 != pTuple ) {
00371 pTuple->setTupleService(this);
00372 status = StatusCode::SUCCESS;
00373 }
00374 refpTuple = pTuple;
00375 return status;
00376 }
00377
00379 NTuple::Tuple* NTupleSvc::book (const std::string& fullPath, const CLID& type, const std::string& title) {
00380 DataObject* pObj = 0;
00381 std::string path = fullPath;
00382 MsgStream log(msgSvc(), name());
00383 if ( path[0] != SEPARATOR ) {
00384 path = m_rootName;
00385 path += SEPARATOR;
00386 path += fullPath;
00387 }
00388 StatusCode status = retrieveObject(path, pObj);
00389 if ( !status.isSuccess() ) {
00390 int sep = path.rfind(SEPARATOR);
00391 if ( sep > 0 ) {
00392 std::string p_path (path, 0, sep);
00393 std::string o_path (path, sep, path.length());
00394 DataObject* dir = createDirectory(p_path);
00395 if ( 0 != dir ) {
00396 NTuple::Tuple* tup = book( dir, o_path, type, title);
00397 if ( 0 == tup ) {
00398 log << MSG::ERROR << "Cannot book N-tuple " << path << " (Unknown reason)" << endmsg;
00399 }
00400 return tup;
00401 }
00402 log << MSG::ERROR << "Cannot book N-tuple " << path << " (Invalid parent directory)" << endmsg;
00403 return 0;
00404 }
00405 log << MSG::ERROR << "Cannot book N-tuple " << path << " (Invalid path)" << endmsg;
00406 return 0;
00407 }
00408 log << MSG::ERROR << "Cannot book N-tuple " << path << " (Exists already)" << endmsg;
00409 return 0;
00410 }
00411
00413 NTuple::Tuple* NTupleSvc::book (const std::string& dirPath, const std::string& relPath, const CLID& type, const std::string& title) {
00414 std::string full = dirPath;
00415 if (relPath[0] != SEPARATOR) full += SEPARATOR;
00416 full += relPath;
00417 return book(full, type, title);
00418 }
00419
00421 NTuple::Tuple* NTupleSvc::book (const std::string& dirPath, long id, const CLID& type, const std::string& title) {
00422 char txt[32];
00423 return book( dirPath, _itoa(id, txt, 10), type, title);
00424 }
00425
00427 NTuple::Tuple* NTupleSvc::book (DataObject* pParent, const std::string& relPath, const CLID& type, const std::string& title) {
00428 NTuple::Tuple* pObj = 0;
00429
00430 StatusCode status = findObject(pParent, relPath, *pp_cast<DataObject>(&pObj));
00431
00432 if ( !status.isSuccess() ) {
00433 status = create( type, title, pObj);
00434 if ( status.isSuccess() ) {
00435
00436 status = registerObject(pParent, relPath, pObj);
00437 if ( status.isSuccess() ) {
00438 return pObj;
00439 }
00440 pObj->release();
00441 }
00442 }
00443 return 0;
00444 }
00445
00447 NTuple::Tuple* NTupleSvc::book (DataObject* pParent,
00448 long id,
00449 const CLID& type,
00450 const std::string& title) {
00451 char txt[32];
00452 return book( pParent, ::_itoa(id, txt,10), type, title);
00453 }
00454
00456 NTuple::Directory* NTupleSvc::createDirectory (DataObject* pParent,
00457 const std::string& relPath) {
00458 if ( 0 != pParent ) {
00459 IRegistry* pDir = pParent->registry();
00460 if ( 0 != pDir ) {
00461 std::string full = pDir->identifier();
00462 full += (relPath[0]=='/') ? "" : "/";
00463 full += relPath;
00464 return createDirectory(full);
00465 }
00466 }
00467 return 0;
00468 }
00469
00471 NTuple::Directory* NTupleSvc::createDirectory (DataObject* pParent, long id) {
00472 char txt[32];
00473 return createDirectory( pParent, ::_itoa(id, txt,10) );
00474 }
00475
00477 NTuple::Directory* NTupleSvc::createDirectory (const std::string& dirPath, long id) {
00478 char txt[32];
00479 return createDirectory( dirPath, ::_itoa(id, txt,10) );
00480 }
00481
00483 NTuple::Directory* NTupleSvc::createDirectory (const std::string& dirPath, const std::string& relPath ) {
00484 std::string full = dirPath;
00485 full += (relPath[0]=='/') ? "" : "/";
00486 full += relPath;
00487 return createDirectory(full);
00488 }
00489
00490 StatusCode NTupleSvc::attachTuple(const std::string& filename, const std::string& logname, const char typ, const long t) {
00491 MsgStream log(msgSvc(), name());
00492 DataObject* p;
00493
00494 StatusCode status = retrieveObject(m_rootName, p);
00495 if ( status.isSuccess() ) {
00496
00497 std::string entryname = m_rootName;
00498 entryname += '/';
00499 entryname += logname;
00500 GenericAddress* pA =
00501 new GenericAddress(t, CLID_NTupleFile, filename, entryname, 0, typ);
00502 status = registerAddress(p, logname, pA);
00503 if ( status.isSuccess() ) {
00504 log << MSG::INFO << "Added stream file:" << filename << " as " << logname << endmsg;
00505 return status;
00506 }
00507 pA->release();
00508 }
00509 log << MSG::ERROR << "Cannot add file:" << filename << " as " << logname << endmsg;
00510 return status;
00511 }
00512
00514 NTuple::Directory* NTupleSvc::createDirectory (const std::string& fullPath) {
00515 NTuple::Directory* p = 0;
00516 StatusCode status = findObject(fullPath, *pp_cast<DataObject>(&p));
00517 if ( !status.isSuccess() ) {
00518 int sep2 = fullPath.rfind(SEPARATOR);
00519 if ( sep2 > 0 ) {
00520 std::string relPath = fullPath.substr(0, sep2);
00521 p = createDirectory(relPath);
00522 if ( 0 != p ) {
00523 p = new NTuple::Directory();
00524
00525 status = registerObject(fullPath, p);
00526 if ( status.isSuccess() ) {
00527
00528 IConversionSvc* svc = getDataLoader(p->registry());
00529 if ( 0 != svc ) {
00530 IOpaqueAddress* pAddr = 0;
00531 status = svc->createRep (p, pAddr);
00532 if ( status.isSuccess() ) {
00533 p->registry()->setAddress(pAddr);
00534 status = svc->fillRepRefs (pAddr, p);
00535 if ( status.isSuccess() ) {
00536 return p;
00537 }
00538 }
00539 }
00540 unregisterObject(p);
00541 }
00542 p->release();
00543 p = 0;
00544 }
00545 }
00546 }
00547 try {
00548 p = dynamic_cast<NTuple::Directory*>(p);
00549 return p;
00550 }
00551 catch (...) {
00552 }
00553 return 0;
00554 }
00555
00557 NTuple::Tuple* NTupleSvc::access(const std::string&, const std::string&) {
00558 MsgStream log ( msgSvc(), name() );
00559 return 0;
00560 }
00561
00563 StatusCode NTupleSvc::save(const std::string& fullPath) {
00564 MsgStream log ( msgSvc(), name() );
00565 NTuple::Tuple* pObj = 0;
00566 StatusCode status = findObject(fullPath, *pp_cast<DataObject>(&pObj));
00567 if ( status.isSuccess() ) {
00568 return save ( pObj );
00569 }
00570 return INVALID_OBJ_PATH;
00571 }
00572
00574 StatusCode NTupleSvc::save(NTuple::Tuple* n_tuple) {
00575 NTuple::TupleImp* tuple = (NTuple::TupleImp*)n_tuple;
00576 if ( 0 != tuple ) {
00577 try {
00578 IConversionSvc* pSvc = tuple->conversionService();
00579 IRegistry* pReg = tuple->registry();
00580 if ( 0 != pSvc && 0 != pReg ) {
00581 IOpaqueAddress* pAddr = pReg->address();
00582 StatusCode status = pSvc->updateRep(pAddr, n_tuple);
00583 if ( status.isSuccess() ) {
00584 status = pSvc->updateRepRefs(pAddr, n_tuple);
00585 }
00586 return status;
00587 }
00588 return IDataProviderSvc::NO_DATA_LOADER;
00589 }
00590 catch(...) {
00591 }
00592 }
00593 return INVALID_OBJECT;
00594 }
00595
00597 StatusCode NTupleSvc::save(DataObject* pParent, const std::string& relPath) {
00598 NTuple::Tuple* pObj = 0;
00599 StatusCode status = findObject(pParent, relPath, *pp_cast<DataObject>(&pObj));
00600 if ( status.isSuccess() ) {
00601 return save ( pObj );
00602 }
00603 return INVALID_OBJ_PATH;
00604 }
00605
00607 StatusCode NTupleSvc::writeRecord( NTuple::Tuple* n_tuple ) {
00608 NTuple::TupleImp* tuple = (NTuple::TupleImp*)n_tuple;
00609 if ( 0 != tuple ) {
00610 try {
00611 IConversionSvc* pSvc = tuple->conversionService();
00612 if ( 0 == pSvc ) {
00613 pSvc = getDataLoader(n_tuple->registry());
00614 tuple->setConversionService(pSvc);
00615 }
00616 if ( 0 != pSvc ) {
00617 IRegistry* pReg = n_tuple->registry();
00618 IOpaqueAddress* pAddr = pReg->address();
00619 StatusCode status = pSvc->createRep(n_tuple, pAddr);
00620 if ( status.isSuccess() ) {
00621 pReg->setAddress(pAddr);
00622 status = pSvc->fillRepRefs(pAddr, n_tuple);
00623 }
00624 return status;
00625 }
00626 return IDataProviderSvc::NO_DATA_LOADER;
00627 }
00628 catch(...) {
00629 }
00630 }
00631 return INVALID_OBJECT;
00632 }
00633
00635 StatusCode NTupleSvc::writeRecord(const std::string& fullPath ) {
00636 NTuple::Tuple* pObj = 0;
00637 StatusCode status = findObject(fullPath, *pp_cast<DataObject>(&pObj));
00638 if ( status.isSuccess() ) {
00639 return writeRecord ( pObj );
00640 }
00641 return INVALID_OBJ_PATH;
00642 }
00643
00645 StatusCode NTupleSvc::writeRecord( DataObject* pParent, const std::string& relPath) {
00646 NTuple::Tuple* pObj = 0;
00647 StatusCode status = findObject(pParent, relPath, *pp_cast<DataObject>(&pObj));
00648 if ( status.isSuccess() ) {
00649 return writeRecord ( pObj );
00650 }
00651 return INVALID_OBJ_PATH;
00652 }
00653
00655 StatusCode NTupleSvc::readRecord( NTuple::Tuple* n_tuple ) {
00656 StatusCode status = INVALID_OBJECT;
00657 NTuple::TupleImp* tuple = (NTuple::TupleImp*)n_tuple;
00658 if ( 0 != tuple ) {
00659 try {
00660 IConversionSvc* pSvc = tuple->conversionService();
00661 if ( 0 == pSvc ) {
00662 pSvc = getDataLoader(n_tuple->registry());
00663 tuple->setConversionService(pSvc);
00664 }
00665 if ( 0 != pSvc ) {
00666 IRegistry* pReg = n_tuple->registry();
00667 IOpaqueAddress* pAddr = pReg->address();
00668 status = pSvc->updateObj(pAddr, n_tuple);
00669 if ( status.isSuccess() ) {
00670 status = pSvc->updateObjRefs(pAddr, n_tuple);
00671 }
00672 return status;
00673 }
00674 status = IDataProviderSvc::NO_DATA_LOADER;
00675 }
00676 catch(...) {
00677 status = INVALID_OBJECT;
00678 }
00679 }
00680 return status;
00681 }
00682
00684 StatusCode NTupleSvc::readRecord(const std::string& fullPath) {
00685 NTuple::Tuple* pObj = 0;
00686 StatusCode status = findObject(fullPath, *pp_cast<DataObject>(&pObj));
00687 if ( status.isSuccess() ) {
00688 return readRecord ( pObj );
00689 }
00690 return INVALID_OBJ_PATH;
00691 }
00692
00694 StatusCode NTupleSvc::readRecord(DataObject* pParent, const std::string& relPath) {
00695 NTuple::Tuple* pObj = 0;
00696 StatusCode status = findObject(pParent, relPath, *pp_cast<DataObject>(&pObj));
00697 if ( status.isSuccess() ) {
00698 return readRecord ( pObj );
00699 }
00700 return INVALID_OBJ_PATH;
00701 }
00702