GME  13
CoreAttribute.cpp
Go to the documentation of this file.
00001 
00002 #include "stdafx.h"
00003 
00004 #include "CoreAttribute.h"
00005 #include "CommonCollection.h"
00006 #include "CoreProject.h"
00007 #include "CoreTerritory.h"
00008 #include "..\Mga\MgaGeneric.h"
00009 
00010 // --------------------------- Defines
00011 
00012 #define LOCKING_GETVALUE LOCKING_READ
00013 #define LOCKING_PUTVALUE LOCKING_EXCLUSIVE
00014 #define LOCKING_GETCOLLECTION LOCKING_READ
00015 
00016 #define CHECK_ZOMBIE() \
00017         if( IsZombie() ) \
00018                 COMRETURN(E_ZOMBIE);
00019 
00020 // --------------------------- LOCKVAL Constants
00021 
00022 #define LOCKVAL_NONE            0
00023 #define LOCKVAL_EXCLUSIVE       -1
00024 #define LOCKVAL_READ_START      1
00025 #define LOCKVAL_READ_END        32767
00026 #define LOCKVAL_WRITE_START     -2
00027 #define LOCKVAL_WRITE_END       -32768
00028 
00029 // --------------------------- CCoreAttribute
00030 
00031 CCoreAttribute::CCoreAttribute()
00032 {
00033         status = 0;
00034 
00035 #ifdef DEBUG
00036         footprint[0] = '(';
00037         footprint[1] = 'C';
00038         footprint[2] = 'A';
00039         footprint[3] = ')';
00040 #endif
00041 }
00042 
00043 typedef CCoreDataAttribute<CCorePointerAttrBase, VALTYPE_POINTER> CCorePointerAttribute;
00044 typedef CCoreDataAttribute<CCoreDataAttrBase<long>, VALTYPE_LONG> CCoreLongAttribute;
00045 typedef CCoreDataAttribute<CCoreDataAttrBase<CComBstrObj>, VALTYPE_STRING> CCoreStringAttribute;
00046 typedef CCoreDataAttribute<CCoreDataAttrBase<bindata>, VALTYPE_BINARY> CCoreBinaryAttribute;
00047 typedef CCoreDataAttribute<CCoreDataAttrBase<double>, VALTYPE_REAL> CCoreRealAttribute;
00048 typedef CCoreDataAttribute<CCoreDataAttrBase<CComPtr<CCoreDictionaryAttributeValue>>, VALTYPE_DICT> CCoreDictAttribute;
00049 
00050 void CCoreAttribute::Create(CCoreObject *object, CCoreMetaAttribute *metaattribute)
00051 {
00052         ASSERT( object != NULL );
00053         ASSERT( metaattribute != NULL );
00054 
00055         CCoreAttribute* attribute = NULL;
00056 
00057         switch( metaattribute->GetValType() )
00058         {
00059         case VALTYPE_POINTER:
00060                 {
00061                         typedef CComPartObject< CCorePointerAttribute > COMTYPE;
00062 
00063                         COMTYPE *p = NULL;
00064                         COMTHROW( COMTYPE::CreateInstance(CastToUnknown_Object(object), &p) );
00065                         attribute = p;
00066 
00067                         break;
00068                 }
00069 
00070         case VALTYPE_COLLECTION:
00071                 {
00072                         typedef CComPartObject< CCoreCollectionAttribute > COMTYPE;
00073 
00074                         COMTYPE *p = NULL;
00075                         COMTHROW( COMTYPE::CreateInstance(CastToUnknown_Object(object), &p) );
00076                         attribute = p;
00077 
00078                         break;
00079                 }
00080 
00081         case VALTYPE_LONG:
00082                 {
00083                         typedef CComPartObject< CCoreLongAttribute > COMTYPE;
00084 
00085                         COMTYPE *p = NULL;
00086                         COMTHROW( COMTYPE::CreateInstance(CastToUnknown_Object(object), &p) );
00087                         attribute = p;
00088 
00089                         break;
00090                 }
00091 
00092                 case VALTYPE_DICT:
00093                 {
00094                         typedef CComPartObject< CCoreDictAttribute > COMTYPE;
00095 
00096                         COMTYPE *p = NULL;
00097                         COMTHROW( COMTYPE::CreateInstance(CastToUnknown_Object(object), &p) );
00098                         attribute = p;
00099 
00100                         break;
00101                 }
00102 
00103         case VALTYPE_STRING:
00104                 {
00105                         typedef CComPartObject< CCoreStringAttribute > COMTYPE;
00106 
00107                         COMTYPE *p = NULL;
00108                         COMTHROW( COMTYPE::CreateInstance(CastToUnknown_Object(object), &p) );
00109                         attribute = p;
00110 
00111                         break;
00112                 }
00113 
00114         case VALTYPE_BINARY:
00115                 {
00116                         typedef CComPartObject< CCoreBinaryAttribute > COMTYPE;
00117 
00118                         COMTYPE *p = NULL;
00119                         COMTHROW( COMTYPE::CreateInstance(CastToUnknown_Object(object), &p) );
00120                         attribute = p;
00121 
00122                         break;
00123                 }
00124 
00125         case VALTYPE_REAL:
00126                 {
00127                         typedef CComPartObject< CCoreRealAttribute > COMTYPE;
00128 
00129                         COMTYPE *p = NULL;
00130                         COMTHROW( COMTYPE::CreateInstance(CastToUnknown_Object(object), &p) );
00131                         attribute = p;
00132 
00133                         break;
00134                 }
00135 
00136         case VALTYPE_LOCK:
00137                 {
00138                         typedef CComPartObject< CCoreLockAttribute > COMTYPE;
00139 
00140                         COMTYPE *p = NULL;
00141                         COMTHROW( COMTYPE::CreateInstance(CastToUnknown_Object(object), &p) );
00142                         attribute = p;
00143 
00144                         break;
00145                 }
00146 
00147         default:
00148                 HR_THROW(E_VALTYPE);
00149         }
00150 
00151         ASSERT( attribute != NULL );
00152 
00153         // nothing throws here
00154         attribute->metaattribute = metaattribute;
00155 
00156         object->RegisterAttribute(attribute);
00157         // object is ready for deletion
00158 }
00159 
00160 CCoreAttribute::~CCoreAttribute()
00161 {
00162         ASSERT( metaattribute != NULL );
00163         ASSERT( !IsDirty() );
00164 
00165 #ifndef _ATL_DEBUG_INTERFACES
00166         GetObject()->UnregisterAttribute(this);
00167 #endif
00168 }
00169 
00170 #ifdef DEBUG
00171 
00172 
00173 void CCoreAttribute::Dump() {
00174         CComBstrObj attrbstr;
00175         COMTHROW( metaattribute->get_Name(PutOut(attrbstr)) );
00176 
00177         std::string attrname;
00178         CopyTo(attrbstr, attrname);
00179 
00180         AtlTrace("attribute_dump attrid=%d name=\"%s\" \n",
00181                 (int)GetAttrID(), attrname.c_str());
00182 
00183 }
00184 
00185 #endif
00186 
00187 
00188 // ------- Inline
00189 
00190 inline CCoreProject *CCoreAttribute::GetProject() const
00191 {
00192         return GetObject()->GetProject();
00193 }
00194 
00195 inline CCoreTerritory *CCoreAttribute::GetTerritory() const
00196 {
00197         return GetProject()->GetTerritory();
00198 }
00199 
00200 // ------- COM methods
00201 
00202 STDMETHODIMP CCoreAttribute::get_Object(ICoreObject **p)
00203 {
00204         CHECK_OUT(p);
00205 
00206         CopyTo(GetObject(), p);
00207 
00208         return S_OK;
00209 }
00210 
00211 STDMETHODIMP CCoreAttribute::get_MetaAttribute(ICoreMetaAttribute **p)
00212 {
00213         CHECK_OUT(p);
00214 
00215         ASSERT( metaattribute != NULL );
00216         CopyTo(metaattribute, p);
00217 
00218         return S_OK;
00219 }
00220 
00221 // ------- Methods
00222 
00223 CCoreLockAttribute *CCoreAttribute::GetLockAttr() const
00224 {
00225         ASSERT( metaattribute != NULL );
00226 
00227         attrid_type attrid = 0;
00228         COMTHROW( metaattribute->get_LockAttrID(&attrid) );
00229         ASSERT( attrid != 0 );
00230 
00231         CCoreAttribute *attribute = GetObject()->FindAttribute(attrid);
00232         ASSERT( attribute != NULL );
00233 
00234         ASSERT( attribute->GetValType() == VALTYPE_LOCK );
00235         return (CCoreLockAttribute*)attribute;
00236 }
00237 
00238 ICoreStorage *CCoreAttribute::SetStorageThisAttribute()
00239 {
00240         ICoreStorage *storage = GetProject()->SetStorageObject(GetObject());
00241         ASSERT( storage != NULL );
00242 
00243         ASSERT( metaattribute != NULL );
00244         COMTHROW( storage->put_MetaAttribute(metaattribute) );
00245 
00246         return storage;
00247 }
00248 
00249 // ------- Status
00250 
00251 inline bool CCoreAttribute::InTransaction() const
00252 {
00253         return GetObject()->InTransaction();
00254 }
00255 
00256 inline bool CCoreAttribute::InWriteTransaction() const
00257 {
00258         return GetObject()->InWriteTransaction();
00259 }
00260 
00261 inline bool CCoreAttribute::IsZombie() const
00262 {
00263         return GetObject()->IsZombie();
00264 }
00265 
00266 // --------------------------- CCoreLockAttribute
00267 
00268 CCoreLockAttribute::CCoreLockAttribute()
00269 {
00270         original_locking = 0;
00271         others_lockval = 0;
00272         read_count = 0;
00273         write_count = 0;
00274         others_lockval = 0;
00275 }
00276 
00277 #ifdef _DEBUG
00278 
00279 CCoreLockAttribute::~CCoreLockAttribute()
00280 {
00281         ASSERT( read_count == 0 );
00282         ASSERT( write_count == 0 );
00283         ASSERT( !GetStatusFlag(COREATTRIBUTE_LOCKGROUP_LOADED) );
00284 }
00285 
00286 #endif
00287 
00288 STDMETHODIMP CCoreLockAttribute::get_Value(VARIANT *p)
00289 {
00290         CHECK_OUT(p);
00291         CHECK_ZOMBIE();
00292 
00293         COMTRY
00294         {
00295                 // this may not be right, but it shouldn't matter
00296                 CopyTo(original_locking, p);
00297         }
00298         COMCATCH(;)
00299 }
00300 
00301 STDMETHODIMP CCoreLockAttribute::put_Value(VARIANT p)
00302 {
00303         CHECK_ZOMBIE();
00304 
00305         if( !InTransaction() )
00306                 COMRETURN(E_TRANSACTION);
00307 
00308         COMTRY
00309         {
00310                 locking_type locking = LOCKING_NONE;
00311                 CopyTo(p, locking);
00312 
00313                 // this kludge value is used by meta to indicate that the project is about to be closed, so just call Release on our object and be done with it
00314                 if (locking == (unsigned char)-1)
00315                 {
00316                         SetStatusFlag(COREATTRIBUTE_LOCK_CLOSED);
00317                         read_count = write_count = 0;
00318                         SetDirty();
00319                         Unload();
00320                         return S_OK;
00321                 }
00322                 locking_type oldVal = 0;
00323                 if (locking == PUT_DELETE_DONE_LOCK) {
00324                         locking = LOCKING_NONE;
00325                         oldVal = LOCKING_EXCLUSIVE;
00326                 }
00327 
00328                 if( !(LOCKING_NONE <= locking && locking <= LOCKING_EXCLUSIVE) )
00329                         HR_THROW(E_INVALIDARG);
00330 
00331                 RegisterLockTry(oldVal, locking);
00332         }
00333         COMCATCH(;)
00334 }
00335 
00336 STDMETHODIMP CCoreLockAttribute::get_PeerLockValue(locking_type *p)
00337 {
00338         CHECK_ZOMBIE();
00339 
00340         COMTRY
00341         {
00342                 if ( read_count > 0 && write_count > 0 )
00343                         *p = LOCKING_NONE;              
00344                 else if( IsDirty() || !InTransaction() )
00345                         *p = CalcLocking(others_lockval);
00346                 else 
00347                 {
00348                         ICoreStorage *storage = SetStorageThisAttribute();
00349                         ASSERT( storage != NULL );
00350 
00351                         CComVariant v;
00352                         COMTHROW( storage->get_AttributeValue(PutOut(v)) );
00353 
00354                         lockval_type lockval;
00355                         CopyTo(v, lockval);
00356 
00357                         locking_type locking = CombineLock(read_count, write_count);
00358 
00359                         // if this fails then something is wrong in the storage
00360                         lockval = CalcUnlock(locking, lockval);
00361                         *p = CalcLocking(lockval);
00362                 }
00363         }
00364         COMCATCH(;)
00365 }
00366 
00367 void CCoreLockAttribute::RegisterLockTry(locking_type unreg, locking_type reg)
00368 {
00369         if (GetStatusFlag(COREATTRIBUTE_LOCK_CLOSED))
00370                 return;
00371         ASSERT( InTransaction() );
00372 
00373         locking_type old_locking = CombineLock(read_count, write_count);
00374 
00375         ASSERT( ((unreg & LOCKING_READ) ? 1 : 0) <= read_count );
00376         ASSERT( ((unreg & LOCKING_WRITE) ? 1 : 0) <= write_count );
00377 
00378         // temporary, possible exception
00379         lock_count_type new_read_count = read_count + ((reg & LOCKING_READ) != 0) - ((unreg & LOCKING_READ) != 0);
00380         lock_count_type new_write_count = write_count + ((reg & LOCKING_WRITE) != 0) - ((unreg & LOCKING_WRITE) != 0);
00381 
00382         ASSERT( ((reg & LOCKING_READ) ? 1 : 0) <= new_read_count );
00383         ASSERT( ((reg & LOCKING_WRITE) ? 1 : 0) <= new_write_count );
00384 
00385         locking_type new_locking = CombineLock(new_read_count, new_write_count);
00386 
00387         if( old_locking != new_locking )
00388         {
00389                 if( !IsDirty() )
00390                         Load();
00391 
00392                 // no sideeffect, may throw, make sure that we can have new_locking
00393                 CalcLock(new_locking, others_lockval);
00394         }
00395 
00396         read_count = new_read_count;
00397         write_count = new_write_count;
00398 
00399         // Load() should take care of ControlLockGroup
00400         ASSERT( IsLoaded() == GetStatusFlag(COREATTRIBUTE_LOCKGROUP_LOADED) );
00401 }
00402 
00403 void CCoreLockAttribute::RegisterLockDo(locking_type unreg, locking_type reg)
00404 {
00405         ASSERT( InTransaction() );
00406 
00407         ASSERT( ((unreg & LOCKING_READ) ? 1 : 0) <= read_count );
00408         ASSERT( ((unreg & LOCKING_WRITE) ? 1 : 0) <= write_count );
00409 
00410         read_count += ((reg & LOCKING_READ) != 0) - ((unreg & LOCKING_READ) != 0);
00411         write_count += ((reg & LOCKING_WRITE) != 0) - ((unreg & LOCKING_WRITE) != 0);
00412 
00413         ASSERT( ((reg & LOCKING_READ) ? 1 : 0) <= read_count );
00414         ASSERT( ((reg & LOCKING_WRITE) ? 1 : 0) <= write_count );
00415 
00416         ControlLockGroupDo();
00417 }
00418 
00419 void CCoreLockAttribute::Load()
00420 {
00421         ASSERT( InTransaction() );
00422         ASSERT( !IsDirty() );
00423 
00424         if( read_count > 0 && write_count > 0 )
00425         {
00426                 original_locking = LOCKING_EXCLUSIVE;
00427                 others_lockval = LOCKVAL_NONE;  // no other can have access
00428         }
00429         else
00430         {
00431                 ICoreStorage *storage = SetStorageThisAttribute();
00432                 ASSERT( storage != NULL );
00433 
00434                 COMTHROW( storage->LockObject() );
00435 
00436                 CComVariant v;
00437                 COMTHROW( storage->get_AttributeValue(PutOut(v)) );
00438 
00439                 lockval_type original_lockval;
00440                 CopyTo(v, original_lockval);
00441 
00442                 original_locking = CombineLock(read_count, write_count);
00443 
00444                 // if this fails then something is wrong in the storage
00445                 others_lockval = CalcUnlock(original_locking, original_lockval);
00446         }
00447 
00448         // we have to set to dirty because in LoadAttributes
00449         // we try to lock this object (while put_Value), and
00450         // the lock attribute will still not be loaded (infinite cycle)
00451 
00452         SetDirty();
00453 
00454         try
00455         {
00456                 ControlLockGroup();
00457         }
00458         catch(hresult_exception &)
00459         {
00460                 ResetDirty();
00461                 throw;
00462         }
00463 
00464         GetObject()->RegisterFinalTrItem();
00465 }
00466 
00467 void CCoreLockAttribute::ControlLockGroup()
00468 {
00469         if( GetStatusFlag(COREATTRIBUTE_LOCKGROUP_LOADED) && !IsLoaded() )
00470         {
00471                 GetObject()->UnloadAttributes(this);
00472                 ResetStatusFlag(COREATTRIBUTE_LOCKGROUP_LOADED);
00473                 GetObject()->Release();
00474         }
00475         else if( !GetStatusFlag(COREATTRIBUTE_LOCKGROUP_LOADED) && IsLoaded() )
00476         {
00477                 // this may fail
00478                 GetObject()->LoadAttributes(this);
00479 
00480                 GetObject()->AddRef();
00481                 SetStatusFlag(COREATTRIBUTE_LOCKGROUP_LOADED);
00482         }
00483 }
00484 
00485 void CCoreLockAttribute::ControlLockGroupDo()
00486 {
00487         if( GetStatusFlag(COREATTRIBUTE_LOCKGROUP_LOADED) && !IsLoaded() )
00488         {
00489                 GetObject()->UnloadAttributes(this);
00490                 ResetStatusFlag(COREATTRIBUTE_LOCKGROUP_LOADED);
00491                 GetObject()->Release();
00492         }
00493 
00494         // no loading
00495         ASSERT( GetStatusFlag(COREATTRIBUTE_LOCKGROUP_LOADED) == IsLoaded() );
00496 }
00497 
00498 void CCoreLockAttribute::Unload()
00499 {
00500         ASSERT( IsDirty() );
00501 
00502         ResetDirty();
00503         ControlLockGroupDo();
00504 
00505         // nothing can be here, the object might get destroyed
00506 }
00507 
00508 inline void CCoreLockAttribute::Save()
00509 {
00510         ASSERT( InTransaction() );
00511         ASSERT( IsDirty() );
00512 
00513         locking_type local_locking = CombineLock(read_count, write_count);
00514 
00515         if( local_locking != original_locking )
00516         {
00517 #ifdef DEBUG
00518                 lockval_type total_lockval;
00519                 try
00520                 {
00521                         total_lockval = CalcLock(local_locking, others_lockval);
00522                 }
00523                 catch(hresult_exception &)
00524                 {
00525                         // if this fails then something is wrong in RegisterLockTry
00526                         ASSERT(false);
00527                 }
00528 #else
00529                 lockval_type total_lockval = CalcLock(local_locking, others_lockval);
00530 #endif
00531 
00532                 ICoreStorage *storage = SetStorageThisAttribute();
00533                 ASSERT( storage != NULL );
00534 
00535                 CComVariant v;
00536                 CopyTo(total_lockval, v);
00537 
00538                 COMTHROW( storage->put_AttributeValue(v) );
00539         }
00540 }
00541 
00542 void CCoreLockAttribute::FillAfterCreateObject()
00543 {
00544         ASSERT( InTransaction() );
00545         ASSERT( !IsDirty() );
00546 
00547         ASSERT( read_count == 0 );
00548         ASSERT( write_count == 0 );
00549 
00550         original_locking = LOCKING_NONE;
00551         others_lockval = LOCKVAL_NONE;
00552 
00553         SetDirty();
00554 
00555         // do not call ControlLockGroup, FillAfterCreateObject is called for each attribute
00556         GetObject()->AddRef();
00557         SetStatusFlag(COREATTRIBUTE_LOCKGROUP_LOADED);
00558 }
00559 
00560 void CCoreLockAttribute::CommitFinalTransaction()
00561 {
00562         ASSERT( InTransaction() );
00563         ASSERT( IsDirty() );
00564 
00565         Save();
00566 }
00567 
00568 lockval_type CCoreLockAttribute::CalcLock(locking_type locking, lockval_type lockval)
00569 {
00570         switch( locking )
00571         {
00572         case LOCKING_READ:
00573                 if( lockval == LOCKVAL_NONE )
00574                         lockval = LOCKVAL_READ_START;
00575 #if LOCKVAL_READ_START < LOCKVAL_READ_END
00576                 else if( LOCKVAL_READ_START <= lockval && lockval < LOCKVAL_READ_END )
00577                         ++lockval;
00578 #else
00579                 else if( LOCKVAL_READ_END < lockval && lockval <= LOCKVAL_READ_START )
00580                         --lockval;
00581 #endif
00582                 else
00583                 {
00584 #ifdef _DEBUG
00585                         AtlTrace("Lock violation while locking with LOCKING_READ\n");
00586                         GetObject()->Dump();
00587 #endif
00588                         HR_THROW(E_LOCK_VIOLATION);
00589                 }
00590                 break;
00591 
00592         case LOCKING_WRITE:
00593                 if( lockval == LOCKVAL_NONE )
00594                         lockval = LOCKVAL_WRITE_START;
00595 #if LOCKVAL_WRITE_START < LOCKVAL_WRITE_END
00596                 else if( LOCKVAL_WRITE_START <= lockval && lockval < LOCKVAL_WRITE_END )
00597                         ++lockval;
00598 #else
00599                 else if( LOCKVAL_WRITE_END < lockval && lockval <= LOCKVAL_WRITE_START )
00600                         --lockval;
00601 #endif
00602                 else
00603                 {
00604 #ifdef _DEBUG
00605                         AtlTrace("Lock violation while locking with LOCKING_WRITE\n");
00606                         GetObject()->Dump();
00607 #endif
00608                         HR_THROW(E_LOCK_VIOLATION);
00609                 }
00610                 break;
00611 
00612         case LOCKING_EXCLUSIVE:
00613                 if( lockval == LOCKVAL_NONE )
00614                         lockval = LOCKVAL_EXCLUSIVE;
00615                 else
00616                 {
00617 #ifdef _DEBUG
00618                         AtlTrace("Lock violation while locking with LOCKING_EXCLUSIVE\n");
00619                         GetObject()->Dump();
00620 #endif
00621                         HR_THROW(E_LOCK_VIOLATION);
00622                 }
00623                 break;
00624 
00625         default:
00626                 ASSERT( locking == LOCKING_NONE );
00627         }
00628 
00629         return lockval;
00630 }
00631 
00632 lockval_type CCoreLockAttribute::CalcUnlock(locking_type locking, lockval_type lockval)
00633 {
00634         switch( locking )
00635         {
00636         case LOCKING_READ:
00637                 if( lockval == LOCKVAL_READ_START )
00638                         lockval = LOCKVAL_NONE;
00639 #if LOCKVAL_READ_START < LOCKVAL_READ_END
00640                 else if( LOCKVAL_READ_START < lockval && lockval <= LOCKVAL_READ_END )
00641                         --lockval;
00642 #else
00643                 else if( LOCKVAL_READ_END <= lockval && lockval < LOCKVAL_READ_START )
00644                         ++lockval;
00645 #endif
00646                 else
00647                         HR_THROW(E_INVALID_LOCK_VALUE);
00648                 break;
00649 
00650         case LOCKING_WRITE:
00651                 if( lockval == LOCKVAL_WRITE_START )
00652                         lockval = LOCKVAL_NONE;
00653 #if LOCKVAL_WRITE_START < LOCKVAL_WRITE_END
00654                 else if( LOCKVAL_WRITE_START < lockval && lockval <= LOCKVAL_WRITE_END )
00655                         --lockval;
00656 #else
00657                 else if( LOCKVAL_WRITE_END <= lockval && lockval < LOCKVAL_WRITE_START )
00658                         ++lockval;
00659 #endif
00660                 else
00661                         HR_THROW(E_INVALID_LOCK_VALUE);
00662                 break;
00663 
00664         case LOCKING_EXCLUSIVE:
00665                 if( lockval == LOCKVAL_EXCLUSIVE )
00666                         lockval = LOCKVAL_NONE;
00667                 else
00668                         HR_THROW(E_INVALID_LOCK_VALUE);
00669                 break;
00670 
00671         default:
00672                 ASSERT( locking == LOCKING_NONE );
00673         }
00674 
00675         return lockval;
00676 }
00677 
00678 locking_type CCoreLockAttribute::CalcLocking(lockval_type lockval)
00679 {
00680         if( lockval == LOCKVAL_NONE )
00681                 return LOCKING_NONE;
00682         else if( lockval == LOCKVAL_EXCLUSIVE )
00683                 return LOCKING_EXCLUSIVE;
00684 #if LOCKVAL_READ_START < LOCKVAL_READ_END
00685         else if( LOCKVAL_READ_START <= lockval && lockval <= LOCKVAL_READ_END )
00686 #else
00687         else if( LOCKVAL_READ_END <= lockval && lockval <= LOCKVAL_READ_START )
00688 #endif
00689                 return LOCKING_READ;
00690 #if LOCKVAL_WRITE_START < LOCKVAL_WRITE_END
00691         else if( LOCKVAL_WRITE_START <= lockval && lockval <= LOCKVAL_WRITE_END )
00692 #else
00693         else if( LOCKVAL_WRITE_END <= lockval && lockval <= LOCKVAL_WRITE_START )
00694 #endif
00695                 return LOCKING_WRITE;
00696 
00697         HR_THROW(E_INVALID_LOCK_VALUE);
00698 }
00699 
00700 locking_type CCoreLockAttribute::CombineLock(lock_count_type read_count,
00701         lock_count_type write_count)
00702 {
00703         ASSERT( 0 <= read_count );
00704         ASSERT( 0 <= write_count );
00705         ASSERT( LOCKING_READ + LOCKING_WRITE == LOCKING_EXCLUSIVE );
00706 
00707         return (read_count ? LOCKING_READ : LOCKING_NONE) +
00708                 (write_count ? LOCKING_WRITE : LOCKING_NONE) - LOCKING_NONE;
00709 };
00710 
00711 // ------- Debug
00712 
00713 #ifdef _DEBUG
00714 
00715 void CCoreLockAttribute::Dump()
00716 {
00717         ASSERT( metaattribute != NULL );
00718 
00719         CComBstrObj attrbstr;
00720         COMTHROW( metaattribute->get_Name(PutOut(attrbstr)) );
00721 
00722         std::string attrname;
00723         CopyTo(attrbstr, attrname);
00724 
00725         AtlTrace("attribute_dump attrid=%d name=\"%s\" read_count=%d write_count=%d"
00726                 " original_locking=%d others_lockval=%d ",
00727                 (int)GetAttrID(), attrname.c_str(), (int)read_count, (int)write_count, 
00728                 (int)original_locking, (int)others_lockval );
00729 
00730         if( InTransaction() )
00731         {
00732                 ICoreStorage *storage = SetStorageThisAttribute();
00733                 ASSERT( storage != NULL );
00734 
00735                 CComVariant v;
00736                 COMTHROW( storage->get_AttributeValue(PutOut(v)) );
00737 
00738                 lockval_type val;
00739                 CopyTo(v, val);
00740 
00741                 AtlTrace("storage=%d\n", (int)val);
00742         }
00743         else
00744                 AtlTrace("storage=<unknown>\n");
00745 }
00746 
00747 #endif
00748 
00749 // --------------------------- CCoreDataAttrBase
00750 
00751 // ------- Low level
00752 
00753 template<class DATA>
00754 inline void CCoreDataAttrBase<DATA>::LockSelfTry()
00755 {
00756         GetLockAttr()->RegisterLockTry(LOCKING_NONE, LOCKING_EXCLUSIVE);
00757 }
00758 
00759 template<class DATA>
00760 inline void CCoreDataAttrBase<DATA>::LockSelfCancel()
00761 {
00762         GetLockAttr()->RegisterLockDo(LOCKING_EXCLUSIVE, LOCKING_NONE);
00763 }
00764 
00765 template<class DATA>
00766 inline void CCoreDataAttrBase<DATA>::UnlockSelfTry()
00767 {
00768         GetLockAttr()->RegisterLockTry(LOCKING_EXCLUSIVE, LOCKING_NONE);
00769 }
00770 
00771 template<class DATA>
00772 inline void CCoreDataAttrBase<DATA>::UnlockSelfCancel()
00773 {
00774         GetLockAttr()->RegisterLockDo(LOCKING_NONE, LOCKING_EXCLUSIVE);
00775 }
00776 
00777 template<class DATA>
00778 inline void CCoreDataAttrBase<DATA>::UnlockSelfDo()
00779 {
00780         GetLockAttr()->RegisterLockDo(LOCKING_EXCLUSIVE, LOCKING_NONE);
00781 }
00782 
00783 // ------- Medium level
00784 
00785 template<class DATA>
00786 inline void CCoreDataAttrBase<DATA>::RemoveValueTry(values_iterator pos)
00787 {
00788         ASSERT( !values.empty() && pos != values.end() );
00789 
00790         if( limited_size(values, 3) == 2 )
00791                 UnlockSelfTry();
00792 }
00793 
00794 template<class DATA>
00795 inline void CCoreDataAttrBase<DATA>::RemoveValueCancel(values_iterator pos)
00796 {
00797         ASSERT( !values.empty() && pos != values.end() );
00798 
00799         if( limited_size(values, 3) == 2 )
00800                 UnlockSelfCancel();
00801 }
00802 
00803 template<class DATA>
00804 inline void CCoreDataAttrBase<DATA>::RemoveValueFinish(values_iterator pos)
00805 {
00806         ASSERT( !values.empty() && pos != values.end() );
00807 
00808         values.erase(pos);
00809 }
00810 
00811 template<class DATA>
00812 inline void CCoreDataAttrBase<DATA>::RemoveValue(values_iterator pos)
00813 {
00814         RemoveValueTry(pos);
00815 
00816         // we do not clean up, since try cleans up if falis
00817         RemoveValueFinish(pos);
00818 }
00819 
00820 template<class DATA>
00821 inline void CCoreDataAttrBase<DATA>::RemoveValueDo(values_iterator pos)
00822 {
00823         ASSERT( !values.empty() && pos != values.end() );
00824 
00825         // UnlockSelfDo may call Unload back
00826         // so we must remove the value first
00827 
00828         values.erase(pos);
00829 
00830         if( limited_size(values, 2) == 1 )
00831                 UnlockSelfDo();
00832 }
00833 
00834 template<class DATA>
00835 inline void CCoreDataAttrBase<DATA>::SpliceValue(values_iterator before, values_iterator pos)
00836 {
00837         ASSERT( !values.empty() );
00838 
00839         // nothing throw here
00840         values.splice(before, values, pos);
00841 }
00842 
00843 template<class DATA>
00844 inline void CCoreDataAttrBase<DATA>::ChangeFrontValue(VARIANT &v)
00845 {
00846         ASSERT( values.size() >= 2 );
00847 
00848         // only users overwrite
00849         CopyTo(v, values.front());
00850 }
00851 
00852 template<>
00853 inline void CCoreDataAttrBase<CComPtr<CCoreDictionaryAttributeValue>>::ChangeFrontValue(VARIANT &v)
00854 {
00855         ASSERT( values.size() >= 2 );
00856 }
00857 
00858 
00859 template<class DATA>
00860 DATA CCoreDataAttrBase<DATA>::CreateValue()
00861 {
00862         return value_type();
00863 }
00864 
00865 template<>
00866 CComPtr<CCoreDictionaryAttributeValue> CCoreDataAttrBase<CComPtr<CCoreDictionaryAttributeValue>>::CreateValue()
00867 {
00868         CCoreDictionaryAttributeValue *val = NULL;
00869         typedef CComObject< CCoreDictionaryAttributeValue > COMTYPE;
00870         // FIXME: is this necessary?
00871         COMTHROW( COMTYPE::CreateInstance((COMTYPE **)&val) );
00872         return CComPtr<CCoreDictionaryAttributeValue>(val);
00873 }
00874 
00875 template<class DATA>
00876 void CCoreDataAttrBase<DATA>::InsertFrontValue(VARIANT &v)
00877 {
00878         if( limited_size(values, 2) == 1 )
00879         {
00880                 LockSelfTry();
00881                 values.push_front(CreateValue());
00882                 try
00883                 {
00884                         CopyTo(v, values.front());
00885                 }
00886                 catch(hresult_exception &)
00887                 {
00888                         values.pop_front();
00889                         LockSelfCancel();
00890 
00891                         throw;
00892                 }
00893         }
00894         else
00895         {
00896                 values.push_front(CreateValue());
00897                 try
00898                 {
00899                         CopyTo(v, values.front());
00900                 }
00901                 catch(hresult_exception &)
00902                 {
00903                         values.pop_front();
00904                         throw;
00905                 }
00906         }
00907 }
00908 
00909 // ------- Methods
00910 
00911 template<class DATA>
00912 inline bool CCoreDataAttrBase<DATA>::DoesMatchBase(const value_type &a, const VARIANT &v)
00913 {
00914         return false;
00915 }
00916 
00917 template<>
00918 inline bool CCoreDataAttrBase<long>::DoesMatchBase(const long &a, const VARIANT &v)
00919 {
00920         return v.vt == VT_I4 && a == v.lVal;
00921 }
00922 
00923 template<>
00924 inline bool CCoreDataAttrBase<CComBstrObj>::DoesMatchBase(const CComBstrObj &a, const VARIANT &v)
00925 {
00926         return v.vt == VT_BSTR && a == v.bstrVal;
00927 }
00928 
00929 // ------- Debug
00930 
00931 #ifdef _DEBUG
00932 
00933 template<>
00934 void CCoreDataAttrBase<CComBstrObj>::Dump()
00935 {
00936         ASSERT( metaattribute != NULL );
00937 
00938         CComBstrObj bstr;
00939         COMTHROW( metaattribute->get_Name(PutOut(bstr)) );
00940 
00941         std::string name;
00942         CopyTo(bstr, name);
00943 
00944         attrid_type attrid = GetAttrID();
00945 
00946         AtlTrace("attribute_dump attrid=%d name=\"%s\" ", 
00947                 (int)attrid, name.begin());
00948 
00949         if( values.empty() )
00950                 AtlTrace("value=<unloaded> ");
00951         else
00952         {
00953                 std::string val;
00954                 CopyTo(values.front(), val);
00955 
00956                 AtlTrace("value=\"%s\" ", val.begin());
00957         }
00958 
00959         if( InTransaction() )
00960         {
00961                 ICoreStorage *storage = SetStorageThisAttribute();
00962                 ASSERT( storage != NULL );
00963 
00964                 CComVariant v;
00965                 COMTHROW( storage->get_AttributeValue(PutOut(v)) );
00966 
00967                 std::string val;
00968                 CopyTo(v, val);
00969 
00970                 AtlTrace("storage=\"%s\"\n", val.begin());
00971         }
00972         else
00973                 AtlTrace("storage=<unknown>\n");
00974 }
00975 
00976 template<>
00977 void CCoreDataAttrBase<long>::Dump()
00978 {
00979         ASSERT( metaattribute != NULL );
00980 
00981         CComBstrObj bstr;
00982         COMTHROW( metaattribute->get_Name(PutOut(bstr)) );
00983 
00984         std::string name;
00985         CopyTo(bstr, name);
00986 
00987         attrid_type attrid = GetAttrID();
00988 
00989         AtlTrace("attribute_dump attrid=%d name=\"%s\" ", 
00990                 (int)attrid, name.begin());
00991 
00992         if(values.empty())
00993                 AtlTrace("value=<unloaded> ");
00994         else
00995                 AtlTrace("value=%ld ", (long)values.front());
00996 
00997         if( InTransaction() )
00998         {
00999                 ICoreStorage *storage = SetStorageThisAttribute();
01000                 ASSERT( storage != NULL );
01001 
01002                 CComVariant v;
01003                 COMTHROW( storage->get_AttributeValue(PutOut(v)) );
01004 
01005                 long val;
01006                 CopyTo(v, val);
01007 
01008                 AtlTrace("storage=%ld\n", (long)val);
01009         }
01010         else
01011                 AtlTrace("storage=<unknown>\n");
01012 }
01013 
01014 #endif
01015 
01016 // --------------------------- CCorePointerAttrBase
01017 
01018 CCorePointerAttrBase::CCorePointerAttrBase() : isEmpty(true)
01019 {
01020 }
01021 
01022 #ifdef _DEBUG
01023 
01024 CCorePointerAttrBase::~CCorePointerAttrBase()
01025 {
01026         ASSERT( values.empty() );
01027         ASSERT( isEmpty );
01028 }
01029 
01030 
01031 #endif
01032 
01033 // ------- CopyTo
01034 
01035 void CCorePointerAttrBase::UserCopyTo(CCoreCollectionAttribute* const p, VARIANT *v)
01036 {
01037         ASSERT( v != NULL && v->vt == VT_EMPTY );
01038 
01039         v->pdispVal = NULL;
01040         v->vt = VT_DISPATCH;
01041 
01042         if( p != NULL )
01043         {
01044                 CCoreObject * o = p->GetObject();
01045                 ASSERT( o != NULL );
01046 
01047                 CopyTo(o, &v->pdispVal);
01048         }
01049 }
01050 
01051 void CCorePointerAttrBase::UserCopyTo(const VARIANT &v, CComObjPtr<CCoreCollectionAttribute> &p)
01052 {
01053         if( v.vt == VT_DISPATCH )
01054         {
01055                 if( v.pdispVal == NULL )
01056                         p = NULL;
01057                 else
01058                 {
01059                         CComObjPtr<ICoreObject> iobject;
01060                         COMTHROW( ::QueryInterface(v.pdispVal, iobject) );
01061                         ASSERT( iobject != NULL );
01062 
01063                         CCoreObject *object = GetProject()->CastObject(iobject);
01064                         ASSERT( object != NULL );
01065 
01066                         CComObjPtr<CCoreAttribute> attribute = object->FindAttribute(GetAttrID() + ATTRID_COLLECTION);
01067                         ASSERT( attribute != NULL && attribute->GetValType() == VALTYPE_COLLECTION );
01068                         ASSERT( attribute->GetObject() == object );
01069 
01070                         p.Attach((CCoreCollectionAttribute*)attribute.Detach());
01071                 }
01072         }
01073         else if( v.vt == VT_EMPTY )
01074                 p = NULL;
01075         else
01076                 HR_THROW(E_INVALIDARG);
01077 }
01078 
01079 void CCorePointerAttrBase::StorageCopyTo(CCoreCollectionAttribute* const p, VARIANT *v)
01080 {
01081         ASSERT( v != NULL && v->vt == VT_EMPTY );
01082 
01083         metaobjidpair_type idpair;
01084 
01085         if( p != NULL )
01086         {
01087                 CCoreObject *object = p->GetObject();
01088                 ASSERT( object != NULL );
01089 
01090                 idpair.objid = object->GetObjID();
01091                 idpair.metaid = object->GetMetaID();
01092         }
01093         else
01094         {
01095                 idpair.objid = OBJID_NONE;
01096                 idpair.metaid = METAID_NONE;
01097         }
01098 
01099         CopyTo(idpair, v);
01100 }
01101 
01102 void CCorePointerAttrBase::StorageCopyTo(const VARIANT &v, CComObjPtr<CCoreCollectionAttribute> &p)
01103 {
01104         metaobjidpair_type idpair;
01105         CopyTo(v, idpair);
01106 
01107         if( idpair.metaid != METAID_NONE )
01108         {
01109                 ASSERT( idpair.objid != OBJID_NONE );
01110 
01111 #pragma warning( disable: 4244) // conversion from 'long' to 'short', possible loss of data
01112                 CComObjPtr<CCoreObject> object = GetProject()->GetObject(idpair.metaid, idpair.objid);
01113 #pragma warning( default: 4244) // conversion from 'long' to 'short', possible loss of data
01114                 ASSERT( object != NULL );
01115 
01116                 CComObjPtr<CCoreAttribute> attribute = object->FindAttribute(GetAttrID() + ATTRID_COLLECTION);
01117                 ASSERT( attribute != NULL && attribute->GetValType() == VALTYPE_COLLECTION );
01118                 ASSERT( attribute->GetObject() == object );
01119 
01120                 p.Attach((CCoreCollectionAttribute*)attribute.Detach());
01121         }
01122         else
01123         {
01124                 ASSERT( idpair.objid == OBJID_NONE );
01125 
01126                 p = NULL;
01127         }
01128 }
01129 
01130 // ------- Low level
01131 
01132 void CCorePointerAttrBase::InsertIntoCollection()
01133 {
01134         ASSERT( isEmpty );
01135         ASSERT( !values.empty() );
01136 
01137         if( values.front() != NULL )
01138         {
01139                 CCoreCollectionAttribute::objects_type &collection = values.front()->GetCollection();
01140 
01141                 std::pair<objects_iterator, bool> t = collection.insert(GetObject());
01142                 ASSERT( t.second );
01143                 backref = t.first;
01144                 isEmpty = false;
01145         }
01146 }
01147 
01148 void CCorePointerAttrBase::RemoveFromCollection()
01149 {
01150         ASSERT( !values.empty() );
01151 
01152         if( !isEmpty )
01153         {
01154                 ASSERT( values.front() != NULL );
01155 
01156                 objects_type &collection = values.front()->GetCollection();
01157                 ASSERT( IsValidIterator(collection, backref) );
01158 
01159                 collection.erase( backref );
01160                 // KMS: assigning a singular iterator is undefined. I saw a crash when registering MetaGME
01161                 // backref = objects_iterator(); // was: backref = NULL;
01162                 isEmpty = true;
01163         }
01164         else
01165                 ASSERT( values.front() == NULL );
01166 }
01167 
01168 void CCorePointerAttrBase::CollectionNotUpToDate()
01169 {
01170         ASSERT( values.size() == 1 );
01171 
01172         if( values.front() != NULL )
01173                 values.front()->NotUpToDate();
01174 }
01175 
01176 inline void CCorePointerAttrBase::LockCollectionTry(CCoreCollectionAttribute *p)
01177 {
01178         if( p != NULL )
01179                 p->GetLockAttr()->RegisterLockTry(LOCKING_NONE, LOCKING_WRITE);
01180 }
01181 
01182 inline void CCorePointerAttrBase::LockCollectionCancel(CCoreCollectionAttribute *p)
01183 {
01184         if( p != NULL )
01185                 p->GetLockAttr()->RegisterLockDo(LOCKING_WRITE, LOCKING_NONE);
01186 }
01187 
01188 inline void CCorePointerAttrBase::UnlockCollectionTry(CCoreCollectionAttribute *p)
01189 {
01190         if( p != NULL )
01191                 p->GetLockAttr()->RegisterLockTry(LOCKING_WRITE, LOCKING_NONE);
01192 }
01193 
01194 inline void CCorePointerAttrBase::UnlockCollectionCancel(CCoreCollectionAttribute *p)
01195 {
01196         if( p != NULL )
01197                 p->GetLockAttr()->RegisterLockDo(LOCKING_NONE, LOCKING_WRITE);
01198 }
01199 
01200 inline void CCorePointerAttrBase::UnlockCollectionDo(CCoreCollectionAttribute *p)
01201 {
01202         if( p != NULL )
01203                 p->GetLockAttr()->RegisterLockDo(LOCKING_WRITE, LOCKING_NONE);
01204 }
01205 
01206 inline void CCorePointerAttrBase::LockSelfTry()
01207 {
01208         GetLockAttr()->RegisterLockTry(LOCKING_NONE, LOCKING_EXCLUSIVE);
01209 }
01210 
01211 inline void CCorePointerAttrBase::LockSelfCancel()
01212 {
01213         GetLockAttr()->RegisterLockDo(LOCKING_EXCLUSIVE, LOCKING_NONE);
01214 }
01215 
01216 inline void CCorePointerAttrBase::UnlockSelfTry()
01217 {
01218         GetLockAttr()->RegisterLockTry(LOCKING_EXCLUSIVE, LOCKING_NONE);
01219 }
01220 
01221 inline void CCorePointerAttrBase::UnlockSelfCancel()
01222 {
01223         GetLockAttr()->RegisterLockDo(LOCKING_NONE, LOCKING_EXCLUSIVE);
01224 }
01225 
01226 inline void CCorePointerAttrBase::UnlockSelfDo()
01227 {
01228         GetLockAttr()->RegisterLockDo(LOCKING_EXCLUSIVE, LOCKING_NONE);
01229 }
01230 
01231 // ------- Medium level
01232 
01233 void CCorePointerAttrBase::RemoveValueTry(values_iterator pos)
01234 {
01235         ASSERT( !values.empty() && pos != values.end() );
01236 
01237         switch( limited_size(values, 3) )
01238         {
01239         case 3:
01240                 ASSERT( values.size() >= 3 );
01241 
01242                 UnlockCollectionTry(*pos);
01243 
01244                 break;
01245 
01246         case 2:
01247                 ASSERT( values.size() == 2 );
01248 
01249                 UnlockSelfTry();
01250                 try
01251                 {
01252                         UnlockCollectionTry(values.front());
01253                         try
01254                         {
01255                                 UnlockCollectionTry(values.back());
01256                         }
01257                         catch(hresult_exception &)
01258                         {
01259                                 UnlockCollectionCancel(values.front());
01260                                 throw;
01261                         }
01262                 }
01263                 catch(hresult_exception &)
01264                 {
01265                         UnlockSelfCancel();
01266                         throw;
01267                 }
01268 
01269                 break;
01270         }
01271 }
01272 
01273 void CCorePointerAttrBase::RemoveValueCancel(values_iterator pos)
01274 {
01275         ASSERT( !values.empty() && pos != values.end() );
01276 
01277         switch( limited_size(values, 3) )
01278         {
01279         case 3:
01280                 ASSERT( values.size() >= 3 );
01281 
01282                 UnlockCollectionCancel(*pos);
01283 
01284                 break;
01285 
01286         case 2:
01287                 ASSERT( values.size() == 2 );
01288 
01289                 // in reverse order
01290                 UnlockCollectionCancel(values.back());
01291                 UnlockCollectionCancel(values.front());
01292                 UnlockSelfCancel();
01293 
01294                 break;
01295         }
01296 }
01297 
01298 void CCorePointerAttrBase::RemoveValueFinish(values_iterator pos)
01299 {
01300         ASSERT( !values.empty() && pos != values.end() );
01301 
01302         if( pos == values.begin() )
01303         {
01304                 RemoveFromCollection();
01305 
01306                 if( limited_size(values, 2) == 1 )
01307                         CollectionNotUpToDate();
01308 
01309                 values.erase(pos);
01310 
01311                 if( !values.empty() )
01312                         InsertIntoCollection();
01313         }
01314         else
01315                 values.erase(pos);
01316 }
01317 
01318 void CCorePointerAttrBase::RemoveValue(values_iterator pos)
01319 {
01320         RemoveValueTry(pos);
01321 
01322         // we do not clean up, since try cleans up if falis
01323         RemoveValueFinish(pos);
01324 }
01325 
01326 void CCorePointerAttrBase::RemoveValueDo(values_iterator pos)
01327 {
01328         ASSERT( !values.empty() && pos != values.end() );
01329 
01330         // RemoveValueDo may call Unload back
01331         // so we have to remove the value first
01332 
01333         switch( limited_size(values, 3) )
01334         {
01335         case 3:
01336                 ASSERT( values.size() >= 3 );
01337 
01338                 UnlockCollectionDo(*pos);
01339 
01340                 break;
01341 
01342         case 2:
01343                 ASSERT( values.size() == 2 );
01344 
01345                 UnlockCollectionDo(values.front());
01346                 UnlockCollectionDo(values.back());
01347 
01348                 break;
01349         }
01350 
01351         if( pos == values.begin() )
01352         {
01353                 RemoveFromCollection();
01354 
01355                 if( limited_size(values, 2) == 1 )
01356                         CollectionNotUpToDate();
01357 
01358                 values.erase(pos);
01359 
01360                 if( !values.empty() )
01361                         InsertIntoCollection();
01362         }
01363         else
01364                 values.erase(pos);
01365 
01366         if( limited_size(values, 2) == 1 )
01367                 UnlockSelfDo();
01368 }
01369 
01370 void CCorePointerAttrBase::SpliceValue(values_iterator before, values_iterator pos)
01371 {
01372         ASSERT( !values.empty() );
01373 
01374         // nothing throw here
01375         RemoveFromCollection();
01376         values.splice(before, values, pos);
01377         InsertIntoCollection();
01378 }
01379 
01380 void CCorePointerAttrBase::ChangeFrontValue(VARIANT &v)
01381 {
01382         ASSERT( values.size() >= 2 );
01383 
01384         // templorary, possible exception
01385         CComObjPtr<CCoreCollectionAttribute> collection;
01386 
01387         // only users overwrite
01388         UserCopyTo(v, collection);
01389 
01390         LockCollectionTry(collection);
01391         try
01392         {
01393                 UnlockCollectionTry(values.front());
01394         }
01395         catch(hresult_exception &)
01396         {
01397                 LockCollectionCancel(collection);
01398                 throw;
01399         }
01400 
01401         // nothing throw here
01402         RemoveFromCollection();
01403         values.front() = collection;
01404         InsertIntoCollection();
01405 }
01406 
01407 void CCorePointerAttrBase::InsertFrontValue(VARIANT &v)
01408 {
01409         // templorary, possible exception
01410         CComObjPtr<CCoreCollectionAttribute> collection;
01411 
01412         if( values.empty() )
01413         {
01414                 StorageCopyTo(v, collection);
01415 
01416                 // nothing throw here
01417                 values.push_front(collection);
01418                 InsertIntoCollection();
01419         }
01420         else if( limited_size(values, 2) == 1 )
01421         {
01422                 ASSERT( values.size() == 1 );
01423 
01424                 UserCopyTo(v, collection);
01425 
01426                 LockSelfTry();
01427                 try
01428                 {
01429                         LockCollectionTry(collection);
01430                         try
01431                         {
01432                                 LockCollectionTry(values.front());
01433                         }
01434                         catch(hresult_exception &)
01435                         {
01436                                 LockCollectionCancel(collection);
01437                                 throw;
01438                         }
01439                 }
01440                 catch(hresult_exception &)
01441                 {
01442                         LockSelfCancel();
01443                         throw;
01444                 }
01445 
01446                 RemoveFromCollection();
01447                 values.push_front(collection);
01448                 InsertIntoCollection();
01449         }
01450         else
01451         {
01452                 ASSERT( values.size() >= 2 );
01453                 
01454                 UserCopyTo(v, collection);
01455                 LockCollectionTry(collection);
01456 
01457                 RemoveFromCollection();
01458                 values.push_front(collection);
01459                 InsertIntoCollection();
01460         }
01461 }
01462 
01463 // ------- Methods
01464 
01465 inline bool CCorePointerAttrBase::DoesMatchBase(const value_type &a, const VARIANT &v)
01466 {
01467         if( v.vt != VT_DISPATCH && v.vt != VT_UNKNOWN )
01468                 return false;
01469 
01470         if( a == NULL )
01471                 return v.punkVal == NULL;
01472 
01473         return IsEqualObject(CastToUnknown(a->GetObject()), v.punkVal);
01474 }
01475 
01476 // --------------------------- CCoreDataAttribute
01477 
01478 // ------- Methods
01479 
01480 template<class BASE, const int VALTYPE>
01481 STDMETHODIMP CCoreDataAttribute<BASE, VALTYPE>::get_Value(VARIANT *p)
01482 {
01483         CHECK_OUT(p);
01484         CHECK_ZOMBIE();
01485 
01486         COMTRY
01487         {
01488                 if( InTransaction() )
01489                 {
01490                         if( !IsLoaded() )
01491                                 GetLockAttr()->Load();
01492 
01493             // BGY: this hack makes sure that the sourcecontrol status is always
01494             // read from the storage.
01495                         if( GetValType() == VALTYPE_LONG)
01496                         {
01497                                 ICoreStorage *storage = SetStorageThisAttribute();
01498                                 ASSERT( storage != NULL );
01499                                 COMTHROW( storage->LockObject() );
01500 
01501                                 attrid_type a_id;
01502                                 COMTHROW( storage->get_AttrID( &a_id));
01503                                 if( a_id == ATTRID_FILESTATUS)
01504                                 {
01505                                         COMTHROW( storage->get_AttributeValue( p));
01506                                         return S_OK;
01507                                 }
01508                         }
01509         }
01510                 else
01511                 {
01512 //                      if( GetTerritory()->GetLocking(GetLockAttr()) == LOCKING_NONE )
01513 //                              HR_THROW(E_NOTLOCKED);
01514 
01515                         if( !IsLoaded() )
01516                                 HR_THROW(E_NOTLOCKED);
01517                 }
01518 
01519                 ASSERT( !values.empty() );
01520                 UserCopyTo(values.front(), p);
01521         }
01522         COMCATCH(;)
01523 }
01524 
01525 template<class BASE, const int VALTYPE>
01526 STDMETHODIMP CCoreDataAttribute<BASE, VALTYPE>::put_Value(VARIANT p)
01527 {
01528         CHECK_ZOMBIE();
01529 
01530         if( !InWriteTransaction() )
01531                 COMRETURN(E_TRANSACTION);
01532 
01533         COMTRY
01534         {
01535                 if( !IsLoaded() )
01536                         GetLockAttr()->Load();
01537 
01538                 ASSERT( !values.empty() );
01539 
01540                 if( !IsDirty() )
01541                 {
01542                         InsertFrontValue(p);
01543 
01544                         // nothing will throw here
01545 
01546                         GetObject()->RegisterFinalTrItem();
01547                         GetProject()->RegisterTransactionItem(this);
01548                         SetDirty();
01549                 }
01550                 else
01551                         ChangeFrontValue(p);
01552         }
01553         COMCATCH(;)
01554 }
01555 
01556 template<class BASE, const int VALTYPE>
01557 STDMETHODIMP CCoreDataAttribute<BASE, VALTYPE>::get_LoadedValue(VARIANT *p)
01558 {
01559         CHECK_OUT(p);
01560         CHECK_ZOMBIE();
01561 
01562         COMTRY
01563         {
01564                 if( values.empty() )
01565                         HR_THROW(E_NOTLOCKED);
01566 
01567                 UserCopyTo(values.front(), p);
01568         }
01569         COMCATCH(;)
01570 }
01571 
01572 template<class BASE, const int VALTYPE>
01573 STDMETHODIMP CCoreDataAttribute<BASE, VALTYPE>::get_PreviousValue(VARIANT *p)
01574 {
01575         CHECK_OUT(p);
01576         CHECK_ZOMBIE();
01577 
01578         COMTRY
01579         {
01580                 if (GetLockAttr()->IsLoaded() == false)
01581                         HR_THROW(E_NOTLOCKED);
01582 
01583                 if( IsDirty() )
01584                 {
01585                         // lph: Return last committed value.  Previously returned last set value (commented below).
01586                         ICoreStorage *storage = SetStorageThisAttribute();
01587                         ASSERT( storage != NULL );
01588                         COMTHROW(storage->get_AttributeValue(p));
01589 
01590                         //ASSERT( values.size() >= 2 );
01591                         //UserCopyTo(*(++values.begin()), p);
01592                 }
01593                 else
01594                 {
01595                         ASSERT( !values.empty() );
01596                         UserCopyTo(values.front(), p);
01597                 }
01598         }
01599         COMCATCH(;)
01600 }
01601 
01602 template<class BASE, const int VALTYPE>
01603 void CCoreDataAttribute<BASE, VALTYPE>::Load()
01604 {
01605         ASSERT( !IsZombie() );
01606         ASSERT( values.empty() );
01607 
01608         ICoreStorage *storage = SetStorageThisAttribute();
01609         ASSERT( storage != NULL );
01610 
01611         CComVariant v;
01612         COMTHROW( storage->get_AttributeValue(PutOut(v)) );
01613 
01614         InsertFrontValue(v);
01615 }
01616 
01617 template<class BASE, const int VALTYPE>
01618 void CCoreDataAttribute<BASE, VALTYPE>::Unload()
01619 {
01620         ASSERT( values.size() == 1 );
01621         ASSERT( !IsDirty() );
01622 
01623         RemoveValue(values.begin());
01624 
01625         ASSERT( values.empty() );
01626 }
01627 
01628 template<class BASE, const int VALTYPE>
01629 void CCoreDataAttribute<BASE, VALTYPE>::Save(value_type &value)
01630 {
01631         ASSERT( !IsZombie() );
01632 
01633         ICoreStorage *storage = SetStorageThisAttribute();
01634         ASSERT( storage != NULL );
01635 
01636         CComVariant v;
01637         StorageCopyTo(value, &v);
01638 
01639         COMTHROW( storage->put_AttributeValue(v) );
01640 }
01641 
01642 template<class BASE, const int VALTYPE>
01643 void CCoreDataAttribute<BASE, VALTYPE>::FillAfterCreateObject()
01644 {
01645         ASSERT( values.empty() );
01646 
01647         CComVariant v;
01648         InsertFrontValue(v);
01649 
01650         ASSERT( values.size() == 1 );
01651 }
01652 
01653 // ------- NestedTrItem
01654 
01655 template<class BASE, const int VALTYPE>
01656 void CCoreDataAttribute<BASE, VALTYPE>::AbortNestedTransaction()
01657 {
01658         ASSERT( IsDirty() );
01659         ASSERT( values.size() >= 2 );
01660 
01661         RemoveValueDo(values.begin());
01662 
01663         ResetDirty();
01664 }
01665 
01666 template<class BASE, const int VALTYPE>
01667 void CCoreDataAttribute<BASE, VALTYPE>::DiscardPreviousValue()
01668 {
01669         ASSERT( IsDirty() );
01670         ASSERT( values.size() >= 3 );
01671 
01672         RemoveValueDo(++values.begin());
01673 }
01674 
01675 // ------- FinalTrItem
01676 
01677 template<class BASE, const int VALTYPE>
01678 void CCoreDataAttribute<BASE, VALTYPE>::AbortFinalTransaction()
01679 {
01680         ASSERT( IsDirty() );
01681         ASSERT( values.size() >= 2 );
01682 
01683         // RemoveValueDo may call Unload back
01684         // so we have to reset dirty first
01685 
01686         ResetDirty();
01687 
01688         RemoveValueDo(values.begin());
01689 }
01690 
01691 template<class BASE, const int VALTYPE>
01692 void CCoreDataAttribute<BASE, VALTYPE>::CommitFinalTransaction()
01693 {
01694         ASSERT( IsDirty() );
01695         ASSERT( values.size() >= 2 );
01696 
01697         Save( values.front() );
01698 }
01699 
01700 template<class BASE, const int VALTYPE>
01701 void CCoreDataAttribute<BASE, VALTYPE>::CommitFinalTransactionFinish(bool undo)
01702 {
01703         ASSERT( IsDirty() );
01704         ASSERT( values.size() >= 2 );
01705 
01706         GetProject()->RegisterUndoItem(this);
01707 
01708         ResetDirty();
01709 }
01710 
01711 // ------- UndoItem
01712 
01713 template<class BASE, const int VALTYPE>
01714 void CCoreDataAttribute<BASE, VALTYPE>::UndoTransaction()
01715 {
01716         ASSERT( values.size() >= 2 );
01717         ASSERT( !IsDirty() );
01718 
01719         Save( *(++values.begin()) );
01720 }
01721 
01722 template<class BASE, const int VALTYPE>
01723 void CCoreDataAttribute<BASE, VALTYPE>::UndoTransactionFinish()
01724 {
01725         ASSERT( values.size() >= 2 );
01726         ASSERT( !IsDirty() );
01727 
01728         SpliceValue(values.end(), values.begin());
01729 }
01730 
01731 template<class BASE, const int VALTYPE>
01732 void CCoreDataAttribute<BASE, VALTYPE>::RedoTransaction()
01733 {
01734         ASSERT( values.size() >= 2 );
01735         ASSERT( !IsDirty() );
01736 
01737         Save( values.back() );
01738 }
01739 
01740 template<class BASE, const int VALTYPE>
01741 void CCoreDataAttribute<BASE, VALTYPE>::RedoTransactionFinish()
01742 {
01743         ASSERT( values.size() >= 2 );
01744         ASSERT( !IsDirty() );
01745 
01746         SpliceValue(values.begin(), --values.end());
01747 }
01748 
01749 template<class BASE, const int VALTYPE>
01750 void CCoreDataAttribute<BASE, VALTYPE>::DiscardLastItem()
01751 {
01752         ASSERT( values.size() >= 2 );
01753         ASSERT( !IsDirty() );
01754 
01755         RemoveValueTry(--values.end());
01756 }
01757 
01758 template<class BASE, const int VALTYPE>
01759 void CCoreDataAttribute<BASE, VALTYPE>::DiscardLastItemFinish()
01760 {
01761         ASSERT( values.size() >= 2 );
01762         ASSERT( !IsDirty() );
01763 
01764         RemoveValueFinish(--values.end());
01765 }
01766 
01767 template<class BASE, const int VALTYPE>
01768 void CCoreDataAttribute<BASE, VALTYPE>::DiscardLastItemCancel()
01769 {
01770         ASSERT( values.size() >= 2 );
01771         ASSERT( !IsDirty() );
01772 
01773         RemoveValueCancel(--values.end());
01774 }
01775 
01776 // ------- DoesMatch
01777 
01778 template<class BASE, const int VALTYPE>
01779 bool CCoreDataAttribute<BASE, VALTYPE>::DoesMatch(bool do_load, const VARIANT &v)
01780 {
01781         if( IsLoaded() )
01782                 return DoesMatchBase(values.front(), v);
01783         else if( do_load )
01784         {
01785                 GetLockAttr()->Load();
01786                 ASSERT( IsLoaded() );
01787 
01788                 return DoesMatchBase(values.front(), v);
01789         }
01790 
01791         return false;
01792 }
01793 
01794 // --------------------------- CCoreCollectionAttribute
01795 
01796 #ifdef _DEBUG
01797 
01798 CCoreCollectionAttribute::~CCoreCollectionAttribute()
01799 {
01800         ASSERT( collection.empty() );
01801 }
01802 
01803 #endif
01804 
01805 STDMETHODIMP CCoreCollectionAttribute::get_Value(VARIANT *p)
01806 {
01807         CHECK_OUT(p);
01808         CHECK_ZOMBIE();
01809 
01810         COMTRY
01811         {
01812                 if( InTransaction() )
01813                 {
01814                         if (GetLockAttr()->IsLoaded() &&
01815                                 GetStatusFlag(COREATTRIBUTE_COLL_UPTODATE) )
01816                         {
01817                                 CopyCollectionFromMemory(*p);
01818                         }
01819                         else
01820                         {
01821                                 if (GetLockAttr()->IsLoaded() == false)
01822                                         GetLockAttr()->Load();
01823 
01824                                 CopyCollectionFromStorage(*p);
01825                         }
01826                 }
01827                 else
01828                         CopyCollectionFromMemory(*p);
01829         }
01830         COMCATCH(;)
01831 }
01832 
01833 STDMETHODIMP CCoreCollectionAttribute::put_Value(VARIANT p)
01834 {
01835         COMRETURN(E_INVALID_USAGE);
01836 }
01837 
01838 STDMETHODIMP CCoreCollectionAttribute::get_LoadedValue(VARIANT *p)
01839 {
01840         CHECK_OUT(p);
01841         CHECK_ZOMBIE();
01842 
01843         COMTRY
01844         {
01845                 CopyCollectionFromMemory(*p);
01846         }
01847         COMCATCH(;)
01848 }
01849 
01850 void CCoreCollectionAttribute::CopyCollectionFromMemory(VARIANT &v)
01851 {
01852         ASSERT( v.vt == VT_EMPTY );
01853 
01854         typedef CCoreCollection<TYPENAME_ELEM2COLL(ICoreObject), std::vector<ICoreObject*>, ICoreObject, CCoreObject> COMTYPE;
01855 
01856         CComObjPtr<COMTYPE> p;
01857         CreateComObject(p);
01858 
01859         p->FillAll(collection);
01860 
01861         v.pdispVal = p.Detach();
01862         v.vt = VT_DISPATCH;
01863 }
01864 
01865 void CCoreCollectionAttribute::CopyCollectionFromStorage(VARIANT &v)
01866 {
01867         ASSERT( v.vt == VT_EMPTY );
01868 
01869         ICoreStorage *storage = SetStorageThisAttribute();
01870         ASSERT( storage != NULL );
01871 
01872         CComVariant a;
01873         COMTHROW( storage->get_AttributeValue(PutOut(a)) );
01874 
01875         CCoreProject *project = GetProject();
01876         ASSERT( project != NULL );
01877 
01878         attrid_type pointer_attrid = GetAttrID() - ATTRID_COLLECTION;
01879         ASSERT( pointer_attrid != ATTRID_NONE && pointer_attrid != - ATTRID_COLLECTION );
01880 
01881         metaobjidpair_type *i;
01882         metaobjidpair_type *e;
01883         GetArrayBounds(a, i, e);
01884 
01885         typedef CCoreCollection<ICoreObjects, std::vector<ICoreObject*>, ICoreObject, CCoreObject> COMTYPE;
01886 
01887         CComObjPtr<COMTYPE> p;
01888         CreateComObject(p);
01889 
01890         SetStatusFlag(COREATTRIBUTE_COLL_UPTODATE);
01891 
01892         while( i != e )
01893         {
01894                 // *** later every loaded object will be locked
01895 
01896 #pragma warning( disable: 4244) // conversion from 'long' to 'short', possible loss of data
01897                 CComObjPtr<CCoreObject> object = project->FindObject((*i).metaid, (*i).objid);
01898 #pragma warning( default: 4244) // conversion from 'long' to 'short', possible loss of data
01899                 if( object == NULL )
01900                 {
01901 #pragma warning( disable: 4244) // conversion from 'long' to 'short', possible loss of data
01902                         object = project->CreateObject((*i).metaid, (*i).objid);
01903 #pragma warning( default: 4244) // conversion from 'long' to 'short', possible loss of data
01904                         ASSERT( object != NULL );
01905                 }
01906 
01907                 // By creating an object the value of the collection could be modified.
01908                 // Aggregated objects can make the object loaded, and thus the loaded
01909                 // pointers can point to this object.
01910 
01911                 CCoreAttribute *attribute = object->FindAttribute(pointer_attrid);
01912                 ASSERT( attribute != NULL );
01913 
01914                 if( !((CCorePointerAttrBase*)attribute)->IsLoaded() )
01915                 {
01916                         ASSERT( collection.find(object) == collection.end() );
01917                         p->Add(object);
01918 
01919                         ResetStatusFlag(COREATTRIBUTE_COLL_UPTODATE);
01920                 }
01921 
01922                 // If the attribute is loaded then the object is taken into account by the collection. 
01923                 // Actually, the pointer can point to somewhere else, or can be NULL.
01924 
01925                 ++i;
01926         }
01927 
01928         p->FillAll(collection);
01929 
01930         v.pdispVal = p.Detach();
01931         v.vt = VT_DISPATCH;
01932 }
01933 
01934 bool CCoreCollectionAttribute::IsEmptyFromStorage()
01935 {
01936         if( !collection.empty() )
01937                 return false;
01938 
01939         if( GetStatusFlag(COREATTRIBUTE_COLL_UPTODATE) )
01940                 return true;
01941 
01942         ICoreStorage *storage = SetStorageThisAttribute();
01943         ASSERT( storage != NULL );
01944 
01945         CComVariant a;
01946         COMTHROW( storage->get_AttributeValue(PutOut(a)) );
01947 
01948         CCoreProject *project = GetProject();
01949         ASSERT( project != NULL );
01950 
01951         metaobjidpair_type *i;
01952         metaobjidpair_type *e;
01953         GetArrayBounds(a, i, e);
01954 
01955         while( i != e )
01956         {
01957 #pragma warning( disable: 4244) // conversion from 'long' to 'short', possible loss of data
01958                 CComObjPtr<CCoreObject> object = project->FindObject((*i).metaid, (*i).objid);
01959 #pragma warning( default: 4244) // conversion from 'long' to 'short', possible loss of data
01960                 if( object == NULL )
01961                         return false;
01962 
01963                 ++i;
01964         }
01965 
01966         return true;
01967 }
01968