GME
13
|
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