00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012 #ifdef __ICC
00013
00014
00015 #pragma warning(disable:2259)
00016 #endif
00017
00018
00019 #include <algorithm>
00020
00021
00022 #include "GaudiKernel/MsgStream.h"
00023 #include "GaudiKernel/IRegistry.h"
00024 #include "GaudiKernel/DataObject.h"
00025 #include "GaudiKernel/LinkManager.h"
00026 #include "GaudiKernel/ContainedObject.h"
00027 #include "GaudiKernel/IDataManagerSvc.h"
00028 #include "GaudiKernel/IAddressCreator.h"
00029 #include "GaudiKernel/IDataProviderSvc.h"
00030
00031 #include "GaudiPoolDb/IPoolDbMgr.h"
00032 #include "GaudiPoolDb/PoolDbBaseCnv.h"
00033 #include "GaudiPoolDb/PoolDbAddress.h"
00034
00035 #include "GaudiKernel/CnvFactory.h"
00036 #include "GaudiPoolDb/PoolDbLinkManager.h"
00037
00038 #include "PersistencySvc/IPersistencySvc.h"
00039 #include "PersistencySvc/IDataTransform.h"
00040 #include "StorageSvc/DbObjectCallBack.h"
00041 #include "StorageSvc/DbInstanceCount.h"
00042 #include "StorageSvc/DbTransform.h"
00043 #include "StorageSvc/DbTypeInfo.h"
00044 #include "StorageSvc/DbColumn.h"
00045 #include "StorageSvc/DbReflex.h"
00046 #include "Reflex/Reflex.h"
00047 #include "POOLCore/Token.h"
00048
00049 #include <stdexcept>
00050
00051 static pool::DbInstanceCount::Counter* s_count =
00052 pool::DbInstanceCount::getCounter(typeid(PoolDbBaseCnv));
00053
00054
00055 PLUGINSVC_FACTORY_WITH_ID( PoolDbBaseCnv,
00056 ConverterID(POOL_StorageType,CLID_Any),
00057 IConverter*(long, CLID, ISvcLocator*) )
00058 PLUGINSVC_FACTORY_WITH_ID( PoolDbBaseCnv,
00059 ConverterID(POOL_StorageType,CLID_Any+CLID_ObjectList),
00060 IConverter*(long, CLID, ISvcLocator*) )
00061 PLUGINSVC_FACTORY_WITH_ID( PoolDbBaseCnv,
00062 ConverterID(POOL_StorageType,CLID_Any+CLID_ObjectVector),
00063 IConverter*(long, CLID, ISvcLocator*) )
00064
00065 PLUGINSVC_FACTORY_WITH_ID( PoolDbBaseCnv,
00066 ConverterID(POOL_StorageType,CLID_Any + CLID_ObjectVector+0x00030000),
00067 IConverter*(long, CLID, ISvcLocator*) )
00068 PLUGINSVC_FACTORY_WITH_ID( PoolDbBaseCnv,
00069 ConverterID(POOL_StorageType,CLID_Any + CLID_ObjectVector+0x00040000),
00070 IConverter*(long, CLID, ISvcLocator*) )
00071 PLUGINSVC_FACTORY_WITH_ID( PoolDbBaseCnv,
00072 ConverterID(POOL_StorageType,CLID_Any + CLID_ObjectVector+0x00050000),
00073 IConverter*(long, CLID, ISvcLocator*) )
00074 PLUGINSVC_FACTORY_WITH_ID( PoolDbBaseCnv,
00075 ConverterID(POOL_StorageType,CLID_Any | (1<<31)),
00076 IConverter*(long, CLID, ISvcLocator*) )
00077
00078
00079 class PoolDbObjectContext;
00080 static PoolDbObjectContext* s_context = 0;
00081
00082 class PoolDbObjectContext {
00083 PoolDbBaseCnv* m_converter;
00084 IRegistry* m_registry;
00085 public:
00086 PoolDbObjectContext(PoolDbBaseCnv* dm, IRegistry* pReg) {
00087 m_converter = dm;
00088 m_registry = pReg;
00089 s_context = this;
00090 }
00091 ~PoolDbObjectContext() {
00092 m_converter = 0;
00093 s_context = 0;
00094 }
00095 PoolDbBaseCnv* cnv() {
00096 return m_converter;
00097 }
00098 IRegistry* registry() {
00099 return m_registry;
00100 }
00101 };
00102
00103
00104 class PoolDbDataObjectHandler : public pool::DbObjectCallBack {
00105 protected:
00106 LinkManager* m_links;
00107 PoolDbLinkManager* m_refs;
00108 PoolDbBaseCnv* m_converter;
00109 IRegistry* m_registry;
00110 public:
00112 PoolDbDataObjectHandler(const ROOT::Reflex::Type& cl)
00113 : pool::DbObjectCallBack(cl), m_links(0), m_refs(0),
00114 m_converter(0), m_registry(0)
00115 {
00116 }
00118 PoolDbDataObjectHandler(const ROOT::Reflex::Type& cl,
00119 PoolDbBaseCnv* dm,
00120 IRegistry* pReg)
00121 : pool::DbObjectCallBack(cl), m_links(0), m_refs(0),
00122 m_converter(dm), m_registry(pReg)
00123 {
00124 }
00126 virtual ~PoolDbDataObjectHandler() {
00127 }
00129 virtual pool::DataCallBack* clone() const {
00130 if ( s_context ) {
00131 PoolDbDataObjectHandler* p =
00132 new PoolDbDataObjectHandler( transientType(),
00133 s_context->cnv(),
00134 s_context->registry());
00135 p->setShape(shape());
00136 return p;
00137 }
00138 PoolDbDataObjectHandler* p =
00139 new PoolDbDataObjectHandler(transientType(),0,0);
00140 p->setShape(shape());
00141 return p;
00142 }
00144
00150 pool::DbStatus start(pool::DataCallBack::CallType action_type,
00151 void* data,
00152 void** context);
00154 pool::DbStatus bind(pool::DataCallBack::CallType action_type,
00155 const pool::DbColumn* col_ident,
00156 int col_number,
00157 void* context,
00158 void** data_pointer);
00160 pool::DbStatus end(pool::DataCallBack::CallType action_type, void* context );
00161 };
00162
00163 void popCurrentDataObject();
00164 void pushCurrentDataObject(DataObject** pobjAddr);
00165
00166 namespace {
00167 static bool printLinks() {
00168 static bool prt = false;
00169 return prt;
00170 }
00171 }
00172
00174 pool::DbStatus
00175 PoolDbDataObjectHandler::bind(pool::DataCallBack::CallType action_type,
00176 const pool::DbColumn* ,
00177 int col_number ,
00178 void* ,
00179 void** data_pointer)
00180 {
00181 DataObject* pObj = (DataObject*)m_objectData;
00182 switch(action_type) {
00183 case GET:
00184 switch(col_number) {
00185 case 0:
00186 *data_pointer = &m_objectData;
00187 return pool::Success;
00188 case 1:
00189 *data_pointer = &m_links;
00190 return pool::Success;
00191 case 2:
00192 *data_pointer = &m_refs;
00193 return pool::Success;
00194 }
00195 break;
00196 case PUT:
00197 switch(col_number) {
00198 case 0:
00199 *data_pointer = pObj;
00200 return pool::Success;
00201 case 1:
00202 *data_pointer = pObj->linkMgr();
00203 return pool::Success;
00204 case 2:
00205 m_refs = m_converter->createReferences(pObj);
00206 *data_pointer = m_refs;
00207 return pool::Success;
00208 }
00209 break;
00210 default:
00211 break;
00212 }
00213 return pool::Error;
00214 }
00215
00217 pool::DbStatus
00218 PoolDbDataObjectHandler::end(pool::DataCallBack::CallType action_type, void* )
00219 {
00220 DataObject* pObj = (DataObject*)m_objectData;
00221 switch(action_type) {
00222 case GET:
00223 m_converter->setReferences(m_refs, m_links, pObj, m_registry).ignore();
00224 pool::deletePtr(m_links);
00225 break;
00226 case PUT:
00227 m_converter->dumpReferences(m_refs, m_links, pObj, m_registry).ignore();
00228 break;
00229 }
00230 pool::deletePtr(m_refs);
00231 popCurrentDataObject();
00232 return pool::Success;
00233 }
00234
00235 pool::DbStatus
00236 PoolDbDataObjectHandler::start( pool::DataCallBack::CallType action_type,
00237 void* ,
00238 void** context)
00239 {
00240 m_refs = 0;
00241 *context = 0;
00242 switch(action_type) {
00243 case GET:
00244 m_objectData = 0;
00245 break;
00246 case PUT:
00247 break;
00248 }
00249 void **ptr = const_cast<void**>(&m_objectData);
00250 pushCurrentDataObject((DataObject**)ptr);
00251 return pool::Success;
00252 }
00253
00255 PoolDbBaseCnv::PoolDbBaseCnv(long typ, const CLID& clid, ISvcLocator* svc)
00256 : Converter(typ, clid, svc), m_dbMgr(0), m_dataMgr(0),
00257 m_objGuid(pool::Guid::null()), m_call(0)
00258 {
00259 s_count->increment();
00260 m_objGuid.Data1 = clid;
00261 }
00262
00264 PoolDbBaseCnv::~PoolDbBaseCnv() {
00265 pool::releasePtr(m_dbMgr);
00266 s_count->decrement();
00267 }
00268
00270 StatusCode PoolDbBaseCnv::initialize() {
00271 StatusCode status = Converter::initialize();
00272 MsgStream log(msgSvc(),"PoolDbBaseCnv");
00273 if ( !status.isSuccess() ) {
00274 log << MSG::ERROR << "Cannot initialize base class \"Converter\"" << endmsg;
00275 return status;
00276 }
00277 IPoolDbMgr **ptr1 = &m_dbMgr;
00278 status = conversionSvc()->queryInterface(IPoolDbMgr::interfaceID(), (void**)ptr1);
00279 if ( !status.isSuccess() ) {
00280 log << MSG::ERROR << "Cannot connect to \"IPoolDbMgr\" interface." << endmsg;
00281 return status;
00282 }
00283 IDataManagerSvc **ptr2 = &m_dataMgr;
00284 status = dataProvider()->queryInterface(IDataManagerSvc::interfaceID(), (void**)ptr2);
00285 if ( !status.isSuccess() ) {
00286 log << MSG::ERROR << "Cannot connect to \"IDataManagerSvc\" interface." << endmsg;
00287 return status;
00288 }
00289 const pool::DbTypeInfo* shapeH = 0;
00290 const ROOT::Reflex::Type refH = ROOT::Reflex::Type::ByName("PoolDbLinkManager");
00291 if ( !refH ) {
00292 log << MSG::ERROR << "Dictionary for class \"PoolDbLinkManager\" missing." << endmsg;
00293 return StatusCode::FAILURE;
00294 }
00295 const ROOT::Reflex::Type lnkH = ROOT::Reflex::Type::ByName("LinkManager");
00296 if ( !lnkH ) {
00297 log << MSG::ERROR << "Dictionary for class \"LinkManager\" missing." << endmsg;
00298 return StatusCode::FAILURE;
00299 }
00300 m_class = pool::DbReflex::forGuid(m_objGuid);
00301 if ( !m_class ) {
00302
00303 log << MSG::DEBUG << "Dictionary for class with GUID:" << m_objGuid.toString()
00304 << " missing." << endmsg;
00305 return StatusCode::FAILURE;
00306 }
00307 if ( !pool::DbTransform::getShape(m_objGuid, shapeH).isSuccess() ) {
00308 std::vector<const pool::DbColumn*> c;
00309 c.push_back(new pool::DbColumn(m_class.Name(),
00310 m_class.Name(ROOT::Reflex::SCOPED),
00311 pool::DbColumn::POINTER,
00312 0));
00313 c.push_back(new pool::DbColumn("Links",
00314 lnkH.Name(ROOT::Reflex::SCOPED),
00315 pool::DbColumn::POINTER,
00316 0));
00317 c.push_back(new pool::DbColumn("Refs",
00318 refH.Name(ROOT::Reflex::SCOPED),
00319 pool::DbColumn::POINTER,
00320 0));
00321 shapeH = pool::DbTypeInfo::create(m_objGuid, c);
00322 }
00323 if ( shapeH ) {
00324 log << MSG::DEBUG << "Created object shape for class:"
00325 << m_class.Name(ROOT::Reflex::SCOPED) << endmsg
00326 << shapeH->toString() << endmsg;
00327 shapeH->addRef();
00328 m_call = new PoolDbDataObjectHandler(m_class);
00329 m_call->setShape(shapeH);
00330 }
00331 else {
00332 return makeError("Failed to create POOL shape information for GUID:"+
00333 m_objGuid.toString(),false);
00334 }
00335 return status;
00336 }
00337
00339 StatusCode PoolDbBaseCnv::finalize() {
00340 pool::DbTypeInfo* shapeH = 0;
00341 if ( m_call ) {
00342 shapeH = dynamic_cast<pool::DbTypeInfo*>((pool::Shape*)m_call->shape());
00343 if ( shapeH ) shapeH->deleteRef();
00344 }
00345 pool::releasePtr(m_call);
00346 pool::releasePtr(m_dbMgr);
00347 pool::releasePtr(m_dataMgr);
00348 return Converter::finalize();
00349 }
00350
00352 const std::string
00353 PoolDbBaseCnv::containerName(IRegistry* pRegistry) const {
00354 if ( 0 != pRegistry ) {
00355 return pRegistry->identifier();
00356 }
00357 return "";
00358 }
00359
00360 StatusCode PoolDbBaseCnv::makeError(const std::string& msg, bool rethrow)
00361 {
00362 MsgStream log(msgSvc(),"PoolDbBaseCnv");
00363 log << MSG::ERROR << "Trouble with class:" << m_objGuid.toString() << " ";
00364 if ( m_class ) log << "<" << m_class.Name(ROOT::Reflex::SCOPED) << "> ";
00365 log << endmsg;
00366 log << msg << endmsg;
00367 if ( rethrow ) {
00368 pool::debugBreak("Error:"+msg, "PoolDbBaseCnv", true);
00369 }
00370 return StatusCode::FAILURE;
00371 }
00372
00373 StatusCode
00374 PoolDbBaseCnv::dumpReferences(PoolDbLinkManager* ,
00375 LinkManager* ,
00376 DataObject* pObj,
00377 IRegistry* )
00378 {
00379 if ( printLinks() ) {
00380 MsgStream log(msgSvc(), "dumpReferences");
00381 LinkManager* mgr = pObj->linkMgr();
00382 for ( int i = 0; i < mgr->size(); ++i) {
00383 LinkManager::Link* lnk = mgr->link(i);
00384 log << MSG::ALWAYS << "PUT> " << pObj->registry()->identifier() << "[" << i << "] = " << lnk->path() << endmsg;
00385 }
00386 }
00387 return StatusCode::SUCCESS;
00388 }
00389
00390 StatusCode
00391 PoolDbBaseCnv::setReferences(PoolDbLinkManager* mgr,
00392 LinkManager* pLinks,
00393 DataObject* pObj,
00394 IRegistry* pReg)
00395 {
00396 std::string tmp;
00397 LinkManager* pmgr = pObj->linkMgr();
00398 for(int i = 0; i < pLinks->size(); ++i) {
00399 LinkManager::Link* lnk = pLinks->link(i);
00400 pmgr->addLink(lnk->path(), 0);
00401 }
00402 size_t ref_size = mgr->references().size();
00403 for(size_t j = 0; j < ref_size; ++j) {
00404 IOpaqueAddress* pA = 0;
00405 const pool::Token* token = mgr->references()[j];
00406 std::string& location = mgr->links()[j];
00407 long typ = token->technology();
00408 CLID clid = token->classID().Data1;
00409 std::string spar[] = {token->dbID(),
00410 token->contID()};
00411 unsigned long ipar[] = {token->oid().first,
00412 token->oid().second};
00413 StatusCode sc = addressCreator()->createAddress(typ,clid,spar,ipar,pA);
00414 if ( sc.isSuccess() ) {
00415
00416
00417 if ( location.substr(0,7) == "/Event/" ) {
00418 size_t idx = location.rfind("/");
00419 tmp = (idx==std::string::npos) ? location : location.substr(idx);
00420 location = tmp;
00421 }
00422 sc = m_dataMgr->registerAddress(pReg, location, pA);
00423 if ( sc.isSuccess() ) {
00424
00425
00426 continue;
00427 }
00428 pA->release();
00429 ROOT::Reflex::Type classH = pool::DbReflex::forGuid(token->classID());
00430 MsgStream err(msgSvc(), "Reflection");
00431 if ( 0 == classH ) {
00432 err << MSG::ERROR << "No reflection information availible for class ID:"
00433 << token->classID().toString() << endmsg;
00434 }
00435 else {
00436 err << MSG::ERROR << "Reflection information availible for class ID:"
00437 << token->classID().toString() << endmsg
00438 << classH.Name(ROOT::Reflex::SCOPED) << endmsg;
00439 }
00440 makeError("setReferences> Failed to register opaque address:"+location+
00441 "\n"+token->toString());
00442 }
00443 }
00444 return StatusCode::SUCCESS;
00445 }
00446
00447 PoolDbLinkManager*
00448 PoolDbBaseCnv::createReferences(DataObject* pObj)
00449 {
00450 typedef std::vector<IRegistry*> Leaves;
00451 PoolDbLinkManager* refs = new PoolDbLinkManager;
00452 Leaves leaves;
00453 StatusCode status = m_dataMgr->objectLeaves(pObj, leaves);
00454 if ( status.isSuccess() ) {
00455 for(Leaves::iterator i=leaves.begin(), iend=leaves.end(); i != iend; ++i) {
00456 IRegistry* pR = *i;
00457 IOpaqueAddress* pA = pR->address();
00458 if ( 0 != pA ) {
00459 PoolDbAddress* pdbA = dynamic_cast<PoolDbAddress*>(pA);
00460 if ( 0 != pdbA ) {
00461 pool::Token* tok = const_cast<pool::Token*>(pdbA->token());
00462 if ( tok ) {
00463 tok->addRef();
00464 refs->references().push_back(tok);
00465 refs->links().push_back(pR->name());
00466 }
00467 else {
00468
00469
00470 }
00471 }
00472 else {
00473 const std::string* spar = pA->par();
00474 const unsigned long* ipar = pA->ipar();
00475 pool::Guid guid(pool::Guid::null());
00476 guid.Data1 = pA->clID();
00477 pool::Token* tok = new pool::Token();
00478 tok->setClassID(guid);
00479 tok->setTechnology(pA->svcType());
00480 tok->setDb(spar[0]).setCont(spar[1]);
00481 tok->oid().first = ipar[0];
00482 tok->oid().second = ipar[1];
00483 refs->references().push_back(tok);
00484 refs->links().push_back(pR->name());
00485 }
00486 }
00487 else {
00488
00489
00490
00491 }
00492 }
00493 }
00494 return refs;
00495 }
00496
00497
00499 StatusCode
00500 PoolDbBaseCnv::createObj(IOpaqueAddress* pAddress, DataObject*& refpObject)
00501 {
00502 try {
00503 PoolDbAddress* pA = dynamic_cast<PoolDbAddress*>(pAddress);
00504 if ( pA ) {
00505 PoolDbObjectContext ctxt(this, pAddress->registry());
00506 pool::DataCallBack* call = m_call->clone();
00507 StatusCode sc = m_dbMgr->read(call, pA);
00508 if ( sc.isSuccess() ) {
00509 refpObject = (DataObject*)call->object();
00510 call->release();
00511 return StatusCode::SUCCESS;
00512 }
00513 call->release();
00514 std::string tag = pA->par()[0]+":"+pA->par()[1];
00515 if ( sc.getCode() == IPoolDbMgr::BAD_DATA_CONNECTION ) {
00516 if ( m_badFiles.find(tag) != m_badFiles.end() ) {
00517 return sc;
00518 }
00519 m_badFiles.insert(tag);
00520 }
00521 MsgStream log(msgSvc(),"PoolDbBaseCnv");
00522 log << MSG::ERROR << "createObj> Cannot access the object:"+tag << endmsg;
00523 return StatusCode::FAILURE;
00524 }
00525 return makeError("createObj> Invalid object address.", false);
00526 }
00527 catch (std::exception& e) {
00528 return makeError(std::string("createObj> Caught exception:")+e.what(), false);
00529 }
00530 catch(...) {
00531 }
00532 return makeError("createObj> Unknown exception occurred.", false);
00533 }
00534
00536 StatusCode
00537 PoolDbBaseCnv::fillObjRefs(IOpaqueAddress* pAddress, DataObject* pObject)
00538 {
00539 return updateObjRefs(pAddress, pObject);
00540 }
00541
00543 StatusCode
00544 PoolDbBaseCnv::updateObj(IOpaqueAddress* pAddr, DataObject* )
00545 {
00546 try {
00547 PoolDbAddress* pA = dynamic_cast<PoolDbAddress*>(pAddr);
00548 if ( 0 != pA ) {
00549 return makeError("updateObj> Sorry folks, not yet implemented...");
00550 }
00551 return makeError("updateObj> Invalid opaque object address.");
00552 }
00553 catch (std::exception& e) {
00554 return makeError(std::string("updateObj> Caught exception:")+e.what());
00555 }
00556 catch (...) {
00557 }
00558 return makeError("updateObj> Unknown Error - exception was thrown.");
00559 }
00560
00562 StatusCode
00563 PoolDbBaseCnv::updateObjRefs(IOpaqueAddress* , DataObject* pObj)
00564 {
00565 if ( 0 != pObj ) {
00566
00567 StatusCode sc = pObj->update();
00568 if ( sc.isSuccess() && printLinks() ) {
00569 MsgStream log(msgSvc(), "updateObjRefs");
00570 LinkManager* mgr = pObj->linkMgr();
00571 std::string id = pObj->registry()->identifier();
00572 for ( int i = 0; i < mgr->size(); ++i) {
00573 LinkManager::Link* lnk = mgr->link(i);
00574 log << MSG::ALWAYS << "GET> " << id << "[" << i << "] = " << lnk->path() << endmsg;
00575 }
00576 }
00577 return sc;
00578 }
00579 return makeError("updateObjRefs> Invalid object reference.");
00580 }
00581
00583 StatusCode
00584 PoolDbBaseCnv::createRep(DataObject* pObj, IOpaqueAddress*& refpA)
00585 {
00586 try {
00587 refpA = 0;
00588 if ( pObj ) {
00589 IRegistry* pReg = pObj->registry();
00590 if ( pReg ) {
00591 PoolDbAddress* pA = 0;
00592 std::string cnt = containerName(pReg);
00593 PoolDbObjectContext ctxt(this, pObj->registry());
00594 pool::DataCallBack* call = m_call->clone();
00595 call->setObject(pObj);
00596 StatusCode sc = m_dbMgr->markWrite(call, cnt, &pA);
00597 if ( sc.isSuccess() ) {
00598 refpA = pA;
00599 return sc;
00600 }
00601 }
00602 return makeError("createRep> Invalid object registry entry.");
00603 }
00604 return makeError("createRep> Invalid object reference.");
00605 }
00606 catch (std::exception& e) {
00607 makeError(std::string("createRep> Caught exception:")+e.what());
00608 }
00609 catch (...) {
00610 return makeError("createRep> Unknown Fatal Exception.");
00611 }
00612 return makeError("createRep> Fatal Error.");
00613 }
00614
00616 StatusCode
00617 PoolDbBaseCnv::updateRep(IOpaqueAddress* pAddr, DataObject* pObj) {
00618 try {
00619 PoolDbAddress* pA = dynamic_cast<PoolDbAddress*>(pAddr);
00620 if ( 0 != pA ) {
00621 if ( pObj ) {
00622 PoolDbObjectContext ctxt(this, pAddr->registry());
00623 pool::DataCallBack* call = m_call->clone();
00624 call->setObject(pObj);
00625 return m_dbMgr->markUpdate(call, pA);
00626 }
00627 return makeError("updateRep> Invalid object reference.");
00628 }
00629 return makeError("updateRep> Invalid opaque object address.");
00630 }
00631 catch (std::exception& e) {
00632 makeError(std::string("updateRep> Caught exception:")+e.what());
00633 }
00634 catch (...) {
00635 return makeError("updateRep> Unknown Fatal Exception.");
00636 }
00637 return makeError("updateRep> Fatal Error.");
00638 }
00639
00641 StatusCode
00642 PoolDbBaseCnv::fillRepRefs(IOpaqueAddress* pAddr, DataObject* pObj)
00643 {
00644 return updateRepRefs(pAddr, pObj);
00645 }
00646
00648 StatusCode
00649 PoolDbBaseCnv::updateRepRefs(IOpaqueAddress* , DataObject* pObj)
00650 {
00651 if ( pObj ) {
00652 return StatusCode::SUCCESS;
00653 }
00654 return makeError("updateRepRefs> Invalid object reference.");
00655 }