GME
13
|
00001 00002 #include "stdafx.h" 00003 00004 #include <algorithm> 00005 00006 #include "CoreObject.h" 00007 #include "CoreAttribute.h" 00008 #include "CoreProject.h" 00009 #include "CommonCollection.h" 00010 #include "CoreMetaProject.h" 00011 00012 // --------------------------- CCoreObject 00013 00014 CCoreObject::CCoreObject() 00015 { 00016 status = 0; 00017 00018 #ifdef _DEBUG 00019 project = NULL; 00020 objid = OBJID_NONE; 00021 00022 footprint[0] = '('; 00023 footprint[1] = 'C'; 00024 footprint[2] = 'O'; 00025 footprint[3] = ')'; 00026 #endif 00027 } 00028 00029 CComObjPtr<CCoreObject> CCoreObject::Create(CCoreProject *project, metaid_type metaid, objid_type objid) 00030 { 00031 ASSERT( project != NULL ); 00032 ASSERT( metaid != METAID_NONE ); 00033 ASSERT( objid != OBJID_NONE ); 00034 00035 CCoreMetaObject *metaobject; 00036 metaobject = project->GetMetaProject()->GetObject(metaid); 00037 if( metaobject == NULL ) 00038 HR_THROW(E_NOTFOUND); 00039 00040 CComObjPtr<CCoreObject> object; 00041 CreateComObject(object); 00042 00043 // nothing will throw here 00044 object->project = project; 00045 object->objid = objid; 00046 object->metaobject = metaobject; 00047 00048 project->RegisterObject(metaid, objid, object); 00049 // the object is ready for deletion 00050 00051 object->CreateAttributes(); 00052 object->CreateAggregates(); 00053 00054 return object; 00055 } 00056 00057 CCoreObject::~CCoreObject() 00058 { 00059 //ASSERT( (objid == OBJID_NONE && project == NULL && metaobject == NULL ) || 00060 // (objid != OBJID_NONE && project != NULL && metaobject != NULL) ); 00061 00062 // If this assertion fails, then we have killed the CCoreObject already. 00063 // Probably the reference count on this is wrong. 00064 00065 // TL: If the project COM object is freed before the model element COM objects, this assertion does not hold. 00066 // This is a situation when you use garbage collected environments. 00067 00068 // first kill the aggregated components 00069 aggregates.clear(); 00070 00071 // the attribute will remove itself from the list 00072 #ifndef _ATL_DEBUG_INTERFACES 00073 while( !attributes.empty() ) 00074 delete attributes.front(); 00075 #else 00076 for (auto it = attributes.begin(); it != attributes.end(); it++) 00077 delete *it; 00078 attributes.clear(); 00079 #endif 00080 00081 if( project != NULL ) 00082 project->UnregisterObject(GetMetaID(), objid); 00083 00084 #ifdef _DEBUG 00085 project = NULL; 00086 objid = OBJID_NONE; 00087 #endif 00088 } 00089 00090 HRESULT CCoreObject::AggregatedInterfaceLookup(void *pvThis, REFIID riid, LPVOID *ppv, DWORD_PTR dw) 00091 { 00092 ASSERT( ppv != NULL && *ppv == NULL ); 00093 ASSERT( dw == 0 ); 00094 00095 HRESULT hr = E_NOINTERFACE; 00096 00097 aggregates_type &aggregates = ((CCoreObject*)pvThis)->aggregates; 00098 //ASSERT( aggregates.cbegin() != aggregates.cend() ); 00099 00100 aggregates_iterator i = aggregates.begin(); 00101 aggregates_iterator e = aggregates.end(); 00102 while( i != e && hr == E_NOINTERFACE ) 00103 { 00104 ASSERT( *i != NULL ); 00105 hr = (*i)->QueryInterface(riid, ppv); 00106 00107 ++i; 00108 } 00109 00110 return hr; 00111 } 00112 00113 // ------- COM methods 00114 00115 STDMETHODIMP CCoreObject::get_Project(ICoreProject **p) 00116 { 00117 CHECK_OUT(p); 00118 00119 if( IsZombie() ) 00120 COMRETURN(E_ZOMBIE); 00121 00122 ASSERT( project != NULL ); 00123 CopyTo(project, p); 00124 return S_OK; 00125 } 00126 00127 STDMETHODIMP CCoreObject::get_MetaObject(ICoreMetaObject **p) 00128 { 00129 CHECK_OUT(p); 00130 00131 ASSERT( metaobject != NULL ); 00132 CopyTo(metaobject, p); 00133 return S_OK; 00134 } 00135 00136 STDMETHODIMP CCoreObject::get_ObjID(objid_type *p) 00137 { 00138 CHECK_OUT(p); 00139 00140 if( IsZombie() ) 00141 COMRETURN(E_ZOMBIE); 00142 00143 ASSERT( objid != 0 ); 00144 *p = objid; 00145 return S_OK; 00146 } 00147 00148 STDMETHODIMP CCoreObject::get_Attribute(attrid_type attrid, ICoreAttribute **p) 00149 { 00150 CHECK_OUT(p); 00151 00152 if( attrid == ATTRID_NONE ) 00153 return E_INVALIDARG; 00154 00155 if( IsZombie() ) 00156 COMRETURN(E_ZOMBIE); 00157 00158 CCoreAttribute *attribute = FindAttribute(attrid); 00159 if( attribute == NULL ) 00160 return E_INVALIDARG; 00161 00162 CopyTo(attribute, p); 00163 return S_OK; 00164 } 00165 00166 STDMETHODIMP CCoreObject::get_Attributes(ICoreAttributes **p) 00167 { 00168 CHECK_OUT(p); 00169 00170 COMTRY 00171 { 00172 typedef CCoreCollection<ICoreAttributes, std::vector<ICoreAttribute*>, 00173 ICoreAttribute, CCoreAttribute> COMTYPE; 00174 00175 CComObjPtr<COMTYPE> q; 00176 CreateComObject(q); 00177 00178 // forward_list doesn't have size(), so we can't reserve 00179 q->FillAllNoReserve(attributes); 00180 MoveTo(q,p); 00181 } 00182 COMCATCH(;) 00183 } 00184 00185 STDMETHODIMP CCoreObject::get_AttributeValue(attrid_type attrid, VARIANT *p) 00186 { 00187 CHECK_OUT(p); 00188 00189 if( IsZombie() ) 00190 COMRETURN(E_ZOMBIE); 00191 00192 CCoreAttribute *attribute = FindAttribute(attrid); 00193 if( attribute == NULL ) 00194 return E_INVALIDARG; 00195 00196 return attribute->get_Value(p); 00197 } 00198 00199 STDMETHODIMP CCoreObject::put_AttributeValue(attrid_type attrid, VARIANT p) 00200 { 00201 if( IsZombie() ) 00202 COMRETURN(E_ZOMBIE); 00203 00204 CCoreAttribute *attribute = FindAttribute(attrid); 00205 if( attribute == NULL ) 00206 return E_INVALIDARG; 00207 00208 return attribute->put_Value(p); 00209 } 00210 00211 STDMETHODIMP CCoreObject::get_LoadedAttrValue(attrid_type attrid, VARIANT *p) 00212 { 00213 CHECK_OUT(p); 00214 00215 if( IsZombie() ) 00216 COMRETURN(E_ZOMBIE); 00217 00218 CCoreAttribute *attribute = FindAttribute(attrid); 00219 if( attribute == NULL ) 00220 return E_INVALIDARG; 00221 00222 return attribute->get_LoadedValue(p); 00223 } 00224 00225 STDMETHODIMP CCoreObject::get_PreviousAttrValue(attrid_type attrid, VARIANT *p) 00226 { 00227 CHECK_OUT(p); 00228 00229 if( IsZombie() ) 00230 COMRETURN(E_ZOMBIE); 00231 00232 CCoreAttribute *attribute = FindAttribute(attrid); 00233 if( attribute == NULL ) 00234 return E_INVALIDARG; 00235 00236 return attribute->get_PreviousValue(p); 00237 } 00238 00239 STDMETHODIMP CCoreObject::get_PeerLockValue(attrid_type attrid, locking_type *p) 00240 { 00241 CHECK_OUT(p); 00242 00243 if( IsZombie() ) 00244 COMRETURN(E_ZOMBIE); 00245 00246 CCoreAttribute *attribute = FindAttribute(attrid); 00247 if( attribute == NULL || attribute->GetValType() != VALTYPE_LOCK ) 00248 return E_INVALIDARG; 00249 00250 return ((CCoreLockAttribute*)attribute)->get_PeerLockValue(p); 00251 } 00252 00253 STDMETHODIMP CCoreObject::SearchCollection(attrid_type coll_attrid, attrid_type search_attrid, 00254 VARIANT search_value, ICoreObject **p) 00255 { 00256 return E_NOTIMPL; 00257 } 00258 00259 STDMETHODIMP CCoreObject::get_IsDeleted(VARIANT_BOOL *p) 00260 { 00261 CHECK_OUT(p); 00262 00263 if( IsZombie() ) 00264 COMRETURN(E_ZOMBIE); 00265 00266 *p = VARIANT_FALSE; 00267 00268 COMTRY 00269 { 00270 CCoreAttribute *lock = FindAttribute(ATTRID_LOCK); 00271 ASSERT( lock != NULL && lock->GetValType() == VALTYPE_LOCK ); 00272 00273 if( static_cast<CCoreLockAttribute*>(lock)->IsLoaded() && 00274 HasEmptyPointers() && 00275 (objid != OBJID_ROOT || GetMetaID() != METAID_ROOT) ) 00276 { 00277 *p = VARIANT_TRUE; 00278 } 00279 } 00280 COMCATCH(;) 00281 } 00282 00283 STDMETHODIMP CCoreObject::Delete() 00284 { 00285 if( IsZombie() ) 00286 COMRETURN(E_ZOMBIE); 00287 00288 COMTRY 00289 { 00290 CCoreAttribute *lock = FindAttribute(ATTRID_LOCK); 00291 ASSERT( lock != NULL && lock->GetValType() == VALTYPE_LOCK ); 00292 00293 COMTHROW( lock->put_Value(PutInVariant(locking_type(LOCKING_EXCLUSIVE))) ); 00294 00295 attributes_iterator i = attributes.begin(); 00296 attributes_iterator e = attributes.end(); 00297 while( i != e ) 00298 { 00299 if( (*i)->GetValType() == VALTYPE_COLLECTION ) 00300 { 00301 if( !((CCoreCollectionAttribute*)(*i))->IsEmptyFromStorage() ) 00302 HR_THROW(E_NONEMPTY_COLL); 00303 } 00304 00305 ++i; 00306 } 00307 00308 i = attributes.begin(); 00309 while( i != e ) 00310 { 00311 if( (*i)->GetValType() == VALTYPE_POINTER ) 00312 COMTHROW( (*i)->put_Value(PutInVariant((IDispatch*)NULL)) ); 00313 00314 ++i; 00315 } 00316 00317 COMTHROW( lock->put_Value(PutInVariant(locking_type(PUT_DELETE_DONE_LOCK))) ); 00318 } 00319 COMCATCH(;) 00320 } 00321 00322 STDMETHODIMP CCoreObject::Clone(ICoreObject **p) 00323 { 00324 return E_NOTIMPL; 00325 } 00326 00327 // ------- Creation 00328 00329 void CCoreObject::CreateAttributes() 00330 { 00331 ASSERT( attributes.empty() ); 00332 00333 typedef CCoreMetaObject::attributes_type metaattributes_type; 00334 00335 ASSERT( metaobject != NULL ); 00336 const metaattributes_type &metaattributes = metaobject->GetAttributes(); 00337 00338 metaattributes_type::const_iterator i = metaattributes.begin(); 00339 metaattributes_type::const_iterator e = metaattributes.end(); 00340 while( i != e ) 00341 { 00342 CCoreAttribute::Create(this, *i); 00343 00344 ++i; 00345 } 00346 } 00347 00348 void CCoreObject::CreateAggregates() 00349 { 00350 CComSafeArray p; 00351 COMTHROW( metaobject->get_ClassIDs(PutOut(p)) ); 00352 ASSERT( p != NULL ); 00353 00354 const std::vector<::GUID> &classids = metaobject->GetClassIDs(); 00355 00356 std::vector<::GUID>::const_iterator i = classids.begin(); 00357 std::vector<::GUID>::const_iterator e = classids.end(); 00358 while( i != e ) 00359 { 00360 CComObjPtr<IUnknown> aggregated; 00361 00362 COMTHROW( CoCreateInstance(*i, CastToUnknown(this), CLSCTX_ALL, IID_IUnknown, 00363 (void**)PutOut(aggregated)) ); 00364 ASSERT( aggregated != NULL ); 00365 00366 aggregates.push_front(CComObjPtr<IUnknown>(0)); 00367 MoveTo(aggregated, aggregates.front()); 00368 00369 ++i; 00370 } 00371 } 00372 00373 void CCoreObject::FillAfterCreateObject() 00374 { 00375 ASSERT( !attributes.empty() ); 00376 00377 attributes_iterator i = attributes.begin(); 00378 attributes_iterator e = attributes.end(); 00379 while( i != e ) 00380 { 00381 (*i)->FillAfterCreateObject(); 00382 ++i; 00383 } 00384 00385 RegisterFinalTrItem(); 00386 } 00387 00388 // ------- Methods 00389 00390 CCoreAttribute *CCoreObject::FindAttribute(attrid_type attrid) const 00391 { 00392 attributes_type::const_iterator i = attributes.begin(); 00393 attributes_type::const_iterator e = attributes.end(); 00394 while( i != e ) 00395 { 00396 if( (*i)->GetAttrID() == attrid ) 00397 { 00398 ASSERT( attrid != ATTRID_NONE ); 00399 return *i; 00400 } 00401 00402 ++i; 00403 } 00404 00405 return NULL; 00406 } 00407 00408 void CCoreObject::RegisterAttribute(CCoreAttribute *attribute) 00409 { 00410 ASSERT( attribute != NULL ); 00411 #ifdef DEBUG_CONTAINERS 00412 ASSERT( find(attributes.begin(), attributes.end(), attribute) == attributes.end() ); 00413 ASSERT( FindAttribute(attribute->GetAttrID()) == NULL ); 00414 #endif 00415 00416 attributes.push_front(attribute); 00417 } 00418 00419 void CCoreObject::UnregisterAttribute(CCoreAttribute *attribute) 00420 { 00421 ASSERT( attribute != NULL ); 00422 ASSERT( FindAttribute(attribute->GetAttrID()) != NULL ); 00423 00424 attributes_iterator i = std::find(attributes.begin(), attributes.end(), attribute); 00425 ASSERT( i != attributes.end() ); 00426 00427 //attributes.erase(i); 00428 attributes.remove(attribute); 00429 } 00430 00431 template<class Functor, class UnwindFunctor> 00432 void CCoreObject::GetAttributes(CCoreLockAttribute *lockattribute, Functor& f, UnwindFunctor& uf) 00433 { 00434 ASSERT( lockattribute != NULL ); 00435 00436 #ifdef _DEBUG 00437 attrid_type attrid = lockattribute->GetAttrID(); 00438 #endif 00439 00440 attributes_iterator i = attributes.begin(); 00441 attributes_iterator e = attributes.end(); 00442 try 00443 { 00444 while( i != e ) 00445 { 00446 00447 #ifdef _DEBUG 00448 attrid_type lockattrid = ATTRID_NONE; 00449 ASSERT( (*i)->GetMetaAttribute()->get_LockAttrID(&lockattrid) == S_OK ); 00450 #endif 00451 00452 if( (*i)->GetLockAttr() == lockattribute ) 00453 { 00454 ASSERT( lockattrid == attrid ); 00455 f(*i); 00456 } 00457 00458 ++i; 00459 } 00460 } 00461 catch(hresult_exception&) 00462 { 00463 e = i; 00464 i = attributes.begin(); 00465 while( i != e ) 00466 { 00467 if( (*i)->GetLockAttr() == lockattribute ) 00468 { 00469 uf(*i); 00470 } 00471 00472 ++i; 00473 } 00474 00475 throw; 00476 } 00477 } 00478 00479 void CCoreObject::LoadAttributes(CCoreLockAttribute *lockattribute) 00480 { 00481 ASSERT( lockattribute != NULL ); 00482 00483 GetAttributes(lockattribute, [](CCoreAttribute* i){ i->Load(); }, 00484 [](CCoreAttribute* i){ i->Unload(); } 00485 ); 00486 } 00487 00488 void CCoreObject::UnloadAttributes(CCoreLockAttribute *lockattribute) 00489 { 00490 ASSERT( lockattribute != NULL ); 00491 00492 GetAttributes(lockattribute, [](CCoreAttribute* i){ i->Unload(); }, [](CCoreAttribute* i){}); 00493 } 00494 00495 // ------- Status 00496 00497 bool CCoreObject::InTransaction() const 00498 { 00499 ASSERT( !IsZombie() ); 00500 ASSERT( project != NULL ); 00501 00502 return project->InTransaction(); 00503 } 00504 00505 bool CCoreObject::InWriteTransaction() const 00506 { 00507 ASSERT( !IsZombie() ); 00508 ASSERT( project != NULL ); 00509 00510 return project->InWriteTransaction(); 00511 } 00512 00513 void CCoreObject::SetZombie() 00514 { 00515 ASSERT( project != NULL ); 00516 00517 // we do not unregister, the object_lookup is cleared 00518 00519 #ifdef _ATL_DEBUG_INTERFACES 00520 attributes_type::const_iterator i = attributes.begin(); 00521 attributes_type::const_iterator e = attributes.end(); 00522 while( i != e ) 00523 { 00524 if ((*i)->GetAttrID() == ATTRID_LOCK) 00525 ASSERT(!((CCoreLockAttribute*)*i)->GetStatusFlag(CCoreAttribute::COREATTRIBUTE_LOCKGROUP_LOADED)); 00526 00527 (*i)->Release(); 00528 i++; 00529 } 00530 cleanup.clear(); 00531 #endif 00532 00533 project = NULL; 00534 metaobject = NULL; 00535 } 00536 00537 bool CCoreObject::HasEmptyPointers() const 00538 { 00539 ASSERT( project != NULL ); 00540 00541 attributes_type::const_iterator i = attributes.begin(); 00542 attributes_type::const_iterator e = attributes.end(); 00543 while( i != e ) 00544 { 00545 if( (*i)->GetValType() == VALTYPE_POINTER ) 00546 { 00547 if( !((CCorePointerAttrBase*)(*i))->IsEmpty() ) 00548 return false; 00549 } 00550 00551 ++i; 00552 } 00553 00554 return true; 00555 } 00556 00557 bool CCoreObject::HasEmptyPointersAndLocks() const 00558 { 00559 ASSERT( project != NULL ); 00560 00561 attributes_type::const_iterator i = attributes.begin(); 00562 attributes_type::const_iterator e = attributes.end(); 00563 while( i != e ) 00564 { 00565 valtype_type valtype = (*i)->GetValType(); 00566 00567 if( valtype == VALTYPE_LOCK ) 00568 { 00569 if( !((CCoreLockAttribute*)(*i))->IsEmpty() ) 00570 return false; 00571 } 00572 else if( valtype == VALTYPE_POINTER ) 00573 { 00574 if( !((CCorePointerAttrBase*)(*i))->IsEmpty() ) 00575 return false; 00576 } 00577 00578 ++i; 00579 } 00580 00581 return true; 00582 } 00583 00584 // ------- Debug 00585 00586 #ifdef _DEBUG 00587 00588 void CCoreObject::Dump() 00589 { 00590 ASSERT( metaobject != NULL ); 00591 00592 CComBstrObj metabstr; 00593 COMTHROW( metaobject->get_Name(PutOut(metabstr)) ); 00594 00595 std::string metaname; 00596 CopyTo(metabstr, metaname); 00597 00598 attributes_type::size_type size = 0; 00599 std::for_each(attributes.begin(), attributes.end(), 00600 [&size](const attributes_type::value_type& e) { size++; }); 00601 AtlTrace("object_dump metaid=%d metaname=\"%s\" objid=%d, #attrs: %d\n", 00602 (int)GetMetaID(), metaname.begin(), (int)objid, size); 00603 00604 attributes_iterator i = attributes.begin(); 00605 attributes_iterator e = attributes.end(); 00606 while( i != e ) 00607 { 00608 (*i)->Dump(); 00609 00610 ++i; 00611 } 00612 } 00613 00614 #endif 00615 00616 // ------- FinalTrItem 00617 00618 void CCoreObject::RegisterFinalTrItem() 00619 { 00620 ASSERT( project ); 00621 00622 if( !IsDirty() ) 00623 { 00624 project->RegisterFinalTrItem(this); 00625 SetDirty(); 00626 } 00627 } 00628 00629 void CCoreObject::AbortFinalTransaction() 00630 { 00631 ASSERT( IsDirty() ); 00632 00633 // keep this object alive 00634 CComObjPtr<ICoreObject> self(this); 00635 00636 attributes_iterator i = attributes.begin(); 00637 attributes_iterator e = attributes.end(); 00638 while( i != e ) 00639 { 00640 if( (*i)->IsDirty() ) 00641 { 00642 (*i)->AbortFinalTransaction(); 00643 ASSERT( !(*i)->IsDirty() ); 00644 } 00645 00646 ++i; 00647 } 00648 00649 ResetDirty(); 00650 } 00651 00652 void CCoreObject::CommitFinalTransaction() 00653 { 00654 ASSERT( IsDirty() ); 00655 00656 if( HasEmptyPointersAndLocks() && (objid != OBJID_ROOT || GetMetaID() != METAID_ROOT) ) 00657 { 00658 ASSERT( project != NULL ); 00659 ICoreStorage *storage = project->SetStorageObject(this); 00660 ASSERT( storage != NULL ); 00661 00662 COMTHROW( storage->DeleteObject() ); 00663 } 00664 else 00665 { 00666 attributes_iterator i = attributes.begin(); 00667 attributes_iterator e = attributes.end(); 00668 while( i != e ) 00669 { 00670 if( (*i)->IsDirty() ) 00671 { 00672 (*i)->CommitFinalTransaction(); 00673 ASSERT( (*i)->IsDirty() ); 00674 } 00675 00676 ++i; 00677 } 00678 } 00679 } 00680 00681 void CCoreObject::CommitFinalTransactionFinish(bool undo) 00682 { 00683 ASSERT( IsDirty() ); 00684 00685 // keep this object alive 00686 CComObjPtr<ICoreObject> self(this); 00687 00688 attributes_iterator i = attributes.begin(); 00689 attributes_iterator e = attributes.end(); 00690 while( i != e ) 00691 { 00692 if( (*i)->IsDirty() ) 00693 { 00694 (*i)->CommitFinalTransactionFinish(undo); 00695 ASSERT( !(*i)->IsDirty() ); 00696 } 00697 00698 ++i; 00699 } 00700 00701 ResetDirty(); 00702 } 00703