Resolve "Toggle Free Look with Hotkey"
[ryzomcore.git] / ryzom / server / src / shard_unifier_service / database_mapping.cpp
blob46b4a3cae1478f7ceea29a719909355f08ddc7ad
2 // Ryzom - MMORPG Framework <http://dev.ryzom.com/projects/ryzom/>
3 // Copyright (C) 2010-2021 Winch Gate Property Limited
4 //
5 // This program is free software: you can redistribute it and/or modify
6 // it under the terms of the GNU Affero General Public License as
7 // published by the Free Software Foundation, either version 3 of the
8 // License, or (at your option) any later version.
9 //
10 // This program is distributed in the hope that it will be useful,
11 // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 // GNU Affero General Public License for more details.
15 // You should have received a copy of the GNU Affero General Public License
16 // along with this program. If not, see <http://www.gnu.org/licenses/>.
18 /////////////////////////////////////////////////////////////////
19 // WARNING : this is a generated file, don't change it !
20 /////////////////////////////////////////////////////////////////
22 #include "stdpch.h"
24 #include "database_mapping.h"
26 namespace RSMGR
29 void CKnownUserPtr::linkPtr()
31 nlassert(_NextPtr == NULL);
32 nlassert(_PrevPtr == NULL);
33 if (_Ptr != NULL)
35 _NextPtr = _Ptr->getFirstPtr();
36 if (_NextPtr != NULL)
38 _PrevPtr = _NextPtr->_PrevPtr;
39 _PrevPtr->_NextPtr = this;
40 _NextPtr->_PrevPtr = this;
42 else
44 _NextPtr = this;
45 _PrevPtr = this;
46 _Ptr->setFirstPtr(this);
51 void CKnownUserPtr::unlinkPtr()
53 if (_NextPtr == NULL)
55 nlassert(_PrevPtr == NULL);
56 return;
59 if (_Ptr != NULL)
61 if (_NextPtr == this)
63 nlassert(_PrevPtr == this);
64 // last pointer !
65 _Ptr->setFirstPtr(NULL);
67 else
69 if (_Ptr->getFirstPtr() == this)
71 // the first ptr is the current one, we need to switch to next one
72 _Ptr->setFirstPtr(_NextPtr);
77 if (_NextPtr != this)
79 nlassert(_PrevPtr != this);
81 _NextPtr->_PrevPtr = _PrevPtr;
82 _PrevPtr->_NextPtr = _NextPtr;
84 _NextPtr = NULL;
85 _PrevPtr = NULL;
89 CKnownUser::TObjectCache CKnownUser::_ObjectCache;
90 CKnownUser::TReleasedObject CKnownUser::_ReleasedObject;
93 // Destructor, delete any children
94 CKnownUser::~CKnownUser()
96 // release childs reference
99 if (_PtrList != NULL)
101 nlwarning("ERROR : someone try to delete this object, but there are still ptr on it !");
102 CKnownUserPtr *ptr = _PtrList;
105 nlwarning(" Pointer created from '%s', line %u", ptr->_FileName, ptr->_LineNum);
106 ptr = _PtrList->getNextPtr();
107 } while(ptr != _PtrList);
108 nlstop;
110 // remove object from cache map
111 if (_RelationId != NOPE::INVALID_OBJECT_ID
112 && _ObjectState != NOPE::os_removed
113 && _ObjectState != NOPE::os_transient)
115 nldebug("NOPE: clearing CKnownUser @%p from cache with id %u", this, static_cast<uint32>(_RelationId));
116 nlverify(_ObjectCache.erase(_RelationId) == 1);
118 else if (_ObjectState != NOPE::os_transient)
120 nlassert(_ObjectCache.find(_RelationId) == _ObjectCache.end());
122 if (_ObjectState == NOPE::os_released)
124 removeFromReleased();
126 else
128 TReleasedObject::iterator it(_ReleasedObject.find(_ReleaseDate));
129 if (it != _ReleasedObject.end())
131 nlassert(it->second.find(this) == it->second.end());
136 void CKnownUser::removeFromReleased()
138 TReleasedObject::iterator it(_ReleasedObject.find(_ReleaseDate));
139 nlassert(it != _ReleasedObject.end());
140 TObjectSet &os = it->second;
142 nlverify(os.erase(this) == 1);
144 // nb : _ReleasedObject time entry are removed by the cache update
147 bool CKnownUser::create(MSW::CConnection &connection)
149 nlassert(getPersistentState() == NOPE::os_transient);
151 std::string qs;
152 qs = "INSERT INTO known_users (";
154 qs += "owner, targer_user, targer_character, relation_type, comments";
155 qs += ") VALUES (";
157 qs += "'"+MSW::escapeString(NLMISC::toString(_OwnerId), connection)+"'";
158 qs += ", ";
159 qs += "'"+MSW::escapeString(NLMISC::toString(_TargetUser), connection)+"'";
160 qs += ", ";
161 qs += "'"+MSW::escapeString(NLMISC::toString(_TargetCharacter), connection)+"'";
162 qs += ", ";
163 qs += _Relation.isValid()
164 ? "'"+_Relation.toString()+"'"
165 : "DEFAULT(relation_type)";
166 qs += ", ";
167 qs += "'"+MSW::escapeString(NLMISC::toString(_Comments), connection)+"'";
169 qs += ")";
171 if (connection.query(qs))
173 uint32 _id_ = connection.getLastGeneratedId();
174 setObjectId(_id_);
177 setPersistentState(NOPE::os_clean);
179 // update the parent class instance in cache if any
181 if (_OwnerId != 0)
183 // need to update the parent class child list if it is in the cache
184 CRingUser *parent = CRingUser::loadFromCache(_OwnerId, false);
185 if (parent && parent->_KnownUsers != NULL)
188 nlassert(std::find(parent->_KnownUsers->begin(), parent->_KnownUsers->end(), CKnownUserPtr(this, __FILE__, __LINE__)) == parent->_KnownUsers->end());
189 parent->_KnownUsers->push_back(CKnownUserPtr(this, __FILE__, __LINE__));
194 if (_TargetUser != 0)
196 // need to update the parent class child list if it is in the cache
197 CCharacter *parent = CCharacter::loadFromCache(_TargetUser, false);
198 if (parent && parent->_KnownBy != NULL)
201 nlassert(std::find(parent->_KnownBy->begin(), parent->_KnownBy->end(), CKnownUserPtr(this, __FILE__, __LINE__)) == parent->_KnownBy->end());
202 parent->_KnownBy->push_back(CKnownUserPtr(this, __FILE__, __LINE__));
207 return true;
210 return false;
213 bool CKnownUser::update(MSW::CConnection &connection)
215 nlassert(getPersistentState() == NOPE::os_dirty || getPersistentState() == NOPE::os_clean);
217 if (getPersistentState() == NOPE::os_clean)
218 // the object is clean, just ignore the save
219 return true;
221 std::string qs;
222 qs = "UPDATE known_users SET ";
224 qs += "owner = '"+MSW::escapeString(NLMISC::toString(_OwnerId), connection)+"'";
225 qs += ", ";
226 qs += "targer_user = '"+MSW::escapeString(NLMISC::toString(_TargetUser), connection)+"'";
227 qs += ", ";
228 qs += "targer_character = '"+MSW::escapeString(NLMISC::toString(_TargetCharacter), connection)+"'";
229 qs += ", ";
230 qs += "relation_type = " + (_Relation.isValid()
231 ? "'"+_Relation.toString()+"'"
232 : "DEFAULT(relation_type)");
233 qs += ", ";
234 qs += "comments = '"+MSW::escapeString(NLMISC::toString(_Comments), connection)+"'";
236 qs += " WHERE Id = '"+NLMISC::toString(_RelationId)+"'";
239 if (connection.query(qs))
241 if (connection.getAffectedRows() == 1)
243 setPersistentState(NOPE::os_clean);
244 return true;
248 return false;
251 bool CKnownUser::remove(MSW::CConnection &connection)
253 nlassert(getPersistentState() == NOPE::os_dirty || getPersistentState() == NOPE::os_clean);
255 std::string qs;
256 qs = "DELETE FROM known_users ";
258 qs += " WHERE Id = '"+NLMISC::toString(_RelationId)+"'";
261 if (connection.query(qs))
263 if (connection.getAffectedRows() == 1)
267 // change the persistant state to 'removed'.
268 setPersistentState(NOPE::os_removed);
270 // need to remove ref from parent class container (if any)
273 CRingUserPtr parent(CRingUser::loadFromCache(_OwnerId, true), __FILE__, __LINE__);
274 if (parent != NULL && parent->_KnownUsers != NULL)
277 std::vector < CKnownUserPtr >::iterator it = std::find(parent->_KnownUsers->begin(), parent->_KnownUsers->end(), this);
278 if (it != parent->_KnownUsers->end())
280 parent->_KnownUsers->erase(it);
287 CCharacterPtr parent(CCharacter::loadFromCache(_TargetUser, true), __FILE__, __LINE__);
288 if (parent != NULL && parent->_KnownBy != NULL)
291 std::vector < CKnownUserPtr >::iterator it = std::find(parent->_KnownBy->begin(), parent->_KnownBy->end(), this);
292 if (it != parent->_KnownBy->end())
294 parent->_KnownBy->erase(it);
300 // need to remove ref from parent (if any)
303 return true;
306 return false;
309 bool CKnownUser::removeById(MSW::CConnection &connection, uint32 id)
311 CKnownUser *object = loadFromCache(id, true);
312 if (object != NULL)
314 return object->remove(connection);
316 // not in cache, run a SQL query
317 std::string qs;
318 qs = "DELETE FROM known_users ";
320 qs += " WHERE Id = '"+NLMISC::toString(id)+"'";
323 if (connection.query(qs))
325 if (connection.getAffectedRows() == 1)
327 // ok, the row is removed
328 return true;
332 return false;
336 // Try to load the specified object from the memory cache, return NULL if the object is not in the cache
337 CKnownUser *CKnownUser::loadFromCache(uint32 objectId, bool unrelease)
339 // look in the cache
340 TObjectCache::iterator it(_ObjectCache.find(objectId));
341 if (it == _ObjectCache.end())
343 // not found, return null
344 return NULL;
346 else
348 CKnownUser *object = it->second;
350 if (object->_ObjectState == NOPE::os_released)
352 if (unrelease)
354 // we need to remove this object from the released object set.
355 object->removeFromReleased();
356 object->_ObjectState = NOPE::os_clean;
360 return it->second;
363 // Receive and execute command from the cache manager.
364 uint32 CKnownUser::cacheCmd(NOPE::TCacheCmd cmd)
366 if (cmd == NOPE::cc_update)
368 updateCache();
370 else if (cmd == NOPE::cc_clear)
372 clearCache();
374 else if (cmd == NOPE::cc_dump)
376 dump();
378 else if (cmd == NOPE::cc_instance_count)
380 return (uint32)_ObjectCache.size();
383 // default return value
384 return 0;
387 void CKnownUser::dump()
389 nlinfo(" Cache info for class CKnownUser :");
390 nlinfo(" There are %u object instances in cache", _ObjectCache.size());
392 // count the number of object in the released object set
393 uint32 nbReleased = 0;
395 TReleasedObject::iterator first(_ReleasedObject.begin()), last(_ReleasedObject.end());
396 for (; first != last; ++first)
398 nbReleased += (uint32)first->second.size();
401 nlinfo(" There are %u object instances in cache not referenced (waiting deletion or re-use))", nbReleased);
404 void CKnownUser::updateCache()
406 if (_ReleasedObject.empty())
407 return;
409 // 30 s hold in cache
410 const time_t MAX_CACHE_OLD_TIME = 30;
412 time_t now = NLMISC::CTime::getSecondsSince1970();
414 // look for object set older than MAX_CACHE_OLD_TIME and delete them
415 while (!_ReleasedObject.empty() && _ReleasedObject.begin()->first < now-MAX_CACHE_OLD_TIME)
417 TObjectSet &delSet = _ReleasedObject.begin()->second;
418 // unload this objects
419 while (!delSet.empty())
421 CKnownUser *object = *delSet.begin();
422 delete object;
425 _ReleasedObject.erase(_ReleasedObject.begin());
429 void CKnownUser::clearCache()
431 // remove any unreferenced object from the cache
432 while (!_ReleasedObject.empty())
434 TObjectSet &delSet = _ReleasedObject.begin()->second;
435 // unload this objects
436 while (!delSet.empty())
438 CKnownUser *object = *delSet.begin();
439 delete object;
442 _ReleasedObject.erase(_ReleasedObject.begin());
446 void CKnownUser::registerUpdatable()
448 static bool registered = false;
449 if (!registered)
451 NOPE::CPersistentCache::getInstance().registerCache(&CKnownUser::cacheCmd);
453 registered = true;
457 // set the pointer on the first pointer of the pointer list (set to null when there is no more pointer)
458 void CKnownUser::setFirstPtr(CKnownUserPtr *ptr)
460 _PtrList = ptr;
462 if (ptr == NULL)
464 // this is the last pointer !
465 if (_ObjectState == NOPE::os_transient
466 || _ObjectState == NOPE::os_removed)
468 // not a persistent object, or removed object, just delet it
469 delete this;
471 else if (_ObjectState != NOPE::os_removed)
473 setPersistentState(NOPE::os_released);
478 // Set the persistent state of the object and do some house keeping
479 void CKnownUser::setPersistentState(NOPE::TObjectState state)
481 nlassert(NOPE::AllowedTransition[_ObjectState][state] == true);
483 if(_ObjectState == NOPE::os_released && state == NOPE::os_removed)
485 // a release object gets removed (e.g. by remove by id)
487 // delete the object
488 delete this;
490 // no more to do
491 return;
494 if (_ObjectState == NOPE::os_transient && state != NOPE::os_transient)
496 nldebug("NOPE: inserting CKnownUser @%p in cache with id %u", this, static_cast<uint32>(_RelationId));
497 nlverify(_ObjectCache.insert(std::make_pair(_RelationId, this)).second);
500 if (_ObjectState != NOPE::os_transient)
501 nlassert(_ObjectCache.find(_RelationId) != _ObjectCache.end());
503 _ObjectState = state;
505 if (state == NOPE::os_released)
507 _ReleaseDate = NLMISC::CTime::getSecondsSince1970();
508 nlverify(_ReleasedObject[_ReleaseDate].insert(this).second);
510 else if (state == NOPE::os_removed)
512 nldebug("NOPE: erasing CKnownUser @%p in cache with id %u", this, static_cast<uint32>(_RelationId));
513 nlverify(_ObjectCache.erase(_RelationId) == 1);
518 CKnownUserPtr CKnownUser::load(MSW::CConnection &connection, uint32 id, const char *filename, uint32 lineNum)
520 CKnownUser *inCache = loadFromCache(id, true);
521 if (inCache != NULL)
523 return CKnownUserPtr(inCache, filename, lineNum);
526 std::string qs;
527 qs = "SELECT ";
529 qs += "Id, owner, targer_user, targer_character, relation_type, comments";
531 qs += " FROM known_users";
533 qs += " WHERE Id = '"+NLMISC::toString(id)+"'";
534 CKnownUserPtr ret;
535 if (!connection.query(qs))
537 return ret;
540 MSW::CStoreResult *result = connection.storeResult().release();
542 nlassert(result->getNumRows() <= 1);
543 if (result->getNumRows() == 1)
545 ret.assign(new CKnownUser, filename, lineNum);
546 // ok, we have an object
547 result->fetchRow();
549 result->getField(0, ret->_RelationId);
550 result->getField(1, ret->_OwnerId);
551 result->getField(2, ret->_TargetUser);
552 result->getField(3, ret->_TargetCharacter);
554 std::string s;
555 result->getField(4, s);
556 ret->_Relation = TKnownUserRelation(s);
558 result->getField(5, ret->_Comments);
561 ret->setPersistentState(NOPE::os_clean);
564 delete result;
566 return ret;
570 bool CKnownUser::loadChildrenOfCRingUser(MSW::CConnection &connection, uint32 parentId, std::vector < CKnownUserPtr > & container, const char *filename, uint32 lineNum)
573 std::string qs;
574 qs = "SELECT ";
576 qs += "Id, owner, targer_user, targer_character, relation_type, comments";
578 qs += " FROM known_users";
579 qs += " WHERE owner = '"+NLMISC::toString(parentId)+"'";
581 if (!connection.query(qs))
583 return false;
586 CUniquePtr<MSW::CStoreResult> result = connection.storeResult();
588 for (uint i=0; i<result->getNumRows(); ++i)
590 CKnownUser *ret = new CKnownUser();
591 // ok, we have an object
592 result->fetchRow();
594 result->getField(0, ret->_RelationId);
596 result->getField(1, ret->_OwnerId);
598 result->getField(2, ret->_TargetUser);
600 result->getField(3, ret->_TargetCharacter);
603 std::string s;
604 result->getField(4, s);
605 ret->_Relation = TKnownUserRelation(s);
608 result->getField(5, ret->_Comments);
609 CKnownUser *inCache = loadFromCache(ret->_RelationId, true);
610 if (inCache != NULL)
613 container.push_back(CKnownUserPtr(inCache, filename, lineNum));
615 // no more needed
616 delete ret;
618 else
620 ret->setPersistentState(NOPE::os_clean);
622 container.push_back(CKnownUserPtr(ret, filename, lineNum));
627 return true;
630 bool CKnownUser::loadChildrenOfCCharacter(MSW::CConnection &connection, uint32 parentId, std::vector < CKnownUserPtr > & container, const char *filename, uint32 lineNum)
633 std::string qs;
634 qs = "SELECT ";
636 qs += "Id, owner, targer_user, targer_character, relation_type, comments";
638 qs += " FROM known_users";
639 qs += " WHERE targer_user = '"+NLMISC::toString(parentId)+"'";
641 if (!connection.query(qs))
643 return false;
646 CUniquePtr<MSW::CStoreResult> result = connection.storeResult();
648 for (uint i=0; i<result->getNumRows(); ++i)
650 CKnownUser *ret = new CKnownUser();
651 // ok, we have an object
652 result->fetchRow();
654 result->getField(0, ret->_RelationId);
656 result->getField(1, ret->_OwnerId);
658 result->getField(2, ret->_TargetUser);
660 result->getField(3, ret->_TargetCharacter);
663 std::string s;
664 result->getField(4, s);
665 ret->_Relation = TKnownUserRelation(s);
668 result->getField(5, ret->_Comments);
669 CKnownUser *inCache = loadFromCache(ret->_RelationId, true);
670 if (inCache != NULL)
673 container.push_back(CKnownUserPtr(inCache, filename, lineNum));
675 // no more needed
676 delete ret;
678 else
680 ret->setPersistentState(NOPE::os_clean);
682 container.push_back(CKnownUserPtr(ret, filename, lineNum));
687 return true;
690 void CSessionParticipantPtr::linkPtr()
692 nlassert(_NextPtr == NULL);
693 nlassert(_PrevPtr == NULL);
694 if (_Ptr != NULL)
696 _NextPtr = _Ptr->getFirstPtr();
697 if (_NextPtr != NULL)
699 _PrevPtr = _NextPtr->_PrevPtr;
700 _PrevPtr->_NextPtr = this;
701 _NextPtr->_PrevPtr = this;
703 else
705 _NextPtr = this;
706 _PrevPtr = this;
707 _Ptr->setFirstPtr(this);
712 void CSessionParticipantPtr::unlinkPtr()
714 if (_NextPtr == NULL)
716 nlassert(_PrevPtr == NULL);
717 return;
720 if (_Ptr != NULL)
722 if (_NextPtr == this)
724 nlassert(_PrevPtr == this);
725 // last pointer !
726 _Ptr->setFirstPtr(NULL);
728 else
730 if (_Ptr->getFirstPtr() == this)
732 // the first ptr is the current one, we need to switch to next one
733 _Ptr->setFirstPtr(_NextPtr);
738 if (_NextPtr != this)
740 nlassert(_PrevPtr != this);
742 _NextPtr->_PrevPtr = _PrevPtr;
743 _PrevPtr->_NextPtr = _NextPtr;
745 _NextPtr = NULL;
746 _PrevPtr = NULL;
750 CSessionParticipant::TObjectCache CSessionParticipant::_ObjectCache;
751 CSessionParticipant::TReleasedObject CSessionParticipant::_ReleasedObject;
754 // Destructor, delete any children
755 CSessionParticipant::~CSessionParticipant()
757 // release childs reference
760 if (_PtrList != NULL)
762 nlwarning("ERROR : someone try to delete this object, but there are still ptr on it !");
763 CSessionParticipantPtr *ptr = _PtrList;
766 nlwarning(" Pointer created from '%s', line %u", ptr->_FileName, ptr->_LineNum);
767 ptr = _PtrList->getNextPtr();
768 } while(ptr != _PtrList);
769 nlstop;
771 // remove object from cache map
772 if (_Id != NOPE::INVALID_OBJECT_ID
773 && _ObjectState != NOPE::os_removed
774 && _ObjectState != NOPE::os_transient)
776 nldebug("NOPE: clearing CSessionParticipant @%p from cache with id %u", this, static_cast<uint32>(_Id));
777 nlverify(_ObjectCache.erase(_Id) == 1);
779 else if (_ObjectState != NOPE::os_transient)
781 nlassert(_ObjectCache.find(_Id) == _ObjectCache.end());
783 if (_ObjectState == NOPE::os_released)
785 removeFromReleased();
787 else
789 TReleasedObject::iterator it(_ReleasedObject.find(_ReleaseDate));
790 if (it != _ReleasedObject.end())
792 nlassert(it->second.find(this) == it->second.end());
797 void CSessionParticipant::removeFromReleased()
799 TReleasedObject::iterator it(_ReleasedObject.find(_ReleaseDate));
800 nlassert(it != _ReleasedObject.end());
801 TObjectSet &os = it->second;
803 nlverify(os.erase(this) == 1);
805 // nb : _ReleasedObject time entry are removed by the cache update
808 bool CSessionParticipant::create(MSW::CConnection &connection)
810 nlassert(getPersistentState() == NOPE::os_transient);
812 std::string qs;
813 qs = "INSERT INTO session_participant (";
815 qs += "session_id, char_id, status, kicked";
816 qs += ") VALUES (";
818 qs += "'"+MSW::escapeString(NLMISC::toString(_SessionId), connection)+"'";
819 qs += ", ";
820 qs += "'"+MSW::escapeString(NLMISC::toString(_CharId), connection)+"'";
821 qs += ", ";
822 qs += _Status.isValid()
823 ? "'"+_Status.toString()+"'"
824 : "DEFAULT(status)";
825 qs += ", ";
826 qs += "'"+MSW::escapeString(NLMISC::toString(_Kicked), connection)+"'";
828 qs += ")";
830 if (connection.query(qs))
832 uint32 _id_ = connection.getLastGeneratedId();
833 setObjectId(_id_);
836 setPersistentState(NOPE::os_clean);
838 // update the parent class instance in cache if any
840 if (_CharId != 0)
842 // need to update the parent class child list if it is in the cache
843 CCharacter *parent = CCharacter::loadFromCache(_CharId, false);
844 if (parent && parent->_SessionParticipants != NULL)
847 nlassert(std::find(parent->_SessionParticipants->begin(), parent->_SessionParticipants->end(), CSessionParticipantPtr(this, __FILE__, __LINE__)) == parent->_SessionParticipants->end());
848 parent->_SessionParticipants->push_back(CSessionParticipantPtr(this, __FILE__, __LINE__));
853 if (_SessionId != 0)
855 // need to update the parent class child list if it is in the cache
856 CSession *parent = CSession::loadFromCache(_SessionId, false);
857 if (parent && parent->_SessionParticipants != NULL)
860 nlassert(std::find(parent->_SessionParticipants->begin(), parent->_SessionParticipants->end(), CSessionParticipantPtr(this, __FILE__, __LINE__)) == parent->_SessionParticipants->end());
861 parent->_SessionParticipants->push_back(CSessionParticipantPtr(this, __FILE__, __LINE__));
866 return true;
869 return false;
872 bool CSessionParticipant::update(MSW::CConnection &connection)
874 nlassert(getPersistentState() == NOPE::os_dirty || getPersistentState() == NOPE::os_clean);
876 if (getPersistentState() == NOPE::os_clean)
877 // the object is clean, just ignore the save
878 return true;
880 std::string qs;
881 qs = "UPDATE session_participant SET ";
883 qs += "session_id = '"+MSW::escapeString(NLMISC::toString(_SessionId), connection)+"'";
884 qs += ", ";
885 qs += "char_id = '"+MSW::escapeString(NLMISC::toString(_CharId), connection)+"'";
886 qs += ", ";
887 qs += "status = " + (_Status.isValid()
888 ? "'"+_Status.toString()+"'"
889 : "DEFAULT(status)");
890 qs += ", ";
891 qs += "kicked = '"+MSW::escapeString(NLMISC::toString(_Kicked), connection)+"'";
893 qs += " WHERE Id = '"+NLMISC::toString(_Id)+"'";
896 if (connection.query(qs))
898 if (connection.getAffectedRows() == 1)
900 setPersistentState(NOPE::os_clean);
901 return true;
905 return false;
908 bool CSessionParticipant::remove(MSW::CConnection &connection)
910 nlassert(getPersistentState() == NOPE::os_dirty || getPersistentState() == NOPE::os_clean);
912 std::string qs;
913 qs = "DELETE FROM session_participant ";
915 qs += " WHERE Id = '"+NLMISC::toString(_Id)+"'";
918 if (connection.query(qs))
920 if (connection.getAffectedRows() == 1)
924 // change the persistant state to 'removed'.
925 setPersistentState(NOPE::os_removed);
927 // need to remove ref from parent class container (if any)
930 CCharacterPtr parent(CCharacter::loadFromCache(_CharId, true), __FILE__, __LINE__);
931 if (parent != NULL && parent->_SessionParticipants != NULL)
934 std::vector < CSessionParticipantPtr >::iterator it = std::find(parent->_SessionParticipants->begin(), parent->_SessionParticipants->end(), this);
935 if (it != parent->_SessionParticipants->end())
937 parent->_SessionParticipants->erase(it);
944 CSessionPtr parent(CSession::loadFromCache(_SessionId, true), __FILE__, __LINE__);
945 if (parent != NULL && parent->_SessionParticipants != NULL)
948 std::vector < CSessionParticipantPtr >::iterator it = std::find(parent->_SessionParticipants->begin(), parent->_SessionParticipants->end(), this);
949 if (it != parent->_SessionParticipants->end())
951 parent->_SessionParticipants->erase(it);
957 // need to remove ref from parent (if any)
960 return true;
963 return false;
966 bool CSessionParticipant::removeById(MSW::CConnection &connection, uint32 id)
968 CSessionParticipant *object = loadFromCache(id, true);
969 if (object != NULL)
971 return object->remove(connection);
973 // not in cache, run a SQL query
974 std::string qs;
975 qs = "DELETE FROM session_participant ";
977 qs += " WHERE Id = '"+NLMISC::toString(id)+"'";
980 if (connection.query(qs))
982 if (connection.getAffectedRows() == 1)
984 // ok, the row is removed
985 return true;
989 return false;
993 // Try to load the specified object from the memory cache, return NULL if the object is not in the cache
994 CSessionParticipant *CSessionParticipant::loadFromCache(uint32 objectId, bool unrelease)
996 // look in the cache
997 TObjectCache::iterator it(_ObjectCache.find(objectId));
998 if (it == _ObjectCache.end())
1000 // not found, return null
1001 return NULL;
1003 else
1005 CSessionParticipant *object = it->second;
1007 if (object->_ObjectState == NOPE::os_released)
1009 if (unrelease)
1011 // we need to remove this object from the released object set.
1012 object->removeFromReleased();
1013 object->_ObjectState = NOPE::os_clean;
1017 return it->second;
1020 // Receive and execute command from the cache manager.
1021 uint32 CSessionParticipant::cacheCmd(NOPE::TCacheCmd cmd)
1023 if (cmd == NOPE::cc_update)
1025 updateCache();
1027 else if (cmd == NOPE::cc_clear)
1029 clearCache();
1031 else if (cmd == NOPE::cc_dump)
1033 dump();
1035 else if (cmd == NOPE::cc_instance_count)
1037 return (uint32)_ObjectCache.size();
1040 // default return value
1041 return 0;
1044 void CSessionParticipant::dump()
1046 nlinfo(" Cache info for class CSessionParticipant :");
1047 nlinfo(" There are %u object instances in cache", _ObjectCache.size());
1049 // count the number of object in the released object set
1050 uint32 nbReleased = 0;
1052 TReleasedObject::iterator first(_ReleasedObject.begin()), last(_ReleasedObject.end());
1053 for (; first != last; ++first)
1055 nbReleased += (uint32)first->second.size();
1058 nlinfo(" There are %u object instances in cache not referenced (waiting deletion or re-use))", nbReleased);
1061 void CSessionParticipant::updateCache()
1063 if (_ReleasedObject.empty())
1064 return;
1066 // 30 s hold in cache
1067 const time_t MAX_CACHE_OLD_TIME = 30;
1069 time_t now = NLMISC::CTime::getSecondsSince1970();
1071 // look for object set older than MAX_CACHE_OLD_TIME and delete them
1072 while (!_ReleasedObject.empty() && _ReleasedObject.begin()->first < now-MAX_CACHE_OLD_TIME)
1074 TObjectSet &delSet = _ReleasedObject.begin()->second;
1075 // unload this objects
1076 while (!delSet.empty())
1078 CSessionParticipant *object = *delSet.begin();
1079 delete object;
1082 _ReleasedObject.erase(_ReleasedObject.begin());
1086 void CSessionParticipant::clearCache()
1088 // remove any unreferenced object from the cache
1089 while (!_ReleasedObject.empty())
1091 TObjectSet &delSet = _ReleasedObject.begin()->second;
1092 // unload this objects
1093 while (!delSet.empty())
1095 CSessionParticipant *object = *delSet.begin();
1096 delete object;
1099 _ReleasedObject.erase(_ReleasedObject.begin());
1103 void CSessionParticipant::registerUpdatable()
1105 static bool registered = false;
1106 if (!registered)
1108 NOPE::CPersistentCache::getInstance().registerCache(&CSessionParticipant::cacheCmd);
1110 registered = true;
1114 // set the pointer on the first pointer of the pointer list (set to null when there is no more pointer)
1115 void CSessionParticipant::setFirstPtr(CSessionParticipantPtr *ptr)
1117 _PtrList = ptr;
1119 if (ptr == NULL)
1121 // this is the last pointer !
1122 if (_ObjectState == NOPE::os_transient
1123 || _ObjectState == NOPE::os_removed)
1125 // not a persistent object, or removed object, just delet it
1126 delete this;
1128 else if (_ObjectState != NOPE::os_removed)
1130 setPersistentState(NOPE::os_released);
1135 // Set the persistent state of the object and do some house keeping
1136 void CSessionParticipant::setPersistentState(NOPE::TObjectState state)
1138 nlassert(NOPE::AllowedTransition[_ObjectState][state] == true);
1140 if(_ObjectState == NOPE::os_released && state == NOPE::os_removed)
1142 // a release object gets removed (e.g. by remove by id)
1144 // delete the object
1145 delete this;
1147 // no more to do
1148 return;
1151 if (_ObjectState == NOPE::os_transient && state != NOPE::os_transient)
1153 nldebug("NOPE: inserting CSessionParticipant @%p in cache with id %u", this, static_cast<uint32>(_Id));
1154 nlverify(_ObjectCache.insert(std::make_pair(_Id, this)).second);
1157 if (_ObjectState != NOPE::os_transient)
1158 nlassert(_ObjectCache.find(_Id) != _ObjectCache.end());
1160 _ObjectState = state;
1162 if (state == NOPE::os_released)
1164 _ReleaseDate = NLMISC::CTime::getSecondsSince1970();
1165 nlverify(_ReleasedObject[_ReleaseDate].insert(this).second);
1167 else if (state == NOPE::os_removed)
1169 nldebug("NOPE: erasing CSessionParticipant @%p in cache with id %u", this, static_cast<uint32>(_Id));
1170 nlverify(_ObjectCache.erase(_Id) == 1);
1175 CSessionParticipantPtr CSessionParticipant::load(MSW::CConnection &connection, uint32 id, const char *filename, uint32 lineNum)
1177 CSessionParticipant *inCache = loadFromCache(id, true);
1178 if (inCache != NULL)
1180 return CSessionParticipantPtr(inCache, filename, lineNum);
1183 std::string qs;
1184 qs = "SELECT ";
1186 qs += "Id, session_id, char_id, status, kicked";
1188 qs += " FROM session_participant";
1190 qs += " WHERE Id = '"+NLMISC::toString(id)+"'";
1191 CSessionParticipantPtr ret;
1192 if (!connection.query(qs))
1194 return ret;
1197 MSW::CStoreResult *result = connection.storeResult().release();
1199 nlassert(result->getNumRows() <= 1);
1200 if (result->getNumRows() == 1)
1202 ret.assign(new CSessionParticipant, filename, lineNum);
1203 // ok, we have an object
1204 result->fetchRow();
1206 result->getField(0, ret->_Id);
1207 result->getField(1, ret->_SessionId);
1208 result->getField(2, ret->_CharId);
1210 std::string s;
1211 result->getField(3, s);
1212 ret->_Status = TSessionPartStatus(s);
1214 result->getField(4, ret->_Kicked);
1217 ret->setPersistentState(NOPE::os_clean);
1220 delete result;
1222 return ret;
1226 bool CSessionParticipant::loadChildrenOfCCharacter(MSW::CConnection &connection, uint32 parentId, std::vector < CSessionParticipantPtr > & container, const char *filename, uint32 lineNum)
1229 std::string qs;
1230 qs = "SELECT ";
1232 qs += "Id, session_id, char_id, status, kicked";
1234 qs += " FROM session_participant";
1235 qs += " WHERE char_id = '"+NLMISC::toString(parentId)+"'";
1237 if (!connection.query(qs))
1239 return false;
1242 CUniquePtr<MSW::CStoreResult> result = connection.storeResult();
1244 for (uint i=0; i<result->getNumRows(); ++i)
1246 CSessionParticipant *ret = new CSessionParticipant();
1247 // ok, we have an object
1248 result->fetchRow();
1250 result->getField(0, ret->_Id);
1252 result->getField(1, ret->_SessionId);
1254 result->getField(2, ret->_CharId);
1257 std::string s;
1258 result->getField(3, s);
1259 ret->_Status = TSessionPartStatus(s);
1262 result->getField(4, ret->_Kicked);
1263 CSessionParticipant *inCache = loadFromCache(ret->_Id, true);
1264 if (inCache != NULL)
1267 container.push_back(CSessionParticipantPtr(inCache, filename, lineNum));
1269 // no more needed
1270 delete ret;
1272 else
1274 ret->setPersistentState(NOPE::os_clean);
1276 container.push_back(CSessionParticipantPtr(ret, filename, lineNum));
1281 return true;
1284 bool CSessionParticipant::loadChildrenOfCSession(MSW::CConnection &connection, uint32 parentId, std::vector < CSessionParticipantPtr > & container, const char *filename, uint32 lineNum)
1287 std::string qs;
1288 qs = "SELECT ";
1290 qs += "Id, session_id, char_id, status, kicked";
1292 qs += " FROM session_participant";
1293 qs += " WHERE session_id = '"+NLMISC::toString(parentId)+"'";
1295 if (!connection.query(qs))
1297 return false;
1300 CUniquePtr<MSW::CStoreResult> result = connection.storeResult();
1302 for (uint i=0; i<result->getNumRows(); ++i)
1304 CSessionParticipant *ret = new CSessionParticipant();
1305 // ok, we have an object
1306 result->fetchRow();
1308 result->getField(0, ret->_Id);
1310 result->getField(1, ret->_SessionId);
1312 result->getField(2, ret->_CharId);
1315 std::string s;
1316 result->getField(3, s);
1317 ret->_Status = TSessionPartStatus(s);
1320 result->getField(4, ret->_Kicked);
1321 CSessionParticipant *inCache = loadFromCache(ret->_Id, true);
1322 if (inCache != NULL)
1325 container.push_back(CSessionParticipantPtr(inCache, filename, lineNum));
1327 // no more needed
1328 delete ret;
1330 else
1332 ret->setPersistentState(NOPE::os_clean);
1334 container.push_back(CSessionParticipantPtr(ret, filename, lineNum));
1339 return true;
1342 void CCharacterPtr::linkPtr()
1344 nlassert(_NextPtr == NULL);
1345 nlassert(_PrevPtr == NULL);
1346 if (_Ptr != NULL)
1348 _NextPtr = _Ptr->getFirstPtr();
1349 if (_NextPtr != NULL)
1351 _PrevPtr = _NextPtr->_PrevPtr;
1352 _PrevPtr->_NextPtr = this;
1353 _NextPtr->_PrevPtr = this;
1355 else
1357 _NextPtr = this;
1358 _PrevPtr = this;
1359 _Ptr->setFirstPtr(this);
1364 void CCharacterPtr::unlinkPtr()
1366 if (_NextPtr == NULL)
1368 nlassert(_PrevPtr == NULL);
1369 return;
1372 if (_Ptr != NULL)
1374 if (_NextPtr == this)
1376 nlassert(_PrevPtr == this);
1377 // last pointer !
1378 _Ptr->setFirstPtr(NULL);
1380 else
1382 if (_Ptr->getFirstPtr() == this)
1384 // the first ptr is the current one, we need to switch to next one
1385 _Ptr->setFirstPtr(_NextPtr);
1390 if (_NextPtr != this)
1392 nlassert(_PrevPtr != this);
1394 _NextPtr->_PrevPtr = _PrevPtr;
1395 _PrevPtr->_NextPtr = _NextPtr;
1397 _NextPtr = NULL;
1398 _PrevPtr = NULL;
1402 CCharacter::TObjectCache CCharacter::_ObjectCache;
1403 CCharacter::TReleasedObject CCharacter::_ReleasedObject;
1406 // Destructor, delete any children
1407 CCharacter::~CCharacter()
1409 // release childs reference
1410 if (_Sessions != NULL)
1411 delete _Sessions;
1412 if (_SessionParticipants != NULL)
1413 delete _SessionParticipants;
1414 if (_KnownBy != NULL)
1415 delete _KnownBy;
1416 if (_PlayerRatings != NULL)
1417 delete _PlayerRatings;
1420 if (_PtrList != NULL)
1422 nlwarning("ERROR : someone try to delete this object, but there are still ptr on it !");
1423 CCharacterPtr *ptr = _PtrList;
1426 nlwarning(" Pointer created from '%s', line %u", ptr->_FileName, ptr->_LineNum);
1427 ptr = _PtrList->getNextPtr();
1428 } while(ptr != _PtrList);
1429 nlstop;
1431 // remove object from cache map
1432 if (_CharId != NOPE::INVALID_OBJECT_ID
1433 && _ObjectState != NOPE::os_removed
1434 && _ObjectState != NOPE::os_transient)
1436 nldebug("NOPE: clearing CCharacter @%p from cache with id %u", this, static_cast<uint32>(_CharId));
1437 nlverify(_ObjectCache.erase(_CharId) == 1);
1439 else if (_ObjectState != NOPE::os_transient)
1441 nlassert(_ObjectCache.find(_CharId) == _ObjectCache.end());
1443 if (_ObjectState == NOPE::os_released)
1445 removeFromReleased();
1447 else
1449 TReleasedObject::iterator it(_ReleasedObject.find(_ReleaseDate));
1450 if (it != _ReleasedObject.end())
1452 nlassert(it->second.find(this) == it->second.end());
1457 void CCharacter::removeFromReleased()
1459 TReleasedObject::iterator it(_ReleasedObject.find(_ReleaseDate));
1460 nlassert(it != _ReleasedObject.end());
1461 TObjectSet &os = it->second;
1463 nlverify(os.erase(this) == 1);
1465 // nb : _ReleasedObject time entry are removed by the cache update
1468 bool CCharacter::create(MSW::CConnection &connection)
1470 nlassert(getPersistentState() == NOPE::os_transient);
1472 nlassert(_CharId != 0);
1473 std::string qs;
1474 qs = "INSERT INTO characters (";
1476 qs += "char_id, char_name, user_id, guild_id, best_combat_level, home_mainland_session_id, ring_access, race, civilisation, cult, current_session, rrp_am, rrp_masterless, rrp_author, newcomer, creation_date, last_played_date";
1477 qs += ") VALUES (";
1479 qs += "'"+MSW::escapeString(NLMISC::toString(_CharId), connection)+"'";
1480 qs += ", ";
1481 qs += "'"+MSW::escapeString(NLMISC::toString(_CharName), connection)+"'";
1482 qs += ", ";
1483 qs += "'"+MSW::escapeString(NLMISC::toString(_UserId), connection)+"'";
1484 qs += ", ";
1485 qs += "'"+MSW::escapeString(NLMISC::toString(_GuildId), connection)+"'";
1486 qs += ", ";
1487 qs += "'"+MSW::escapeString(NLMISC::toString(_BestCombatLevel), connection)+"'";
1488 qs += ", ";
1489 qs += "'"+MSW::escapeString(NLMISC::toString(_HomeMainlandSessionId), connection)+"'";
1490 qs += ", ";
1491 qs += "'"+MSW::escapeString(NLMISC::toString(_RingAccess), connection)+"'";
1492 qs += ", ";
1493 qs += _Race.isValid()
1494 ? "'"+_Race.toString()+"'"
1495 : "DEFAULT(race)";
1496 qs += ", ";
1497 qs += _Civilisation.isValid()
1498 ? "'"+_Civilisation.toString()+"'"
1499 : "DEFAULT(civilisation)";
1500 qs += ", ";
1501 qs += _Cult.isValid()
1502 ? "'"+_Cult.toString()+"'"
1503 : "DEFAULT(cult)";
1504 qs += ", ";
1505 qs += "'"+MSW::escapeString(NLMISC::toString(_CurrentSession), connection)+"'";
1506 qs += ", ";
1507 qs += "'"+MSW::escapeString(NLMISC::toString(_RRPAM), connection)+"'";
1508 qs += ", ";
1509 qs += "'"+MSW::escapeString(NLMISC::toString(_RRPMasterless), connection)+"'";
1510 qs += ", ";
1511 qs += "'"+MSW::escapeString(NLMISC::toString(_RRPAuthor), connection)+"'";
1512 qs += ", ";
1513 qs += "'"+MSW::escapeString(NLMISC::toString(_Newcomer), connection)+"'";
1514 qs += ", ";
1515 qs += "'"+MSW::encodeDate(_CreationDate)+"'";
1516 qs += ", ";
1517 qs += "'"+MSW::encodeDate(_LastPlayedDate)+"'";
1519 qs += ")";
1521 if (connection.query(qs))
1525 setPersistentState(NOPE::os_clean);
1527 // update the parent class instance in cache if any
1529 if (_UserId != 0)
1531 // need to update the parent class child list if it is in the cache
1532 CRingUser *parent = CRingUser::loadFromCache(_UserId, false);
1533 if (parent && parent->_Characters != NULL)
1536 nlverify(parent->_Characters->insert(std::make_pair(getObjectId(), CCharacterPtr(this, __FILE__, __LINE__))).second);
1541 if (_GuildId != 0)
1543 // need to update the parent class child list if it is in the cache
1544 CGuild *parent = CGuild::loadFromCache(_GuildId, false);
1545 if (parent && parent->_Characters != NULL)
1548 nlassert(std::find(parent->_Characters->begin(), parent->_Characters->end(), CCharacterPtr(this, __FILE__, __LINE__)) == parent->_Characters->end());
1549 parent->_Characters->push_back(CCharacterPtr(this, __FILE__, __LINE__));
1554 return true;
1557 return false;
1560 bool CCharacter::update(MSW::CConnection &connection)
1562 nlassert(getPersistentState() == NOPE::os_dirty || getPersistentState() == NOPE::os_clean);
1564 if (getPersistentState() == NOPE::os_clean)
1565 // the object is clean, just ignore the save
1566 return true;
1568 std::string qs;
1569 qs = "UPDATE characters SET ";
1571 qs += "char_id = '"+MSW::escapeString(NLMISC::toString(_CharId), connection)+"'";
1572 qs += ", ";
1573 qs += "char_name = '"+MSW::escapeString(NLMISC::toString(_CharName), connection)+"'";
1574 qs += ", ";
1575 qs += "user_id = '"+MSW::escapeString(NLMISC::toString(_UserId), connection)+"'";
1576 qs += ", ";
1577 qs += "guild_id = '"+MSW::escapeString(NLMISC::toString(_GuildId), connection)+"'";
1578 qs += ", ";
1579 qs += "best_combat_level = '"+MSW::escapeString(NLMISC::toString(_BestCombatLevel), connection)+"'";
1580 qs += ", ";
1581 qs += "home_mainland_session_id = '"+MSW::escapeString(NLMISC::toString(_HomeMainlandSessionId), connection)+"'";
1582 qs += ", ";
1583 qs += "ring_access = '"+MSW::escapeString(NLMISC::toString(_RingAccess), connection)+"'";
1584 qs += ", ";
1585 qs += "race = " + (_Race.isValid()
1586 ? "'"+_Race.toString()+"'"
1587 : "DEFAULT(race)");
1588 qs += ", ";
1589 qs += "civilisation = " + (_Civilisation.isValid()
1590 ? "'"+_Civilisation.toString()+"'"
1591 : "DEFAULT(civilisation)");
1592 qs += ", ";
1593 qs += "cult = " + (_Cult.isValid()
1594 ? "'"+_Cult.toString()+"'"
1595 : "DEFAULT(cult)");
1596 qs += ", ";
1597 qs += "current_session = '"+MSW::escapeString(NLMISC::toString(_CurrentSession), connection)+"'";
1598 qs += ", ";
1599 qs += "rrp_am = '"+MSW::escapeString(NLMISC::toString(_RRPAM), connection)+"'";
1600 qs += ", ";
1601 qs += "rrp_masterless = '"+MSW::escapeString(NLMISC::toString(_RRPMasterless), connection)+"'";
1602 qs += ", ";
1603 qs += "rrp_author = '"+MSW::escapeString(NLMISC::toString(_RRPAuthor), connection)+"'";
1604 qs += ", ";
1605 qs += "newcomer = '"+MSW::escapeString(NLMISC::toString(_Newcomer), connection)+"'";
1606 qs += ", ";
1607 qs += "creation_date = '"+MSW::encodeDate(_CreationDate)+"'";
1608 qs += ", ";
1609 qs += "last_played_date = '"+MSW::encodeDate(_LastPlayedDate)+"'";
1611 qs += " WHERE char_id = '"+NLMISC::toString(_CharId)+"'";
1614 if (connection.query(qs))
1616 if (connection.getAffectedRows() == 1)
1618 setPersistentState(NOPE::os_clean);
1619 return true;
1623 return false;
1626 bool CCharacter::remove(MSW::CConnection &connection)
1628 nlassert(getPersistentState() == NOPE::os_dirty || getPersistentState() == NOPE::os_clean);
1630 std::string qs;
1631 qs = "DELETE FROM characters ";
1633 qs += " WHERE char_id = '"+NLMISC::toString(_CharId)+"'";
1636 if (connection.query(qs))
1638 if (connection.getAffectedRows() == 1)
1642 // cascading deletion for vector child SessionParticipants
1643 if (loadSessionParticipants(connection, __FILE__, __LINE__))
1645 const std::vector < CSessionParticipantPtr > & childs = getSessionParticipants();
1647 while (!childs.empty())
1649 getSessionParticipantsByIndex((uint32)childs.size()-1)->remove(connection);
1656 // cascading deletion for vector child KnownBy
1657 if (loadKnownBy(connection, __FILE__, __LINE__))
1659 const std::vector < CKnownUserPtr > & childs = getKnownBy();
1661 while (!childs.empty())
1663 getKnownByByIndex((uint32)childs.size()-1)->remove(connection);
1670 // unreference (and update) for vector child PlayerRatings
1671 if (loadPlayerRatings(connection, __FILE__, __LINE__))
1673 const std::vector < CPlayerRatingPtr > & childs = getPlayerRatings();
1675 for (uint i=0; i < childs.size(); ++i)
1678 getPlayerRatingsByIndex(i)->setAuthor(0);
1679 getPlayerRatingsByIndex(i)->update(connection);
1685 // change the persistant state to 'removed'.
1686 setPersistentState(NOPE::os_removed);
1688 // need to remove ref from parent class container (if any)
1691 CRingUserPtr parent(CRingUser::loadFromCache(_UserId, true), __FILE__, __LINE__);
1692 if (parent != NULL && parent->_Characters != NULL)
1695 parent->_Characters->erase(getObjectId());
1701 CGuildPtr parent(CGuild::loadFromCache(_GuildId, true), __FILE__, __LINE__);
1702 if (parent != NULL && parent->_Characters != NULL)
1705 std::vector < CCharacterPtr >::iterator it = std::find(parent->_Characters->begin(), parent->_Characters->end(), this);
1706 if (it != parent->_Characters->end())
1708 parent->_Characters->erase(it);
1714 // need to remove ref from parent (if any)
1717 return true;
1720 return false;
1723 bool CCharacter::removeById(MSW::CConnection &connection, uint32 id)
1725 CCharacter *object = loadFromCache(id, true);
1726 if (object != NULL)
1728 return object->remove(connection);
1730 // not in cache, run a SQL query
1731 std::string qs;
1732 qs = "DELETE FROM characters ";
1734 qs += " WHERE char_id = '"+NLMISC::toString(id)+"'";
1737 if (connection.query(qs))
1739 if (connection.getAffectedRows() == 1)
1741 // ok, the row is removed
1742 return true;
1746 return false;
1750 // Try to load the specified object from the memory cache, return NULL if the object is not in the cache
1751 CCharacter *CCharacter::loadFromCache(uint32 objectId, bool unrelease)
1753 // look in the cache
1754 TObjectCache::iterator it(_ObjectCache.find(objectId));
1755 if (it == _ObjectCache.end())
1757 // not found, return null
1758 return NULL;
1760 else
1762 CCharacter *object = it->second;
1764 if (object->_ObjectState == NOPE::os_released)
1766 if (unrelease)
1768 // we need to remove this object from the released object set.
1769 object->removeFromReleased();
1770 object->_ObjectState = NOPE::os_clean;
1774 return it->second;
1777 // Receive and execute command from the cache manager.
1778 uint32 CCharacter::cacheCmd(NOPE::TCacheCmd cmd)
1780 if (cmd == NOPE::cc_update)
1782 updateCache();
1784 else if (cmd == NOPE::cc_clear)
1786 clearCache();
1788 else if (cmd == NOPE::cc_dump)
1790 dump();
1792 else if (cmd == NOPE::cc_instance_count)
1794 return (uint32)_ObjectCache.size();
1797 // default return value
1798 return 0;
1801 void CCharacter::dump()
1803 nlinfo(" Cache info for class CCharacter :");
1804 nlinfo(" There are %u object instances in cache", _ObjectCache.size());
1806 // count the number of object in the released object set
1807 uint32 nbReleased = 0;
1809 TReleasedObject::iterator first(_ReleasedObject.begin()), last(_ReleasedObject.end());
1810 for (; first != last; ++first)
1812 nbReleased += (uint32)first->second.size();
1815 nlinfo(" There are %u object instances in cache not referenced (waiting deletion or re-use))", nbReleased);
1818 void CCharacter::updateCache()
1820 if (_ReleasedObject.empty())
1821 return;
1823 // 30 s hold in cache
1824 const time_t MAX_CACHE_OLD_TIME = 30;
1826 time_t now = NLMISC::CTime::getSecondsSince1970();
1828 // look for object set older than MAX_CACHE_OLD_TIME and delete them
1829 while (!_ReleasedObject.empty() && _ReleasedObject.begin()->first < now-MAX_CACHE_OLD_TIME)
1831 TObjectSet &delSet = _ReleasedObject.begin()->second;
1832 // unload this objects
1833 while (!delSet.empty())
1835 CCharacter *object = *delSet.begin();
1836 delete object;
1839 _ReleasedObject.erase(_ReleasedObject.begin());
1843 void CCharacter::clearCache()
1845 // remove any unreferenced object from the cache
1846 while (!_ReleasedObject.empty())
1848 TObjectSet &delSet = _ReleasedObject.begin()->second;
1849 // unload this objects
1850 while (!delSet.empty())
1852 CCharacter *object = *delSet.begin();
1853 delete object;
1856 _ReleasedObject.erase(_ReleasedObject.begin());
1860 void CCharacter::registerUpdatable()
1862 static bool registered = false;
1863 if (!registered)
1865 NOPE::CPersistentCache::getInstance().registerCache(&CCharacter::cacheCmd);
1867 registered = true;
1871 // set the pointer on the first pointer of the pointer list (set to null when there is no more pointer)
1872 void CCharacter::setFirstPtr(CCharacterPtr *ptr)
1874 _PtrList = ptr;
1876 if (ptr == NULL)
1878 // this is the last pointer !
1879 if (_ObjectState == NOPE::os_transient
1880 || _ObjectState == NOPE::os_removed)
1882 // not a persistent object, or removed object, just delet it
1883 delete this;
1885 else if (_ObjectState != NOPE::os_removed)
1887 setPersistentState(NOPE::os_released);
1892 // Set the persistent state of the object and do some house keeping
1893 void CCharacter::setPersistentState(NOPE::TObjectState state)
1895 nlassert(NOPE::AllowedTransition[_ObjectState][state] == true);
1897 if(_ObjectState == NOPE::os_released && state == NOPE::os_removed)
1899 // a release object gets removed (e.g. by remove by id)
1901 // delete the object
1902 delete this;
1904 // no more to do
1905 return;
1908 if (_ObjectState == NOPE::os_transient && state != NOPE::os_transient)
1910 nldebug("NOPE: inserting CCharacter @%p in cache with id %u", this, static_cast<uint32>(_CharId));
1911 nlverify(_ObjectCache.insert(std::make_pair(_CharId, this)).second);
1914 if (_ObjectState != NOPE::os_transient)
1915 nlassert(_ObjectCache.find(_CharId) != _ObjectCache.end());
1917 _ObjectState = state;
1919 if (state == NOPE::os_released)
1921 _ReleaseDate = NLMISC::CTime::getSecondsSince1970();
1922 nlverify(_ReleasedObject[_ReleaseDate].insert(this).second);
1924 else if (state == NOPE::os_removed)
1926 nldebug("NOPE: erasing CCharacter @%p in cache with id %u", this, static_cast<uint32>(_CharId));
1927 nlverify(_ObjectCache.erase(_CharId) == 1);
1932 CCharacterPtr CCharacter::load(MSW::CConnection &connection, uint32 id, const char *filename, uint32 lineNum)
1934 CCharacter *inCache = loadFromCache(id, true);
1935 if (inCache != NULL)
1937 return CCharacterPtr(inCache, filename, lineNum);
1940 std::string qs;
1941 qs = "SELECT ";
1943 qs += "char_id, char_name, user_id, guild_id, best_combat_level, home_mainland_session_id, ring_access, race, civilisation, cult, current_session, rrp_am, rrp_masterless, rrp_author, newcomer, creation_date, last_played_date";
1945 qs += " FROM characters";
1947 qs += " WHERE char_id = '"+NLMISC::toString(id)+"'";
1948 CCharacterPtr ret;
1949 if (!connection.query(qs))
1951 return ret;
1954 MSW::CStoreResult *result = connection.storeResult().release();
1956 nlassert(result->getNumRows() <= 1);
1957 if (result->getNumRows() == 1)
1959 ret.assign(new CCharacter, filename, lineNum);
1960 // ok, we have an object
1961 result->fetchRow();
1963 result->getField(0, ret->_CharId);
1964 result->getField(1, ret->_CharName);
1965 result->getField(2, ret->_UserId);
1966 result->getField(3, ret->_GuildId);
1967 result->getField(4, ret->_BestCombatLevel);
1968 result->getField(5, ret->_HomeMainlandSessionId);
1969 result->getField(6, ret->_RingAccess);
1971 std::string s;
1972 result->getField(7, s);
1973 ret->_Race = CHARSYNC::TRace(s);
1976 std::string s;
1977 result->getField(8, s);
1978 ret->_Civilisation = CHARSYNC::TCivilisation(s);
1981 std::string s;
1982 result->getField(9, s);
1983 ret->_Cult = CHARSYNC::TCult(s);
1985 result->getField(10, ret->_CurrentSession);
1986 result->getField(11, ret->_RRPAM);
1987 result->getField(12, ret->_RRPMasterless);
1988 result->getField(13, ret->_RRPAuthor);
1989 result->getField(14, ret->_Newcomer);
1990 result->getDateField(15, ret->_CreationDate);
1991 result->getDateField(16, ret->_LastPlayedDate);
1994 ret->setPersistentState(NOPE::os_clean);
1997 delete result;
1999 return ret;
2003 bool CCharacter::loadChildrenOfCRingUser(MSW::CConnection &connection, uint32 parentId, std::map < uint32, CCharacterPtr > & container, const char *filename, uint32 lineNum)
2006 std::string qs;
2007 qs = "SELECT ";
2009 qs += "char_id, char_name, user_id, guild_id, best_combat_level, home_mainland_session_id, ring_access, race, civilisation, cult, current_session, rrp_am, rrp_masterless, rrp_author, newcomer, creation_date, last_played_date";
2011 qs += " FROM characters";
2012 qs += " WHERE user_id = '"+NLMISC::toString(parentId)+"'";
2014 if (!connection.query(qs))
2016 return false;
2019 CUniquePtr<MSW::CStoreResult> result = connection.storeResult();
2021 for (uint i=0; i<result->getNumRows(); ++i)
2023 CCharacter *ret = new CCharacter();
2024 // ok, we have an object
2025 result->fetchRow();
2027 result->getField(0, ret->_CharId);
2029 result->getField(1, ret->_CharName);
2031 result->getField(2, ret->_UserId);
2033 result->getField(3, ret->_GuildId);
2035 result->getField(4, ret->_BestCombatLevel);
2037 result->getField(5, ret->_HomeMainlandSessionId);
2039 result->getField(6, ret->_RingAccess);
2042 std::string s;
2043 result->getField(7, s);
2044 ret->_Race = CHARSYNC::TRace(s);
2048 std::string s;
2049 result->getField(8, s);
2050 ret->_Civilisation = CHARSYNC::TCivilisation(s);
2054 std::string s;
2055 result->getField(9, s);
2056 ret->_Cult = CHARSYNC::TCult(s);
2059 result->getField(10, ret->_CurrentSession);
2061 result->getField(11, ret->_RRPAM);
2063 result->getField(12, ret->_RRPMasterless);
2065 result->getField(13, ret->_RRPAuthor);
2067 result->getField(14, ret->_Newcomer);
2069 result->getDateField(15, ret->_CreationDate);
2071 result->getDateField(16, ret->_LastPlayedDate);
2072 CCharacter *inCache = loadFromCache(ret->_CharId, true);
2073 if (inCache != NULL)
2076 container.insert(std::make_pair(inCache->getObjectId(), CCharacterPtr(inCache, filename, lineNum)));
2078 // no more needed
2079 delete ret;
2081 else
2083 ret->setPersistentState(NOPE::os_clean);
2085 container.insert(std::make_pair(ret->getObjectId(), CCharacterPtr(ret, filename, lineNum)));
2090 return true;
2093 bool CCharacter::loadChildrenOfCGuild(MSW::CConnection &connection, uint32 parentId, std::vector < CCharacterPtr > & container, const char *filename, uint32 lineNum)
2096 std::string qs;
2097 qs = "SELECT ";
2099 qs += "char_id, char_name, user_id, guild_id, best_combat_level, home_mainland_session_id, ring_access, race, civilisation, cult, current_session, rrp_am, rrp_masterless, rrp_author, newcomer, creation_date, last_played_date";
2101 qs += " FROM characters";
2102 qs += " WHERE guild_id = '"+NLMISC::toString(parentId)+"'";
2104 if (!connection.query(qs))
2106 return false;
2109 CUniquePtr<MSW::CStoreResult> result = connection.storeResult();
2111 for (uint i=0; i<result->getNumRows(); ++i)
2113 CCharacter *ret = new CCharacter();
2114 // ok, we have an object
2115 result->fetchRow();
2117 result->getField(0, ret->_CharId);
2119 result->getField(1, ret->_CharName);
2121 result->getField(2, ret->_UserId);
2123 result->getField(3, ret->_GuildId);
2125 result->getField(4, ret->_BestCombatLevel);
2127 result->getField(5, ret->_HomeMainlandSessionId);
2129 result->getField(6, ret->_RingAccess);
2132 std::string s;
2133 result->getField(7, s);
2134 ret->_Race = CHARSYNC::TRace(s);
2138 std::string s;
2139 result->getField(8, s);
2140 ret->_Civilisation = CHARSYNC::TCivilisation(s);
2144 std::string s;
2145 result->getField(9, s);
2146 ret->_Cult = CHARSYNC::TCult(s);
2149 result->getField(10, ret->_CurrentSession);
2151 result->getField(11, ret->_RRPAM);
2153 result->getField(12, ret->_RRPMasterless);
2155 result->getField(13, ret->_RRPAuthor);
2157 result->getField(14, ret->_Newcomer);
2159 result->getDateField(15, ret->_CreationDate);
2161 result->getDateField(16, ret->_LastPlayedDate);
2162 CCharacter *inCache = loadFromCache(ret->_CharId, true);
2163 if (inCache != NULL)
2166 container.push_back(CCharacterPtr(inCache, filename, lineNum));
2168 // no more needed
2169 delete ret;
2171 else
2173 ret->setPersistentState(NOPE::os_clean);
2175 container.push_back(CCharacterPtr(ret, filename, lineNum));
2180 return true;
2183 bool CCharacter::loadSessions(MSW::CConnection &connection, const char *filename, uint32 lineNum)
2185 bool ret = true;
2186 if (_Sessions != NULL)
2188 // the children are already loaded, just return true
2189 return true;
2192 // allocate the container
2193 _Sessions = new std::vector < CSessionPtr >;
2195 // load the childs
2196 ret &= CSession::loadChildrenOfCCharacter(connection, getObjectId(), *_Sessions, filename, lineNum);
2197 return ret;
2201 const std::vector<CSessionPtr> &CCharacter::getSessions() const
2203 nlassert(_Sessions != NULL);
2204 return *_Sessions;
2207 CSessionPtr &CCharacter::getSessionsByIndex(uint32 index) const
2209 nlassert(_Sessions != NULL);
2210 nlassert(index < _Sessions->size());
2211 return const_cast< CSessionPtr & >(_Sessions->operator[](index));
2214 CSessionPtr &CCharacter::getSessionsById(uint32 id) const
2216 nlassert(_Sessions != NULL);
2217 std::vector<CSessionPtr >::const_iterator first(_Sessions->begin()), last(_Sessions->end());
2218 for (; first != last; ++first)
2220 const CSessionPtr &child = *first;
2221 if (child->getObjectId() == id)
2223 return const_cast< CSessionPtr & >(child);
2227 // no object with this id, return a null pointer
2228 static CSessionPtr nilPtr;
2230 return nilPtr;
2234 bool CCharacter::loadSessionParticipants(MSW::CConnection &connection, const char *filename, uint32 lineNum)
2236 bool ret = true;
2237 if (_SessionParticipants != NULL)
2239 // the children are already loaded, just return true
2240 return true;
2243 // allocate the container
2244 _SessionParticipants = new std::vector < CSessionParticipantPtr >;
2246 // load the childs
2247 ret &= CSessionParticipant::loadChildrenOfCCharacter(connection, getObjectId(), *_SessionParticipants, filename, lineNum);
2248 return ret;
2252 const std::vector<CSessionParticipantPtr> &CCharacter::getSessionParticipants() const
2254 nlassert(_SessionParticipants != NULL);
2255 return *_SessionParticipants;
2258 CSessionParticipantPtr &CCharacter::getSessionParticipantsByIndex(uint32 index) const
2260 nlassert(_SessionParticipants != NULL);
2261 nlassert(index < _SessionParticipants->size());
2262 return const_cast< CSessionParticipantPtr & >(_SessionParticipants->operator[](index));
2265 CSessionParticipantPtr &CCharacter::getSessionParticipantsById(uint32 id) const
2267 nlassert(_SessionParticipants != NULL);
2268 std::vector<CSessionParticipantPtr >::const_iterator first(_SessionParticipants->begin()), last(_SessionParticipants->end());
2269 for (; first != last; ++first)
2271 const CSessionParticipantPtr &child = *first;
2272 if (child->getObjectId() == id)
2274 return const_cast< CSessionParticipantPtr & >(child);
2278 // no object with this id, return a null pointer
2279 static CSessionParticipantPtr nilPtr;
2281 return nilPtr;
2285 bool CCharacter::loadKnownBy(MSW::CConnection &connection, const char *filename, uint32 lineNum)
2287 bool ret = true;
2288 if (_KnownBy != NULL)
2290 // the children are already loaded, just return true
2291 return true;
2294 // allocate the container
2295 _KnownBy = new std::vector < CKnownUserPtr >;
2297 // load the childs
2298 ret &= CKnownUser::loadChildrenOfCCharacter(connection, getObjectId(), *_KnownBy, filename, lineNum);
2299 return ret;
2303 const std::vector<CKnownUserPtr> &CCharacter::getKnownBy() const
2305 nlassert(_KnownBy != NULL);
2306 return *_KnownBy;
2309 CKnownUserPtr &CCharacter::getKnownByByIndex(uint32 index) const
2311 nlassert(_KnownBy != NULL);
2312 nlassert(index < _KnownBy->size());
2313 return const_cast< CKnownUserPtr & >(_KnownBy->operator[](index));
2316 CKnownUserPtr &CCharacter::getKnownByById(uint32 id) const
2318 nlassert(_KnownBy != NULL);
2319 std::vector<CKnownUserPtr >::const_iterator first(_KnownBy->begin()), last(_KnownBy->end());
2320 for (; first != last; ++first)
2322 const CKnownUserPtr &child = *first;
2323 if (child->getObjectId() == id)
2325 return const_cast< CKnownUserPtr & >(child);
2329 // no object with this id, return a null pointer
2330 static CKnownUserPtr nilPtr;
2332 return nilPtr;
2336 bool CCharacter::loadPlayerRatings(MSW::CConnection &connection, const char *filename, uint32 lineNum)
2338 bool ret = true;
2339 if (_PlayerRatings != NULL)
2341 // the children are already loaded, just return true
2342 return true;
2345 // allocate the container
2346 _PlayerRatings = new std::vector < CPlayerRatingPtr >;
2348 // load the childs
2349 ret &= CPlayerRating::loadChildrenOfCCharacter(connection, getObjectId(), *_PlayerRatings, filename, lineNum);
2350 return ret;
2354 const std::vector<CPlayerRatingPtr> &CCharacter::getPlayerRatings() const
2356 nlassert(_PlayerRatings != NULL);
2357 return *_PlayerRatings;
2360 CPlayerRatingPtr &CCharacter::getPlayerRatingsByIndex(uint32 index) const
2362 nlassert(_PlayerRatings != NULL);
2363 nlassert(index < _PlayerRatings->size());
2364 return const_cast< CPlayerRatingPtr & >(_PlayerRatings->operator[](index));
2367 CPlayerRatingPtr &CCharacter::getPlayerRatingsById(uint32 id) const
2369 nlassert(_PlayerRatings != NULL);
2370 std::vector<CPlayerRatingPtr >::const_iterator first(_PlayerRatings->begin()), last(_PlayerRatings->end());
2371 for (; first != last; ++first)
2373 const CPlayerRatingPtr &child = *first;
2374 if (child->getObjectId() == id)
2376 return const_cast< CPlayerRatingPtr & >(child);
2380 // no object with this id, return a null pointer
2381 static CPlayerRatingPtr nilPtr;
2383 return nilPtr;
2387 void CRingUserPtr::linkPtr()
2389 nlassert(_NextPtr == NULL);
2390 nlassert(_PrevPtr == NULL);
2391 if (_Ptr != NULL)
2393 _NextPtr = _Ptr->getFirstPtr();
2394 if (_NextPtr != NULL)
2396 _PrevPtr = _NextPtr->_PrevPtr;
2397 _PrevPtr->_NextPtr = this;
2398 _NextPtr->_PrevPtr = this;
2400 else
2402 _NextPtr = this;
2403 _PrevPtr = this;
2404 _Ptr->setFirstPtr(this);
2409 void CRingUserPtr::unlinkPtr()
2411 if (_NextPtr == NULL)
2413 nlassert(_PrevPtr == NULL);
2414 return;
2417 if (_Ptr != NULL)
2419 if (_NextPtr == this)
2421 nlassert(_PrevPtr == this);
2422 // last pointer !
2423 _Ptr->setFirstPtr(NULL);
2425 else
2427 if (_Ptr->getFirstPtr() == this)
2429 // the first ptr is the current one, we need to switch to next one
2430 _Ptr->setFirstPtr(_NextPtr);
2435 if (_NextPtr != this)
2437 nlassert(_PrevPtr != this);
2439 _NextPtr->_PrevPtr = _PrevPtr;
2440 _PrevPtr->_NextPtr = _NextPtr;
2442 _NextPtr = NULL;
2443 _PrevPtr = NULL;
2447 CRingUser::TObjectCache CRingUser::_ObjectCache;
2448 CRingUser::TReleasedObject CRingUser::_ReleasedObject;
2451 // Destructor, delete any children
2452 CRingUser::~CRingUser()
2454 // release childs reference
2455 if (_KnownUsers != NULL)
2456 delete _KnownUsers;
2457 if (_Characters != NULL)
2458 delete _Characters;
2459 if (_Folders != NULL)
2460 delete _Folders;
2461 if (_FolderAccess != NULL)
2462 delete _FolderAccess;
2465 if (_PtrList != NULL)
2467 nlwarning("ERROR : someone try to delete this object, but there are still ptr on it !");
2468 CRingUserPtr *ptr = _PtrList;
2471 nlwarning(" Pointer created from '%s', line %u", ptr->_FileName, ptr->_LineNum);
2472 ptr = _PtrList->getNextPtr();
2473 } while(ptr != _PtrList);
2474 nlstop;
2476 // remove object from cache map
2477 if (_UserId != NOPE::INVALID_OBJECT_ID
2478 && _ObjectState != NOPE::os_removed
2479 && _ObjectState != NOPE::os_transient)
2481 nldebug("NOPE: clearing CRingUser @%p from cache with id %u", this, static_cast<uint32>(_UserId));
2482 nlverify(_ObjectCache.erase(_UserId) == 1);
2484 else if (_ObjectState != NOPE::os_transient)
2486 nlassert(_ObjectCache.find(_UserId) == _ObjectCache.end());
2488 if (_ObjectState == NOPE::os_released)
2490 removeFromReleased();
2492 else
2494 TReleasedObject::iterator it(_ReleasedObject.find(_ReleaseDate));
2495 if (it != _ReleasedObject.end())
2497 nlassert(it->second.find(this) == it->second.end());
2502 void CRingUser::removeFromReleased()
2504 TReleasedObject::iterator it(_ReleasedObject.find(_ReleaseDate));
2505 nlassert(it != _ReleasedObject.end());
2506 TObjectSet &os = it->second;
2508 nlverify(os.erase(this) == 1);
2510 // nb : _ReleasedObject time entry are removed by the cache update
2513 bool CRingUser::create(MSW::CConnection &connection)
2515 nlassert(getPersistentState() == NOPE::os_transient);
2517 nlassert(_UserId != 0);
2518 std::string qs;
2519 qs = "INSERT INTO ring_users (";
2521 qs += "user_id, user_name, current_char, current_session, current_activity, current_status, public_level, account_type, content_access_level, description, lang, cookie, current_domain_id, add_privileges";
2522 qs += ") VALUES (";
2524 qs += "'"+MSW::escapeString(NLMISC::toString(_UserId), connection)+"'";
2525 qs += ", ";
2526 qs += "'"+MSW::escapeString(NLMISC::toString(_UserName), connection)+"'";
2527 qs += ", ";
2528 qs += "'"+MSW::escapeString(NLMISC::toString(_CurrentCharacter), connection)+"'";
2529 qs += ", ";
2530 qs += "'"+MSW::escapeString(NLMISC::toString(_CurrentSession), connection)+"'";
2531 qs += ", ";
2532 qs += _CurrentActivity.isValid()
2533 ? "'"+_CurrentActivity.toString()+"'"
2534 : "DEFAULT(current_activity)";
2535 qs += ", ";
2536 qs += _CurrentStatus.isValid()
2537 ? "'"+_CurrentStatus.toString()+"'"
2538 : "DEFAULT(current_status)";
2539 qs += ", ";
2540 qs += _PublicLevel.isValid()
2541 ? "'"+_PublicLevel.toString()+"'"
2542 : "DEFAULT(public_level)";
2543 qs += ", ";
2544 qs += _AccountType.isValid()
2545 ? "'"+_AccountType.toString()+"'"
2546 : "DEFAULT(account_type)";
2547 qs += ", ";
2548 qs += "'"+MSW::escapeString(NLMISC::toString(_ContentAccessLevel), connection)+"'";
2549 qs += ", ";
2550 qs += "'"+MSW::escapeString(NLMISC::toString(_Description), connection)+"'";
2551 qs += ", ";
2552 qs += _Lang.isValid()
2553 ? "'"+_Lang.toString()+"'"
2554 : "DEFAULT(lang)";
2555 qs += ", ";
2556 qs += "'"+MSW::escapeString(NLMISC::toString(_Cookie), connection)+"'";
2557 qs += ", ";
2558 qs += "'"+MSW::escapeString(NLMISC::toString(_CurrentDomainId), connection)+"'";
2559 qs += ", ";
2560 qs += "'"+MSW::escapeString(NLMISC::toString(_AddedPrivileges), connection)+"'";
2562 qs += ")";
2564 if (connection.query(qs))
2568 setPersistentState(NOPE::os_clean);
2570 // update the parent class instance in cache if any
2572 return true;
2575 return false;
2578 bool CRingUser::update(MSW::CConnection &connection)
2580 nlassert(getPersistentState() == NOPE::os_dirty || getPersistentState() == NOPE::os_clean);
2582 if (getPersistentState() == NOPE::os_clean)
2583 // the object is clean, just ignore the save
2584 return true;
2586 std::string qs;
2587 qs = "UPDATE ring_users SET ";
2589 qs += "user_id = '"+MSW::escapeString(NLMISC::toString(_UserId), connection)+"'";
2590 qs += ", ";
2591 qs += "user_name = '"+MSW::escapeString(NLMISC::toString(_UserName), connection)+"'";
2592 qs += ", ";
2593 qs += "current_char = '"+MSW::escapeString(NLMISC::toString(_CurrentCharacter), connection)+"'";
2594 qs += ", ";
2595 qs += "current_session = '"+MSW::escapeString(NLMISC::toString(_CurrentSession), connection)+"'";
2596 qs += ", ";
2597 qs += "current_activity = " + (_CurrentActivity.isValid()
2598 ? "'"+_CurrentActivity.toString()+"'"
2599 : "DEFAULT(current_activity)");
2600 qs += ", ";
2601 qs += "current_status = " + (_CurrentStatus.isValid()
2602 ? "'"+_CurrentStatus.toString()+"'"
2603 : "DEFAULT(current_status)");
2604 qs += ", ";
2605 qs += "public_level = " + (_PublicLevel.isValid()
2606 ? "'"+_PublicLevel.toString()+"'"
2607 : "DEFAULT(public_level)");
2608 qs += ", ";
2609 qs += "account_type = " + (_AccountType.isValid()
2610 ? "'"+_AccountType.toString()+"'"
2611 : "DEFAULT(account_type)");
2612 qs += ", ";
2613 qs += "content_access_level = '"+MSW::escapeString(NLMISC::toString(_ContentAccessLevel), connection)+"'";
2614 qs += ", ";
2615 qs += "description = '"+MSW::escapeString(NLMISC::toString(_Description), connection)+"'";
2616 qs += ", ";
2617 qs += "lang = " + (_Lang.isValid()
2618 ? "'"+_Lang.toString()+"'"
2619 : "DEFAULT(lang)");
2620 qs += ", ";
2621 qs += "cookie = '"+MSW::escapeString(NLMISC::toString(_Cookie), connection)+"'";
2622 qs += ", ";
2623 qs += "current_domain_id = '"+MSW::escapeString(NLMISC::toString(_CurrentDomainId), connection)+"'";
2624 qs += ", ";
2625 qs += "add_privileges = '"+MSW::escapeString(NLMISC::toString(_AddedPrivileges), connection)+"'";
2627 qs += " WHERE user_id = '"+NLMISC::toString(_UserId)+"'";
2630 if (connection.query(qs))
2632 if (connection.getAffectedRows() == 1)
2634 setPersistentState(NOPE::os_clean);
2635 return true;
2639 return false;
2642 bool CRingUser::remove(MSW::CConnection &connection)
2644 nlassert(getPersistentState() == NOPE::os_dirty || getPersistentState() == NOPE::os_clean);
2646 std::string qs;
2647 qs = "DELETE FROM ring_users ";
2649 qs += " WHERE user_id = '"+NLMISC::toString(_UserId)+"'";
2652 if (connection.query(qs))
2654 if (connection.getAffectedRows() == 1)
2658 // cascading deletion for vector child KnownUsers
2659 if (loadKnownUsers(connection, __FILE__, __LINE__))
2661 const std::vector < CKnownUserPtr > & childs = getKnownUsers();
2663 while (!childs.empty())
2665 getKnownUsersByIndex((uint32)childs.size()-1)->remove(connection);
2672 // cascading deletion for map child Characters
2673 if (loadCharacters(connection, __FILE__, __LINE__))
2675 const std::map < uint32, CCharacterPtr > & childs = getCharacters();
2677 while (!childs.empty())
2679 getCharactersById(childs.begin()->first)->remove(connection);
2685 // cascading deletion for single child GMStatus
2686 if (loadGMStatus(connection, __FILE__, __LINE__))
2688 if (getGMStatus() != NULL)
2689 getGMStatus()->remove(connection);
2694 // unreference (and update) for vector child Folders
2695 if (loadFolders(connection, __FILE__, __LINE__))
2697 const std::vector < CFolderPtr > & childs = getFolders();
2699 for (uint i=0; i < childs.size(); ++i)
2702 getFoldersByIndex(i)->setAuthor(0);
2703 getFoldersByIndex(i)->update(connection);
2709 // unreference (and update) for vector child FolderAccess
2710 if (loadFolderAccess(connection, __FILE__, __LINE__))
2712 const std::vector < CFolderAccessPtr > & childs = getFolderAccess();
2714 for (uint i=0; i < childs.size(); ++i)
2717 getFolderAccessByIndex(i)->setUserId(0);
2718 getFolderAccessByIndex(i)->update(connection);
2724 // change the persistant state to 'removed'.
2725 setPersistentState(NOPE::os_removed);
2727 // need to remove ref from parent class container (if any)
2729 // need to remove ref from parent (if any)
2732 return true;
2735 return false;
2738 bool CRingUser::removeById(MSW::CConnection &connection, uint32 id)
2740 CRingUser *object = loadFromCache(id, true);
2741 if (object != NULL)
2743 return object->remove(connection);
2745 // not in cache, run a SQL query
2746 std::string qs;
2747 qs = "DELETE FROM ring_users ";
2749 qs += " WHERE user_id = '"+NLMISC::toString(id)+"'";
2752 if (connection.query(qs))
2754 if (connection.getAffectedRows() == 1)
2756 // ok, the row is removed
2757 return true;
2761 return false;
2765 // Try to load the specified object from the memory cache, return NULL if the object is not in the cache
2766 CRingUser *CRingUser::loadFromCache(uint32 objectId, bool unrelease)
2768 // look in the cache
2769 TObjectCache::iterator it(_ObjectCache.find(objectId));
2770 if (it == _ObjectCache.end())
2772 // not found, return null
2773 return NULL;
2775 else
2777 CRingUser *object = it->second;
2779 if (object->_ObjectState == NOPE::os_released)
2781 if (unrelease)
2783 // we need to remove this object from the released object set.
2784 object->removeFromReleased();
2785 object->_ObjectState = NOPE::os_clean;
2789 return it->second;
2792 // Receive and execute command from the cache manager.
2793 uint32 CRingUser::cacheCmd(NOPE::TCacheCmd cmd)
2795 if (cmd == NOPE::cc_update)
2797 updateCache();
2799 else if (cmd == NOPE::cc_clear)
2801 clearCache();
2803 else if (cmd == NOPE::cc_dump)
2805 dump();
2807 else if (cmd == NOPE::cc_instance_count)
2809 return (uint32)_ObjectCache.size();
2812 // default return value
2813 return 0;
2816 void CRingUser::dump()
2818 nlinfo(" Cache info for class CRingUser :");
2819 nlinfo(" There are %u object instances in cache", _ObjectCache.size());
2821 // count the number of object in the released object set
2822 uint32 nbReleased = 0;
2824 TReleasedObject::iterator first(_ReleasedObject.begin()), last(_ReleasedObject.end());
2825 for (; first != last; ++first)
2827 nbReleased += (uint32)first->second.size();
2830 nlinfo(" There are %u object instances in cache not referenced (waiting deletion or re-use))", nbReleased);
2833 void CRingUser::updateCache()
2835 if (_ReleasedObject.empty())
2836 return;
2838 // 30 s hold in cache
2839 const time_t MAX_CACHE_OLD_TIME = 30;
2841 time_t now = NLMISC::CTime::getSecondsSince1970();
2843 // look for object set older than MAX_CACHE_OLD_TIME and delete them
2844 while (!_ReleasedObject.empty() && _ReleasedObject.begin()->first < now-MAX_CACHE_OLD_TIME)
2846 TObjectSet &delSet = _ReleasedObject.begin()->second;
2847 // unload this objects
2848 while (!delSet.empty())
2850 CRingUser *object = *delSet.begin();
2851 delete object;
2854 _ReleasedObject.erase(_ReleasedObject.begin());
2858 void CRingUser::clearCache()
2860 // remove any unreferenced object from the cache
2861 while (!_ReleasedObject.empty())
2863 TObjectSet &delSet = _ReleasedObject.begin()->second;
2864 // unload this objects
2865 while (!delSet.empty())
2867 CRingUser *object = *delSet.begin();
2868 delete object;
2871 _ReleasedObject.erase(_ReleasedObject.begin());
2875 void CRingUser::registerUpdatable()
2877 static bool registered = false;
2878 if (!registered)
2880 NOPE::CPersistentCache::getInstance().registerCache(&CRingUser::cacheCmd);
2882 registered = true;
2886 // set the pointer on the first pointer of the pointer list (set to null when there is no more pointer)
2887 void CRingUser::setFirstPtr(CRingUserPtr *ptr)
2889 _PtrList = ptr;
2891 if (ptr == NULL)
2893 // this is the last pointer !
2894 if (_ObjectState == NOPE::os_transient
2895 || _ObjectState == NOPE::os_removed)
2897 // not a persistent object, or removed object, just delet it
2898 delete this;
2900 else if (_ObjectState != NOPE::os_removed)
2902 setPersistentState(NOPE::os_released);
2907 // Set the persistent state of the object and do some house keeping
2908 void CRingUser::setPersistentState(NOPE::TObjectState state)
2910 nlassert(NOPE::AllowedTransition[_ObjectState][state] == true);
2912 if(_ObjectState == NOPE::os_released && state == NOPE::os_removed)
2914 // a release object gets removed (e.g. by remove by id)
2916 // delete the object
2917 delete this;
2919 // no more to do
2920 return;
2923 if (_ObjectState == NOPE::os_transient && state != NOPE::os_transient)
2925 nldebug("NOPE: inserting CRingUser @%p in cache with id %u", this, static_cast<uint32>(_UserId));
2926 nlverify(_ObjectCache.insert(std::make_pair(_UserId, this)).second);
2929 if (_ObjectState != NOPE::os_transient)
2930 nlassert(_ObjectCache.find(_UserId) != _ObjectCache.end());
2932 _ObjectState = state;
2934 if (state == NOPE::os_released)
2936 _ReleaseDate = NLMISC::CTime::getSecondsSince1970();
2937 nlverify(_ReleasedObject[_ReleaseDate].insert(this).second);
2939 else if (state == NOPE::os_removed)
2941 nldebug("NOPE: erasing CRingUser @%p in cache with id %u", this, static_cast<uint32>(_UserId));
2942 nlverify(_ObjectCache.erase(_UserId) == 1);
2947 CRingUserPtr CRingUser::load(MSW::CConnection &connection, uint32 id, const char *filename, uint32 lineNum)
2949 CRingUser *inCache = loadFromCache(id, true);
2950 if (inCache != NULL)
2952 return CRingUserPtr(inCache, filename, lineNum);
2955 std::string qs;
2956 qs = "SELECT ";
2958 qs += "user_id, user_name, current_char, current_session, current_activity, current_status, public_level, account_type, content_access_level, description, lang, cookie, current_domain_id, add_privileges";
2960 qs += " FROM ring_users";
2962 qs += " WHERE user_id = '"+NLMISC::toString(id)+"'";
2963 CRingUserPtr ret;
2964 if (!connection.query(qs))
2966 return ret;
2969 MSW::CStoreResult *result = connection.storeResult().release();
2971 nlassert(result->getNumRows() <= 1);
2972 if (result->getNumRows() == 1)
2974 ret.assign(new CRingUser, filename, lineNum);
2975 // ok, we have an object
2976 result->fetchRow();
2978 result->getField(0, ret->_UserId);
2979 result->getField(1, ret->_UserName);
2980 result->getField(2, ret->_CurrentCharacter);
2981 result->getField(3, ret->_CurrentSession);
2983 std::string s;
2984 result->getField(4, s);
2985 ret->_CurrentActivity = TCurrentActivity(s);
2988 std::string s;
2989 result->getField(5, s);
2990 ret->_CurrentStatus = TCurrentStatus(s);
2993 std::string s;
2994 result->getField(6, s);
2995 ret->_PublicLevel = TPublicLevel(s);
2998 std::string s;
2999 result->getField(7, s);
3000 ret->_AccountType = TAccountType(s);
3002 result->getField(8, ret->_ContentAccessLevel);
3003 result->getField(9, ret->_Description);
3005 std::string s;
3006 result->getField(10, s);
3007 ret->_Lang = TLanguage(s);
3009 result->getField(11, ret->_Cookie);
3010 result->getField(12, ret->_CurrentDomainId);
3011 result->getField(13, ret->_AddedPrivileges);
3014 ret->setPersistentState(NOPE::os_clean);
3017 delete result;
3019 return ret;
3023 bool CRingUser::loadKnownUsers(MSW::CConnection &connection, const char *filename, uint32 lineNum)
3025 bool ret = true;
3026 if (_KnownUsers != NULL)
3028 // the children are already loaded, just return true
3029 return true;
3032 // allocate the container
3033 _KnownUsers = new std::vector < CKnownUserPtr >;
3035 // load the childs
3036 ret &= CKnownUser::loadChildrenOfCRingUser(connection, getObjectId(), *_KnownUsers, filename, lineNum);
3037 return ret;
3041 const std::vector<CKnownUserPtr> &CRingUser::getKnownUsers() const
3043 nlassert(_KnownUsers != NULL);
3044 return *_KnownUsers;
3047 CKnownUserPtr &CRingUser::getKnownUsersByIndex(uint32 index) const
3049 nlassert(_KnownUsers != NULL);
3050 nlassert(index < _KnownUsers->size());
3051 return const_cast< CKnownUserPtr & >(_KnownUsers->operator[](index));
3054 CKnownUserPtr &CRingUser::getKnownUsersById(uint32 id) const
3056 nlassert(_KnownUsers != NULL);
3057 std::vector<CKnownUserPtr >::const_iterator first(_KnownUsers->begin()), last(_KnownUsers->end());
3058 for (; first != last; ++first)
3060 const CKnownUserPtr &child = *first;
3061 if (child->getObjectId() == id)
3063 return const_cast< CKnownUserPtr & >(child);
3067 // no object with this id, return a null pointer
3068 static CKnownUserPtr nilPtr;
3070 return nilPtr;
3074 bool CRingUser::loadCharacters(MSW::CConnection &connection, const char *filename, uint32 lineNum)
3076 bool ret = true;
3077 if (_Characters != NULL)
3079 // the children are already loaded, just return true
3080 return true;
3083 // allocate the container
3084 _Characters = new std::map < uint32, CCharacterPtr >;
3086 // load the childs
3087 ret &= CCharacter::loadChildrenOfCRingUser(connection, getObjectId(), *_Characters, filename, lineNum);
3088 return ret;
3092 const std::map<uint32, CCharacterPtr> &CRingUser::getCharacters() const
3094 nlassert(_Characters != NULL);
3095 return *_Characters;
3098 CCharacterPtr &CRingUser::getCharactersById(uint32 id) const
3100 nlassert(_Characters != NULL);
3101 std::map<uint32, CCharacterPtr>::const_iterator it(_Characters->find(id));
3103 if (it == _Characters->end())
3105 // no object with this id, return a null pointer
3106 static CCharacterPtr nilPtr;
3107 return nilPtr;
3110 return const_cast< CCharacterPtr & >(it->second);
3114 bool CRingUser::loadFolders(MSW::CConnection &connection, const char *filename, uint32 lineNum)
3116 bool ret = true;
3117 if (_Folders != NULL)
3119 // the children are already loaded, just return true
3120 return true;
3123 // allocate the container
3124 _Folders = new std::vector < CFolderPtr >;
3126 // load the childs
3127 ret &= CFolder::loadChildrenOfCRingUser(connection, getObjectId(), *_Folders, filename, lineNum);
3128 return ret;
3132 const std::vector<CFolderPtr> &CRingUser::getFolders() const
3134 nlassert(_Folders != NULL);
3135 return *_Folders;
3138 CFolderPtr &CRingUser::getFoldersByIndex(uint32 index) const
3140 nlassert(_Folders != NULL);
3141 nlassert(index < _Folders->size());
3142 return const_cast< CFolderPtr & >(_Folders->operator[](index));
3145 CFolderPtr &CRingUser::getFoldersById(uint32 id) const
3147 nlassert(_Folders != NULL);
3148 std::vector<CFolderPtr >::const_iterator first(_Folders->begin()), last(_Folders->end());
3149 for (; first != last; ++first)
3151 const CFolderPtr &child = *first;
3152 if (child->getObjectId() == id)
3154 return const_cast< CFolderPtr & >(child);
3158 // no object with this id, return a null pointer
3159 static CFolderPtr nilPtr;
3161 return nilPtr;
3165 bool CRingUser::loadFolderAccess(MSW::CConnection &connection, const char *filename, uint32 lineNum)
3167 bool ret = true;
3168 if (_FolderAccess != NULL)
3170 // the children are already loaded, just return true
3171 return true;
3174 // allocate the container
3175 _FolderAccess = new std::vector < CFolderAccessPtr >;
3177 // load the childs
3178 ret &= CFolderAccess::loadChildrenOfCRingUser(connection, getObjectId(), *_FolderAccess, filename, lineNum);
3179 return ret;
3183 const std::vector<CFolderAccessPtr> &CRingUser::getFolderAccess() const
3185 nlassert(_FolderAccess != NULL);
3186 return *_FolderAccess;
3189 CFolderAccessPtr &CRingUser::getFolderAccessByIndex(uint32 index) const
3191 nlassert(_FolderAccess != NULL);
3192 nlassert(index < _FolderAccess->size());
3193 return const_cast< CFolderAccessPtr & >(_FolderAccess->operator[](index));
3196 CFolderAccessPtr &CRingUser::getFolderAccessById(uint32 id) const
3198 nlassert(_FolderAccess != NULL);
3199 std::vector<CFolderAccessPtr >::const_iterator first(_FolderAccess->begin()), last(_FolderAccess->end());
3200 for (; first != last; ++first)
3202 const CFolderAccessPtr &child = *first;
3203 if (child->getObjectId() == id)
3205 return const_cast< CFolderAccessPtr & >(child);
3209 // no object with this id, return a null pointer
3210 static CFolderAccessPtr nilPtr;
3212 return nilPtr;
3216 bool CRingUser::loadGMStatus(MSW::CConnection &connection, const char *filename, uint32 lineNum)
3218 if (_GMStatusLoaded)
3220 // the child is already loaded, just return true
3221 return true;
3223 bool ret = CGmStatus::loadChildOfCRingUser(connection, getObjectId(), _GMStatus, filename, lineNum);
3224 _GMStatusLoaded = true;
3225 return ret;
3228 /** Return the one child object (or null if not) */
3229 CGmStatusPtr CRingUser::getGMStatus()
3231 nlassert(_GMStatusLoaded);
3232 return _GMStatus;
3236 void CSessionPtr::linkPtr()
3238 nlassert(_NextPtr == NULL);
3239 nlassert(_PrevPtr == NULL);
3240 if (_Ptr != NULL)
3242 _NextPtr = _Ptr->getFirstPtr();
3243 if (_NextPtr != NULL)
3245 _PrevPtr = _NextPtr->_PrevPtr;
3246 _PrevPtr->_NextPtr = this;
3247 _NextPtr->_PrevPtr = this;
3249 else
3251 _NextPtr = this;
3252 _PrevPtr = this;
3253 _Ptr->setFirstPtr(this);
3258 void CSessionPtr::unlinkPtr()
3260 if (_NextPtr == NULL)
3262 nlassert(_PrevPtr == NULL);
3263 return;
3266 if (_Ptr != NULL)
3268 if (_NextPtr == this)
3270 nlassert(_PrevPtr == this);
3271 // last pointer !
3272 _Ptr->setFirstPtr(NULL);
3274 else
3276 if (_Ptr->getFirstPtr() == this)
3278 // the first ptr is the current one, we need to switch to next one
3279 _Ptr->setFirstPtr(_NextPtr);
3284 if (_NextPtr != this)
3286 nlassert(_PrevPtr != this);
3288 _NextPtr->_PrevPtr = _PrevPtr;
3289 _PrevPtr->_NextPtr = _NextPtr;
3291 _NextPtr = NULL;
3292 _PrevPtr = NULL;
3296 CSession::TObjectCache CSession::_ObjectCache;
3297 CSession::TReleasedObject CSession::_ReleasedObject;
3300 // Destructor, delete any children
3301 CSession::~CSession()
3303 // release childs reference
3304 if (_SessionParticipants != NULL)
3305 delete _SessionParticipants;
3306 if (_GuildInvites != NULL)
3307 delete _GuildInvites;
3308 if (_JournalEntries != NULL)
3309 delete _JournalEntries;
3312 if (_PtrList != NULL)
3314 nlwarning("ERROR : someone try to delete this object, but there are still ptr on it !");
3315 CSessionPtr *ptr = _PtrList;
3318 nlwarning(" Pointer created from '%s', line %u", ptr->_FileName, ptr->_LineNum);
3319 ptr = _PtrList->getNextPtr();
3320 } while(ptr != _PtrList);
3321 nlstop;
3323 // remove object from cache map
3324 if (_SessionId != NOPE::INVALID_OBJECT_ID
3325 && _ObjectState != NOPE::os_removed
3326 && _ObjectState != NOPE::os_transient)
3328 nldebug("NOPE: clearing CSession @%p from cache with id %u", this, static_cast<uint32>(_SessionId));
3329 nlverify(_ObjectCache.erase(_SessionId) == 1);
3331 else if (_ObjectState != NOPE::os_transient)
3333 nlassert(_ObjectCache.find(_SessionId) == _ObjectCache.end());
3335 if (_ObjectState == NOPE::os_released)
3337 removeFromReleased();
3339 else
3341 TReleasedObject::iterator it(_ReleasedObject.find(_ReleaseDate));
3342 if (it != _ReleasedObject.end())
3344 nlassert(it->second.find(this) == it->second.end());
3349 void CSession::removeFromReleased()
3351 TReleasedObject::iterator it(_ReleasedObject.find(_ReleaseDate));
3352 nlassert(it != _ReleasedObject.end());
3353 TObjectSet &os = it->second;
3355 nlverify(os.erase(this) == 1);
3357 // nb : _ReleasedObject time entry are removed by the cache update
3360 bool CSession::create(MSW::CConnection &connection)
3362 nlassert(getPersistentState() == NOPE::os_transient);
3364 std::string qs;
3365 qs = "INSERT INTO sessions (";
3367 qs += "session_type, title, owner, plan_date, start_date, description, orientation, level, rule_type, access_type, state, host_shard_id, subscription_slots, reserved_slots, estimated_duration, final_duration, folder_id, lang, icone, anim_mode, race_filter, religion_filter, guild_filter, shard_filter, level_filter, subscription_closed, newcomer";
3368 qs += ") VALUES (";
3370 qs += "'"+_SessionType.toString()+"'";
3371 qs += ", ";
3372 qs += "'"+MSW::escapeString(NLMISC::toString(_Title), connection)+"'";
3373 qs += ", ";
3374 qs += "'"+MSW::escapeString(NLMISC::toString(_OwnerId), connection)+"'";
3375 qs += ", ";
3376 qs += "'"+MSW::encodeDate(_PlanDate)+"'";
3377 qs += ", ";
3378 qs += "'"+MSW::encodeDate(_StartDate)+"'";
3379 qs += ", ";
3380 qs += "'"+MSW::escapeString(NLMISC::toString(_Description), connection)+"'";
3381 qs += ", ";
3382 qs += _Orientation.isValid()
3383 ? "'"+_Orientation.toString()+"'"
3384 : "DEFAULT(orientation)";
3385 qs += ", ";
3386 qs += _Level.isValid()
3387 ? "'"+_Level.toString()+"'"
3388 : "DEFAULT(level)";
3389 qs += ", ";
3390 qs += _RuleType.isValid()
3391 ? "'"+_RuleType.toString()+"'"
3392 : "DEFAULT(rule_type)";
3393 qs += ", ";
3394 qs += _AccessType.isValid()
3395 ? "'"+_AccessType.toString()+"'"
3396 : "DEFAULT(access_type)";
3397 qs += ", ";
3398 qs += _State.isValid()
3399 ? "'"+_State.toString()+"'"
3400 : "DEFAULT(state)";
3401 qs += ", ";
3402 qs += "'"+MSW::escapeString(NLMISC::toString(_HostShardId), connection)+"'";
3403 qs += ", ";
3404 qs += "'"+MSW::escapeString(NLMISC::toString(_SubscriptionSlots), connection)+"'";
3405 qs += ", ";
3406 qs += "'"+MSW::escapeString(NLMISC::toString(_ReservedSlots), connection)+"'";
3407 qs += ", ";
3408 qs += _EstimatedDuration.isValid()
3409 ? "'"+_EstimatedDuration.toString()+"'"
3410 : "DEFAULT(estimated_duration)";
3411 qs += ", ";
3412 qs += "'"+MSW::escapeString(NLMISC::toString(_FinalDuration), connection)+"'";
3413 qs += ", ";
3414 qs += "'"+MSW::escapeString(NLMISC::toString(_FolderId), connection)+"'";
3415 qs += ", ";
3416 qs += "'"+MSW::escapeString(NLMISC::toString(_Lang), connection)+"'";
3417 qs += ", ";
3418 qs += "'"+MSW::escapeString(NLMISC::toString(_Icone), connection)+"'";
3419 qs += ", ";
3420 qs += _AnimMode.isValid()
3421 ? "'"+_AnimMode.toString()+"'"
3422 : "DEFAULT(anim_mode)";
3423 qs += ", ";
3424 qs += "'"+_RaceFilter.toString()+"'";
3425 qs += ", ";
3426 qs += "'"+_ReligionFilter.toString()+"'";
3427 qs += ", ";
3428 qs += _GuildFilter.isValid()
3429 ? "'"+_GuildFilter.toString()+"'"
3430 : "DEFAULT(guild_filter)";
3431 qs += ", ";
3432 qs += "'"+_ShardFilter.toString()+"'";
3433 qs += ", ";
3434 qs += "'"+_LevelFilter.toString()+"'";
3435 qs += ", ";
3436 qs += "'"+MSW::escapeString(NLMISC::toString(_SubscriptionClosed), connection)+"'";
3437 qs += ", ";
3438 qs += "'"+MSW::escapeString(NLMISC::toString(_Newcomer), connection)+"'";
3440 qs += ")";
3442 if (connection.query(qs))
3444 uint32 _id_ = connection.getLastGeneratedId();
3445 setObjectId(_id_);
3448 setPersistentState(NOPE::os_clean);
3450 // update the parent class instance in cache if any
3452 if (_OwnerId != 0)
3454 // need to update the parent class child list if it is in the cache
3455 CCharacter *parent = CCharacter::loadFromCache(_OwnerId, false);
3456 if (parent && parent->_Sessions != NULL)
3459 nlassert(std::find(parent->_Sessions->begin(), parent->_Sessions->end(), CSessionPtr(this, __FILE__, __LINE__)) == parent->_Sessions->end());
3460 parent->_Sessions->push_back(CSessionPtr(this, __FILE__, __LINE__));
3465 if (_FolderId != 0)
3467 // need to update the parent class child list if it is in the cache
3468 CFolder *parent = CFolder::loadFromCache(_FolderId, false);
3469 if (parent && parent->_Sessions != NULL)
3472 nlassert(std::find(parent->_Sessions->begin(), parent->_Sessions->end(), CSessionPtr(this, __FILE__, __LINE__)) == parent->_Sessions->end());
3473 parent->_Sessions->push_back(CSessionPtr(this, __FILE__, __LINE__));
3478 return true;
3481 return false;
3484 bool CSession::update(MSW::CConnection &connection)
3486 nlassert(getPersistentState() == NOPE::os_dirty || getPersistentState() == NOPE::os_clean);
3488 if (getPersistentState() == NOPE::os_clean)
3489 // the object is clean, just ignore the save
3490 return true;
3492 std::string qs;
3493 qs = "UPDATE sessions SET ";
3495 qs += "session_type = '"+_SessionType.toString()+"'";
3496 qs += ", ";
3497 qs += "title = '"+MSW::escapeString(NLMISC::toString(_Title), connection)+"'";
3498 qs += ", ";
3499 qs += "owner = '"+MSW::escapeString(NLMISC::toString(_OwnerId), connection)+"'";
3500 qs += ", ";
3501 qs += "plan_date = '"+MSW::encodeDate(_PlanDate)+"'";
3502 qs += ", ";
3503 qs += "start_date = '"+MSW::encodeDate(_StartDate)+"'";
3504 qs += ", ";
3505 qs += "description = '"+MSW::escapeString(NLMISC::toString(_Description), connection)+"'";
3506 qs += ", ";
3507 qs += "orientation = " + (_Orientation.isValid()
3508 ? "'"+_Orientation.toString()+"'"
3509 : "DEFAULT(orientation)");
3510 qs += ", ";
3511 qs += "level = " + (_Level.isValid()
3512 ? "'"+_Level.toString()+"'"
3513 : "DEFAULT(level)");
3514 qs += ", ";
3515 qs += "rule_type = " + (_RuleType.isValid()
3516 ? "'"+_RuleType.toString()+"'"
3517 : "DEFAULT(rule_type)");
3518 qs += ", ";
3519 qs += "access_type = " + (_AccessType.isValid()
3520 ? "'"+_AccessType.toString()+"'"
3521 : "DEFAULT(access_type)");
3522 qs += ", ";
3523 qs += "state = " + (_State.isValid()
3524 ? "'"+_State.toString()+"'"
3525 : "DEFAULT(state)");
3526 qs += ", ";
3527 qs += "host_shard_id = '"+MSW::escapeString(NLMISC::toString(_HostShardId), connection)+"'";
3528 qs += ", ";
3529 qs += "subscription_slots = '"+MSW::escapeString(NLMISC::toString(_SubscriptionSlots), connection)+"'";
3530 qs += ", ";
3531 qs += "reserved_slots = '"+MSW::escapeString(NLMISC::toString(_ReservedSlots), connection)+"'";
3532 qs += ", ";
3533 qs += "estimated_duration = " + (_EstimatedDuration.isValid()
3534 ? "'"+_EstimatedDuration.toString()+"'"
3535 : "DEFAULT(estimated_duration)");
3536 qs += ", ";
3537 qs += "final_duration = '"+MSW::escapeString(NLMISC::toString(_FinalDuration), connection)+"'";
3538 qs += ", ";
3539 qs += "folder_id = '"+MSW::escapeString(NLMISC::toString(_FolderId), connection)+"'";
3540 qs += ", ";
3541 qs += "lang = '"+MSW::escapeString(NLMISC::toString(_Lang), connection)+"'";
3542 qs += ", ";
3543 qs += "icone = '"+MSW::escapeString(NLMISC::toString(_Icone), connection)+"'";
3544 qs += ", ";
3545 qs += "anim_mode = " + (_AnimMode.isValid()
3546 ? "'"+_AnimMode.toString()+"'"
3547 : "DEFAULT(anim_mode)");
3548 qs += ", ";
3549 qs += "race_filter = '"+_RaceFilter.toString()+"'";
3550 qs += ", ";
3551 qs += "religion_filter = '"+_ReligionFilter.toString()+"'";
3552 qs += ", ";
3553 qs += "guild_filter = " + (_GuildFilter.isValid()
3554 ? "'"+_GuildFilter.toString()+"'"
3555 : "DEFAULT(guild_filter)");
3556 qs += ", ";
3557 qs += "shard_filter = '"+_ShardFilter.toString()+"'";
3558 qs += ", ";
3559 qs += "level_filter = '"+_LevelFilter.toString()+"'";
3560 qs += ", ";
3561 qs += "subscription_closed = '"+MSW::escapeString(NLMISC::toString(_SubscriptionClosed), connection)+"'";
3562 qs += ", ";
3563 qs += "newcomer = '"+MSW::escapeString(NLMISC::toString(_Newcomer), connection)+"'";
3565 qs += " WHERE session_id = '"+NLMISC::toString(_SessionId)+"'";
3568 if (connection.query(qs))
3570 if (connection.getAffectedRows() == 1)
3572 setPersistentState(NOPE::os_clean);
3573 return true;
3577 return false;
3580 bool CSession::remove(MSW::CConnection &connection)
3582 nlassert(getPersistentState() == NOPE::os_dirty || getPersistentState() == NOPE::os_clean);
3584 std::string qs;
3585 qs = "DELETE FROM sessions ";
3587 qs += " WHERE session_id = '"+NLMISC::toString(_SessionId)+"'";
3590 if (connection.query(qs))
3592 if (connection.getAffectedRows() == 1)
3596 // cascading deletion for vector child SessionParticipants
3597 if (loadSessionParticipants(connection, __FILE__, __LINE__))
3599 const std::vector < CSessionParticipantPtr > & childs = getSessionParticipants();
3601 while (!childs.empty())
3603 getSessionParticipantsByIndex((uint32)childs.size()-1)->remove(connection);
3610 // cascading deletion for vector child GuildInvites
3611 if (loadGuildInvites(connection, __FILE__, __LINE__))
3613 const std::vector < CGuildInvitePtr > & childs = getGuildInvites();
3615 while (!childs.empty())
3617 getGuildInvitesByIndex((uint32)childs.size()-1)->remove(connection);
3624 // cascading deletion for vector child JournalEntries
3625 if (loadJournalEntries(connection, __FILE__, __LINE__))
3627 const std::vector < CJournalEntryPtr > & childs = getJournalEntries();
3629 while (!childs.empty())
3631 getJournalEntriesByIndex((uint32)childs.size()-1)->remove(connection);
3638 // change the persistant state to 'removed'.
3639 setPersistentState(NOPE::os_removed);
3641 // need to remove ref from parent class container (if any)
3644 CCharacterPtr parent(CCharacter::loadFromCache(_OwnerId, true), __FILE__, __LINE__);
3645 if (parent != NULL && parent->_Sessions != NULL)
3648 std::vector < CSessionPtr >::iterator it = std::find(parent->_Sessions->begin(), parent->_Sessions->end(), this);
3649 if (it != parent->_Sessions->end())
3651 parent->_Sessions->erase(it);
3658 CFolderPtr parent(CFolder::loadFromCache(_FolderId, true), __FILE__, __LINE__);
3659 if (parent != NULL && parent->_Sessions != NULL)
3662 std::vector < CSessionPtr >::iterator it = std::find(parent->_Sessions->begin(), parent->_Sessions->end(), this);
3663 if (it != parent->_Sessions->end())
3665 parent->_Sessions->erase(it);
3671 // need to remove ref from parent (if any)
3674 return true;
3677 return false;
3680 bool CSession::removeById(MSW::CConnection &connection, uint32 id)
3682 CSession *object = loadFromCache(id, true);
3683 if (object != NULL)
3685 return object->remove(connection);
3687 // not in cache, run a SQL query
3688 std::string qs;
3689 qs = "DELETE FROM sessions ";
3691 qs += " WHERE session_id = '"+NLMISC::toString(id)+"'";
3694 if (connection.query(qs))
3696 if (connection.getAffectedRows() == 1)
3698 // ok, the row is removed
3699 return true;
3703 return false;
3707 // Try to load the specified object from the memory cache, return NULL if the object is not in the cache
3708 CSession *CSession::loadFromCache(uint32 objectId, bool unrelease)
3710 // look in the cache
3711 TObjectCache::iterator it(_ObjectCache.find(objectId));
3712 if (it == _ObjectCache.end())
3714 // not found, return null
3715 return NULL;
3717 else
3719 CSession *object = it->second;
3721 if (object->_ObjectState == NOPE::os_released)
3723 if (unrelease)
3725 // we need to remove this object from the released object set.
3726 object->removeFromReleased();
3727 object->_ObjectState = NOPE::os_clean;
3731 return it->second;
3734 // Receive and execute command from the cache manager.
3735 uint32 CSession::cacheCmd(NOPE::TCacheCmd cmd)
3737 if (cmd == NOPE::cc_update)
3739 updateCache();
3741 else if (cmd == NOPE::cc_clear)
3743 clearCache();
3745 else if (cmd == NOPE::cc_dump)
3747 dump();
3749 else if (cmd == NOPE::cc_instance_count)
3751 return (uint32)_ObjectCache.size();
3754 // default return value
3755 return 0;
3758 void CSession::dump()
3760 nlinfo(" Cache info for class CSession :");
3761 nlinfo(" There are %u object instances in cache", _ObjectCache.size());
3763 // count the number of object in the released object set
3764 uint32 nbReleased = 0;
3766 TReleasedObject::iterator first(_ReleasedObject.begin()), last(_ReleasedObject.end());
3767 for (; first != last; ++first)
3769 nbReleased += (uint32)first->second.size();
3772 nlinfo(" There are %u object instances in cache not referenced (waiting deletion or re-use))", nbReleased);
3775 void CSession::updateCache()
3777 if (_ReleasedObject.empty())
3778 return;
3780 // 30 s hold in cache
3781 const time_t MAX_CACHE_OLD_TIME = 30;
3783 time_t now = NLMISC::CTime::getSecondsSince1970();
3785 // look for object set older than MAX_CACHE_OLD_TIME and delete them
3786 while (!_ReleasedObject.empty() && _ReleasedObject.begin()->first < now-MAX_CACHE_OLD_TIME)
3788 TObjectSet &delSet = _ReleasedObject.begin()->second;
3789 // unload this objects
3790 while (!delSet.empty())
3792 CSession *object = *delSet.begin();
3793 delete object;
3796 _ReleasedObject.erase(_ReleasedObject.begin());
3800 void CSession::clearCache()
3802 // remove any unreferenced object from the cache
3803 while (!_ReleasedObject.empty())
3805 TObjectSet &delSet = _ReleasedObject.begin()->second;
3806 // unload this objects
3807 while (!delSet.empty())
3809 CSession *object = *delSet.begin();
3810 delete object;
3813 _ReleasedObject.erase(_ReleasedObject.begin());
3817 void CSession::registerUpdatable()
3819 static bool registered = false;
3820 if (!registered)
3822 NOPE::CPersistentCache::getInstance().registerCache(&CSession::cacheCmd);
3824 registered = true;
3828 // set the pointer on the first pointer of the pointer list (set to null when there is no more pointer)
3829 void CSession::setFirstPtr(CSessionPtr *ptr)
3831 _PtrList = ptr;
3833 if (ptr == NULL)
3835 // this is the last pointer !
3836 if (_ObjectState == NOPE::os_transient
3837 || _ObjectState == NOPE::os_removed)
3839 // not a persistent object, or removed object, just delet it
3840 delete this;
3842 else if (_ObjectState != NOPE::os_removed)
3844 setPersistentState(NOPE::os_released);
3849 // Set the persistent state of the object and do some house keeping
3850 void CSession::setPersistentState(NOPE::TObjectState state)
3852 nlassert(NOPE::AllowedTransition[_ObjectState][state] == true);
3854 if(_ObjectState == NOPE::os_released && state == NOPE::os_removed)
3856 // a release object gets removed (e.g. by remove by id)
3858 // delete the object
3859 delete this;
3861 // no more to do
3862 return;
3865 if (_ObjectState == NOPE::os_transient && state != NOPE::os_transient)
3867 nldebug("NOPE: inserting CSession @%p in cache with id %u", this, static_cast<uint32>(_SessionId));
3868 nlverify(_ObjectCache.insert(std::make_pair(_SessionId, this)).second);
3871 if (_ObjectState != NOPE::os_transient)
3872 nlassert(_ObjectCache.find(_SessionId) != _ObjectCache.end());
3874 _ObjectState = state;
3876 if (state == NOPE::os_released)
3878 _ReleaseDate = NLMISC::CTime::getSecondsSince1970();
3879 nlverify(_ReleasedObject[_ReleaseDate].insert(this).second);
3881 else if (state == NOPE::os_removed)
3883 nldebug("NOPE: erasing CSession @%p in cache with id %u", this, static_cast<uint32>(_SessionId));
3884 nlverify(_ObjectCache.erase(_SessionId) == 1);
3889 CSessionPtr CSession::load(MSW::CConnection &connection, uint32 id, const char *filename, uint32 lineNum)
3891 CSession *inCache = loadFromCache(id, true);
3892 if (inCache != NULL)
3894 return CSessionPtr(inCache, filename, lineNum);
3897 std::string qs;
3898 qs = "SELECT ";
3900 qs += "session_id, session_type, title, owner, plan_date, start_date, description, orientation, level, rule_type, access_type, state, host_shard_id, subscription_slots, reserved_slots, estimated_duration, final_duration, folder_id, lang, icone, anim_mode, race_filter, religion_filter, guild_filter, shard_filter, level_filter, subscription_closed, newcomer";
3902 qs += " FROM sessions";
3904 qs += " WHERE session_id = '"+NLMISC::toString(id)+"'";
3905 CSessionPtr ret;
3906 if (!connection.query(qs))
3908 return ret;
3911 MSW::CStoreResult *result = connection.storeResult().release();
3913 nlassert(result->getNumRows() <= 1);
3914 if (result->getNumRows() == 1)
3916 ret.assign(new CSession, filename, lineNum);
3917 // ok, we have an object
3918 result->fetchRow();
3920 result->getField(0, ret->_SessionId);
3922 std::string s;
3923 result->getField(1, s);
3924 ret->_SessionType = TSessionType(s);
3926 result->getField(2, ret->_Title);
3927 result->getField(3, ret->_OwnerId);
3928 result->getDateField(4, ret->_PlanDate);
3929 result->getDateField(5, ret->_StartDate);
3930 result->getField(6, ret->_Description);
3932 std::string s;
3933 result->getField(7, s);
3934 ret->_Orientation = TSessionOrientation(s);
3937 std::string s;
3938 result->getField(8, s);
3939 ret->_Level = R2::TSessionLevel(s);
3942 std::string s;
3943 result->getField(9, s);
3944 ret->_RuleType = TRuleType(s);
3947 std::string s;
3948 result->getField(10, s);
3949 ret->_AccessType = TAccessType(s);
3952 std::string s;
3953 result->getField(11, s);
3954 ret->_State = TSessionState(s);
3956 result->getField(12, ret->_HostShardId);
3957 result->getField(13, ret->_SubscriptionSlots);
3958 result->getField(14, ret->_ReservedSlots);
3960 std::string s;
3961 result->getField(15, s);
3962 ret->_EstimatedDuration = TEstimatedDuration(s);
3964 result->getField(16, ret->_FinalDuration);
3965 result->getField(17, ret->_FolderId);
3966 result->getField(18, ret->_Lang);
3967 result->getField(19, ret->_Icone);
3969 std::string s;
3970 result->getField(20, s);
3971 ret->_AnimMode = TAnimMode(s);
3974 std::string s;
3975 result->getField(21, s);
3976 ret->_RaceFilter = TRaceFilter(s);
3979 std::string s;
3980 result->getField(22, s);
3981 ret->_ReligionFilter = TReligionFilter(s);
3984 std::string s;
3985 result->getField(23, s);
3986 ret->_GuildFilter = TGuildFilter(s);
3989 std::string s;
3990 result->getField(24, s);
3991 ret->_ShardFilter = TShardFilter(s);
3994 std::string s;
3995 result->getField(25, s);
3996 ret->_LevelFilter = TLevelFilter(s);
3998 result->getField(26, ret->_SubscriptionClosed);
3999 result->getField(27, ret->_Newcomer);
4002 ret->setPersistentState(NOPE::os_clean);
4005 delete result;
4007 return ret;
4011 bool CSession::loadChildrenOfCCharacter(MSW::CConnection &connection, uint32 parentId, std::vector < CSessionPtr > & container, const char *filename, uint32 lineNum)
4014 std::string qs;
4015 qs = "SELECT ";
4017 qs += "session_id, session_type, title, owner, plan_date, start_date, description, orientation, level, rule_type, access_type, state, host_shard_id, subscription_slots, reserved_slots, estimated_duration, final_duration, folder_id, lang, icone, anim_mode, race_filter, religion_filter, guild_filter, shard_filter, level_filter, subscription_closed, newcomer";
4019 qs += " FROM sessions";
4020 qs += " WHERE owner = '"+NLMISC::toString(parentId)+"'";
4022 if (!connection.query(qs))
4024 return false;
4027 CUniquePtr<MSW::CStoreResult> result = connection.storeResult();
4029 for (uint i=0; i<result->getNumRows(); ++i)
4031 CSession *ret = new CSession();
4032 // ok, we have an object
4033 result->fetchRow();
4035 result->getField(0, ret->_SessionId);
4038 std::string s;
4039 result->getField(1, s);
4040 ret->_SessionType = TSessionType(s);
4043 result->getField(2, ret->_Title);
4045 result->getField(3, ret->_OwnerId);
4047 result->getDateField(4, ret->_PlanDate);
4049 result->getDateField(5, ret->_StartDate);
4051 result->getField(6, ret->_Description);
4054 std::string s;
4055 result->getField(7, s);
4056 ret->_Orientation = TSessionOrientation(s);
4060 std::string s;
4061 result->getField(8, s);
4062 ret->_Level = R2::TSessionLevel(s);
4066 std::string s;
4067 result->getField(9, s);
4068 ret->_RuleType = TRuleType(s);
4072 std::string s;
4073 result->getField(10, s);
4074 ret->_AccessType = TAccessType(s);
4078 std::string s;
4079 result->getField(11, s);
4080 ret->_State = TSessionState(s);
4083 result->getField(12, ret->_HostShardId);
4085 result->getField(13, ret->_SubscriptionSlots);
4087 result->getField(14, ret->_ReservedSlots);
4090 std::string s;
4091 result->getField(15, s);
4092 ret->_EstimatedDuration = TEstimatedDuration(s);
4095 result->getField(16, ret->_FinalDuration);
4097 result->getField(17, ret->_FolderId);
4099 result->getField(18, ret->_Lang);
4101 result->getField(19, ret->_Icone);
4104 std::string s;
4105 result->getField(20, s);
4106 ret->_AnimMode = TAnimMode(s);
4110 std::string s;
4111 result->getField(21, s);
4112 ret->_RaceFilter = TRaceFilter(s);
4116 std::string s;
4117 result->getField(22, s);
4118 ret->_ReligionFilter = TReligionFilter(s);
4122 std::string s;
4123 result->getField(23, s);
4124 ret->_GuildFilter = TGuildFilter(s);
4128 std::string s;
4129 result->getField(24, s);
4130 ret->_ShardFilter = TShardFilter(s);
4134 std::string s;
4135 result->getField(25, s);
4136 ret->_LevelFilter = TLevelFilter(s);
4139 result->getField(26, ret->_SubscriptionClosed);
4141 result->getField(27, ret->_Newcomer);
4142 CSession *inCache = loadFromCache(ret->_SessionId, true);
4143 if (inCache != NULL)
4146 container.push_back(CSessionPtr(inCache, filename, lineNum));
4148 // no more needed
4149 delete ret;
4151 else
4153 ret->setPersistentState(NOPE::os_clean);
4155 container.push_back(CSessionPtr(ret, filename, lineNum));
4160 return true;
4163 bool CSession::loadChildrenOfCFolder(MSW::CConnection &connection, uint32 parentId, std::vector < CSessionPtr > & container, const char *filename, uint32 lineNum)
4166 std::string qs;
4167 qs = "SELECT ";
4169 qs += "session_id, session_type, title, owner, plan_date, start_date, description, orientation, level, rule_type, access_type, state, host_shard_id, subscription_slots, reserved_slots, estimated_duration, final_duration, folder_id, lang, icone, anim_mode, race_filter, religion_filter, guild_filter, shard_filter, level_filter, subscription_closed, newcomer";
4171 qs += " FROM sessions";
4172 qs += " WHERE folder_id = '"+NLMISC::toString(parentId)+"'";
4174 if (!connection.query(qs))
4176 return false;
4179 CUniquePtr<MSW::CStoreResult> result = connection.storeResult();
4181 for (uint i=0; i<result->getNumRows(); ++i)
4183 CSession *ret = new CSession();
4184 // ok, we have an object
4185 result->fetchRow();
4187 result->getField(0, ret->_SessionId);
4190 std::string s;
4191 result->getField(1, s);
4192 ret->_SessionType = TSessionType(s);
4195 result->getField(2, ret->_Title);
4197 result->getField(3, ret->_OwnerId);
4199 result->getDateField(4, ret->_PlanDate);
4201 result->getDateField(5, ret->_StartDate);
4203 result->getField(6, ret->_Description);
4206 std::string s;
4207 result->getField(7, s);
4208 ret->_Orientation = TSessionOrientation(s);
4212 std::string s;
4213 result->getField(8, s);
4214 ret->_Level = R2::TSessionLevel(s);
4218 std::string s;
4219 result->getField(9, s);
4220 ret->_RuleType = TRuleType(s);
4224 std::string s;
4225 result->getField(10, s);
4226 ret->_AccessType = TAccessType(s);
4230 std::string s;
4231 result->getField(11, s);
4232 ret->_State = TSessionState(s);
4235 result->getField(12, ret->_HostShardId);
4237 result->getField(13, ret->_SubscriptionSlots);
4239 result->getField(14, ret->_ReservedSlots);
4242 std::string s;
4243 result->getField(15, s);
4244 ret->_EstimatedDuration = TEstimatedDuration(s);
4247 result->getField(16, ret->_FinalDuration);
4249 result->getField(17, ret->_FolderId);
4251 result->getField(18, ret->_Lang);
4253 result->getField(19, ret->_Icone);
4256 std::string s;
4257 result->getField(20, s);
4258 ret->_AnimMode = TAnimMode(s);
4262 std::string s;
4263 result->getField(21, s);
4264 ret->_RaceFilter = TRaceFilter(s);
4268 std::string s;
4269 result->getField(22, s);
4270 ret->_ReligionFilter = TReligionFilter(s);
4274 std::string s;
4275 result->getField(23, s);
4276 ret->_GuildFilter = TGuildFilter(s);
4280 std::string s;
4281 result->getField(24, s);
4282 ret->_ShardFilter = TShardFilter(s);
4286 std::string s;
4287 result->getField(25, s);
4288 ret->_LevelFilter = TLevelFilter(s);
4291 result->getField(26, ret->_SubscriptionClosed);
4293 result->getField(27, ret->_Newcomer);
4294 CSession *inCache = loadFromCache(ret->_SessionId, true);
4295 if (inCache != NULL)
4298 container.push_back(CSessionPtr(inCache, filename, lineNum));
4300 // no more needed
4301 delete ret;
4303 else
4305 ret->setPersistentState(NOPE::os_clean);
4307 container.push_back(CSessionPtr(ret, filename, lineNum));
4312 return true;
4315 bool CSession::loadSessionParticipants(MSW::CConnection &connection, const char *filename, uint32 lineNum)
4317 bool ret = true;
4318 if (_SessionParticipants != NULL)
4320 // the children are already loaded, just return true
4321 return true;
4324 // allocate the container
4325 _SessionParticipants = new std::vector < CSessionParticipantPtr >;
4327 // load the childs
4328 ret &= CSessionParticipant::loadChildrenOfCSession(connection, getObjectId(), *_SessionParticipants, filename, lineNum);
4329 return ret;
4333 const std::vector<CSessionParticipantPtr> &CSession::getSessionParticipants() const
4335 nlassert(_SessionParticipants != NULL);
4336 return *_SessionParticipants;
4339 CSessionParticipantPtr &CSession::getSessionParticipantsByIndex(uint32 index) const
4341 nlassert(_SessionParticipants != NULL);
4342 nlassert(index < _SessionParticipants->size());
4343 return const_cast< CSessionParticipantPtr & >(_SessionParticipants->operator[](index));
4346 CSessionParticipantPtr &CSession::getSessionParticipantsById(uint32 id) const
4348 nlassert(_SessionParticipants != NULL);
4349 std::vector<CSessionParticipantPtr >::const_iterator first(_SessionParticipants->begin()), last(_SessionParticipants->end());
4350 for (; first != last; ++first)
4352 const CSessionParticipantPtr &child = *first;
4353 if (child->getObjectId() == id)
4355 return const_cast< CSessionParticipantPtr & >(child);
4359 // no object with this id, return a null pointer
4360 static CSessionParticipantPtr nilPtr;
4362 return nilPtr;
4366 bool CSession::loadGuildInvites(MSW::CConnection &connection, const char *filename, uint32 lineNum)
4368 bool ret = true;
4369 if (_GuildInvites != NULL)
4371 // the children are already loaded, just return true
4372 return true;
4375 // allocate the container
4376 _GuildInvites = new std::vector < CGuildInvitePtr >;
4378 // load the childs
4379 ret &= CGuildInvite::loadChildrenOfCSession(connection, getObjectId(), *_GuildInvites, filename, lineNum);
4380 return ret;
4384 const std::vector<CGuildInvitePtr> &CSession::getGuildInvites() const
4386 nlassert(_GuildInvites != NULL);
4387 return *_GuildInvites;
4390 CGuildInvitePtr &CSession::getGuildInvitesByIndex(uint32 index) const
4392 nlassert(_GuildInvites != NULL);
4393 nlassert(index < _GuildInvites->size());
4394 return const_cast< CGuildInvitePtr & >(_GuildInvites->operator[](index));
4397 CGuildInvitePtr &CSession::getGuildInvitesById(uint32 id) const
4399 nlassert(_GuildInvites != NULL);
4400 std::vector<CGuildInvitePtr >::const_iterator first(_GuildInvites->begin()), last(_GuildInvites->end());
4401 for (; first != last; ++first)
4403 const CGuildInvitePtr &child = *first;
4404 if (child->getObjectId() == id)
4406 return const_cast< CGuildInvitePtr & >(child);
4410 // no object with this id, return a null pointer
4411 static CGuildInvitePtr nilPtr;
4413 return nilPtr;
4417 bool CSession::loadJournalEntries(MSW::CConnection &connection, const char *filename, uint32 lineNum)
4419 bool ret = true;
4420 if (_JournalEntries != NULL)
4422 // the children are already loaded, just return true
4423 return true;
4426 // allocate the container
4427 _JournalEntries = new std::vector < CJournalEntryPtr >;
4429 // load the childs
4430 ret &= CJournalEntry::loadChildrenOfCSession(connection, getObjectId(), *_JournalEntries, filename, lineNum);
4431 return ret;
4435 const std::vector<CJournalEntryPtr> &CSession::getJournalEntries() const
4437 nlassert(_JournalEntries != NULL);
4438 return *_JournalEntries;
4441 CJournalEntryPtr &CSession::getJournalEntriesByIndex(uint32 index) const
4443 nlassert(_JournalEntries != NULL);
4444 nlassert(index < _JournalEntries->size());
4445 return const_cast< CJournalEntryPtr & >(_JournalEntries->operator[](index));
4448 CJournalEntryPtr &CSession::getJournalEntriesById(uint32 id) const
4450 nlassert(_JournalEntries != NULL);
4451 std::vector<CJournalEntryPtr >::const_iterator first(_JournalEntries->begin()), last(_JournalEntries->end());
4452 for (; first != last; ++first)
4454 const CJournalEntryPtr &child = *first;
4455 if (child->getObjectId() == id)
4457 return const_cast< CJournalEntryPtr & >(child);
4461 // no object with this id, return a null pointer
4462 static CJournalEntryPtr nilPtr;
4464 return nilPtr;
4468 void CShardPtr::linkPtr()
4470 nlassert(_NextPtr == NULL);
4471 nlassert(_PrevPtr == NULL);
4472 if (_Ptr != NULL)
4474 _NextPtr = _Ptr->getFirstPtr();
4475 if (_NextPtr != NULL)
4477 _PrevPtr = _NextPtr->_PrevPtr;
4478 _PrevPtr->_NextPtr = this;
4479 _NextPtr->_PrevPtr = this;
4481 else
4483 _NextPtr = this;
4484 _PrevPtr = this;
4485 _Ptr->setFirstPtr(this);
4490 void CShardPtr::unlinkPtr()
4492 if (_NextPtr == NULL)
4494 nlassert(_PrevPtr == NULL);
4495 return;
4498 if (_Ptr != NULL)
4500 if (_NextPtr == this)
4502 nlassert(_PrevPtr == this);
4503 // last pointer !
4504 _Ptr->setFirstPtr(NULL);
4506 else
4508 if (_Ptr->getFirstPtr() == this)
4510 // the first ptr is the current one, we need to switch to next one
4511 _Ptr->setFirstPtr(_NextPtr);
4516 if (_NextPtr != this)
4518 nlassert(_PrevPtr != this);
4520 _NextPtr->_PrevPtr = _PrevPtr;
4521 _PrevPtr->_NextPtr = _NextPtr;
4523 _NextPtr = NULL;
4524 _PrevPtr = NULL;
4528 CShard::TObjectCache CShard::_ObjectCache;
4529 CShard::TReleasedObject CShard::_ReleasedObject;
4532 // Destructor, delete any children
4533 CShard::~CShard()
4535 // release childs reference
4536 if (_Guilds != NULL)
4537 delete _Guilds;
4540 if (_PtrList != NULL)
4542 nlwarning("ERROR : someone try to delete this object, but there are still ptr on it !");
4543 CShardPtr *ptr = _PtrList;
4546 nlwarning(" Pointer created from '%s', line %u", ptr->_FileName, ptr->_LineNum);
4547 ptr = _PtrList->getNextPtr();
4548 } while(ptr != _PtrList);
4549 nlstop;
4551 // remove object from cache map
4552 if (_ShardId != NOPE::INVALID_OBJECT_ID
4553 && _ObjectState != NOPE::os_removed
4554 && _ObjectState != NOPE::os_transient)
4556 nldebug("NOPE: clearing CShard @%p from cache with id %u", this, static_cast<uint32>(_ShardId));
4557 nlverify(_ObjectCache.erase(_ShardId) == 1);
4559 else if (_ObjectState != NOPE::os_transient)
4561 nlassert(_ObjectCache.find(_ShardId) == _ObjectCache.end());
4563 if (_ObjectState == NOPE::os_released)
4565 removeFromReleased();
4567 else
4569 TReleasedObject::iterator it(_ReleasedObject.find(_ReleaseDate));
4570 if (it != _ReleasedObject.end())
4572 nlassert(it->second.find(this) == it->second.end());
4577 void CShard::removeFromReleased()
4579 TReleasedObject::iterator it(_ReleasedObject.find(_ReleaseDate));
4580 nlassert(it != _ReleasedObject.end());
4581 TObjectSet &os = it->second;
4583 nlverify(os.erase(this) == 1);
4585 // nb : _ReleasedObject time entry are removed by the cache update
4588 bool CShard::create(MSW::CConnection &connection)
4590 nlassert(getPersistentState() == NOPE::os_transient);
4592 nlassert(_ShardId != 0);
4593 std::string qs;
4594 qs = "INSERT INTO shard (";
4596 qs += "shard_id, WSOnline, RequiredState, MOTD";
4597 qs += ") VALUES (";
4599 qs += "'"+MSW::escapeString(NLMISC::toString(_ShardId), connection)+"'";
4600 qs += ", ";
4601 qs += "'"+MSW::escapeString(NLMISC::toString(_WSOnline), connection)+"'";
4602 qs += ", ";
4603 qs += _RequiredState.isValid()
4604 ? "'"+_RequiredState.toString()+"'"
4605 : "DEFAULT(RequiredState)";
4606 qs += ", ";
4607 qs += "'"+MSW::escapeString(NLMISC::toString(_MOTD), connection)+"'";
4609 qs += ")";
4611 if (connection.query(qs))
4615 setPersistentState(NOPE::os_clean);
4617 // update the parent class instance in cache if any
4619 return true;
4622 return false;
4625 bool CShard::update(MSW::CConnection &connection)
4627 nlassert(getPersistentState() == NOPE::os_dirty || getPersistentState() == NOPE::os_clean);
4629 if (getPersistentState() == NOPE::os_clean)
4630 // the object is clean, just ignore the save
4631 return true;
4633 std::string qs;
4634 qs = "UPDATE shard SET ";
4636 qs += "shard_id = '"+MSW::escapeString(NLMISC::toString(_ShardId), connection)+"'";
4637 qs += ", ";
4638 qs += "WSOnline = '"+MSW::escapeString(NLMISC::toString(_WSOnline), connection)+"'";
4639 qs += ", ";
4640 qs += "RequiredState = " + (_RequiredState.isValid()
4641 ? "'"+_RequiredState.toString()+"'"
4642 : "DEFAULT(RequiredState)");
4643 qs += ", ";
4644 qs += "MOTD = '"+MSW::escapeString(NLMISC::toString(_MOTD), connection)+"'";
4646 qs += " WHERE shard_id = '"+NLMISC::toString(_ShardId)+"'";
4649 if (connection.query(qs))
4651 if (connection.getAffectedRows() == 1)
4653 setPersistentState(NOPE::os_clean);
4654 return true;
4658 return false;
4661 bool CShard::remove(MSW::CConnection &connection)
4663 nlassert(getPersistentState() == NOPE::os_dirty || getPersistentState() == NOPE::os_clean);
4665 std::string qs;
4666 qs = "DELETE FROM shard ";
4668 qs += " WHERE shard_id = '"+NLMISC::toString(_ShardId)+"'";
4671 if (connection.query(qs))
4673 if (connection.getAffectedRows() == 1)
4677 // change the persistant state to 'removed'.
4678 setPersistentState(NOPE::os_removed);
4680 // need to remove ref from parent class container (if any)
4682 // need to remove ref from parent (if any)
4685 return true;
4688 return false;
4691 bool CShard::removeById(MSW::CConnection &connection, uint32 id)
4693 CShard *object = loadFromCache(id, true);
4694 if (object != NULL)
4696 return object->remove(connection);
4698 // not in cache, run a SQL query
4699 std::string qs;
4700 qs = "DELETE FROM shard ";
4702 qs += " WHERE shard_id = '"+NLMISC::toString(id)+"'";
4705 if (connection.query(qs))
4707 if (connection.getAffectedRows() == 1)
4709 // ok, the row is removed
4710 return true;
4714 return false;
4718 // Try to load the specified object from the memory cache, return NULL if the object is not in the cache
4719 CShard *CShard::loadFromCache(uint32 objectId, bool unrelease)
4721 // look in the cache
4722 TObjectCache::iterator it(_ObjectCache.find(objectId));
4723 if (it == _ObjectCache.end())
4725 // not found, return null
4726 return NULL;
4728 else
4730 CShard *object = it->second;
4732 if (object->_ObjectState == NOPE::os_released)
4734 if (unrelease)
4736 // we need to remove this object from the released object set.
4737 object->removeFromReleased();
4738 object->_ObjectState = NOPE::os_clean;
4742 return it->second;
4745 // Receive and execute command from the cache manager.
4746 uint32 CShard::cacheCmd(NOPE::TCacheCmd cmd)
4748 if (cmd == NOPE::cc_update)
4750 updateCache();
4752 else if (cmd == NOPE::cc_clear)
4754 clearCache();
4756 else if (cmd == NOPE::cc_dump)
4758 dump();
4760 else if (cmd == NOPE::cc_instance_count)
4762 return (uint32)_ObjectCache.size();
4765 // default return value
4766 return 0;
4769 void CShard::dump()
4771 nlinfo(" Cache info for class CShard :");
4772 nlinfo(" There are %u object instances in cache", _ObjectCache.size());
4774 // count the number of object in the released object set
4775 uint32 nbReleased = 0;
4777 TReleasedObject::iterator first(_ReleasedObject.begin()), last(_ReleasedObject.end());
4778 for (; first != last; ++first)
4780 nbReleased += (uint32)first->second.size();
4783 nlinfo(" There are %u object instances in cache not referenced (waiting deletion or re-use))", nbReleased);
4786 void CShard::updateCache()
4788 if (_ReleasedObject.empty())
4789 return;
4791 // 30 s hold in cache
4792 const time_t MAX_CACHE_OLD_TIME = 30;
4794 time_t now = NLMISC::CTime::getSecondsSince1970();
4796 // look for object set older than MAX_CACHE_OLD_TIME and delete them
4797 while (!_ReleasedObject.empty() && _ReleasedObject.begin()->first < now-MAX_CACHE_OLD_TIME)
4799 TObjectSet &delSet = _ReleasedObject.begin()->second;
4800 // unload this objects
4801 while (!delSet.empty())
4803 CShard *object = *delSet.begin();
4804 delete object;
4807 _ReleasedObject.erase(_ReleasedObject.begin());
4811 void CShard::clearCache()
4813 // remove any unreferenced object from the cache
4814 while (!_ReleasedObject.empty())
4816 TObjectSet &delSet = _ReleasedObject.begin()->second;
4817 // unload this objects
4818 while (!delSet.empty())
4820 CShard *object = *delSet.begin();
4821 delete object;
4824 _ReleasedObject.erase(_ReleasedObject.begin());
4828 void CShard::registerUpdatable()
4830 static bool registered = false;
4831 if (!registered)
4833 NOPE::CPersistentCache::getInstance().registerCache(&CShard::cacheCmd);
4835 registered = true;
4839 // set the pointer on the first pointer of the pointer list (set to null when there is no more pointer)
4840 void CShard::setFirstPtr(CShardPtr *ptr)
4842 _PtrList = ptr;
4844 if (ptr == NULL)
4846 // this is the last pointer !
4847 if (_ObjectState == NOPE::os_transient
4848 || _ObjectState == NOPE::os_removed)
4850 // not a persistent object, or removed object, just delet it
4851 delete this;
4853 else if (_ObjectState != NOPE::os_removed)
4855 setPersistentState(NOPE::os_released);
4860 // Set the persistent state of the object and do some house keeping
4861 void CShard::setPersistentState(NOPE::TObjectState state)
4863 nlassert(NOPE::AllowedTransition[_ObjectState][state] == true);
4865 if(_ObjectState == NOPE::os_released && state == NOPE::os_removed)
4867 // a release object gets removed (e.g. by remove by id)
4869 // delete the object
4870 delete this;
4872 // no more to do
4873 return;
4876 if (_ObjectState == NOPE::os_transient && state != NOPE::os_transient)
4878 nldebug("NOPE: inserting CShard @%p in cache with id %u", this, static_cast<uint32>(_ShardId));
4879 nlverify(_ObjectCache.insert(std::make_pair(_ShardId, this)).second);
4882 if (_ObjectState != NOPE::os_transient)
4883 nlassert(_ObjectCache.find(_ShardId) != _ObjectCache.end());
4885 _ObjectState = state;
4887 if (state == NOPE::os_released)
4889 _ReleaseDate = NLMISC::CTime::getSecondsSince1970();
4890 nlverify(_ReleasedObject[_ReleaseDate].insert(this).second);
4892 else if (state == NOPE::os_removed)
4894 nldebug("NOPE: erasing CShard @%p in cache with id %u", this, static_cast<uint32>(_ShardId));
4895 nlverify(_ObjectCache.erase(_ShardId) == 1);
4900 CShardPtr CShard::load(MSW::CConnection &connection, uint32 id, const char *filename, uint32 lineNum)
4902 CShard *inCache = loadFromCache(id, true);
4903 if (inCache != NULL)
4905 return CShardPtr(inCache, filename, lineNum);
4908 std::string qs;
4909 qs = "SELECT ";
4911 qs += "shard_id, WSOnline, RequiredState, MOTD";
4913 qs += " FROM shard";
4915 qs += " WHERE shard_id = '"+NLMISC::toString(id)+"'";
4916 CShardPtr ret;
4917 if (!connection.query(qs))
4919 return ret;
4922 MSW::CStoreResult *result = connection.storeResult().release();
4924 nlassert(result->getNumRows() <= 1);
4925 if (result->getNumRows() == 1)
4927 ret.assign(new CShard, filename, lineNum);
4928 // ok, we have an object
4929 result->fetchRow();
4931 result->getField(0, ret->_ShardId);
4932 result->getField(1, ret->_WSOnline);
4934 std::string s;
4935 result->getField(2, s);
4936 ret->_RequiredState = TAccessLevel(s);
4938 result->getField(3, ret->_MOTD);
4941 ret->setPersistentState(NOPE::os_clean);
4944 delete result;
4946 return ret;
4950 bool CShard::loadGuilds(MSW::CConnection &connection, const char *filename, uint32 lineNum)
4952 bool ret = true;
4953 if (_Guilds != NULL)
4955 // the children are already loaded, just return true
4956 return true;
4959 // allocate the container
4960 _Guilds = new std::map < uint32, CGuildPtr >;
4962 // load the childs
4963 ret &= CGuild::loadChildrenOfCShard(connection, getObjectId(), *_Guilds, filename, lineNum);
4964 return ret;
4968 const std::map<uint32, CGuildPtr> &CShard::getGuilds() const
4970 nlassert(_Guilds != NULL);
4971 return *_Guilds;
4974 CGuildPtr &CShard::getGuildsById(uint32 id) const
4976 nlassert(_Guilds != NULL);
4977 std::map<uint32, CGuildPtr>::const_iterator it(_Guilds->find(id));
4979 if (it == _Guilds->end())
4981 // no object with this id, return a null pointer
4982 static CGuildPtr nilPtr;
4983 return nilPtr;
4986 return const_cast< CGuildPtr & >(it->second);
4990 void CGuildPtr::linkPtr()
4992 nlassert(_NextPtr == NULL);
4993 nlassert(_PrevPtr == NULL);
4994 if (_Ptr != NULL)
4996 _NextPtr = _Ptr->getFirstPtr();
4997 if (_NextPtr != NULL)
4999 _PrevPtr = _NextPtr->_PrevPtr;
5000 _PrevPtr->_NextPtr = this;
5001 _NextPtr->_PrevPtr = this;
5003 else
5005 _NextPtr = this;
5006 _PrevPtr = this;
5007 _Ptr->setFirstPtr(this);
5012 void CGuildPtr::unlinkPtr()
5014 if (_NextPtr == NULL)
5016 nlassert(_PrevPtr == NULL);
5017 return;
5020 if (_Ptr != NULL)
5022 if (_NextPtr == this)
5024 nlassert(_PrevPtr == this);
5025 // last pointer !
5026 _Ptr->setFirstPtr(NULL);
5028 else
5030 if (_Ptr->getFirstPtr() == this)
5032 // the first ptr is the current one, we need to switch to next one
5033 _Ptr->setFirstPtr(_NextPtr);
5038 if (_NextPtr != this)
5040 nlassert(_PrevPtr != this);
5042 _NextPtr->_PrevPtr = _PrevPtr;
5043 _PrevPtr->_NextPtr = _NextPtr;
5045 _NextPtr = NULL;
5046 _PrevPtr = NULL;
5050 CGuild::TObjectCache CGuild::_ObjectCache;
5051 CGuild::TReleasedObject CGuild::_ReleasedObject;
5054 // Destructor, delete any children
5055 CGuild::~CGuild()
5057 // release childs reference
5058 if (_Characters != NULL)
5059 delete _Characters;
5060 if (_Invites != NULL)
5061 delete _Invites;
5064 if (_PtrList != NULL)
5066 nlwarning("ERROR : someone try to delete this object, but there are still ptr on it !");
5067 CGuildPtr *ptr = _PtrList;
5070 nlwarning(" Pointer created from '%s', line %u", ptr->_FileName, ptr->_LineNum);
5071 ptr = _PtrList->getNextPtr();
5072 } while(ptr != _PtrList);
5073 nlstop;
5075 // remove object from cache map
5076 if (_GuildId != NOPE::INVALID_OBJECT_ID
5077 && _ObjectState != NOPE::os_removed
5078 && _ObjectState != NOPE::os_transient)
5080 nldebug("NOPE: clearing CGuild @%p from cache with id %u", this, static_cast<uint32>(_GuildId));
5081 nlverify(_ObjectCache.erase(_GuildId) == 1);
5083 else if (_ObjectState != NOPE::os_transient)
5085 nlassert(_ObjectCache.find(_GuildId) == _ObjectCache.end());
5087 if (_ObjectState == NOPE::os_released)
5089 removeFromReleased();
5091 else
5093 TReleasedObject::iterator it(_ReleasedObject.find(_ReleaseDate));
5094 if (it != _ReleasedObject.end())
5096 nlassert(it->second.find(this) == it->second.end());
5101 void CGuild::removeFromReleased()
5103 TReleasedObject::iterator it(_ReleasedObject.find(_ReleaseDate));
5104 nlassert(it != _ReleasedObject.end());
5105 TObjectSet &os = it->second;
5107 nlverify(os.erase(this) == 1);
5109 // nb : _ReleasedObject time entry are removed by the cache update
5112 bool CGuild::create(MSW::CConnection &connection)
5114 nlassert(getPersistentState() == NOPE::os_transient);
5116 nlassert(_GuildId != 0);
5117 std::string qs;
5118 qs = "INSERT INTO guilds (";
5120 qs += "guild_id, guild_name, shard_id";
5121 qs += ") VALUES (";
5123 qs += "'"+MSW::escapeString(NLMISC::toString(_GuildId), connection)+"'";
5124 qs += ", ";
5125 qs += "'"+MSW::escapeString(NLMISC::toString(_GuildName), connection)+"'";
5126 qs += ", ";
5127 qs += "'"+MSW::escapeString(NLMISC::toString(_ShardId), connection)+"'";
5129 qs += ")";
5131 if (connection.query(qs))
5135 setPersistentState(NOPE::os_clean);
5137 // update the parent class instance in cache if any
5139 if (_ShardId != 0)
5141 // need to update the parent class child list if it is in the cache
5142 CShard *parent = CShard::loadFromCache(_ShardId, false);
5143 if (parent && parent->_Guilds != NULL)
5146 nlverify(parent->_Guilds->insert(std::make_pair(getObjectId(), CGuildPtr(this, __FILE__, __LINE__))).second);
5151 return true;
5154 return false;
5157 bool CGuild::update(MSW::CConnection &connection)
5159 nlassert(getPersistentState() == NOPE::os_dirty || getPersistentState() == NOPE::os_clean);
5161 if (getPersistentState() == NOPE::os_clean)
5162 // the object is clean, just ignore the save
5163 return true;
5165 std::string qs;
5166 qs = "UPDATE guilds SET ";
5168 qs += "guild_id = '"+MSW::escapeString(NLMISC::toString(_GuildId), connection)+"'";
5169 qs += ", ";
5170 qs += "guild_name = '"+MSW::escapeString(NLMISC::toString(_GuildName), connection)+"'";
5171 qs += ", ";
5172 qs += "shard_id = '"+MSW::escapeString(NLMISC::toString(_ShardId), connection)+"'";
5174 qs += " WHERE guild_id = '"+NLMISC::toString(_GuildId)+"'";
5177 if (connection.query(qs))
5179 if (connection.getAffectedRows() == 1)
5181 setPersistentState(NOPE::os_clean);
5182 return true;
5186 return false;
5189 bool CGuild::remove(MSW::CConnection &connection)
5191 nlassert(getPersistentState() == NOPE::os_dirty || getPersistentState() == NOPE::os_clean);
5193 std::string qs;
5194 qs = "DELETE FROM guilds ";
5196 qs += " WHERE guild_id = '"+NLMISC::toString(_GuildId)+"'";
5199 if (connection.query(qs))
5201 if (connection.getAffectedRows() == 1)
5205 // cascading deletion for vector child Invites
5206 if (loadInvites(connection, __FILE__, __LINE__))
5208 const std::vector < CGuildInvitePtr > & childs = getInvites();
5210 while (!childs.empty())
5212 getInvitesByIndex((uint32)childs.size()-1)->remove(connection);
5219 // unreference (and update) for vector child Characters
5220 if (loadCharacters(connection, __FILE__, __LINE__))
5222 const std::vector < CCharacterPtr > & childs = getCharacters();
5224 for (uint i=0; i < childs.size(); ++i)
5227 getCharactersByIndex(i)->setGuildId(0);
5228 getCharactersByIndex(i)->update(connection);
5234 // change the persistant state to 'removed'.
5235 setPersistentState(NOPE::os_removed);
5237 // need to remove ref from parent class container (if any)
5240 CShardPtr parent(CShard::loadFromCache(_ShardId, true), __FILE__, __LINE__);
5241 if (parent != NULL && parent->_Guilds != NULL)
5244 parent->_Guilds->erase(getObjectId());
5249 // need to remove ref from parent (if any)
5252 return true;
5255 return false;
5258 bool CGuild::removeById(MSW::CConnection &connection, uint32 id)
5260 CGuild *object = loadFromCache(id, true);
5261 if (object != NULL)
5263 return object->remove(connection);
5265 // not in cache, run a SQL query
5266 std::string qs;
5267 qs = "DELETE FROM guilds ";
5269 qs += " WHERE guild_id = '"+NLMISC::toString(id)+"'";
5272 if (connection.query(qs))
5274 if (connection.getAffectedRows() == 1)
5276 // ok, the row is removed
5277 return true;
5281 return false;
5285 // Try to load the specified object from the memory cache, return NULL if the object is not in the cache
5286 CGuild *CGuild::loadFromCache(uint32 objectId, bool unrelease)
5288 // look in the cache
5289 TObjectCache::iterator it(_ObjectCache.find(objectId));
5290 if (it == _ObjectCache.end())
5292 // not found, return null
5293 return NULL;
5295 else
5297 CGuild *object = it->second;
5299 if (object->_ObjectState == NOPE::os_released)
5301 if (unrelease)
5303 // we need to remove this object from the released object set.
5304 object->removeFromReleased();
5305 object->_ObjectState = NOPE::os_clean;
5309 return it->second;
5312 // Receive and execute command from the cache manager.
5313 uint32 CGuild::cacheCmd(NOPE::TCacheCmd cmd)
5315 if (cmd == NOPE::cc_update)
5317 updateCache();
5319 else if (cmd == NOPE::cc_clear)
5321 clearCache();
5323 else if (cmd == NOPE::cc_dump)
5325 dump();
5327 else if (cmd == NOPE::cc_instance_count)
5329 return (uint32)_ObjectCache.size();
5332 // default return value
5333 return 0;
5336 void CGuild::dump()
5338 nlinfo(" Cache info for class CGuild :");
5339 nlinfo(" There are %u object instances in cache", _ObjectCache.size());
5341 // count the number of object in the released object set
5342 uint32 nbReleased = 0;
5344 TReleasedObject::iterator first(_ReleasedObject.begin()), last(_ReleasedObject.end());
5345 for (; first != last; ++first)
5347 nbReleased += (uint32)first->second.size();
5350 nlinfo(" There are %u object instances in cache not referenced (waiting deletion or re-use))", nbReleased);
5353 void CGuild::updateCache()
5355 if (_ReleasedObject.empty())
5356 return;
5358 // 30 s hold in cache
5359 const time_t MAX_CACHE_OLD_TIME = 30;
5361 time_t now = NLMISC::CTime::getSecondsSince1970();
5363 // look for object set older than MAX_CACHE_OLD_TIME and delete them
5364 while (!_ReleasedObject.empty() && _ReleasedObject.begin()->first < now-MAX_CACHE_OLD_TIME)
5366 TObjectSet &delSet = _ReleasedObject.begin()->second;
5367 // unload this objects
5368 while (!delSet.empty())
5370 CGuild *object = *delSet.begin();
5371 delete object;
5374 _ReleasedObject.erase(_ReleasedObject.begin());
5378 void CGuild::clearCache()
5380 // remove any unreferenced object from the cache
5381 while (!_ReleasedObject.empty())
5383 TObjectSet &delSet = _ReleasedObject.begin()->second;
5384 // unload this objects
5385 while (!delSet.empty())
5387 CGuild *object = *delSet.begin();
5388 delete object;
5391 _ReleasedObject.erase(_ReleasedObject.begin());
5395 void CGuild::registerUpdatable()
5397 static bool registered = false;
5398 if (!registered)
5400 NOPE::CPersistentCache::getInstance().registerCache(&CGuild::cacheCmd);
5402 registered = true;
5406 // set the pointer on the first pointer of the pointer list (set to null when there is no more pointer)
5407 void CGuild::setFirstPtr(CGuildPtr *ptr)
5409 _PtrList = ptr;
5411 if (ptr == NULL)
5413 // this is the last pointer !
5414 if (_ObjectState == NOPE::os_transient
5415 || _ObjectState == NOPE::os_removed)
5417 // not a persistent object, or removed object, just delet it
5418 delete this;
5420 else if (_ObjectState != NOPE::os_removed)
5422 setPersistentState(NOPE::os_released);
5427 // Set the persistent state of the object and do some house keeping
5428 void CGuild::setPersistentState(NOPE::TObjectState state)
5430 nlassert(NOPE::AllowedTransition[_ObjectState][state] == true);
5432 if(_ObjectState == NOPE::os_released && state == NOPE::os_removed)
5434 // a release object gets removed (e.g. by remove by id)
5436 // delete the object
5437 delete this;
5439 // no more to do
5440 return;
5443 if (_ObjectState == NOPE::os_transient && state != NOPE::os_transient)
5445 nldebug("NOPE: inserting CGuild @%p in cache with id %u", this, static_cast<uint32>(_GuildId));
5446 nlverify(_ObjectCache.insert(std::make_pair(_GuildId, this)).second);
5449 if (_ObjectState != NOPE::os_transient)
5450 nlassert(_ObjectCache.find(_GuildId) != _ObjectCache.end());
5452 _ObjectState = state;
5454 if (state == NOPE::os_released)
5456 _ReleaseDate = NLMISC::CTime::getSecondsSince1970();
5457 nlverify(_ReleasedObject[_ReleaseDate].insert(this).second);
5459 else if (state == NOPE::os_removed)
5461 nldebug("NOPE: erasing CGuild @%p in cache with id %u", this, static_cast<uint32>(_GuildId));
5462 nlverify(_ObjectCache.erase(_GuildId) == 1);
5467 CGuildPtr CGuild::load(MSW::CConnection &connection, uint32 id, const char *filename, uint32 lineNum)
5469 CGuild *inCache = loadFromCache(id, true);
5470 if (inCache != NULL)
5472 return CGuildPtr(inCache, filename, lineNum);
5475 std::string qs;
5476 qs = "SELECT ";
5478 qs += "guild_id, guild_name, shard_id";
5480 qs += " FROM guilds";
5482 qs += " WHERE guild_id = '"+NLMISC::toString(id)+"'";
5483 CGuildPtr ret;
5484 if (!connection.query(qs))
5486 return ret;
5489 MSW::CStoreResult *result = connection.storeResult().release();
5491 nlassert(result->getNumRows() <= 1);
5492 if (result->getNumRows() == 1)
5494 ret.assign(new CGuild, filename, lineNum);
5495 // ok, we have an object
5496 result->fetchRow();
5498 result->getField(0, ret->_GuildId);
5499 result->getField(1, ret->_GuildName);
5500 result->getField(2, ret->_ShardId);
5503 ret->setPersistentState(NOPE::os_clean);
5506 delete result;
5508 return ret;
5512 bool CGuild::loadChildrenOfCShard(MSW::CConnection &connection, uint32 parentId, std::map < uint32, CGuildPtr > & container, const char *filename, uint32 lineNum)
5515 std::string qs;
5516 qs = "SELECT ";
5518 qs += "guild_id, guild_name, shard_id";
5520 qs += " FROM guilds";
5521 qs += " WHERE shard_id = '"+NLMISC::toString(parentId)+"'";
5523 if (!connection.query(qs))
5525 return false;
5528 CUniquePtr<MSW::CStoreResult> result = connection.storeResult();
5530 for (uint i=0; i<result->getNumRows(); ++i)
5532 CGuild *ret = new CGuild();
5533 // ok, we have an object
5534 result->fetchRow();
5536 result->getField(0, ret->_GuildId);
5538 result->getField(1, ret->_GuildName);
5540 result->getField(2, ret->_ShardId);
5541 CGuild *inCache = loadFromCache(ret->_GuildId, true);
5542 if (inCache != NULL)
5545 container.insert(std::make_pair(inCache->getObjectId(), CGuildPtr(inCache, filename, lineNum)));
5547 // no more needed
5548 delete ret;
5550 else
5552 ret->setPersistentState(NOPE::os_clean);
5554 container.insert(std::make_pair(ret->getObjectId(), CGuildPtr(ret, filename, lineNum)));
5559 return true;
5562 bool CGuild::loadCharacters(MSW::CConnection &connection, const char *filename, uint32 lineNum)
5564 bool ret = true;
5565 if (_Characters != NULL)
5567 // the children are already loaded, just return true
5568 return true;
5571 // allocate the container
5572 _Characters = new std::vector < CCharacterPtr >;
5574 // load the childs
5575 ret &= CCharacter::loadChildrenOfCGuild(connection, getObjectId(), *_Characters, filename, lineNum);
5576 return ret;
5580 const std::vector<CCharacterPtr> &CGuild::getCharacters() const
5582 nlassert(_Characters != NULL);
5583 return *_Characters;
5586 CCharacterPtr &CGuild::getCharactersByIndex(uint32 index) const
5588 nlassert(_Characters != NULL);
5589 nlassert(index < _Characters->size());
5590 return const_cast< CCharacterPtr & >(_Characters->operator[](index));
5593 CCharacterPtr &CGuild::getCharactersById(uint32 id) const
5595 nlassert(_Characters != NULL);
5596 std::vector<CCharacterPtr >::const_iterator first(_Characters->begin()), last(_Characters->end());
5597 for (; first != last; ++first)
5599 const CCharacterPtr &child = *first;
5600 if (child->getObjectId() == id)
5602 return const_cast< CCharacterPtr & >(child);
5606 // no object with this id, return a null pointer
5607 static CCharacterPtr nilPtr;
5609 return nilPtr;
5613 bool CGuild::loadInvites(MSW::CConnection &connection, const char *filename, uint32 lineNum)
5615 bool ret = true;
5616 if (_Invites != NULL)
5618 // the children are already loaded, just return true
5619 return true;
5622 // allocate the container
5623 _Invites = new std::vector < CGuildInvitePtr >;
5625 // load the childs
5626 ret &= CGuildInvite::loadChildrenOfCGuild(connection, getObjectId(), *_Invites, filename, lineNum);
5627 return ret;
5631 const std::vector<CGuildInvitePtr> &CGuild::getInvites() const
5633 nlassert(_Invites != NULL);
5634 return *_Invites;
5637 CGuildInvitePtr &CGuild::getInvitesByIndex(uint32 index) const
5639 nlassert(_Invites != NULL);
5640 nlassert(index < _Invites->size());
5641 return const_cast< CGuildInvitePtr & >(_Invites->operator[](index));
5644 CGuildInvitePtr &CGuild::getInvitesById(uint32 id) const
5646 nlassert(_Invites != NULL);
5647 std::vector<CGuildInvitePtr >::const_iterator first(_Invites->begin()), last(_Invites->end());
5648 for (; first != last; ++first)
5650 const CGuildInvitePtr &child = *first;
5651 if (child->getObjectId() == id)
5653 return const_cast< CGuildInvitePtr & >(child);
5657 // no object with this id, return a null pointer
5658 static CGuildInvitePtr nilPtr;
5660 return nilPtr;
5664 void CGuildInvitePtr::linkPtr()
5666 nlassert(_NextPtr == NULL);
5667 nlassert(_PrevPtr == NULL);
5668 if (_Ptr != NULL)
5670 _NextPtr = _Ptr->getFirstPtr();
5671 if (_NextPtr != NULL)
5673 _PrevPtr = _NextPtr->_PrevPtr;
5674 _PrevPtr->_NextPtr = this;
5675 _NextPtr->_PrevPtr = this;
5677 else
5679 _NextPtr = this;
5680 _PrevPtr = this;
5681 _Ptr->setFirstPtr(this);
5686 void CGuildInvitePtr::unlinkPtr()
5688 if (_NextPtr == NULL)
5690 nlassert(_PrevPtr == NULL);
5691 return;
5694 if (_Ptr != NULL)
5696 if (_NextPtr == this)
5698 nlassert(_PrevPtr == this);
5699 // last pointer !
5700 _Ptr->setFirstPtr(NULL);
5702 else
5704 if (_Ptr->getFirstPtr() == this)
5706 // the first ptr is the current one, we need to switch to next one
5707 _Ptr->setFirstPtr(_NextPtr);
5712 if (_NextPtr != this)
5714 nlassert(_PrevPtr != this);
5716 _NextPtr->_PrevPtr = _PrevPtr;
5717 _PrevPtr->_NextPtr = _NextPtr;
5719 _NextPtr = NULL;
5720 _PrevPtr = NULL;
5724 CGuildInvite::TObjectCache CGuildInvite::_ObjectCache;
5725 CGuildInvite::TReleasedObject CGuildInvite::_ReleasedObject;
5728 // Destructor, delete any children
5729 CGuildInvite::~CGuildInvite()
5731 // release childs reference
5734 if (_PtrList != NULL)
5736 nlwarning("ERROR : someone try to delete this object, but there are still ptr on it !");
5737 CGuildInvitePtr *ptr = _PtrList;
5740 nlwarning(" Pointer created from '%s', line %u", ptr->_FileName, ptr->_LineNum);
5741 ptr = _PtrList->getNextPtr();
5742 } while(ptr != _PtrList);
5743 nlstop;
5745 // remove object from cache map
5746 if (_Id != NOPE::INVALID_OBJECT_ID
5747 && _ObjectState != NOPE::os_removed
5748 && _ObjectState != NOPE::os_transient)
5750 nldebug("NOPE: clearing CGuildInvite @%p from cache with id %u", this, static_cast<uint32>(_Id));
5751 nlverify(_ObjectCache.erase(_Id) == 1);
5753 else if (_ObjectState != NOPE::os_transient)
5755 nlassert(_ObjectCache.find(_Id) == _ObjectCache.end());
5757 if (_ObjectState == NOPE::os_released)
5759 removeFromReleased();
5761 else
5763 TReleasedObject::iterator it(_ReleasedObject.find(_ReleaseDate));
5764 if (it != _ReleasedObject.end())
5766 nlassert(it->second.find(this) == it->second.end());
5771 void CGuildInvite::removeFromReleased()
5773 TReleasedObject::iterator it(_ReleasedObject.find(_ReleaseDate));
5774 nlassert(it != _ReleasedObject.end());
5775 TObjectSet &os = it->second;
5777 nlverify(os.erase(this) == 1);
5779 // nb : _ReleasedObject time entry are removed by the cache update
5782 bool CGuildInvite::create(MSW::CConnection &connection)
5784 nlassert(getPersistentState() == NOPE::os_transient);
5786 std::string qs;
5787 qs = "INSERT INTO guild_invites (";
5789 qs += "guild_id, session_id";
5790 qs += ") VALUES (";
5792 qs += "'"+MSW::escapeString(NLMISC::toString(_GuildId), connection)+"'";
5793 qs += ", ";
5794 qs += "'"+MSW::escapeString(NLMISC::toString(_SessionId), connection)+"'";
5796 qs += ")";
5798 if (connection.query(qs))
5800 uint32 _id_ = connection.getLastGeneratedId();
5801 setObjectId(_id_);
5804 setPersistentState(NOPE::os_clean);
5806 // update the parent class instance in cache if any
5808 if (_GuildId != 0)
5810 // need to update the parent class child list if it is in the cache
5811 CGuild *parent = CGuild::loadFromCache(_GuildId, false);
5812 if (parent && parent->_Invites != NULL)
5815 nlassert(std::find(parent->_Invites->begin(), parent->_Invites->end(), CGuildInvitePtr(this, __FILE__, __LINE__)) == parent->_Invites->end());
5816 parent->_Invites->push_back(CGuildInvitePtr(this, __FILE__, __LINE__));
5821 if (_SessionId != 0)
5823 // need to update the parent class child list if it is in the cache
5824 CSession *parent = CSession::loadFromCache(_SessionId, false);
5825 if (parent && parent->_GuildInvites != NULL)
5828 nlassert(std::find(parent->_GuildInvites->begin(), parent->_GuildInvites->end(), CGuildInvitePtr(this, __FILE__, __LINE__)) == parent->_GuildInvites->end());
5829 parent->_GuildInvites->push_back(CGuildInvitePtr(this, __FILE__, __LINE__));
5834 return true;
5837 return false;
5840 bool CGuildInvite::update(MSW::CConnection &connection)
5842 nlassert(getPersistentState() == NOPE::os_dirty || getPersistentState() == NOPE::os_clean);
5844 if (getPersistentState() == NOPE::os_clean)
5845 // the object is clean, just ignore the save
5846 return true;
5848 std::string qs;
5849 qs = "UPDATE guild_invites SET ";
5851 qs += "guild_id = '"+MSW::escapeString(NLMISC::toString(_GuildId), connection)+"'";
5852 qs += ", ";
5853 qs += "session_id = '"+MSW::escapeString(NLMISC::toString(_SessionId), connection)+"'";
5855 qs += " WHERE Id = '"+NLMISC::toString(_Id)+"'";
5858 if (connection.query(qs))
5860 if (connection.getAffectedRows() == 1)
5862 setPersistentState(NOPE::os_clean);
5863 return true;
5867 return false;
5870 bool CGuildInvite::remove(MSW::CConnection &connection)
5872 nlassert(getPersistentState() == NOPE::os_dirty || getPersistentState() == NOPE::os_clean);
5874 std::string qs;
5875 qs = "DELETE FROM guild_invites ";
5877 qs += " WHERE Id = '"+NLMISC::toString(_Id)+"'";
5880 if (connection.query(qs))
5882 if (connection.getAffectedRows() == 1)
5886 // change the persistant state to 'removed'.
5887 setPersistentState(NOPE::os_removed);
5889 // need to remove ref from parent class container (if any)
5892 CGuildPtr parent(CGuild::loadFromCache(_GuildId, true), __FILE__, __LINE__);
5893 if (parent != NULL && parent->_Invites != NULL)
5896 std::vector < CGuildInvitePtr >::iterator it = std::find(parent->_Invites->begin(), parent->_Invites->end(), this);
5897 if (it != parent->_Invites->end())
5899 parent->_Invites->erase(it);
5906 CSessionPtr parent(CSession::loadFromCache(_SessionId, true), __FILE__, __LINE__);
5907 if (parent != NULL && parent->_GuildInvites != NULL)
5910 std::vector < CGuildInvitePtr >::iterator it = std::find(parent->_GuildInvites->begin(), parent->_GuildInvites->end(), this);
5911 if (it != parent->_GuildInvites->end())
5913 parent->_GuildInvites->erase(it);
5919 // need to remove ref from parent (if any)
5922 return true;
5925 return false;
5928 bool CGuildInvite::removeById(MSW::CConnection &connection, uint32 id)
5930 CGuildInvite *object = loadFromCache(id, true);
5931 if (object != NULL)
5933 return object->remove(connection);
5935 // not in cache, run a SQL query
5936 std::string qs;
5937 qs = "DELETE FROM guild_invites ";
5939 qs += " WHERE Id = '"+NLMISC::toString(id)+"'";
5942 if (connection.query(qs))
5944 if (connection.getAffectedRows() == 1)
5946 // ok, the row is removed
5947 return true;
5951 return false;
5955 // Try to load the specified object from the memory cache, return NULL if the object is not in the cache
5956 CGuildInvite *CGuildInvite::loadFromCache(uint32 objectId, bool unrelease)
5958 // look in the cache
5959 TObjectCache::iterator it(_ObjectCache.find(objectId));
5960 if (it == _ObjectCache.end())
5962 // not found, return null
5963 return NULL;
5965 else
5967 CGuildInvite *object = it->second;
5969 if (object->_ObjectState == NOPE::os_released)
5971 if (unrelease)
5973 // we need to remove this object from the released object set.
5974 object->removeFromReleased();
5975 object->_ObjectState = NOPE::os_clean;
5979 return it->second;
5982 // Receive and execute command from the cache manager.
5983 uint32 CGuildInvite::cacheCmd(NOPE::TCacheCmd cmd)
5985 if (cmd == NOPE::cc_update)
5987 updateCache();
5989 else if (cmd == NOPE::cc_clear)
5991 clearCache();
5993 else if (cmd == NOPE::cc_dump)
5995 dump();
5997 else if (cmd == NOPE::cc_instance_count)
5999 return (uint32)_ObjectCache.size();
6002 // default return value
6003 return 0;
6006 void CGuildInvite::dump()
6008 nlinfo(" Cache info for class CGuildInvite :");
6009 nlinfo(" There are %u object instances in cache", _ObjectCache.size());
6011 // count the number of object in the released object set
6012 uint32 nbReleased = 0;
6014 TReleasedObject::iterator first(_ReleasedObject.begin()), last(_ReleasedObject.end());
6015 for (; first != last; ++first)
6017 nbReleased += (uint32)first->second.size();
6020 nlinfo(" There are %u object instances in cache not referenced (waiting deletion or re-use))", nbReleased);
6023 void CGuildInvite::updateCache()
6025 if (_ReleasedObject.empty())
6026 return;
6028 // 30 s hold in cache
6029 const time_t MAX_CACHE_OLD_TIME = 30;
6031 time_t now = NLMISC::CTime::getSecondsSince1970();
6033 // look for object set older than MAX_CACHE_OLD_TIME and delete them
6034 while (!_ReleasedObject.empty() && _ReleasedObject.begin()->first < now-MAX_CACHE_OLD_TIME)
6036 TObjectSet &delSet = _ReleasedObject.begin()->second;
6037 // unload this objects
6038 while (!delSet.empty())
6040 CGuildInvite *object = *delSet.begin();
6041 delete object;
6044 _ReleasedObject.erase(_ReleasedObject.begin());
6048 void CGuildInvite::clearCache()
6050 // remove any unreferenced object from the cache
6051 while (!_ReleasedObject.empty())
6053 TObjectSet &delSet = _ReleasedObject.begin()->second;
6054 // unload this objects
6055 while (!delSet.empty())
6057 CGuildInvite *object = *delSet.begin();
6058 delete object;
6061 _ReleasedObject.erase(_ReleasedObject.begin());
6065 void CGuildInvite::registerUpdatable()
6067 static bool registered = false;
6068 if (!registered)
6070 NOPE::CPersistentCache::getInstance().registerCache(&CGuildInvite::cacheCmd);
6072 registered = true;
6076 // set the pointer on the first pointer of the pointer list (set to null when there is no more pointer)
6077 void CGuildInvite::setFirstPtr(CGuildInvitePtr *ptr)
6079 _PtrList = ptr;
6081 if (ptr == NULL)
6083 // this is the last pointer !
6084 if (_ObjectState == NOPE::os_transient
6085 || _ObjectState == NOPE::os_removed)
6087 // not a persistent object, or removed object, just delet it
6088 delete this;
6090 else if (_ObjectState != NOPE::os_removed)
6092 setPersistentState(NOPE::os_released);
6097 // Set the persistent state of the object and do some house keeping
6098 void CGuildInvite::setPersistentState(NOPE::TObjectState state)
6100 nlassert(NOPE::AllowedTransition[_ObjectState][state] == true);
6102 if(_ObjectState == NOPE::os_released && state == NOPE::os_removed)
6104 // a release object gets removed (e.g. by remove by id)
6106 // delete the object
6107 delete this;
6109 // no more to do
6110 return;
6113 if (_ObjectState == NOPE::os_transient && state != NOPE::os_transient)
6115 nldebug("NOPE: inserting CGuildInvite @%p in cache with id %u", this, static_cast<uint32>(_Id));
6116 nlverify(_ObjectCache.insert(std::make_pair(_Id, this)).second);
6119 if (_ObjectState != NOPE::os_transient)
6120 nlassert(_ObjectCache.find(_Id) != _ObjectCache.end());
6122 _ObjectState = state;
6124 if (state == NOPE::os_released)
6126 _ReleaseDate = NLMISC::CTime::getSecondsSince1970();
6127 nlverify(_ReleasedObject[_ReleaseDate].insert(this).second);
6129 else if (state == NOPE::os_removed)
6131 nldebug("NOPE: erasing CGuildInvite @%p in cache with id %u", this, static_cast<uint32>(_Id));
6132 nlverify(_ObjectCache.erase(_Id) == 1);
6137 CGuildInvitePtr CGuildInvite::load(MSW::CConnection &connection, uint32 id, const char *filename, uint32 lineNum)
6139 CGuildInvite *inCache = loadFromCache(id, true);
6140 if (inCache != NULL)
6142 return CGuildInvitePtr(inCache, filename, lineNum);
6145 std::string qs;
6146 qs = "SELECT ";
6148 qs += "Id, guild_id, session_id";
6150 qs += " FROM guild_invites";
6152 qs += " WHERE Id = '"+NLMISC::toString(id)+"'";
6153 CGuildInvitePtr ret;
6154 if (!connection.query(qs))
6156 return ret;
6159 MSW::CStoreResult *result = connection.storeResult().release();
6161 nlassert(result->getNumRows() <= 1);
6162 if (result->getNumRows() == 1)
6164 ret.assign(new CGuildInvite, filename, lineNum);
6165 // ok, we have an object
6166 result->fetchRow();
6168 result->getField(0, ret->_Id);
6169 result->getField(1, ret->_GuildId);
6170 result->getField(2, ret->_SessionId);
6173 ret->setPersistentState(NOPE::os_clean);
6176 delete result;
6178 return ret;
6182 bool CGuildInvite::loadChildrenOfCGuild(MSW::CConnection &connection, uint32 parentId, std::vector < CGuildInvitePtr > & container, const char *filename, uint32 lineNum)
6185 std::string qs;
6186 qs = "SELECT ";
6188 qs += "Id, guild_id, session_id";
6190 qs += " FROM guild_invites";
6191 qs += " WHERE guild_id = '"+NLMISC::toString(parentId)+"'";
6193 if (!connection.query(qs))
6195 return false;
6198 CUniquePtr<MSW::CStoreResult> result = connection.storeResult();
6200 for (uint i=0; i<result->getNumRows(); ++i)
6202 CGuildInvite *ret = new CGuildInvite();
6203 // ok, we have an object
6204 result->fetchRow();
6206 result->getField(0, ret->_Id);
6208 result->getField(1, ret->_GuildId);
6210 result->getField(2, ret->_SessionId);
6211 CGuildInvite *inCache = loadFromCache(ret->_Id, true);
6212 if (inCache != NULL)
6215 container.push_back(CGuildInvitePtr(inCache, filename, lineNum));
6217 // no more needed
6218 delete ret;
6220 else
6222 ret->setPersistentState(NOPE::os_clean);
6224 container.push_back(CGuildInvitePtr(ret, filename, lineNum));
6229 return true;
6232 bool CGuildInvite::loadChildrenOfCSession(MSW::CConnection &connection, uint32 parentId, std::vector < CGuildInvitePtr > & container, const char *filename, uint32 lineNum)
6235 std::string qs;
6236 qs = "SELECT ";
6238 qs += "Id, guild_id, session_id";
6240 qs += " FROM guild_invites";
6241 qs += " WHERE session_id = '"+NLMISC::toString(parentId)+"'";
6243 if (!connection.query(qs))
6245 return false;
6248 CUniquePtr<MSW::CStoreResult> result = connection.storeResult();
6250 for (uint i=0; i<result->getNumRows(); ++i)
6252 CGuildInvite *ret = new CGuildInvite();
6253 // ok, we have an object
6254 result->fetchRow();
6256 result->getField(0, ret->_Id);
6258 result->getField(1, ret->_GuildId);
6260 result->getField(2, ret->_SessionId);
6261 CGuildInvite *inCache = loadFromCache(ret->_Id, true);
6262 if (inCache != NULL)
6265 container.push_back(CGuildInvitePtr(inCache, filename, lineNum));
6267 // no more needed
6268 delete ret;
6270 else
6272 ret->setPersistentState(NOPE::os_clean);
6274 container.push_back(CGuildInvitePtr(ret, filename, lineNum));
6279 return true;
6282 void CPlayerRatingPtr::linkPtr()
6284 nlassert(_NextPtr == NULL);
6285 nlassert(_PrevPtr == NULL);
6286 if (_Ptr != NULL)
6288 _NextPtr = _Ptr->getFirstPtr();
6289 if (_NextPtr != NULL)
6291 _PrevPtr = _NextPtr->_PrevPtr;
6292 _PrevPtr->_NextPtr = this;
6293 _NextPtr->_PrevPtr = this;
6295 else
6297 _NextPtr = this;
6298 _PrevPtr = this;
6299 _Ptr->setFirstPtr(this);
6304 void CPlayerRatingPtr::unlinkPtr()
6306 if (_NextPtr == NULL)
6308 nlassert(_PrevPtr == NULL);
6309 return;
6312 if (_Ptr != NULL)
6314 if (_NextPtr == this)
6316 nlassert(_PrevPtr == this);
6317 // last pointer !
6318 _Ptr->setFirstPtr(NULL);
6320 else
6322 if (_Ptr->getFirstPtr() == this)
6324 // the first ptr is the current one, we need to switch to next one
6325 _Ptr->setFirstPtr(_NextPtr);
6330 if (_NextPtr != this)
6332 nlassert(_PrevPtr != this);
6334 _NextPtr->_PrevPtr = _PrevPtr;
6335 _PrevPtr->_NextPtr = _NextPtr;
6337 _NextPtr = NULL;
6338 _PrevPtr = NULL;
6342 CPlayerRating::TObjectCache CPlayerRating::_ObjectCache;
6343 CPlayerRating::TReleasedObject CPlayerRating::_ReleasedObject;
6346 // Destructor, delete any children
6347 CPlayerRating::~CPlayerRating()
6349 // release childs reference
6352 if (_PtrList != NULL)
6354 nlwarning("ERROR : someone try to delete this object, but there are still ptr on it !");
6355 CPlayerRatingPtr *ptr = _PtrList;
6358 nlwarning(" Pointer created from '%s', line %u", ptr->_FileName, ptr->_LineNum);
6359 ptr = _PtrList->getNextPtr();
6360 } while(ptr != _PtrList);
6361 nlstop;
6363 // remove object from cache map
6364 if (_Id != NOPE::INVALID_OBJECT_ID
6365 && _ObjectState != NOPE::os_removed
6366 && _ObjectState != NOPE::os_transient)
6368 nldebug("NOPE: clearing CPlayerRating @%p from cache with id %u", this, static_cast<uint32>(_Id));
6369 nlverify(_ObjectCache.erase(_Id) == 1);
6371 else if (_ObjectState != NOPE::os_transient)
6373 nlassert(_ObjectCache.find(_Id) == _ObjectCache.end());
6375 if (_ObjectState == NOPE::os_released)
6377 removeFromReleased();
6379 else
6381 TReleasedObject::iterator it(_ReleasedObject.find(_ReleaseDate));
6382 if (it != _ReleasedObject.end())
6384 nlassert(it->second.find(this) == it->second.end());
6389 void CPlayerRating::removeFromReleased()
6391 TReleasedObject::iterator it(_ReleasedObject.find(_ReleaseDate));
6392 nlassert(it != _ReleasedObject.end());
6393 TObjectSet &os = it->second;
6395 nlverify(os.erase(this) == 1);
6397 // nb : _ReleasedObject time entry are removed by the cache update
6400 bool CPlayerRating::create(MSW::CConnection &connection)
6402 nlassert(getPersistentState() == NOPE::os_transient);
6404 std::string qs;
6405 qs = "INSERT INTO player_rating (";
6407 qs += "scenario_id, author, rate_fun, rate_difficulty, rate_accessibility, rate_originality, rate_direction";
6408 qs += ") VALUES (";
6410 qs += "'"+MSW::escapeString(NLMISC::toString(_ScenarioId), connection)+"'";
6411 qs += ", ";
6412 qs += "'"+MSW::escapeString(NLMISC::toString(_Author), connection)+"'";
6413 qs += ", ";
6414 qs += "'"+MSW::escapeString(NLMISC::toString(_RateFun), connection)+"'";
6415 qs += ", ";
6416 qs += "'"+MSW::escapeString(NLMISC::toString(_RateDifficulty), connection)+"'";
6417 qs += ", ";
6418 qs += "'"+MSW::escapeString(NLMISC::toString(_RateAccessibility), connection)+"'";
6419 qs += ", ";
6420 qs += "'"+MSW::escapeString(NLMISC::toString(_RateOriginality), connection)+"'";
6421 qs += ", ";
6422 qs += "'"+MSW::escapeString(NLMISC::toString(_RateDirection), connection)+"'";
6424 qs += ")";
6426 if (connection.query(qs))
6428 uint32 _id_ = connection.getLastGeneratedId();
6429 setObjectId(_id_);
6432 setPersistentState(NOPE::os_clean);
6434 // update the parent class instance in cache if any
6436 if (_ScenarioId != 0)
6438 // need to update the parent class child list if it is in the cache
6439 CScenario *parent = CScenario::loadFromCache(_ScenarioId, false);
6440 if (parent && parent->_PlayerRatings != NULL)
6443 nlassert(std::find(parent->_PlayerRatings->begin(), parent->_PlayerRatings->end(), CPlayerRatingPtr(this, __FILE__, __LINE__)) == parent->_PlayerRatings->end());
6444 parent->_PlayerRatings->push_back(CPlayerRatingPtr(this, __FILE__, __LINE__));
6449 if (_Author != 0)
6451 // need to update the parent class child list if it is in the cache
6452 CCharacter *parent = CCharacter::loadFromCache(_Author, false);
6453 if (parent && parent->_PlayerRatings != NULL)
6456 nlassert(std::find(parent->_PlayerRatings->begin(), parent->_PlayerRatings->end(), CPlayerRatingPtr(this, __FILE__, __LINE__)) == parent->_PlayerRatings->end());
6457 parent->_PlayerRatings->push_back(CPlayerRatingPtr(this, __FILE__, __LINE__));
6462 return true;
6465 return false;
6468 bool CPlayerRating::update(MSW::CConnection &connection)
6470 nlassert(getPersistentState() == NOPE::os_dirty || getPersistentState() == NOPE::os_clean);
6472 if (getPersistentState() == NOPE::os_clean)
6473 // the object is clean, just ignore the save
6474 return true;
6476 std::string qs;
6477 qs = "UPDATE player_rating SET ";
6479 qs += "scenario_id = '"+MSW::escapeString(NLMISC::toString(_ScenarioId), connection)+"'";
6480 qs += ", ";
6481 qs += "author = '"+MSW::escapeString(NLMISC::toString(_Author), connection)+"'";
6482 qs += ", ";
6483 qs += "rate_fun = '"+MSW::escapeString(NLMISC::toString(_RateFun), connection)+"'";
6484 qs += ", ";
6485 qs += "rate_difficulty = '"+MSW::escapeString(NLMISC::toString(_RateDifficulty), connection)+"'";
6486 qs += ", ";
6487 qs += "rate_accessibility = '"+MSW::escapeString(NLMISC::toString(_RateAccessibility), connection)+"'";
6488 qs += ", ";
6489 qs += "rate_originality = '"+MSW::escapeString(NLMISC::toString(_RateOriginality), connection)+"'";
6490 qs += ", ";
6491 qs += "rate_direction = '"+MSW::escapeString(NLMISC::toString(_RateDirection), connection)+"'";
6493 qs += " WHERE Id = '"+NLMISC::toString(_Id)+"'";
6496 if (connection.query(qs))
6498 if (connection.getAffectedRows() == 1)
6500 setPersistentState(NOPE::os_clean);
6501 return true;
6505 return false;
6508 bool CPlayerRating::remove(MSW::CConnection &connection)
6510 nlassert(getPersistentState() == NOPE::os_dirty || getPersistentState() == NOPE::os_clean);
6512 std::string qs;
6513 qs = "DELETE FROM player_rating ";
6515 qs += " WHERE Id = '"+NLMISC::toString(_Id)+"'";
6518 if (connection.query(qs))
6520 if (connection.getAffectedRows() == 1)
6524 // change the persistant state to 'removed'.
6525 setPersistentState(NOPE::os_removed);
6527 // need to remove ref from parent class container (if any)
6530 CScenarioPtr parent(CScenario::loadFromCache(_ScenarioId, true), __FILE__, __LINE__);
6531 if (parent != NULL && parent->_PlayerRatings != NULL)
6534 std::vector < CPlayerRatingPtr >::iterator it = std::find(parent->_PlayerRatings->begin(), parent->_PlayerRatings->end(), this);
6535 if (it != parent->_PlayerRatings->end())
6537 parent->_PlayerRatings->erase(it);
6544 CCharacterPtr parent(CCharacter::loadFromCache(_Author, true), __FILE__, __LINE__);
6545 if (parent != NULL && parent->_PlayerRatings != NULL)
6548 std::vector < CPlayerRatingPtr >::iterator it = std::find(parent->_PlayerRatings->begin(), parent->_PlayerRatings->end(), this);
6549 if (it != parent->_PlayerRatings->end())
6551 parent->_PlayerRatings->erase(it);
6557 // need to remove ref from parent (if any)
6560 return true;
6563 return false;
6566 bool CPlayerRating::removeById(MSW::CConnection &connection, uint32 id)
6568 CPlayerRating *object = loadFromCache(id, true);
6569 if (object != NULL)
6571 return object->remove(connection);
6573 // not in cache, run a SQL query
6574 std::string qs;
6575 qs = "DELETE FROM player_rating ";
6577 qs += " WHERE Id = '"+NLMISC::toString(id)+"'";
6580 if (connection.query(qs))
6582 if (connection.getAffectedRows() == 1)
6584 // ok, the row is removed
6585 return true;
6589 return false;
6593 // Try to load the specified object from the memory cache, return NULL if the object is not in the cache
6594 CPlayerRating *CPlayerRating::loadFromCache(uint32 objectId, bool unrelease)
6596 // look in the cache
6597 TObjectCache::iterator it(_ObjectCache.find(objectId));
6598 if (it == _ObjectCache.end())
6600 // not found, return null
6601 return NULL;
6603 else
6605 CPlayerRating *object = it->second;
6607 if (object->_ObjectState == NOPE::os_released)
6609 if (unrelease)
6611 // we need to remove this object from the released object set.
6612 object->removeFromReleased();
6613 object->_ObjectState = NOPE::os_clean;
6617 return it->second;
6620 // Receive and execute command from the cache manager.
6621 uint32 CPlayerRating::cacheCmd(NOPE::TCacheCmd cmd)
6623 if (cmd == NOPE::cc_update)
6625 updateCache();
6627 else if (cmd == NOPE::cc_clear)
6629 clearCache();
6631 else if (cmd == NOPE::cc_dump)
6633 dump();
6635 else if (cmd == NOPE::cc_instance_count)
6637 return (uint32)_ObjectCache.size();
6640 // default return value
6641 return 0;
6644 void CPlayerRating::dump()
6646 nlinfo(" Cache info for class CPlayerRating :");
6647 nlinfo(" There are %u object instances in cache", _ObjectCache.size());
6649 // count the number of object in the released object set
6650 uint32 nbReleased = 0;
6652 TReleasedObject::iterator first(_ReleasedObject.begin()), last(_ReleasedObject.end());
6653 for (; first != last; ++first)
6655 nbReleased += (uint32)first->second.size();
6658 nlinfo(" There are %u object instances in cache not referenced (waiting deletion or re-use))", nbReleased);
6661 void CPlayerRating::updateCache()
6663 if (_ReleasedObject.empty())
6664 return;
6666 // 30 s hold in cache
6667 const time_t MAX_CACHE_OLD_TIME = 30;
6669 time_t now = NLMISC::CTime::getSecondsSince1970();
6671 // look for object set older than MAX_CACHE_OLD_TIME and delete them
6672 while (!_ReleasedObject.empty() && _ReleasedObject.begin()->first < now-MAX_CACHE_OLD_TIME)
6674 TObjectSet &delSet = _ReleasedObject.begin()->second;
6675 // unload this objects
6676 while (!delSet.empty())
6678 CPlayerRating *object = *delSet.begin();
6679 delete object;
6682 _ReleasedObject.erase(_ReleasedObject.begin());
6686 void CPlayerRating::clearCache()
6688 // remove any unreferenced object from the cache
6689 while (!_ReleasedObject.empty())
6691 TObjectSet &delSet = _ReleasedObject.begin()->second;
6692 // unload this objects
6693 while (!delSet.empty())
6695 CPlayerRating *object = *delSet.begin();
6696 delete object;
6699 _ReleasedObject.erase(_ReleasedObject.begin());
6703 void CPlayerRating::registerUpdatable()
6705 static bool registered = false;
6706 if (!registered)
6708 NOPE::CPersistentCache::getInstance().registerCache(&CPlayerRating::cacheCmd);
6710 registered = true;
6714 // set the pointer on the first pointer of the pointer list (set to null when there is no more pointer)
6715 void CPlayerRating::setFirstPtr(CPlayerRatingPtr *ptr)
6717 _PtrList = ptr;
6719 if (ptr == NULL)
6721 // this is the last pointer !
6722 if (_ObjectState == NOPE::os_transient
6723 || _ObjectState == NOPE::os_removed)
6725 // not a persistent object, or removed object, just delet it
6726 delete this;
6728 else if (_ObjectState != NOPE::os_removed)
6730 setPersistentState(NOPE::os_released);
6735 // Set the persistent state of the object and do some house keeping
6736 void CPlayerRating::setPersistentState(NOPE::TObjectState state)
6738 nlassert(NOPE::AllowedTransition[_ObjectState][state] == true);
6740 if(_ObjectState == NOPE::os_released && state == NOPE::os_removed)
6742 // a release object gets removed (e.g. by remove by id)
6744 // delete the object
6745 delete this;
6747 // no more to do
6748 return;
6751 if (_ObjectState == NOPE::os_transient && state != NOPE::os_transient)
6753 nldebug("NOPE: inserting CPlayerRating @%p in cache with id %u", this, static_cast<uint32>(_Id));
6754 nlverify(_ObjectCache.insert(std::make_pair(_Id, this)).second);
6757 if (_ObjectState != NOPE::os_transient)
6758 nlassert(_ObjectCache.find(_Id) != _ObjectCache.end());
6760 _ObjectState = state;
6762 if (state == NOPE::os_released)
6764 _ReleaseDate = NLMISC::CTime::getSecondsSince1970();
6765 nlverify(_ReleasedObject[_ReleaseDate].insert(this).second);
6767 else if (state == NOPE::os_removed)
6769 nldebug("NOPE: erasing CPlayerRating @%p in cache with id %u", this, static_cast<uint32>(_Id));
6770 nlverify(_ObjectCache.erase(_Id) == 1);
6775 CPlayerRatingPtr CPlayerRating::load(MSW::CConnection &connection, uint32 id, const char *filename, uint32 lineNum)
6777 CPlayerRating *inCache = loadFromCache(id, true);
6778 if (inCache != NULL)
6780 return CPlayerRatingPtr(inCache, filename, lineNum);
6783 std::string qs;
6784 qs = "SELECT ";
6786 qs += "Id, scenario_id, author, rate_fun, rate_difficulty, rate_accessibility, rate_originality, rate_direction";
6788 qs += " FROM player_rating";
6790 qs += " WHERE Id = '"+NLMISC::toString(id)+"'";
6791 CPlayerRatingPtr ret;
6792 if (!connection.query(qs))
6794 return ret;
6797 MSW::CStoreResult *result = connection.storeResult().release();
6799 nlassert(result->getNumRows() <= 1);
6800 if (result->getNumRows() == 1)
6802 ret.assign(new CPlayerRating, filename, lineNum);
6803 // ok, we have an object
6804 result->fetchRow();
6806 result->getField(0, ret->_Id);
6807 result->getField(1, ret->_ScenarioId);
6808 result->getField(2, ret->_Author);
6809 result->getField(3, ret->_RateFun);
6810 result->getField(4, ret->_RateDifficulty);
6811 result->getField(5, ret->_RateAccessibility);
6812 result->getField(6, ret->_RateOriginality);
6813 result->getField(7, ret->_RateDirection);
6816 ret->setPersistentState(NOPE::os_clean);
6819 delete result;
6821 return ret;
6825 bool CPlayerRating::loadChildrenOfCScenario(MSW::CConnection &connection, uint32 parentId, std::vector < CPlayerRatingPtr > & container, const char *filename, uint32 lineNum)
6828 std::string qs;
6829 qs = "SELECT ";
6831 qs += "Id, scenario_id, author, rate_fun, rate_difficulty, rate_accessibility, rate_originality, rate_direction";
6833 qs += " FROM player_rating";
6834 qs += " WHERE scenario_id = '"+NLMISC::toString(parentId)+"'";
6836 if (!connection.query(qs))
6838 return false;
6841 CUniquePtr<MSW::CStoreResult> result = connection.storeResult();
6843 for (uint i=0; i<result->getNumRows(); ++i)
6845 CPlayerRating *ret = new CPlayerRating();
6846 // ok, we have an object
6847 result->fetchRow();
6849 result->getField(0, ret->_Id);
6851 result->getField(1, ret->_ScenarioId);
6853 result->getField(2, ret->_Author);
6855 result->getField(3, ret->_RateFun);
6857 result->getField(4, ret->_RateDifficulty);
6859 result->getField(5, ret->_RateAccessibility);
6861 result->getField(6, ret->_RateOriginality);
6863 result->getField(7, ret->_RateDirection);
6864 CPlayerRating *inCache = loadFromCache(ret->_Id, true);
6865 if (inCache != NULL)
6868 container.push_back(CPlayerRatingPtr(inCache, filename, lineNum));
6870 // no more needed
6871 delete ret;
6873 else
6875 ret->setPersistentState(NOPE::os_clean);
6877 container.push_back(CPlayerRatingPtr(ret, filename, lineNum));
6882 return true;
6885 bool CPlayerRating::loadChildrenOfCCharacter(MSW::CConnection &connection, uint32 parentId, std::vector < CPlayerRatingPtr > & container, const char *filename, uint32 lineNum)
6888 std::string qs;
6889 qs = "SELECT ";
6891 qs += "Id, scenario_id, author, rate_fun, rate_difficulty, rate_accessibility, rate_originality, rate_direction";
6893 qs += " FROM player_rating";
6894 qs += " WHERE author = '"+NLMISC::toString(parentId)+"'";
6896 if (!connection.query(qs))
6898 return false;
6901 CUniquePtr<MSW::CStoreResult> result = connection.storeResult();
6903 for (uint i=0; i<result->getNumRows(); ++i)
6905 CPlayerRating *ret = new CPlayerRating();
6906 // ok, we have an object
6907 result->fetchRow();
6909 result->getField(0, ret->_Id);
6911 result->getField(1, ret->_ScenarioId);
6913 result->getField(2, ret->_Author);
6915 result->getField(3, ret->_RateFun);
6917 result->getField(4, ret->_RateDifficulty);
6919 result->getField(5, ret->_RateAccessibility);
6921 result->getField(6, ret->_RateOriginality);
6923 result->getField(7, ret->_RateDirection);
6924 CPlayerRating *inCache = loadFromCache(ret->_Id, true);
6925 if (inCache != NULL)
6928 container.push_back(CPlayerRatingPtr(inCache, filename, lineNum));
6930 // no more needed
6931 delete ret;
6933 else
6935 ret->setPersistentState(NOPE::os_clean);
6937 container.push_back(CPlayerRatingPtr(ret, filename, lineNum));
6942 return true;
6945 void CJournalEntryPtr::linkPtr()
6947 nlassert(_NextPtr == NULL);
6948 nlassert(_PrevPtr == NULL);
6949 if (_Ptr != NULL)
6951 _NextPtr = _Ptr->getFirstPtr();
6952 if (_NextPtr != NULL)
6954 _PrevPtr = _NextPtr->_PrevPtr;
6955 _PrevPtr->_NextPtr = this;
6956 _NextPtr->_PrevPtr = this;
6958 else
6960 _NextPtr = this;
6961 _PrevPtr = this;
6962 _Ptr->setFirstPtr(this);
6967 void CJournalEntryPtr::unlinkPtr()
6969 if (_NextPtr == NULL)
6971 nlassert(_PrevPtr == NULL);
6972 return;
6975 if (_Ptr != NULL)
6977 if (_NextPtr == this)
6979 nlassert(_PrevPtr == this);
6980 // last pointer !
6981 _Ptr->setFirstPtr(NULL);
6983 else
6985 if (_Ptr->getFirstPtr() == this)
6987 // the first ptr is the current one, we need to switch to next one
6988 _Ptr->setFirstPtr(_NextPtr);
6993 if (_NextPtr != this)
6995 nlassert(_PrevPtr != this);
6997 _NextPtr->_PrevPtr = _PrevPtr;
6998 _PrevPtr->_NextPtr = _NextPtr;
7000 _NextPtr = NULL;
7001 _PrevPtr = NULL;
7005 CJournalEntry::TObjectCache CJournalEntry::_ObjectCache;
7006 CJournalEntry::TReleasedObject CJournalEntry::_ReleasedObject;
7009 // Destructor, delete any children
7010 CJournalEntry::~CJournalEntry()
7012 // release childs reference
7015 if (_PtrList != NULL)
7017 nlwarning("ERROR : someone try to delete this object, but there are still ptr on it !");
7018 CJournalEntryPtr *ptr = _PtrList;
7021 nlwarning(" Pointer created from '%s', line %u", ptr->_FileName, ptr->_LineNum);
7022 ptr = _PtrList->getNextPtr();
7023 } while(ptr != _PtrList);
7024 nlstop;
7026 // remove object from cache map
7027 if (_Id != NOPE::INVALID_OBJECT_ID
7028 && _ObjectState != NOPE::os_removed
7029 && _ObjectState != NOPE::os_transient)
7031 nldebug("NOPE: clearing CJournalEntry @%p from cache with id %u", this, static_cast<uint32>(_Id));
7032 nlverify(_ObjectCache.erase(_Id) == 1);
7034 else if (_ObjectState != NOPE::os_transient)
7036 nlassert(_ObjectCache.find(_Id) == _ObjectCache.end());
7038 if (_ObjectState == NOPE::os_released)
7040 removeFromReleased();
7042 else
7044 TReleasedObject::iterator it(_ReleasedObject.find(_ReleaseDate));
7045 if (it != _ReleasedObject.end())
7047 nlassert(it->second.find(this) == it->second.end());
7052 void CJournalEntry::removeFromReleased()
7054 TReleasedObject::iterator it(_ReleasedObject.find(_ReleaseDate));
7055 nlassert(it != _ReleasedObject.end());
7056 TObjectSet &os = it->second;
7058 nlverify(os.erase(this) == 1);
7060 // nb : _ReleasedObject time entry are removed by the cache update
7063 bool CJournalEntry::create(MSW::CConnection &connection)
7065 nlassert(getPersistentState() == NOPE::os_transient);
7067 std::string qs;
7068 qs = "INSERT INTO journal_entry (";
7070 qs += "session_id, author, type, text, time_stamp";
7071 qs += ") VALUES (";
7073 qs += "'"+MSW::escapeString(NLMISC::toString(_SessionId), connection)+"'";
7074 qs += ", ";
7075 qs += "'"+MSW::escapeString(NLMISC::toString(_Author), connection)+"'";
7076 qs += ", ";
7077 qs += _Type.isValid()
7078 ? "'"+_Type.toString()+"'"
7079 : "DEFAULT(type)";
7080 qs += ", ";
7081 qs += "'"+MSW::escapeString(NLMISC::toString(_Text), connection)+"'";
7082 qs += ", ";
7083 qs += "'"+MSW::encodeDate(_TimeStamp)+"'";
7085 qs += ")";
7087 if (connection.query(qs))
7089 uint32 _id_ = connection.getLastGeneratedId();
7090 setObjectId(_id_);
7093 setPersistentState(NOPE::os_clean);
7095 // update the parent class instance in cache if any
7097 if (_SessionId != 0)
7099 // need to update the parent class child list if it is in the cache
7100 CSession *parent = CSession::loadFromCache(_SessionId, false);
7101 if (parent && parent->_JournalEntries != NULL)
7104 nlassert(std::find(parent->_JournalEntries->begin(), parent->_JournalEntries->end(), CJournalEntryPtr(this, __FILE__, __LINE__)) == parent->_JournalEntries->end());
7105 parent->_JournalEntries->push_back(CJournalEntryPtr(this, __FILE__, __LINE__));
7110 return true;
7113 return false;
7116 bool CJournalEntry::update(MSW::CConnection &connection)
7118 nlassert(getPersistentState() == NOPE::os_dirty || getPersistentState() == NOPE::os_clean);
7120 if (getPersistentState() == NOPE::os_clean)
7121 // the object is clean, just ignore the save
7122 return true;
7124 std::string qs;
7125 qs = "UPDATE journal_entry SET ";
7127 qs += "session_id = '"+MSW::escapeString(NLMISC::toString(_SessionId), connection)+"'";
7128 qs += ", ";
7129 qs += "author = '"+MSW::escapeString(NLMISC::toString(_Author), connection)+"'";
7130 qs += ", ";
7131 qs += "type = " + (_Type.isValid()
7132 ? "'"+_Type.toString()+"'"
7133 : "DEFAULT(type)");
7134 qs += ", ";
7135 qs += "text = '"+MSW::escapeString(NLMISC::toString(_Text), connection)+"'";
7136 qs += ", ";
7137 qs += "time_stamp = '"+MSW::encodeDate(_TimeStamp)+"'";
7139 qs += " WHERE Id = '"+NLMISC::toString(_Id)+"'";
7142 if (connection.query(qs))
7144 if (connection.getAffectedRows() == 1)
7146 setPersistentState(NOPE::os_clean);
7147 return true;
7151 return false;
7154 bool CJournalEntry::remove(MSW::CConnection &connection)
7156 nlassert(getPersistentState() == NOPE::os_dirty || getPersistentState() == NOPE::os_clean);
7158 std::string qs;
7159 qs = "DELETE FROM journal_entry ";
7161 qs += " WHERE Id = '"+NLMISC::toString(_Id)+"'";
7164 if (connection.query(qs))
7166 if (connection.getAffectedRows() == 1)
7170 // change the persistant state to 'removed'.
7171 setPersistentState(NOPE::os_removed);
7173 // need to remove ref from parent class container (if any)
7176 CSessionPtr parent(CSession::loadFromCache(_SessionId, true), __FILE__, __LINE__);
7177 if (parent != NULL && parent->_JournalEntries != NULL)
7180 std::vector < CJournalEntryPtr >::iterator it = std::find(parent->_JournalEntries->begin(), parent->_JournalEntries->end(), this);
7181 if (it != parent->_JournalEntries->end())
7183 parent->_JournalEntries->erase(it);
7189 // need to remove ref from parent (if any)
7192 return true;
7195 return false;
7198 bool CJournalEntry::removeById(MSW::CConnection &connection, uint32 id)
7200 CJournalEntry *object = loadFromCache(id, true);
7201 if (object != NULL)
7203 return object->remove(connection);
7205 // not in cache, run a SQL query
7206 std::string qs;
7207 qs = "DELETE FROM journal_entry ";
7209 qs += " WHERE Id = '"+NLMISC::toString(id)+"'";
7212 if (connection.query(qs))
7214 if (connection.getAffectedRows() == 1)
7216 // ok, the row is removed
7217 return true;
7221 return false;
7225 // Try to load the specified object from the memory cache, return NULL if the object is not in the cache
7226 CJournalEntry *CJournalEntry::loadFromCache(uint32 objectId, bool unrelease)
7228 // look in the cache
7229 TObjectCache::iterator it(_ObjectCache.find(objectId));
7230 if (it == _ObjectCache.end())
7232 // not found, return null
7233 return NULL;
7235 else
7237 CJournalEntry *object = it->second;
7239 if (object->_ObjectState == NOPE::os_released)
7241 if (unrelease)
7243 // we need to remove this object from the released object set.
7244 object->removeFromReleased();
7245 object->_ObjectState = NOPE::os_clean;
7249 return it->second;
7252 // Receive and execute command from the cache manager.
7253 uint32 CJournalEntry::cacheCmd(NOPE::TCacheCmd cmd)
7255 if (cmd == NOPE::cc_update)
7257 updateCache();
7259 else if (cmd == NOPE::cc_clear)
7261 clearCache();
7263 else if (cmd == NOPE::cc_dump)
7265 dump();
7267 else if (cmd == NOPE::cc_instance_count)
7269 return (uint32)_ObjectCache.size();
7272 // default return value
7273 return 0;
7276 void CJournalEntry::dump()
7278 nlinfo(" Cache info for class CJournalEntry :");
7279 nlinfo(" There are %u object instances in cache", _ObjectCache.size());
7281 // count the number of object in the released object set
7282 uint32 nbReleased = 0;
7284 TReleasedObject::iterator first(_ReleasedObject.begin()), last(_ReleasedObject.end());
7285 for (; first != last; ++first)
7287 nbReleased += (uint32)first->second.size();
7290 nlinfo(" There are %u object instances in cache not referenced (waiting deletion or re-use))", nbReleased);
7293 void CJournalEntry::updateCache()
7295 if (_ReleasedObject.empty())
7296 return;
7298 // 30 s hold in cache
7299 const time_t MAX_CACHE_OLD_TIME = 30;
7301 time_t now = NLMISC::CTime::getSecondsSince1970();
7303 // look for object set older than MAX_CACHE_OLD_TIME and delete them
7304 while (!_ReleasedObject.empty() && _ReleasedObject.begin()->first < now-MAX_CACHE_OLD_TIME)
7306 TObjectSet &delSet = _ReleasedObject.begin()->second;
7307 // unload this objects
7308 while (!delSet.empty())
7310 CJournalEntry *object = *delSet.begin();
7311 delete object;
7314 _ReleasedObject.erase(_ReleasedObject.begin());
7318 void CJournalEntry::clearCache()
7320 // remove any unreferenced object from the cache
7321 while (!_ReleasedObject.empty())
7323 TObjectSet &delSet = _ReleasedObject.begin()->second;
7324 // unload this objects
7325 while (!delSet.empty())
7327 CJournalEntry *object = *delSet.begin();
7328 delete object;
7331 _ReleasedObject.erase(_ReleasedObject.begin());
7335 void CJournalEntry::registerUpdatable()
7337 static bool registered = false;
7338 if (!registered)
7340 NOPE::CPersistentCache::getInstance().registerCache(&CJournalEntry::cacheCmd);
7342 registered = true;
7346 // set the pointer on the first pointer of the pointer list (set to null when there is no more pointer)
7347 void CJournalEntry::setFirstPtr(CJournalEntryPtr *ptr)
7349 _PtrList = ptr;
7351 if (ptr == NULL)
7353 // this is the last pointer !
7354 if (_ObjectState == NOPE::os_transient
7355 || _ObjectState == NOPE::os_removed)
7357 // not a persistent object, or removed object, just delet it
7358 delete this;
7360 else if (_ObjectState != NOPE::os_removed)
7362 setPersistentState(NOPE::os_released);
7367 // Set the persistent state of the object and do some house keeping
7368 void CJournalEntry::setPersistentState(NOPE::TObjectState state)
7370 nlassert(NOPE::AllowedTransition[_ObjectState][state] == true);
7372 if(_ObjectState == NOPE::os_released && state == NOPE::os_removed)
7374 // a release object gets removed (e.g. by remove by id)
7376 // delete the object
7377 delete this;
7379 // no more to do
7380 return;
7383 if (_ObjectState == NOPE::os_transient && state != NOPE::os_transient)
7385 nldebug("NOPE: inserting CJournalEntry @%p in cache with id %u", this, static_cast<uint32>(_Id));
7386 nlverify(_ObjectCache.insert(std::make_pair(_Id, this)).second);
7389 if (_ObjectState != NOPE::os_transient)
7390 nlassert(_ObjectCache.find(_Id) != _ObjectCache.end());
7392 _ObjectState = state;
7394 if (state == NOPE::os_released)
7396 _ReleaseDate = NLMISC::CTime::getSecondsSince1970();
7397 nlverify(_ReleasedObject[_ReleaseDate].insert(this).second);
7399 else if (state == NOPE::os_removed)
7401 nldebug("NOPE: erasing CJournalEntry @%p in cache with id %u", this, static_cast<uint32>(_Id));
7402 nlverify(_ObjectCache.erase(_Id) == 1);
7407 CJournalEntryPtr CJournalEntry::load(MSW::CConnection &connection, uint32 id, const char *filename, uint32 lineNum)
7409 CJournalEntry *inCache = loadFromCache(id, true);
7410 if (inCache != NULL)
7412 return CJournalEntryPtr(inCache, filename, lineNum);
7415 std::string qs;
7416 qs = "SELECT ";
7418 qs += "Id, session_id, author, type, text, time_stamp";
7420 qs += " FROM journal_entry";
7422 qs += " WHERE Id = '"+NLMISC::toString(id)+"'";
7423 CJournalEntryPtr ret;
7424 if (!connection.query(qs))
7426 return ret;
7429 MSW::CStoreResult *result = connection.storeResult().release();
7431 nlassert(result->getNumRows() <= 1);
7432 if (result->getNumRows() == 1)
7434 ret.assign(new CJournalEntry, filename, lineNum);
7435 // ok, we have an object
7436 result->fetchRow();
7438 result->getField(0, ret->_Id);
7439 result->getField(1, ret->_SessionId);
7440 result->getField(2, ret->_Author);
7442 std::string s;
7443 result->getField(3, s);
7444 ret->_Type = TJournalEntryType(s);
7446 result->getField(4, ret->_Text);
7447 result->getDateField(5, ret->_TimeStamp);
7450 ret->setPersistentState(NOPE::os_clean);
7453 delete result;
7455 return ret;
7459 bool CJournalEntry::loadChildrenOfCSession(MSW::CConnection &connection, uint32 parentId, std::vector < CJournalEntryPtr > & container, const char *filename, uint32 lineNum)
7462 std::string qs;
7463 qs = "SELECT ";
7465 qs += "Id, session_id, author, type, text, time_stamp";
7467 qs += " FROM journal_entry";
7468 qs += " WHERE session_id = '"+NLMISC::toString(parentId)+"'";
7470 if (!connection.query(qs))
7472 return false;
7475 CUniquePtr<MSW::CStoreResult> result = connection.storeResult();
7477 for (uint i=0; i<result->getNumRows(); ++i)
7479 CJournalEntry *ret = new CJournalEntry();
7480 // ok, we have an object
7481 result->fetchRow();
7483 result->getField(0, ret->_Id);
7485 result->getField(1, ret->_SessionId);
7487 result->getField(2, ret->_Author);
7490 std::string s;
7491 result->getField(3, s);
7492 ret->_Type = TJournalEntryType(s);
7495 result->getField(4, ret->_Text);
7497 result->getDateField(5, ret->_TimeStamp);
7498 CJournalEntry *inCache = loadFromCache(ret->_Id, true);
7499 if (inCache != NULL)
7502 container.push_back(CJournalEntryPtr(inCache, filename, lineNum));
7504 // no more needed
7505 delete ret;
7507 else
7509 ret->setPersistentState(NOPE::os_clean);
7511 container.push_back(CJournalEntryPtr(ret, filename, lineNum));
7516 return true;
7519 void CFolderPtr::linkPtr()
7521 nlassert(_NextPtr == NULL);
7522 nlassert(_PrevPtr == NULL);
7523 if (_Ptr != NULL)
7525 _NextPtr = _Ptr->getFirstPtr();
7526 if (_NextPtr != NULL)
7528 _PrevPtr = _NextPtr->_PrevPtr;
7529 _PrevPtr->_NextPtr = this;
7530 _NextPtr->_PrevPtr = this;
7532 else
7534 _NextPtr = this;
7535 _PrevPtr = this;
7536 _Ptr->setFirstPtr(this);
7541 void CFolderPtr::unlinkPtr()
7543 if (_NextPtr == NULL)
7545 nlassert(_PrevPtr == NULL);
7546 return;
7549 if (_Ptr != NULL)
7551 if (_NextPtr == this)
7553 nlassert(_PrevPtr == this);
7554 // last pointer !
7555 _Ptr->setFirstPtr(NULL);
7557 else
7559 if (_Ptr->getFirstPtr() == this)
7561 // the first ptr is the current one, we need to switch to next one
7562 _Ptr->setFirstPtr(_NextPtr);
7567 if (_NextPtr != this)
7569 nlassert(_PrevPtr != this);
7571 _NextPtr->_PrevPtr = _PrevPtr;
7572 _PrevPtr->_NextPtr = _NextPtr;
7574 _NextPtr = NULL;
7575 _PrevPtr = NULL;
7579 CFolder::TObjectCache CFolder::_ObjectCache;
7580 CFolder::TReleasedObject CFolder::_ReleasedObject;
7583 // Destructor, delete any children
7584 CFolder::~CFolder()
7586 // release childs reference
7587 if (_FolderAccess != NULL)
7588 delete _FolderAccess;
7589 if (_Sessions != NULL)
7590 delete _Sessions;
7593 if (_PtrList != NULL)
7595 nlwarning("ERROR : someone try to delete this object, but there are still ptr on it !");
7596 CFolderPtr *ptr = _PtrList;
7599 nlwarning(" Pointer created from '%s', line %u", ptr->_FileName, ptr->_LineNum);
7600 ptr = _PtrList->getNextPtr();
7601 } while(ptr != _PtrList);
7602 nlstop;
7604 // remove object from cache map
7605 if (_Id != NOPE::INVALID_OBJECT_ID
7606 && _ObjectState != NOPE::os_removed
7607 && _ObjectState != NOPE::os_transient)
7609 nldebug("NOPE: clearing CFolder @%p from cache with id %u", this, static_cast<uint32>(_Id));
7610 nlverify(_ObjectCache.erase(_Id) == 1);
7612 else if (_ObjectState != NOPE::os_transient)
7614 nlassert(_ObjectCache.find(_Id) == _ObjectCache.end());
7616 if (_ObjectState == NOPE::os_released)
7618 removeFromReleased();
7620 else
7622 TReleasedObject::iterator it(_ReleasedObject.find(_ReleaseDate));
7623 if (it != _ReleasedObject.end())
7625 nlassert(it->second.find(this) == it->second.end());
7630 void CFolder::removeFromReleased()
7632 TReleasedObject::iterator it(_ReleasedObject.find(_ReleaseDate));
7633 nlassert(it != _ReleasedObject.end());
7634 TObjectSet &os = it->second;
7636 nlverify(os.erase(this) == 1);
7638 // nb : _ReleasedObject time entry are removed by the cache update
7641 bool CFolder::create(MSW::CConnection &connection)
7643 nlassert(getPersistentState() == NOPE::os_transient);
7645 std::string qs;
7646 qs = "INSERT INTO folder (";
7648 qs += "author, title, comments";
7649 qs += ") VALUES (";
7651 qs += "'"+MSW::escapeString(NLMISC::toString(_Author), connection)+"'";
7652 qs += ", ";
7653 qs += "'"+MSW::escapeString(NLMISC::toString(_Title), connection)+"'";
7654 qs += ", ";
7655 qs += "'"+MSW::escapeString(NLMISC::toString(_Comments), connection)+"'";
7657 qs += ")";
7659 if (connection.query(qs))
7661 uint32 _id_ = connection.getLastGeneratedId();
7662 setObjectId(_id_);
7665 setPersistentState(NOPE::os_clean);
7667 // update the parent class instance in cache if any
7669 if (_Author != 0)
7671 // need to update the parent class child list if it is in the cache
7672 CRingUser *parent = CRingUser::loadFromCache(_Author, false);
7673 if (parent && parent->_Folders != NULL)
7676 nlassert(std::find(parent->_Folders->begin(), parent->_Folders->end(), CFolderPtr(this, __FILE__, __LINE__)) == parent->_Folders->end());
7677 parent->_Folders->push_back(CFolderPtr(this, __FILE__, __LINE__));
7682 return true;
7685 return false;
7688 bool CFolder::update(MSW::CConnection &connection)
7690 nlassert(getPersistentState() == NOPE::os_dirty || getPersistentState() == NOPE::os_clean);
7692 if (getPersistentState() == NOPE::os_clean)
7693 // the object is clean, just ignore the save
7694 return true;
7696 std::string qs;
7697 qs = "UPDATE folder SET ";
7699 qs += "author = '"+MSW::escapeString(NLMISC::toString(_Author), connection)+"'";
7700 qs += ", ";
7701 qs += "title = '"+MSW::escapeString(NLMISC::toString(_Title), connection)+"'";
7702 qs += ", ";
7703 qs += "comments = '"+MSW::escapeString(NLMISC::toString(_Comments), connection)+"'";
7705 qs += " WHERE Id = '"+NLMISC::toString(_Id)+"'";
7708 if (connection.query(qs))
7710 if (connection.getAffectedRows() == 1)
7712 setPersistentState(NOPE::os_clean);
7713 return true;
7717 return false;
7720 bool CFolder::remove(MSW::CConnection &connection)
7722 nlassert(getPersistentState() == NOPE::os_dirty || getPersistentState() == NOPE::os_clean);
7724 std::string qs;
7725 qs = "DELETE FROM folder ";
7727 qs += " WHERE Id = '"+NLMISC::toString(_Id)+"'";
7730 if (connection.query(qs))
7732 if (connection.getAffectedRows() == 1)
7736 // cascading deletion for vector child FolderAccess
7737 if (loadFolderAccess(connection, __FILE__, __LINE__))
7739 const std::vector < CFolderAccessPtr > & childs = getFolderAccess();
7741 while (!childs.empty())
7743 getFolderAccessByIndex((uint32)childs.size()-1)->remove(connection);
7750 // unreference (and update) for vector child Sessions
7751 if (loadSessions(connection, __FILE__, __LINE__))
7753 const std::vector < CSessionPtr > & childs = getSessions();
7755 for (uint i=0; i < childs.size(); ++i)
7758 getSessionsByIndex(i)->setFolderId(0);
7759 getSessionsByIndex(i)->update(connection);
7765 // change the persistant state to 'removed'.
7766 setPersistentState(NOPE::os_removed);
7768 // need to remove ref from parent class container (if any)
7771 CRingUserPtr parent(CRingUser::loadFromCache(_Author, true), __FILE__, __LINE__);
7772 if (parent != NULL && parent->_Folders != NULL)
7775 std::vector < CFolderPtr >::iterator it = std::find(parent->_Folders->begin(), parent->_Folders->end(), this);
7776 if (it != parent->_Folders->end())
7778 parent->_Folders->erase(it);
7784 // need to remove ref from parent (if any)
7787 return true;
7790 return false;
7793 bool CFolder::removeById(MSW::CConnection &connection, uint32 id)
7795 CFolder *object = loadFromCache(id, true);
7796 if (object != NULL)
7798 return object->remove(connection);
7800 // not in cache, run a SQL query
7801 std::string qs;
7802 qs = "DELETE FROM folder ";
7804 qs += " WHERE Id = '"+NLMISC::toString(id)+"'";
7807 if (connection.query(qs))
7809 if (connection.getAffectedRows() == 1)
7811 // ok, the row is removed
7812 return true;
7816 return false;
7820 // Try to load the specified object from the memory cache, return NULL if the object is not in the cache
7821 CFolder *CFolder::loadFromCache(uint32 objectId, bool unrelease)
7823 // look in the cache
7824 TObjectCache::iterator it(_ObjectCache.find(objectId));
7825 if (it == _ObjectCache.end())
7827 // not found, return null
7828 return NULL;
7830 else
7832 CFolder *object = it->second;
7834 if (object->_ObjectState == NOPE::os_released)
7836 if (unrelease)
7838 // we need to remove this object from the released object set.
7839 object->removeFromReleased();
7840 object->_ObjectState = NOPE::os_clean;
7844 return it->second;
7847 // Receive and execute command from the cache manager.
7848 uint32 CFolder::cacheCmd(NOPE::TCacheCmd cmd)
7850 if (cmd == NOPE::cc_update)
7852 updateCache();
7854 else if (cmd == NOPE::cc_clear)
7856 clearCache();
7858 else if (cmd == NOPE::cc_dump)
7860 dump();
7862 else if (cmd == NOPE::cc_instance_count)
7864 return (uint32)_ObjectCache.size();
7867 // default return value
7868 return 0;
7871 void CFolder::dump()
7873 nlinfo(" Cache info for class CFolder :");
7874 nlinfo(" There are %u object instances in cache", _ObjectCache.size());
7876 // count the number of object in the released object set
7877 uint32 nbReleased = 0;
7879 TReleasedObject::iterator first(_ReleasedObject.begin()), last(_ReleasedObject.end());
7880 for (; first != last; ++first)
7882 nbReleased += (uint32)first->second.size();
7885 nlinfo(" There are %u object instances in cache not referenced (waiting deletion or re-use))", nbReleased);
7888 void CFolder::updateCache()
7890 if (_ReleasedObject.empty())
7891 return;
7893 // 30 s hold in cache
7894 const time_t MAX_CACHE_OLD_TIME = 30;
7896 time_t now = NLMISC::CTime::getSecondsSince1970();
7898 // look for object set older than MAX_CACHE_OLD_TIME and delete them
7899 while (!_ReleasedObject.empty() && _ReleasedObject.begin()->first < now-MAX_CACHE_OLD_TIME)
7901 TObjectSet &delSet = _ReleasedObject.begin()->second;
7902 // unload this objects
7903 while (!delSet.empty())
7905 CFolder *object = *delSet.begin();
7906 delete object;
7909 _ReleasedObject.erase(_ReleasedObject.begin());
7913 void CFolder::clearCache()
7915 // remove any unreferenced object from the cache
7916 while (!_ReleasedObject.empty())
7918 TObjectSet &delSet = _ReleasedObject.begin()->second;
7919 // unload this objects
7920 while (!delSet.empty())
7922 CFolder *object = *delSet.begin();
7923 delete object;
7926 _ReleasedObject.erase(_ReleasedObject.begin());
7930 void CFolder::registerUpdatable()
7932 static bool registered = false;
7933 if (!registered)
7935 NOPE::CPersistentCache::getInstance().registerCache(&CFolder::cacheCmd);
7937 registered = true;
7941 // set the pointer on the first pointer of the pointer list (set to null when there is no more pointer)
7942 void CFolder::setFirstPtr(CFolderPtr *ptr)
7944 _PtrList = ptr;
7946 if (ptr == NULL)
7948 // this is the last pointer !
7949 if (_ObjectState == NOPE::os_transient
7950 || _ObjectState == NOPE::os_removed)
7952 // not a persistent object, or removed object, just delet it
7953 delete this;
7955 else if (_ObjectState != NOPE::os_removed)
7957 setPersistentState(NOPE::os_released);
7962 // Set the persistent state of the object and do some house keeping
7963 void CFolder::setPersistentState(NOPE::TObjectState state)
7965 nlassert(NOPE::AllowedTransition[_ObjectState][state] == true);
7967 if(_ObjectState == NOPE::os_released && state == NOPE::os_removed)
7969 // a release object gets removed (e.g. by remove by id)
7971 // delete the object
7972 delete this;
7974 // no more to do
7975 return;
7978 if (_ObjectState == NOPE::os_transient && state != NOPE::os_transient)
7980 nldebug("NOPE: inserting CFolder @%p in cache with id %u", this, static_cast<uint32>(_Id));
7981 nlverify(_ObjectCache.insert(std::make_pair(_Id, this)).second);
7984 if (_ObjectState != NOPE::os_transient)
7985 nlassert(_ObjectCache.find(_Id) != _ObjectCache.end());
7987 _ObjectState = state;
7989 if (state == NOPE::os_released)
7991 _ReleaseDate = NLMISC::CTime::getSecondsSince1970();
7992 nlverify(_ReleasedObject[_ReleaseDate].insert(this).second);
7994 else if (state == NOPE::os_removed)
7996 nldebug("NOPE: erasing CFolder @%p in cache with id %u", this, static_cast<uint32>(_Id));
7997 nlverify(_ObjectCache.erase(_Id) == 1);
8002 CFolderPtr CFolder::load(MSW::CConnection &connection, uint32 id, const char *filename, uint32 lineNum)
8004 CFolder *inCache = loadFromCache(id, true);
8005 if (inCache != NULL)
8007 return CFolderPtr(inCache, filename, lineNum);
8010 std::string qs;
8011 qs = "SELECT ";
8013 qs += "Id, author, title, comments";
8015 qs += " FROM folder";
8017 qs += " WHERE Id = '"+NLMISC::toString(id)+"'";
8018 CFolderPtr ret;
8019 if (!connection.query(qs))
8021 return ret;
8024 MSW::CStoreResult *result = connection.storeResult().release();
8026 nlassert(result->getNumRows() <= 1);
8027 if (result->getNumRows() == 1)
8029 ret.assign(new CFolder, filename, lineNum);
8030 // ok, we have an object
8031 result->fetchRow();
8033 result->getField(0, ret->_Id);
8034 result->getField(1, ret->_Author);
8035 result->getField(2, ret->_Title);
8036 result->getField(3, ret->_Comments);
8039 ret->setPersistentState(NOPE::os_clean);
8042 delete result;
8044 return ret;
8048 bool CFolder::loadChildrenOfCRingUser(MSW::CConnection &connection, uint32 parentId, std::vector < CFolderPtr > & container, const char *filename, uint32 lineNum)
8051 std::string qs;
8052 qs = "SELECT ";
8054 qs += "Id, author, title, comments";
8056 qs += " FROM folder";
8057 qs += " WHERE author = '"+NLMISC::toString(parentId)+"'";
8059 if (!connection.query(qs))
8061 return false;
8064 CUniquePtr<MSW::CStoreResult> result = connection.storeResult();
8066 for (uint i=0; i<result->getNumRows(); ++i)
8068 CFolder *ret = new CFolder();
8069 // ok, we have an object
8070 result->fetchRow();
8072 result->getField(0, ret->_Id);
8074 result->getField(1, ret->_Author);
8076 result->getField(2, ret->_Title);
8078 result->getField(3, ret->_Comments);
8079 CFolder *inCache = loadFromCache(ret->_Id, true);
8080 if (inCache != NULL)
8083 container.push_back(CFolderPtr(inCache, filename, lineNum));
8085 // no more needed
8086 delete ret;
8088 else
8090 ret->setPersistentState(NOPE::os_clean);
8092 container.push_back(CFolderPtr(ret, filename, lineNum));
8097 return true;
8100 bool CFolder::loadFolderAccess(MSW::CConnection &connection, const char *filename, uint32 lineNum)
8102 bool ret = true;
8103 if (_FolderAccess != NULL)
8105 // the children are already loaded, just return true
8106 return true;
8109 // allocate the container
8110 _FolderAccess = new std::vector < CFolderAccessPtr >;
8112 // load the childs
8113 ret &= CFolderAccess::loadChildrenOfCFolder(connection, getObjectId(), *_FolderAccess, filename, lineNum);
8114 return ret;
8118 const std::vector<CFolderAccessPtr> &CFolder::getFolderAccess() const
8120 nlassert(_FolderAccess != NULL);
8121 return *_FolderAccess;
8124 CFolderAccessPtr &CFolder::getFolderAccessByIndex(uint32 index) const
8126 nlassert(_FolderAccess != NULL);
8127 nlassert(index < _FolderAccess->size());
8128 return const_cast< CFolderAccessPtr & >(_FolderAccess->operator[](index));
8131 CFolderAccessPtr &CFolder::getFolderAccessById(uint32 id) const
8133 nlassert(_FolderAccess != NULL);
8134 std::vector<CFolderAccessPtr >::const_iterator first(_FolderAccess->begin()), last(_FolderAccess->end());
8135 for (; first != last; ++first)
8137 const CFolderAccessPtr &child = *first;
8138 if (child->getObjectId() == id)
8140 return const_cast< CFolderAccessPtr & >(child);
8144 // no object with this id, return a null pointer
8145 static CFolderAccessPtr nilPtr;
8147 return nilPtr;
8151 bool CFolder::loadSessions(MSW::CConnection &connection, const char *filename, uint32 lineNum)
8153 bool ret = true;
8154 if (_Sessions != NULL)
8156 // the children are already loaded, just return true
8157 return true;
8160 // allocate the container
8161 _Sessions = new std::vector < CSessionPtr >;
8163 // load the childs
8164 ret &= CSession::loadChildrenOfCFolder(connection, getObjectId(), *_Sessions, filename, lineNum);
8165 return ret;
8169 const std::vector<CSessionPtr> &CFolder::getSessions() const
8171 nlassert(_Sessions != NULL);
8172 return *_Sessions;
8175 CSessionPtr &CFolder::getSessionsByIndex(uint32 index) const
8177 nlassert(_Sessions != NULL);
8178 nlassert(index < _Sessions->size());
8179 return const_cast< CSessionPtr & >(_Sessions->operator[](index));
8182 CSessionPtr &CFolder::getSessionsById(uint32 id) const
8184 nlassert(_Sessions != NULL);
8185 std::vector<CSessionPtr >::const_iterator first(_Sessions->begin()), last(_Sessions->end());
8186 for (; first != last; ++first)
8188 const CSessionPtr &child = *first;
8189 if (child->getObjectId() == id)
8191 return const_cast< CSessionPtr & >(child);
8195 // no object with this id, return a null pointer
8196 static CSessionPtr nilPtr;
8198 return nilPtr;
8202 void CFolderAccessPtr::linkPtr()
8204 nlassert(_NextPtr == NULL);
8205 nlassert(_PrevPtr == NULL);
8206 if (_Ptr != NULL)
8208 _NextPtr = _Ptr->getFirstPtr();
8209 if (_NextPtr != NULL)
8211 _PrevPtr = _NextPtr->_PrevPtr;
8212 _PrevPtr->_NextPtr = this;
8213 _NextPtr->_PrevPtr = this;
8215 else
8217 _NextPtr = this;
8218 _PrevPtr = this;
8219 _Ptr->setFirstPtr(this);
8224 void CFolderAccessPtr::unlinkPtr()
8226 if (_NextPtr == NULL)
8228 nlassert(_PrevPtr == NULL);
8229 return;
8232 if (_Ptr != NULL)
8234 if (_NextPtr == this)
8236 nlassert(_PrevPtr == this);
8237 // last pointer !
8238 _Ptr->setFirstPtr(NULL);
8240 else
8242 if (_Ptr->getFirstPtr() == this)
8244 // the first ptr is the current one, we need to switch to next one
8245 _Ptr->setFirstPtr(_NextPtr);
8250 if (_NextPtr != this)
8252 nlassert(_PrevPtr != this);
8254 _NextPtr->_PrevPtr = _PrevPtr;
8255 _PrevPtr->_NextPtr = _NextPtr;
8257 _NextPtr = NULL;
8258 _PrevPtr = NULL;
8262 CFolderAccess::TObjectCache CFolderAccess::_ObjectCache;
8263 CFolderAccess::TReleasedObject CFolderAccess::_ReleasedObject;
8266 // Destructor, delete any children
8267 CFolderAccess::~CFolderAccess()
8269 // release childs reference
8272 if (_PtrList != NULL)
8274 nlwarning("ERROR : someone try to delete this object, but there are still ptr on it !");
8275 CFolderAccessPtr *ptr = _PtrList;
8278 nlwarning(" Pointer created from '%s', line %u", ptr->_FileName, ptr->_LineNum);
8279 ptr = _PtrList->getNextPtr();
8280 } while(ptr != _PtrList);
8281 nlstop;
8283 // remove object from cache map
8284 if (_Id != NOPE::INVALID_OBJECT_ID
8285 && _ObjectState != NOPE::os_removed
8286 && _ObjectState != NOPE::os_transient)
8288 nldebug("NOPE: clearing CFolderAccess @%p from cache with id %u", this, static_cast<uint32>(_Id));
8289 nlverify(_ObjectCache.erase(_Id) == 1);
8291 else if (_ObjectState != NOPE::os_transient)
8293 nlassert(_ObjectCache.find(_Id) == _ObjectCache.end());
8295 if (_ObjectState == NOPE::os_released)
8297 removeFromReleased();
8299 else
8301 TReleasedObject::iterator it(_ReleasedObject.find(_ReleaseDate));
8302 if (it != _ReleasedObject.end())
8304 nlassert(it->second.find(this) == it->second.end());
8309 void CFolderAccess::removeFromReleased()
8311 TReleasedObject::iterator it(_ReleasedObject.find(_ReleaseDate));
8312 nlassert(it != _ReleasedObject.end());
8313 TObjectSet &os = it->second;
8315 nlverify(os.erase(this) == 1);
8317 // nb : _ReleasedObject time entry are removed by the cache update
8320 bool CFolderAccess::create(MSW::CConnection &connection)
8322 nlassert(getPersistentState() == NOPE::os_transient);
8324 std::string qs;
8325 qs = "INSERT INTO folder_access (";
8327 qs += "folder_id, user_id";
8328 qs += ") VALUES (";
8330 qs += "'"+MSW::escapeString(NLMISC::toString(_FolderId), connection)+"'";
8331 qs += ", ";
8332 qs += "'"+MSW::escapeString(NLMISC::toString(_UserId), connection)+"'";
8334 qs += ")";
8336 if (connection.query(qs))
8338 uint32 _id_ = connection.getLastGeneratedId();
8339 setObjectId(_id_);
8342 setPersistentState(NOPE::os_clean);
8344 // update the parent class instance in cache if any
8346 if (_UserId != 0)
8348 // need to update the parent class child list if it is in the cache
8349 CRingUser *parent = CRingUser::loadFromCache(_UserId, false);
8350 if (parent && parent->_FolderAccess != NULL)
8353 nlassert(std::find(parent->_FolderAccess->begin(), parent->_FolderAccess->end(), CFolderAccessPtr(this, __FILE__, __LINE__)) == parent->_FolderAccess->end());
8354 parent->_FolderAccess->push_back(CFolderAccessPtr(this, __FILE__, __LINE__));
8359 if (_FolderId != 0)
8361 // need to update the parent class child list if it is in the cache
8362 CFolder *parent = CFolder::loadFromCache(_FolderId, false);
8363 if (parent && parent->_FolderAccess != NULL)
8366 nlassert(std::find(parent->_FolderAccess->begin(), parent->_FolderAccess->end(), CFolderAccessPtr(this, __FILE__, __LINE__)) == parent->_FolderAccess->end());
8367 parent->_FolderAccess->push_back(CFolderAccessPtr(this, __FILE__, __LINE__));
8372 return true;
8375 return false;
8378 bool CFolderAccess::update(MSW::CConnection &connection)
8380 nlassert(getPersistentState() == NOPE::os_dirty || getPersistentState() == NOPE::os_clean);
8382 if (getPersistentState() == NOPE::os_clean)
8383 // the object is clean, just ignore the save
8384 return true;
8386 std::string qs;
8387 qs = "UPDATE folder_access SET ";
8389 qs += "folder_id = '"+MSW::escapeString(NLMISC::toString(_FolderId), connection)+"'";
8390 qs += ", ";
8391 qs += "user_id = '"+MSW::escapeString(NLMISC::toString(_UserId), connection)+"'";
8393 qs += " WHERE Id = '"+NLMISC::toString(_Id)+"'";
8396 if (connection.query(qs))
8398 if (connection.getAffectedRows() == 1)
8400 setPersistentState(NOPE::os_clean);
8401 return true;
8405 return false;
8408 bool CFolderAccess::remove(MSW::CConnection &connection)
8410 nlassert(getPersistentState() == NOPE::os_dirty || getPersistentState() == NOPE::os_clean);
8412 std::string qs;
8413 qs = "DELETE FROM folder_access ";
8415 qs += " WHERE Id = '"+NLMISC::toString(_Id)+"'";
8418 if (connection.query(qs))
8420 if (connection.getAffectedRows() == 1)
8424 // change the persistant state to 'removed'.
8425 setPersistentState(NOPE::os_removed);
8427 // need to remove ref from parent class container (if any)
8430 CRingUserPtr parent(CRingUser::loadFromCache(_UserId, true), __FILE__, __LINE__);
8431 if (parent != NULL && parent->_FolderAccess != NULL)
8434 std::vector < CFolderAccessPtr >::iterator it = std::find(parent->_FolderAccess->begin(), parent->_FolderAccess->end(), this);
8435 if (it != parent->_FolderAccess->end())
8437 parent->_FolderAccess->erase(it);
8444 CFolderPtr parent(CFolder::loadFromCache(_FolderId, true), __FILE__, __LINE__);
8445 if (parent != NULL && parent->_FolderAccess != NULL)
8448 std::vector < CFolderAccessPtr >::iterator it = std::find(parent->_FolderAccess->begin(), parent->_FolderAccess->end(), this);
8449 if (it != parent->_FolderAccess->end())
8451 parent->_FolderAccess->erase(it);
8457 // need to remove ref from parent (if any)
8460 return true;
8463 return false;
8466 bool CFolderAccess::removeById(MSW::CConnection &connection, uint32 id)
8468 CFolderAccess *object = loadFromCache(id, true);
8469 if (object != NULL)
8471 return object->remove(connection);
8473 // not in cache, run a SQL query
8474 std::string qs;
8475 qs = "DELETE FROM folder_access ";
8477 qs += " WHERE Id = '"+NLMISC::toString(id)+"'";
8480 if (connection.query(qs))
8482 if (connection.getAffectedRows() == 1)
8484 // ok, the row is removed
8485 return true;
8489 return false;
8493 // Try to load the specified object from the memory cache, return NULL if the object is not in the cache
8494 CFolderAccess *CFolderAccess::loadFromCache(uint32 objectId, bool unrelease)
8496 // look in the cache
8497 TObjectCache::iterator it(_ObjectCache.find(objectId));
8498 if (it == _ObjectCache.end())
8500 // not found, return null
8501 return NULL;
8503 else
8505 CFolderAccess *object = it->second;
8507 if (object->_ObjectState == NOPE::os_released)
8509 if (unrelease)
8511 // we need to remove this object from the released object set.
8512 object->removeFromReleased();
8513 object->_ObjectState = NOPE::os_clean;
8517 return it->second;
8520 // Receive and execute command from the cache manager.
8521 uint32 CFolderAccess::cacheCmd(NOPE::TCacheCmd cmd)
8523 if (cmd == NOPE::cc_update)
8525 updateCache();
8527 else if (cmd == NOPE::cc_clear)
8529 clearCache();
8531 else if (cmd == NOPE::cc_dump)
8533 dump();
8535 else if (cmd == NOPE::cc_instance_count)
8537 return (uint32)_ObjectCache.size();
8540 // default return value
8541 return 0;
8544 void CFolderAccess::dump()
8546 nlinfo(" Cache info for class CFolderAccess :");
8547 nlinfo(" There are %u object instances in cache", _ObjectCache.size());
8549 // count the number of object in the released object set
8550 uint32 nbReleased = 0;
8552 TReleasedObject::iterator first(_ReleasedObject.begin()), last(_ReleasedObject.end());
8553 for (; first != last; ++first)
8555 nbReleased += (uint32)first->second.size();
8558 nlinfo(" There are %u object instances in cache not referenced (waiting deletion or re-use))", nbReleased);
8561 void CFolderAccess::updateCache()
8563 if (_ReleasedObject.empty())
8564 return;
8566 // 30 s hold in cache
8567 const time_t MAX_CACHE_OLD_TIME = 30;
8569 time_t now = NLMISC::CTime::getSecondsSince1970();
8571 // look for object set older than MAX_CACHE_OLD_TIME and delete them
8572 while (!_ReleasedObject.empty() && _ReleasedObject.begin()->first < now-MAX_CACHE_OLD_TIME)
8574 TObjectSet &delSet = _ReleasedObject.begin()->second;
8575 // unload this objects
8576 while (!delSet.empty())
8578 CFolderAccess *object = *delSet.begin();
8579 delete object;
8582 _ReleasedObject.erase(_ReleasedObject.begin());
8586 void CFolderAccess::clearCache()
8588 // remove any unreferenced object from the cache
8589 while (!_ReleasedObject.empty())
8591 TObjectSet &delSet = _ReleasedObject.begin()->second;
8592 // unload this objects
8593 while (!delSet.empty())
8595 CFolderAccess *object = *delSet.begin();
8596 delete object;
8599 _ReleasedObject.erase(_ReleasedObject.begin());
8603 void CFolderAccess::registerUpdatable()
8605 static bool registered = false;
8606 if (!registered)
8608 NOPE::CPersistentCache::getInstance().registerCache(&CFolderAccess::cacheCmd);
8610 registered = true;
8614 // set the pointer on the first pointer of the pointer list (set to null when there is no more pointer)
8615 void CFolderAccess::setFirstPtr(CFolderAccessPtr *ptr)
8617 _PtrList = ptr;
8619 if (ptr == NULL)
8621 // this is the last pointer !
8622 if (_ObjectState == NOPE::os_transient
8623 || _ObjectState == NOPE::os_removed)
8625 // not a persistent object, or removed object, just delet it
8626 delete this;
8628 else if (_ObjectState != NOPE::os_removed)
8630 setPersistentState(NOPE::os_released);
8635 // Set the persistent state of the object and do some house keeping
8636 void CFolderAccess::setPersistentState(NOPE::TObjectState state)
8638 nlassert(NOPE::AllowedTransition[_ObjectState][state] == true);
8640 if(_ObjectState == NOPE::os_released && state == NOPE::os_removed)
8642 // a release object gets removed (e.g. by remove by id)
8644 // delete the object
8645 delete this;
8647 // no more to do
8648 return;
8651 if (_ObjectState == NOPE::os_transient && state != NOPE::os_transient)
8653 nldebug("NOPE: inserting CFolderAccess @%p in cache with id %u", this, static_cast<uint32>(_Id));
8654 nlverify(_ObjectCache.insert(std::make_pair(_Id, this)).second);
8657 if (_ObjectState != NOPE::os_transient)
8658 nlassert(_ObjectCache.find(_Id) != _ObjectCache.end());
8660 _ObjectState = state;
8662 if (state == NOPE::os_released)
8664 _ReleaseDate = NLMISC::CTime::getSecondsSince1970();
8665 nlverify(_ReleasedObject[_ReleaseDate].insert(this).second);
8667 else if (state == NOPE::os_removed)
8669 nldebug("NOPE: erasing CFolderAccess @%p in cache with id %u", this, static_cast<uint32>(_Id));
8670 nlverify(_ObjectCache.erase(_Id) == 1);
8675 CFolderAccessPtr CFolderAccess::load(MSW::CConnection &connection, uint32 id, const char *filename, uint32 lineNum)
8677 CFolderAccess *inCache = loadFromCache(id, true);
8678 if (inCache != NULL)
8680 return CFolderAccessPtr(inCache, filename, lineNum);
8683 std::string qs;
8684 qs = "SELECT ";
8686 qs += "Id, folder_id, user_id";
8688 qs += " FROM folder_access";
8690 qs += " WHERE Id = '"+NLMISC::toString(id)+"'";
8691 CFolderAccessPtr ret;
8692 if (!connection.query(qs))
8694 return ret;
8697 MSW::CStoreResult *result = connection.storeResult().release();
8699 nlassert(result->getNumRows() <= 1);
8700 if (result->getNumRows() == 1)
8702 ret.assign(new CFolderAccess, filename, lineNum);
8703 // ok, we have an object
8704 result->fetchRow();
8706 result->getField(0, ret->_Id);
8707 result->getField(1, ret->_FolderId);
8708 result->getField(2, ret->_UserId);
8711 ret->setPersistentState(NOPE::os_clean);
8714 delete result;
8716 return ret;
8720 bool CFolderAccess::loadChildrenOfCRingUser(MSW::CConnection &connection, uint32 parentId, std::vector < CFolderAccessPtr > & container, const char *filename, uint32 lineNum)
8723 std::string qs;
8724 qs = "SELECT ";
8726 qs += "Id, folder_id, user_id";
8728 qs += " FROM folder_access";
8729 qs += " WHERE user_id = '"+NLMISC::toString(parentId)+"'";
8731 if (!connection.query(qs))
8733 return false;
8736 CUniquePtr<MSW::CStoreResult> result = connection.storeResult();
8738 for (uint i=0; i<result->getNumRows(); ++i)
8740 CFolderAccess *ret = new CFolderAccess();
8741 // ok, we have an object
8742 result->fetchRow();
8744 result->getField(0, ret->_Id);
8746 result->getField(1, ret->_FolderId);
8748 result->getField(2, ret->_UserId);
8749 CFolderAccess *inCache = loadFromCache(ret->_Id, true);
8750 if (inCache != NULL)
8753 container.push_back(CFolderAccessPtr(inCache, filename, lineNum));
8755 // no more needed
8756 delete ret;
8758 else
8760 ret->setPersistentState(NOPE::os_clean);
8762 container.push_back(CFolderAccessPtr(ret, filename, lineNum));
8767 return true;
8770 bool CFolderAccess::loadChildrenOfCFolder(MSW::CConnection &connection, uint32 parentId, std::vector < CFolderAccessPtr > & container, const char *filename, uint32 lineNum)
8773 std::string qs;
8774 qs = "SELECT ";
8776 qs += "Id, folder_id, user_id";
8778 qs += " FROM folder_access";
8779 qs += " WHERE folder_id = '"+NLMISC::toString(parentId)+"'";
8781 if (!connection.query(qs))
8783 return false;
8786 CUniquePtr<MSW::CStoreResult> result = connection.storeResult();
8788 for (uint i=0; i<result->getNumRows(); ++i)
8790 CFolderAccess *ret = new CFolderAccess();
8791 // ok, we have an object
8792 result->fetchRow();
8794 result->getField(0, ret->_Id);
8796 result->getField(1, ret->_FolderId);
8798 result->getField(2, ret->_UserId);
8799 CFolderAccess *inCache = loadFromCache(ret->_Id, true);
8800 if (inCache != NULL)
8803 container.push_back(CFolderAccessPtr(inCache, filename, lineNum));
8805 // no more needed
8806 delete ret;
8808 else
8810 ret->setPersistentState(NOPE::os_clean);
8812 container.push_back(CFolderAccessPtr(ret, filename, lineNum));
8817 return true;
8820 void CScenarioPtr::linkPtr()
8822 nlassert(_NextPtr == NULL);
8823 nlassert(_PrevPtr == NULL);
8824 if (_Ptr != NULL)
8826 _NextPtr = _Ptr->getFirstPtr();
8827 if (_NextPtr != NULL)
8829 _PrevPtr = _NextPtr->_PrevPtr;
8830 _PrevPtr->_NextPtr = this;
8831 _NextPtr->_PrevPtr = this;
8833 else
8835 _NextPtr = this;
8836 _PrevPtr = this;
8837 _Ptr->setFirstPtr(this);
8842 void CScenarioPtr::unlinkPtr()
8844 if (_NextPtr == NULL)
8846 nlassert(_PrevPtr == NULL);
8847 return;
8850 if (_Ptr != NULL)
8852 if (_NextPtr == this)
8854 nlassert(_PrevPtr == this);
8855 // last pointer !
8856 _Ptr->setFirstPtr(NULL);
8858 else
8860 if (_Ptr->getFirstPtr() == this)
8862 // the first ptr is the current one, we need to switch to next one
8863 _Ptr->setFirstPtr(_NextPtr);
8868 if (_NextPtr != this)
8870 nlassert(_PrevPtr != this);
8872 _NextPtr->_PrevPtr = _PrevPtr;
8873 _PrevPtr->_NextPtr = _NextPtr;
8875 _NextPtr = NULL;
8876 _PrevPtr = NULL;
8880 CScenario::TObjectCache CScenario::_ObjectCache;
8881 CScenario::TReleasedObject CScenario::_ReleasedObject;
8884 // Destructor, delete any children
8885 CScenario::~CScenario()
8887 // release childs reference
8888 if (_SessionLogs != NULL)
8889 delete _SessionLogs;
8890 if (_PlayerRatings != NULL)
8891 delete _PlayerRatings;
8894 if (_PtrList != NULL)
8896 nlwarning("ERROR : someone try to delete this object, but there are still ptr on it !");
8897 CScenarioPtr *ptr = _PtrList;
8900 nlwarning(" Pointer created from '%s', line %u", ptr->_FileName, ptr->_LineNum);
8901 ptr = _PtrList->getNextPtr();
8902 } while(ptr != _PtrList);
8903 nlstop;
8905 // remove object from cache map
8906 if (_Id != NOPE::INVALID_OBJECT_ID
8907 && _ObjectState != NOPE::os_removed
8908 && _ObjectState != NOPE::os_transient)
8910 nldebug("NOPE: clearing CScenario @%p from cache with id %u", this, static_cast<uint32>(_Id));
8911 nlverify(_ObjectCache.erase(_Id) == 1);
8913 else if (_ObjectState != NOPE::os_transient)
8915 nlassert(_ObjectCache.find(_Id) == _ObjectCache.end());
8917 if (_ObjectState == NOPE::os_released)
8919 removeFromReleased();
8921 else
8923 TReleasedObject::iterator it(_ReleasedObject.find(_ReleaseDate));
8924 if (it != _ReleasedObject.end())
8926 nlassert(it->second.find(this) == it->second.end());
8931 void CScenario::removeFromReleased()
8933 TReleasedObject::iterator it(_ReleasedObject.find(_ReleaseDate));
8934 nlassert(it != _ReleasedObject.end());
8935 TObjectSet &os = it->second;
8937 nlverify(os.erase(this) == 1);
8939 // nb : _ReleasedObject time entry are removed by the cache update
8942 bool CScenario::create(MSW::CConnection &connection)
8944 nlassert(getPersistentState() == NOPE::os_transient);
8946 std::string qs;
8947 qs = "INSERT INTO scenario (";
8949 qs += "md5, title, description, author, rrp_total, anim_mode, language, orientation, level, allow_free_trial";
8950 qs += ") VALUES (";
8952 qs += "'"+MSW::escapeString(_MD5.toString(), connection)+"'";
8953 qs += ", ";
8954 qs += "'"+MSW::escapeString(NLMISC::toString(_Title), connection)+"'";
8955 qs += ", ";
8956 qs += "'"+MSW::escapeString(NLMISC::toString(_Description), connection)+"'";
8957 qs += ", ";
8958 qs += "'"+MSW::escapeString(NLMISC::toString(_Author), connection)+"'";
8959 qs += ", ";
8960 qs += "'"+MSW::escapeString(NLMISC::toString(_RRPTotal), connection)+"'";
8961 qs += ", ";
8962 qs += _AnimMode.isValid()
8963 ? "'"+_AnimMode.toString()+"'"
8964 : "DEFAULT(anim_mode)";
8965 qs += ", ";
8966 qs += "'"+MSW::escapeString(NLMISC::toString(_Language), connection)+"'";
8967 qs += ", ";
8968 qs += _Orientation.isValid()
8969 ? "'"+_Orientation.toString()+"'"
8970 : "DEFAULT(orientation)";
8971 qs += ", ";
8972 qs += _Level.isValid()
8973 ? "'"+_Level.toString()+"'"
8974 : "DEFAULT(level)";
8975 qs += ", ";
8976 qs += "'"+MSW::escapeString(NLMISC::toString(_AllowFreeTrial), connection)+"'";
8978 qs += ")";
8980 if (connection.query(qs))
8982 uint32 _id_ = connection.getLastGeneratedId();
8983 setObjectId(_id_);
8986 setPersistentState(NOPE::os_clean);
8988 // update the parent class instance in cache if any
8990 return true;
8993 return false;
8996 bool CScenario::update(MSW::CConnection &connection)
8998 nlassert(getPersistentState() == NOPE::os_dirty || getPersistentState() == NOPE::os_clean);
9000 if (getPersistentState() == NOPE::os_clean)
9001 // the object is clean, just ignore the save
9002 return true;
9004 std::string qs;
9005 qs = "UPDATE scenario SET ";
9007 qs += "md5 = '"+MSW::escapeString(_MD5.toString(), connection)+"'";
9008 qs += ", ";
9009 qs += "title = '"+MSW::escapeString(NLMISC::toString(_Title), connection)+"'";
9010 qs += ", ";
9011 qs += "description = '"+MSW::escapeString(NLMISC::toString(_Description), connection)+"'";
9012 qs += ", ";
9013 qs += "author = '"+MSW::escapeString(NLMISC::toString(_Author), connection)+"'";
9014 qs += ", ";
9015 qs += "rrp_total = '"+MSW::escapeString(NLMISC::toString(_RRPTotal), connection)+"'";
9016 qs += ", ";
9017 qs += "anim_mode = " + (_AnimMode.isValid()
9018 ? "'"+_AnimMode.toString()+"'"
9019 : "DEFAULT(anim_mode)");
9020 qs += ", ";
9021 qs += "language = '"+MSW::escapeString(NLMISC::toString(_Language), connection)+"'";
9022 qs += ", ";
9023 qs += "orientation = " + (_Orientation.isValid()
9024 ? "'"+_Orientation.toString()+"'"
9025 : "DEFAULT(orientation)");
9026 qs += ", ";
9027 qs += "level = " + (_Level.isValid()
9028 ? "'"+_Level.toString()+"'"
9029 : "DEFAULT(level)");
9030 qs += ", ";
9031 qs += "allow_free_trial = '"+MSW::escapeString(NLMISC::toString(_AllowFreeTrial), connection)+"'";
9033 qs += " WHERE id = '"+NLMISC::toString(_Id)+"'";
9036 if (connection.query(qs))
9038 if (connection.getAffectedRows() == 1)
9040 setPersistentState(NOPE::os_clean);
9041 return true;
9045 return false;
9048 bool CScenario::remove(MSW::CConnection &connection)
9050 nlassert(getPersistentState() == NOPE::os_dirty || getPersistentState() == NOPE::os_clean);
9052 std::string qs;
9053 qs = "DELETE FROM scenario ";
9055 qs += " WHERE id = '"+NLMISC::toString(_Id)+"'";
9058 if (connection.query(qs))
9060 if (connection.getAffectedRows() == 1)
9064 // cascading deletion for vector child SessionLogs
9065 if (loadSessionLogs(connection, __FILE__, __LINE__))
9067 const std::vector < CSessionLogPtr > & childs = getSessionLogs();
9069 while (!childs.empty())
9071 getSessionLogsByIndex((uint32)childs.size()-1)->remove(connection);
9078 // cascading deletion for vector child PlayerRatings
9079 if (loadPlayerRatings(connection, __FILE__, __LINE__))
9081 const std::vector < CPlayerRatingPtr > & childs = getPlayerRatings();
9083 while (!childs.empty())
9085 getPlayerRatingsByIndex((uint32)childs.size()-1)->remove(connection);
9092 // change the persistant state to 'removed'.
9093 setPersistentState(NOPE::os_removed);
9095 // need to remove ref from parent class container (if any)
9097 // need to remove ref from parent (if any)
9100 return true;
9103 return false;
9106 bool CScenario::removeById(MSW::CConnection &connection, uint32 id)
9108 CScenario *object = loadFromCache(id, true);
9109 if (object != NULL)
9111 return object->remove(connection);
9113 // not in cache, run a SQL query
9114 std::string qs;
9115 qs = "DELETE FROM scenario ";
9117 qs += " WHERE id = '"+NLMISC::toString(id)+"'";
9120 if (connection.query(qs))
9122 if (connection.getAffectedRows() == 1)
9124 // ok, the row is removed
9125 return true;
9129 return false;
9133 // Try to load the specified object from the memory cache, return NULL if the object is not in the cache
9134 CScenario *CScenario::loadFromCache(uint32 objectId, bool unrelease)
9136 // look in the cache
9137 TObjectCache::iterator it(_ObjectCache.find(objectId));
9138 if (it == _ObjectCache.end())
9140 // not found, return null
9141 return NULL;
9143 else
9145 CScenario *object = it->second;
9147 if (object->_ObjectState == NOPE::os_released)
9149 if (unrelease)
9151 // we need to remove this object from the released object set.
9152 object->removeFromReleased();
9153 object->_ObjectState = NOPE::os_clean;
9157 return it->second;
9160 // Receive and execute command from the cache manager.
9161 uint32 CScenario::cacheCmd(NOPE::TCacheCmd cmd)
9163 if (cmd == NOPE::cc_update)
9165 updateCache();
9167 else if (cmd == NOPE::cc_clear)
9169 clearCache();
9171 else if (cmd == NOPE::cc_dump)
9173 dump();
9175 else if (cmd == NOPE::cc_instance_count)
9177 return (uint32)_ObjectCache.size();
9180 // default return value
9181 return 0;
9184 void CScenario::dump()
9186 nlinfo(" Cache info for class CScenario :");
9187 nlinfo(" There are %u object instances in cache", _ObjectCache.size());
9189 // count the number of object in the released object set
9190 uint32 nbReleased = 0;
9192 TReleasedObject::iterator first(_ReleasedObject.begin()), last(_ReleasedObject.end());
9193 for (; first != last; ++first)
9195 nbReleased += (uint32)first->second.size();
9198 nlinfo(" There are %u object instances in cache not referenced (waiting deletion or re-use))", nbReleased);
9201 void CScenario::updateCache()
9203 if (_ReleasedObject.empty())
9204 return;
9206 // 30 s hold in cache
9207 const time_t MAX_CACHE_OLD_TIME = 30;
9209 time_t now = NLMISC::CTime::getSecondsSince1970();
9211 // look for object set older than MAX_CACHE_OLD_TIME and delete them
9212 while (!_ReleasedObject.empty() && _ReleasedObject.begin()->first < now-MAX_CACHE_OLD_TIME)
9214 TObjectSet &delSet = _ReleasedObject.begin()->second;
9215 // unload this objects
9216 while (!delSet.empty())
9218 CScenario *object = *delSet.begin();
9219 delete object;
9222 _ReleasedObject.erase(_ReleasedObject.begin());
9226 void CScenario::clearCache()
9228 // remove any unreferenced object from the cache
9229 while (!_ReleasedObject.empty())
9231 TObjectSet &delSet = _ReleasedObject.begin()->second;
9232 // unload this objects
9233 while (!delSet.empty())
9235 CScenario *object = *delSet.begin();
9236 delete object;
9239 _ReleasedObject.erase(_ReleasedObject.begin());
9243 void CScenario::registerUpdatable()
9245 static bool registered = false;
9246 if (!registered)
9248 NOPE::CPersistentCache::getInstance().registerCache(&CScenario::cacheCmd);
9250 registered = true;
9254 // set the pointer on the first pointer of the pointer list (set to null when there is no more pointer)
9255 void CScenario::setFirstPtr(CScenarioPtr *ptr)
9257 _PtrList = ptr;
9259 if (ptr == NULL)
9261 // this is the last pointer !
9262 if (_ObjectState == NOPE::os_transient
9263 || _ObjectState == NOPE::os_removed)
9265 // not a persistent object, or removed object, just delet it
9266 delete this;
9268 else if (_ObjectState != NOPE::os_removed)
9270 setPersistentState(NOPE::os_released);
9275 // Set the persistent state of the object and do some house keeping
9276 void CScenario::setPersistentState(NOPE::TObjectState state)
9278 nlassert(NOPE::AllowedTransition[_ObjectState][state] == true);
9280 if(_ObjectState == NOPE::os_released && state == NOPE::os_removed)
9282 // a release object gets removed (e.g. by remove by id)
9284 // delete the object
9285 delete this;
9287 // no more to do
9288 return;
9291 if (_ObjectState == NOPE::os_transient && state != NOPE::os_transient)
9293 nldebug("NOPE: inserting CScenario @%p in cache with id %u", this, static_cast<uint32>(_Id));
9294 nlverify(_ObjectCache.insert(std::make_pair(_Id, this)).second);
9297 if (_ObjectState != NOPE::os_transient)
9298 nlassert(_ObjectCache.find(_Id) != _ObjectCache.end());
9300 _ObjectState = state;
9302 if (state == NOPE::os_released)
9304 _ReleaseDate = NLMISC::CTime::getSecondsSince1970();
9305 nlverify(_ReleasedObject[_ReleaseDate].insert(this).second);
9307 else if (state == NOPE::os_removed)
9309 nldebug("NOPE: erasing CScenario @%p in cache with id %u", this, static_cast<uint32>(_Id));
9310 nlverify(_ObjectCache.erase(_Id) == 1);
9315 CScenarioPtr CScenario::load(MSW::CConnection &connection, uint32 id, const char *filename, uint32 lineNum)
9317 CScenario *inCache = loadFromCache(id, true);
9318 if (inCache != NULL)
9320 return CScenarioPtr(inCache, filename, lineNum);
9323 std::string qs;
9324 qs = "SELECT ";
9326 qs += "id, md5, title, description, author, rrp_total, anim_mode, language, orientation, level, allow_free_trial";
9328 qs += " FROM scenario";
9330 qs += " WHERE id = '"+NLMISC::toString(id)+"'";
9331 CScenarioPtr ret;
9332 if (!connection.query(qs))
9334 return ret;
9337 MSW::CStoreResult *result = connection.storeResult().release();
9339 nlassert(result->getNumRows() <= 1);
9340 if (result->getNumRows() == 1)
9342 ret.assign(new CScenario, filename, lineNum);
9343 // ok, we have an object
9344 result->fetchRow();
9346 result->getField(0, ret->_Id);
9347 result->getMD5Field(1, ret->_MD5);
9348 result->getField(2, ret->_Title);
9349 result->getField(3, ret->_Description);
9350 result->getField(4, ret->_Author);
9351 result->getField(5, ret->_RRPTotal);
9353 std::string s;
9354 result->getField(6, s);
9355 ret->_AnimMode = TAnimMode(s);
9357 result->getField(7, ret->_Language);
9359 std::string s;
9360 result->getField(8, s);
9361 ret->_Orientation = TSessionOrientation(s);
9364 std::string s;
9365 result->getField(9, s);
9366 ret->_Level = R2::TSessionLevel(s);
9368 result->getField(10, ret->_AllowFreeTrial);
9371 ret->setPersistentState(NOPE::os_clean);
9374 delete result;
9376 return ret;
9380 bool CScenario::loadSessionLogs(MSW::CConnection &connection, const char *filename, uint32 lineNum)
9382 bool ret = true;
9383 if (_SessionLogs != NULL)
9385 // the children are already loaded, just return true
9386 return true;
9389 // allocate the container
9390 _SessionLogs = new std::vector < CSessionLogPtr >;
9392 // load the childs
9393 ret &= CSessionLog::loadChildrenOfCScenario(connection, getObjectId(), *_SessionLogs, filename, lineNum);
9394 return ret;
9398 const std::vector<CSessionLogPtr> &CScenario::getSessionLogs() const
9400 nlassert(_SessionLogs != NULL);
9401 return *_SessionLogs;
9404 CSessionLogPtr &CScenario::getSessionLogsByIndex(uint32 index) const
9406 nlassert(_SessionLogs != NULL);
9407 nlassert(index < _SessionLogs->size());
9408 return const_cast< CSessionLogPtr & >(_SessionLogs->operator[](index));
9411 CSessionLogPtr &CScenario::getSessionLogsById(uint32 id) const
9413 nlassert(_SessionLogs != NULL);
9414 std::vector<CSessionLogPtr >::const_iterator first(_SessionLogs->begin()), last(_SessionLogs->end());
9415 for (; first != last; ++first)
9417 const CSessionLogPtr &child = *first;
9418 if (child->getObjectId() == id)
9420 return const_cast< CSessionLogPtr & >(child);
9424 // no object with this id, return a null pointer
9425 static CSessionLogPtr nilPtr;
9427 return nilPtr;
9431 bool CScenario::loadPlayerRatings(MSW::CConnection &connection, const char *filename, uint32 lineNum)
9433 bool ret = true;
9434 if (_PlayerRatings != NULL)
9436 // the children are already loaded, just return true
9437 return true;
9440 // allocate the container
9441 _PlayerRatings = new std::vector < CPlayerRatingPtr >;
9443 // load the childs
9444 ret &= CPlayerRating::loadChildrenOfCScenario(connection, getObjectId(), *_PlayerRatings, filename, lineNum);
9445 return ret;
9449 const std::vector<CPlayerRatingPtr> &CScenario::getPlayerRatings() const
9451 nlassert(_PlayerRatings != NULL);
9452 return *_PlayerRatings;
9455 CPlayerRatingPtr &CScenario::getPlayerRatingsByIndex(uint32 index) const
9457 nlassert(_PlayerRatings != NULL);
9458 nlassert(index < _PlayerRatings->size());
9459 return const_cast< CPlayerRatingPtr & >(_PlayerRatings->operator[](index));
9462 CPlayerRatingPtr &CScenario::getPlayerRatingsById(uint32 id) const
9464 nlassert(_PlayerRatings != NULL);
9465 std::vector<CPlayerRatingPtr >::const_iterator first(_PlayerRatings->begin()), last(_PlayerRatings->end());
9466 for (; first != last; ++first)
9468 const CPlayerRatingPtr &child = *first;
9469 if (child->getObjectId() == id)
9471 return const_cast< CPlayerRatingPtr & >(child);
9475 // no object with this id, return a null pointer
9476 static CPlayerRatingPtr nilPtr;
9478 return nilPtr;
9482 void CSessionLogPtr::linkPtr()
9484 nlassert(_NextPtr == NULL);
9485 nlassert(_PrevPtr == NULL);
9486 if (_Ptr != NULL)
9488 _NextPtr = _Ptr->getFirstPtr();
9489 if (_NextPtr != NULL)
9491 _PrevPtr = _NextPtr->_PrevPtr;
9492 _PrevPtr->_NextPtr = this;
9493 _NextPtr->_PrevPtr = this;
9495 else
9497 _NextPtr = this;
9498 _PrevPtr = this;
9499 _Ptr->setFirstPtr(this);
9504 void CSessionLogPtr::unlinkPtr()
9506 if (_NextPtr == NULL)
9508 nlassert(_PrevPtr == NULL);
9509 return;
9512 if (_Ptr != NULL)
9514 if (_NextPtr == this)
9516 nlassert(_PrevPtr == this);
9517 // last pointer !
9518 _Ptr->setFirstPtr(NULL);
9520 else
9522 if (_Ptr->getFirstPtr() == this)
9524 // the first ptr is the current one, we need to switch to next one
9525 _Ptr->setFirstPtr(_NextPtr);
9530 if (_NextPtr != this)
9532 nlassert(_PrevPtr != this);
9534 _NextPtr->_PrevPtr = _PrevPtr;
9535 _PrevPtr->_NextPtr = _NextPtr;
9537 _NextPtr = NULL;
9538 _PrevPtr = NULL;
9542 CSessionLog::TObjectCache CSessionLog::_ObjectCache;
9543 CSessionLog::TReleasedObject CSessionLog::_ReleasedObject;
9546 // Destructor, delete any children
9547 CSessionLog::~CSessionLog()
9549 // release childs reference
9552 if (_PtrList != NULL)
9554 nlwarning("ERROR : someone try to delete this object, but there are still ptr on it !");
9555 CSessionLogPtr *ptr = _PtrList;
9558 nlwarning(" Pointer created from '%s', line %u", ptr->_FileName, ptr->_LineNum);
9559 ptr = _PtrList->getNextPtr();
9560 } while(ptr != _PtrList);
9561 nlstop;
9563 // remove object from cache map
9564 if (_Id != NOPE::INVALID_OBJECT_ID
9565 && _ObjectState != NOPE::os_removed
9566 && _ObjectState != NOPE::os_transient)
9568 nldebug("NOPE: clearing CSessionLog @%p from cache with id %u", this, static_cast<uint32>(_Id));
9569 nlverify(_ObjectCache.erase(_Id) == 1);
9571 else if (_ObjectState != NOPE::os_transient)
9573 nlassert(_ObjectCache.find(_Id) == _ObjectCache.end());
9575 if (_ObjectState == NOPE::os_released)
9577 removeFromReleased();
9579 else
9581 TReleasedObject::iterator it(_ReleasedObject.find(_ReleaseDate));
9582 if (it != _ReleasedObject.end())
9584 nlassert(it->second.find(this) == it->second.end());
9589 void CSessionLog::removeFromReleased()
9591 TReleasedObject::iterator it(_ReleasedObject.find(_ReleaseDate));
9592 nlassert(it != _ReleasedObject.end());
9593 TObjectSet &os = it->second;
9595 nlverify(os.erase(this) == 1);
9597 // nb : _ReleasedObject time entry are removed by the cache update
9600 bool CSessionLog::create(MSW::CConnection &connection)
9602 nlassert(getPersistentState() == NOPE::os_transient);
9604 nlassert(_Id != 0);
9605 std::string qs;
9606 qs = "INSERT INTO session_log (";
9608 qs += "id, scenario_id, rrp_scored, scenario_point_scored, time_taken, participants, launch_date, owner, guild_name";
9609 qs += ") VALUES (";
9611 qs += "'"+MSW::escapeString(NLMISC::toString(_Id), connection)+"'";
9612 qs += ", ";
9613 qs += "'"+MSW::escapeString(NLMISC::toString(_ScenarioId), connection)+"'";
9614 qs += ", ";
9615 qs += "'"+MSW::escapeString(NLMISC::toString(_RRPScored), connection)+"'";
9616 qs += ", ";
9617 qs += "'"+MSW::escapeString(NLMISC::toString(_ScenarioPointScored), connection)+"'";
9618 qs += ", ";
9619 qs += "'"+MSW::escapeString(NLMISC::toString(_TimeTaken), connection)+"'";
9620 qs += ", ";
9621 qs += "'"+MSW::escapeString(NLMISC::toString(_Participants), connection)+"'";
9622 qs += ", ";
9623 qs += "'"+MSW::encodeDate(_LaunchDate)+"'";
9624 qs += ", ";
9625 qs += "'"+MSW::escapeString(NLMISC::toString(_Owner), connection)+"'";
9626 qs += ", ";
9627 qs += "'"+MSW::escapeString(NLMISC::toString(_GuildName), connection)+"'";
9629 qs += ")";
9631 if (connection.query(qs))
9635 setPersistentState(NOPE::os_clean);
9637 // update the parent class instance in cache if any
9639 if (_ScenarioId != 0)
9641 // need to update the parent class child list if it is in the cache
9642 CScenario *parent = CScenario::loadFromCache(_ScenarioId, false);
9643 if (parent && parent->_SessionLogs != NULL)
9646 nlassert(std::find(parent->_SessionLogs->begin(), parent->_SessionLogs->end(), CSessionLogPtr(this, __FILE__, __LINE__)) == parent->_SessionLogs->end());
9647 parent->_SessionLogs->push_back(CSessionLogPtr(this, __FILE__, __LINE__));
9652 return true;
9655 return false;
9658 bool CSessionLog::update(MSW::CConnection &connection)
9660 nlassert(getPersistentState() == NOPE::os_dirty || getPersistentState() == NOPE::os_clean);
9662 if (getPersistentState() == NOPE::os_clean)
9663 // the object is clean, just ignore the save
9664 return true;
9666 std::string qs;
9667 qs = "UPDATE session_log SET ";
9669 qs += "id = '"+MSW::escapeString(NLMISC::toString(_Id), connection)+"'";
9670 qs += ", ";
9671 qs += "scenario_id = '"+MSW::escapeString(NLMISC::toString(_ScenarioId), connection)+"'";
9672 qs += ", ";
9673 qs += "rrp_scored = '"+MSW::escapeString(NLMISC::toString(_RRPScored), connection)+"'";
9674 qs += ", ";
9675 qs += "scenario_point_scored = '"+MSW::escapeString(NLMISC::toString(_ScenarioPointScored), connection)+"'";
9676 qs += ", ";
9677 qs += "time_taken = '"+MSW::escapeString(NLMISC::toString(_TimeTaken), connection)+"'";
9678 qs += ", ";
9679 qs += "participants = '"+MSW::escapeString(NLMISC::toString(_Participants), connection)+"'";
9680 qs += ", ";
9681 qs += "launch_date = '"+MSW::encodeDate(_LaunchDate)+"'";
9682 qs += ", ";
9683 qs += "owner = '"+MSW::escapeString(NLMISC::toString(_Owner), connection)+"'";
9684 qs += ", ";
9685 qs += "guild_name = '"+MSW::escapeString(NLMISC::toString(_GuildName), connection)+"'";
9687 qs += " WHERE id = '"+NLMISC::toString(_Id)+"'";
9690 if (connection.query(qs))
9692 if (connection.getAffectedRows() == 1)
9694 setPersistentState(NOPE::os_clean);
9695 return true;
9699 return false;
9702 bool CSessionLog::remove(MSW::CConnection &connection)
9704 nlassert(getPersistentState() == NOPE::os_dirty || getPersistentState() == NOPE::os_clean);
9706 std::string qs;
9707 qs = "DELETE FROM session_log ";
9709 qs += " WHERE id = '"+NLMISC::toString(_Id)+"'";
9712 if (connection.query(qs))
9714 if (connection.getAffectedRows() == 1)
9718 // change the persistant state to 'removed'.
9719 setPersistentState(NOPE::os_removed);
9721 // need to remove ref from parent class container (if any)
9724 CScenarioPtr parent(CScenario::loadFromCache(_ScenarioId, true), __FILE__, __LINE__);
9725 if (parent != NULL && parent->_SessionLogs != NULL)
9728 std::vector < CSessionLogPtr >::iterator it = std::find(parent->_SessionLogs->begin(), parent->_SessionLogs->end(), this);
9729 if (it != parent->_SessionLogs->end())
9731 parent->_SessionLogs->erase(it);
9737 // need to remove ref from parent (if any)
9740 return true;
9743 return false;
9746 bool CSessionLog::removeById(MSW::CConnection &connection, uint32 id)
9748 CSessionLog *object = loadFromCache(id, true);
9749 if (object != NULL)
9751 return object->remove(connection);
9753 // not in cache, run a SQL query
9754 std::string qs;
9755 qs = "DELETE FROM session_log ";
9757 qs += " WHERE id = '"+NLMISC::toString(id)+"'";
9760 if (connection.query(qs))
9762 if (connection.getAffectedRows() == 1)
9764 // ok, the row is removed
9765 return true;
9769 return false;
9773 // Try to load the specified object from the memory cache, return NULL if the object is not in the cache
9774 CSessionLog *CSessionLog::loadFromCache(uint32 objectId, bool unrelease)
9776 // look in the cache
9777 TObjectCache::iterator it(_ObjectCache.find(objectId));
9778 if (it == _ObjectCache.end())
9780 // not found, return null
9781 return NULL;
9783 else
9785 CSessionLog *object = it->second;
9787 if (object->_ObjectState == NOPE::os_released)
9789 if (unrelease)
9791 // we need to remove this object from the released object set.
9792 object->removeFromReleased();
9793 object->_ObjectState = NOPE::os_clean;
9797 return it->second;
9800 // Receive and execute command from the cache manager.
9801 uint32 CSessionLog::cacheCmd(NOPE::TCacheCmd cmd)
9803 if (cmd == NOPE::cc_update)
9805 updateCache();
9807 else if (cmd == NOPE::cc_clear)
9809 clearCache();
9811 else if (cmd == NOPE::cc_dump)
9813 dump();
9815 else if (cmd == NOPE::cc_instance_count)
9817 return (uint32)_ObjectCache.size();
9820 // default return value
9821 return 0;
9824 void CSessionLog::dump()
9826 nlinfo(" Cache info for class CSessionLog :");
9827 nlinfo(" There are %u object instances in cache", _ObjectCache.size());
9829 // count the number of object in the released object set
9830 uint32 nbReleased = 0;
9832 TReleasedObject::iterator first(_ReleasedObject.begin()), last(_ReleasedObject.end());
9833 for (; first != last; ++first)
9835 nbReleased += (uint32)first->second.size();
9838 nlinfo(" There are %u object instances in cache not referenced (waiting deletion or re-use))", nbReleased);
9841 void CSessionLog::updateCache()
9843 if (_ReleasedObject.empty())
9844 return;
9846 // 30 s hold in cache
9847 const time_t MAX_CACHE_OLD_TIME = 30;
9849 time_t now = NLMISC::CTime::getSecondsSince1970();
9851 // look for object set older than MAX_CACHE_OLD_TIME and delete them
9852 while (!_ReleasedObject.empty() && _ReleasedObject.begin()->first < now-MAX_CACHE_OLD_TIME)
9854 TObjectSet &delSet = _ReleasedObject.begin()->second;
9855 // unload this objects
9856 while (!delSet.empty())
9858 CSessionLog *object = *delSet.begin();
9859 delete object;
9862 _ReleasedObject.erase(_ReleasedObject.begin());
9866 void CSessionLog::clearCache()
9868 // remove any unreferenced object from the cache
9869 while (!_ReleasedObject.empty())
9871 TObjectSet &delSet = _ReleasedObject.begin()->second;
9872 // unload this objects
9873 while (!delSet.empty())
9875 CSessionLog *object = *delSet.begin();
9876 delete object;
9879 _ReleasedObject.erase(_ReleasedObject.begin());
9883 void CSessionLog::registerUpdatable()
9885 static bool registered = false;
9886 if (!registered)
9888 NOPE::CPersistentCache::getInstance().registerCache(&CSessionLog::cacheCmd);
9890 registered = true;
9894 // set the pointer on the first pointer of the pointer list (set to null when there is no more pointer)
9895 void CSessionLog::setFirstPtr(CSessionLogPtr *ptr)
9897 _PtrList = ptr;
9899 if (ptr == NULL)
9901 // this is the last pointer !
9902 if (_ObjectState == NOPE::os_transient
9903 || _ObjectState == NOPE::os_removed)
9905 // not a persistent object, or removed object, just delet it
9906 delete this;
9908 else if (_ObjectState != NOPE::os_removed)
9910 setPersistentState(NOPE::os_released);
9915 // Set the persistent state of the object and do some house keeping
9916 void CSessionLog::setPersistentState(NOPE::TObjectState state)
9918 nlassert(NOPE::AllowedTransition[_ObjectState][state] == true);
9920 if(_ObjectState == NOPE::os_released && state == NOPE::os_removed)
9922 // a release object gets removed (e.g. by remove by id)
9924 // delete the object
9925 delete this;
9927 // no more to do
9928 return;
9931 if (_ObjectState == NOPE::os_transient && state != NOPE::os_transient)
9933 nldebug("NOPE: inserting CSessionLog @%p in cache with id %u", this, static_cast<uint32>(_Id));
9934 nlverify(_ObjectCache.insert(std::make_pair(_Id, this)).second);
9937 if (_ObjectState != NOPE::os_transient)
9938 nlassert(_ObjectCache.find(_Id) != _ObjectCache.end());
9940 _ObjectState = state;
9942 if (state == NOPE::os_released)
9944 _ReleaseDate = NLMISC::CTime::getSecondsSince1970();
9945 nlverify(_ReleasedObject[_ReleaseDate].insert(this).second);
9947 else if (state == NOPE::os_removed)
9949 nldebug("NOPE: erasing CSessionLog @%p in cache with id %u", this, static_cast<uint32>(_Id));
9950 nlverify(_ObjectCache.erase(_Id) == 1);
9955 CSessionLogPtr CSessionLog::load(MSW::CConnection &connection, uint32 id, const char *filename, uint32 lineNum)
9957 CSessionLog *inCache = loadFromCache(id, true);
9958 if (inCache != NULL)
9960 return CSessionLogPtr(inCache, filename, lineNum);
9963 std::string qs;
9964 qs = "SELECT ";
9966 qs += "id, scenario_id, rrp_scored, scenario_point_scored, time_taken, participants, launch_date, owner, guild_name";
9968 qs += " FROM session_log";
9970 qs += " WHERE id = '"+NLMISC::toString(id)+"'";
9971 CSessionLogPtr ret;
9972 if (!connection.query(qs))
9974 return ret;
9977 MSW::CStoreResult *result = connection.storeResult().release();
9979 nlassert(result->getNumRows() <= 1);
9980 if (result->getNumRows() == 1)
9982 ret.assign(new CSessionLog, filename, lineNum);
9983 // ok, we have an object
9984 result->fetchRow();
9986 result->getField(0, ret->_Id);
9987 result->getField(1, ret->_ScenarioId);
9988 result->getField(2, ret->_RRPScored);
9989 result->getField(3, ret->_ScenarioPointScored);
9990 result->getField(4, ret->_TimeTaken);
9991 result->getField(5, ret->_Participants);
9992 result->getDateField(6, ret->_LaunchDate);
9993 result->getField(7, ret->_Owner);
9994 result->getField(8, ret->_GuildName);
9997 ret->setPersistentState(NOPE::os_clean);
10000 delete result;
10002 return ret;
10006 bool CSessionLog::loadChildrenOfCScenario(MSW::CConnection &connection, uint32 parentId, std::vector < CSessionLogPtr > & container, const char *filename, uint32 lineNum)
10009 std::string qs;
10010 qs = "SELECT ";
10012 qs += "id, scenario_id, rrp_scored, scenario_point_scored, time_taken, participants, launch_date, owner, guild_name";
10014 qs += " FROM session_log";
10015 qs += " WHERE scenario_id = '"+NLMISC::toString(parentId)+"'";
10017 if (!connection.query(qs))
10019 return false;
10022 CUniquePtr<MSW::CStoreResult> result = connection.storeResult();
10024 for (uint i=0; i<result->getNumRows(); ++i)
10026 CSessionLog *ret = new CSessionLog();
10027 // ok, we have an object
10028 result->fetchRow();
10030 result->getField(0, ret->_Id);
10032 result->getField(1, ret->_ScenarioId);
10034 result->getField(2, ret->_RRPScored);
10036 result->getField(3, ret->_ScenarioPointScored);
10038 result->getField(4, ret->_TimeTaken);
10040 result->getField(5, ret->_Participants);
10042 result->getDateField(6, ret->_LaunchDate);
10044 result->getField(7, ret->_Owner);
10046 result->getField(8, ret->_GuildName);
10047 CSessionLog *inCache = loadFromCache(ret->_Id, true);
10048 if (inCache != NULL)
10051 container.push_back(CSessionLogPtr(inCache, filename, lineNum));
10053 // no more needed
10054 delete ret;
10056 else
10058 ret->setPersistentState(NOPE::os_clean);
10060 container.push_back(CSessionLogPtr(ret, filename, lineNum));
10065 return true;
10068 void CGmStatusPtr::linkPtr()
10070 nlassert(_NextPtr == NULL);
10071 nlassert(_PrevPtr == NULL);
10072 if (_Ptr != NULL)
10074 _NextPtr = _Ptr->getFirstPtr();
10075 if (_NextPtr != NULL)
10077 _PrevPtr = _NextPtr->_PrevPtr;
10078 _PrevPtr->_NextPtr = this;
10079 _NextPtr->_PrevPtr = this;
10081 else
10083 _NextPtr = this;
10084 _PrevPtr = this;
10085 _Ptr->setFirstPtr(this);
10090 void CGmStatusPtr::unlinkPtr()
10092 if (_NextPtr == NULL)
10094 nlassert(_PrevPtr == NULL);
10095 return;
10098 if (_Ptr != NULL)
10100 if (_NextPtr == this)
10102 nlassert(_PrevPtr == this);
10103 // last pointer !
10104 _Ptr->setFirstPtr(NULL);
10106 else
10108 if (_Ptr->getFirstPtr() == this)
10110 // the first ptr is the current one, we need to switch to next one
10111 _Ptr->setFirstPtr(_NextPtr);
10116 if (_NextPtr != this)
10118 nlassert(_PrevPtr != this);
10120 _NextPtr->_PrevPtr = _PrevPtr;
10121 _PrevPtr->_NextPtr = _NextPtr;
10123 _NextPtr = NULL;
10124 _PrevPtr = NULL;
10128 CGmStatus::TObjectCache CGmStatus::_ObjectCache;
10129 CGmStatus::TReleasedObject CGmStatus::_ReleasedObject;
10132 // Destructor, delete any children
10133 CGmStatus::~CGmStatus()
10135 // release childs reference
10138 if (_PtrList != NULL)
10140 nlwarning("ERROR : someone try to delete this object, but there are still ptr on it !");
10141 CGmStatusPtr *ptr = _PtrList;
10144 nlwarning(" Pointer created from '%s', line %u", ptr->_FileName, ptr->_LineNum);
10145 ptr = _PtrList->getNextPtr();
10146 } while(ptr != _PtrList);
10147 nlstop;
10149 // remove object from cache map
10150 if (_UserId != NOPE::INVALID_OBJECT_ID
10151 && _ObjectState != NOPE::os_removed
10152 && _ObjectState != NOPE::os_transient)
10154 nldebug("NOPE: clearing CGmStatus @%p from cache with id %u", this, static_cast<uint32>(_UserId));
10155 nlverify(_ObjectCache.erase(_UserId) == 1);
10157 else if (_ObjectState != NOPE::os_transient)
10159 nlassert(_ObjectCache.find(_UserId) == _ObjectCache.end());
10161 if (_ObjectState == NOPE::os_released)
10163 removeFromReleased();
10165 else
10167 TReleasedObject::iterator it(_ReleasedObject.find(_ReleaseDate));
10168 if (it != _ReleasedObject.end())
10170 nlassert(it->second.find(this) == it->second.end());
10175 void CGmStatus::removeFromReleased()
10177 TReleasedObject::iterator it(_ReleasedObject.find(_ReleaseDate));
10178 nlassert(it != _ReleasedObject.end());
10179 TObjectSet &os = it->second;
10181 nlverify(os.erase(this) == 1);
10183 // nb : _ReleasedObject time entry are removed by the cache update
10186 bool CGmStatus::create(MSW::CConnection &connection)
10188 nlassert(getPersistentState() == NOPE::os_transient);
10190 nlassert(_UserId != 0);
10191 std::string qs;
10192 qs = "INSERT INTO gm_status (";
10194 qs += "user_id, available";
10195 qs += ") VALUES (";
10197 qs += "'"+MSW::escapeString(NLMISC::toString(_UserId), connection)+"'";
10198 qs += ", ";
10199 qs += "'"+MSW::escapeString(NLMISC::toString(_Available), connection)+"'";
10201 qs += ")";
10203 if (connection.query(qs))
10207 setPersistentState(NOPE::os_clean);
10209 // update the parent class instance in cache if any
10211 if (_UserId != 0)
10213 // need to update the parent class child if it is in the cache
10214 CRingUser *parent = CRingUser::loadFromCache(_UserId, false);
10215 if (parent && parent->_GMStatusLoaded)
10217 nlassert(parent->_GMStatus == NULL);
10218 parent->_GMStatus = CGmStatusPtr(this, __FILE__, __LINE__);
10222 return true;
10225 return false;
10228 bool CGmStatus::update(MSW::CConnection &connection)
10230 nlassert(getPersistentState() == NOPE::os_dirty || getPersistentState() == NOPE::os_clean);
10232 if (getPersistentState() == NOPE::os_clean)
10233 // the object is clean, just ignore the save
10234 return true;
10236 std::string qs;
10237 qs = "UPDATE gm_status SET ";
10239 qs += "user_id = '"+MSW::escapeString(NLMISC::toString(_UserId), connection)+"'";
10240 qs += ", ";
10241 qs += "available = '"+MSW::escapeString(NLMISC::toString(_Available), connection)+"'";
10243 qs += " WHERE user_id = '"+NLMISC::toString(_UserId)+"'";
10246 if (connection.query(qs))
10248 if (connection.getAffectedRows() == 1)
10250 setPersistentState(NOPE::os_clean);
10251 return true;
10255 return false;
10258 bool CGmStatus::remove(MSW::CConnection &connection)
10260 nlassert(getPersistentState() == NOPE::os_dirty || getPersistentState() == NOPE::os_clean);
10262 std::string qs;
10263 qs = "DELETE FROM gm_status ";
10265 qs += " WHERE user_id = '"+NLMISC::toString(_UserId)+"'";
10268 if (connection.query(qs))
10270 if (connection.getAffectedRows() == 1)
10274 // change the persistant state to 'removed'.
10275 setPersistentState(NOPE::os_removed);
10277 // need to remove ref from parent class container (if any)
10279 // need to remove ref from parent (if any)
10282 CRingUserPtr parent(CRingUser::loadFromCache(_UserId, true), __FILE__, __LINE__);
10283 if (parent != NULL && parent->_GMStatusLoaded)
10285 // assign a new NULL pointer
10286 parent->_GMStatus.assign(CGmStatusPtr(), __FILE__, __LINE__);
10291 return true;
10294 return false;
10297 bool CGmStatus::removeById(MSW::CConnection &connection, uint32 id)
10299 CGmStatus *object = loadFromCache(id, true);
10300 if (object != NULL)
10302 return object->remove(connection);
10304 // not in cache, run a SQL query
10305 std::string qs;
10306 qs = "DELETE FROM gm_status ";
10308 qs += " WHERE user_id = '"+NLMISC::toString(id)+"'";
10311 if (connection.query(qs))
10313 if (connection.getAffectedRows() == 1)
10315 // ok, the row is removed
10316 return true;
10320 return false;
10324 // Try to load the specified object from the memory cache, return NULL if the object is not in the cache
10325 CGmStatus *CGmStatus::loadFromCache(uint32 objectId, bool unrelease)
10327 // look in the cache
10328 TObjectCache::iterator it(_ObjectCache.find(objectId));
10329 if (it == _ObjectCache.end())
10331 // not found, return null
10332 return NULL;
10334 else
10336 CGmStatus *object = it->second;
10338 if (object->_ObjectState == NOPE::os_released)
10340 if (unrelease)
10342 // we need to remove this object from the released object set.
10343 object->removeFromReleased();
10344 object->_ObjectState = NOPE::os_clean;
10348 return it->second;
10351 // Receive and execute command from the cache manager.
10352 uint32 CGmStatus::cacheCmd(NOPE::TCacheCmd cmd)
10354 if (cmd == NOPE::cc_update)
10356 updateCache();
10358 else if (cmd == NOPE::cc_clear)
10360 clearCache();
10362 else if (cmd == NOPE::cc_dump)
10364 dump();
10366 else if (cmd == NOPE::cc_instance_count)
10368 return (uint32)_ObjectCache.size();
10371 // default return value
10372 return 0;
10375 void CGmStatus::dump()
10377 nlinfo(" Cache info for class CGmStatus :");
10378 nlinfo(" There are %u object instances in cache", _ObjectCache.size());
10380 // count the number of object in the released object set
10381 uint32 nbReleased = 0;
10383 TReleasedObject::iterator first(_ReleasedObject.begin()), last(_ReleasedObject.end());
10384 for (; first != last; ++first)
10386 nbReleased += (uint32)first->second.size();
10389 nlinfo(" There are %u object instances in cache not referenced (waiting deletion or re-use))", nbReleased);
10392 void CGmStatus::updateCache()
10394 if (_ReleasedObject.empty())
10395 return;
10397 // 30 s hold in cache
10398 const time_t MAX_CACHE_OLD_TIME = 30;
10400 time_t now = NLMISC::CTime::getSecondsSince1970();
10402 // look for object set older than MAX_CACHE_OLD_TIME and delete them
10403 while (!_ReleasedObject.empty() && _ReleasedObject.begin()->first < now-MAX_CACHE_OLD_TIME)
10405 TObjectSet &delSet = _ReleasedObject.begin()->second;
10406 // unload this objects
10407 while (!delSet.empty())
10409 CGmStatus *object = *delSet.begin();
10410 delete object;
10413 _ReleasedObject.erase(_ReleasedObject.begin());
10417 void CGmStatus::clearCache()
10419 // remove any unreferenced object from the cache
10420 while (!_ReleasedObject.empty())
10422 TObjectSet &delSet = _ReleasedObject.begin()->second;
10423 // unload this objects
10424 while (!delSet.empty())
10426 CGmStatus *object = *delSet.begin();
10427 delete object;
10430 _ReleasedObject.erase(_ReleasedObject.begin());
10434 void CGmStatus::registerUpdatable()
10436 static bool registered = false;
10437 if (!registered)
10439 NOPE::CPersistentCache::getInstance().registerCache(&CGmStatus::cacheCmd);
10441 registered = true;
10445 // set the pointer on the first pointer of the pointer list (set to null when there is no more pointer)
10446 void CGmStatus::setFirstPtr(CGmStatusPtr *ptr)
10448 _PtrList = ptr;
10450 if (ptr == NULL)
10452 // this is the last pointer !
10453 if (_ObjectState == NOPE::os_transient
10454 || _ObjectState == NOPE::os_removed)
10456 // not a persistent object, or removed object, just delet it
10457 delete this;
10459 else if (_ObjectState != NOPE::os_removed)
10461 setPersistentState(NOPE::os_released);
10466 // Set the persistent state of the object and do some house keeping
10467 void CGmStatus::setPersistentState(NOPE::TObjectState state)
10469 nlassert(NOPE::AllowedTransition[_ObjectState][state] == true);
10471 if(_ObjectState == NOPE::os_released && state == NOPE::os_removed)
10473 // a release object gets removed (e.g. by remove by id)
10475 // delete the object
10476 delete this;
10478 // no more to do
10479 return;
10482 if (_ObjectState == NOPE::os_transient && state != NOPE::os_transient)
10484 nldebug("NOPE: inserting CGmStatus @%p in cache with id %u", this, static_cast<uint32>(_UserId));
10485 nlverify(_ObjectCache.insert(std::make_pair(_UserId, this)).second);
10488 if (_ObjectState != NOPE::os_transient)
10489 nlassert(_ObjectCache.find(_UserId) != _ObjectCache.end());
10491 _ObjectState = state;
10493 if (state == NOPE::os_released)
10495 _ReleaseDate = NLMISC::CTime::getSecondsSince1970();
10496 nlverify(_ReleasedObject[_ReleaseDate].insert(this).second);
10498 else if (state == NOPE::os_removed)
10500 nldebug("NOPE: erasing CGmStatus @%p in cache with id %u", this, static_cast<uint32>(_UserId));
10501 nlverify(_ObjectCache.erase(_UserId) == 1);
10506 CGmStatusPtr CGmStatus::load(MSW::CConnection &connection, uint32 id, const char *filename, uint32 lineNum)
10508 CGmStatus *inCache = loadFromCache(id, true);
10509 if (inCache != NULL)
10511 return CGmStatusPtr(inCache, filename, lineNum);
10514 std::string qs;
10515 qs = "SELECT ";
10517 qs += "user_id, available";
10519 qs += " FROM gm_status";
10521 qs += " WHERE user_id = '"+NLMISC::toString(id)+"'";
10522 CGmStatusPtr ret;
10523 if (!connection.query(qs))
10525 return ret;
10528 MSW::CStoreResult *result = connection.storeResult().release();
10530 nlassert(result->getNumRows() <= 1);
10531 if (result->getNumRows() == 1)
10533 ret.assign(new CGmStatus, filename, lineNum);
10534 // ok, we have an object
10535 result->fetchRow();
10537 result->getField(0, ret->_UserId);
10538 result->getField(1, ret->_Available);
10541 ret->setPersistentState(NOPE::os_clean);
10544 delete result;
10546 return ret;
10549 bool CGmStatus::loadChildOfCRingUser(MSW::CConnection &connection, uint32 parentId, CGmStatusPtr &childPtr, const char *filename, uint32 lineNum)
10551 std::string qs;
10552 qs = "SELECT ";
10554 qs += "user_id, available";
10556 qs += " FROM gm_status";
10557 qs += " WHERE user_id = '"+NLMISC::toString(parentId)+"'";
10559 CGmStatusPtr ret;
10560 if (!connection.query(qs))
10562 childPtr = CGmStatusPtr();
10563 return false;
10566 CUniquePtr<MSW::CStoreResult> result = connection.storeResult();
10568 // check that the data description is consistent with database content
10569 nlassert(result->getNumRows() <= 1);
10571 if (result->getNumRows() == 1)
10573 CGmStatus *object = new CGmStatus;
10574 // ok, we have an object
10575 result->fetchRow();
10577 result->getField(0, object->_UserId);
10579 result->getField(1, object->_Available);
10580 CGmStatus *inCache = loadFromCache(object->_UserId, true);
10581 if (inCache != NULL)
10583 ret.assign(inCache, filename, lineNum);
10584 // no more needed
10585 delete object;
10587 else
10589 object->setPersistentState(NOPE::os_clean);
10590 ret.assign(object, filename, lineNum);
10593 childPtr = ret;
10594 return true;
10597 // no result, but no error
10598 childPtr = CGmStatusPtr();
10599 return true;