GME  13
CoreObject.cpp
Go to the documentation of this file.
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