GME  13
MgaDeriveOps.cpp
Go to the documentation of this file.
00001 //
00002 // MgaDeriveInfoOps.cpp : Implementation of FCO Derive dependency operations
00003 //
00004 #include "stdafx.h"
00005 #include "MgaFCO.h"
00006 
00007 // ----------------------------------------
00008 // Derive information
00009 // ----------------------------------------
00010 HRESULT FCO::GetBaseType(IMgaFCO ** basetype, IMgaFCO ** immbase, VARIANT_BOOL *isinst) {
00011                 COMTRY {
00012                         CheckRead();
00013                         CHECK_OUTPTRPARVALIDNULL(basetype)
00014                         CHECK_OUTPTRPARVALIDNULL(immbase)
00015                         if(isinst) {
00016                                 get_IsInstance(isinst);
00017                         }
00018                         if(basetype || immbase) {
00019                                 CoreObj base = self[ATTRID_DERIVED];
00020                                 if(base) {
00021                                         if(immbase) { ObjForCore(base)->getinterface(immbase); }
00022                                         if(basetype) {
00023                                                 while(self[ATTRID_PERMISSIONS] & INSTANCE_FLAG) {
00024                                                         base = base[ATTRID_DERIVED];
00025                                                         ASSERT(base);
00026                                                 }
00027                                                 ObjForCore(base)->getinterface(basetype); 
00028                                         }
00029                                 }
00030                                 else {
00031                                         if(immbase) *immbase = NULL;
00032                                         if(basetype) *basetype = NULL;
00033                                 }
00034                         }
00035                 } COMCATCH( if(immbase) *immbase = NULL; )
00036 }
00037 
00038 
00039 HRESULT FCO::get_DerivedFrom( IMgaFCO **pVal) {
00040                 COMTRY {
00041                         CheckRead();
00042                         CHECK_OUTPTRPAR(pVal);
00043                         CoreObj d = self[ATTRID_DERIVED];
00044                         if(d) ObjForCore(d)->getinterface(pVal);
00045                 } COMCATCH(; )
00046 }
00047 
00048 HRESULT FCO::get_DerivedObjects( IMgaFCOs **pVal) {
00049                 COMTRY {
00050                         CheckRead();
00051                         CREATEEXCOLLECTION_FOR(MgaFCO, q);
00052                         CoreObjs d = self[ATTRID_DERIVED+ATTRID_COLLECTION];
00053                         ITERATE_THROUGH(d) {
00054                                 CComPtr<IMgaFCO> p;
00055                                 ObjForCore(ITER)->getinterface(&p);
00056                                 q->Add(p);
00057                         }
00058                         *pVal = q.Detach();
00059                 } COMCATCH(; )
00060 }
00061 
00062 HRESULT FCO::get_Type( IMgaFCO **pVal) {
00063                 COMTRY {
00064                         CheckRead();
00065                         CHECK_OUTPTRPAR(pVal);
00066 ;
00067                         if(!(self[ATTRID_PERMISSIONS] & INSTANCE_FLAG)) COMTHROW(E_MGA_NOT_INSTANCE);
00068                         CoreObj d = self[ATTRID_DERIVED], d2;
00069                         if(d) {
00070                                 while((d2 = d[ATTRID_DERIVED]) != NULL) d <<= d2;
00071                                 ObjForCore(d)->getinterface(pVal);
00072                         }
00073                 } COMCATCH(; )
00074 }
00075 
00076 HRESULT FCO::get_BaseType( IMgaFCO **pVal) {
00077                 COMTRY {
00078                         CheckRead();
00079                         CHECK_OUTPTRPAR(pVal);
00080                         if(self[ATTRID_PERMISSIONS] & INSTANCE_FLAG) COMTHROW(E_MGA_INSTANCE);
00081                         CoreObj d = self[ATTRID_DERIVED];
00082                         if(d) ObjForCore(d)->getinterface(pVal);
00083                 } COMCATCH(; )
00084 }
00085 
00086 HRESULT FCO::get_ArcheType( IMgaFCO **pVal) {
00087                 COMTRY {
00088                         CheckRead();
00089                         CHECK_OUTPTRPAR(pVal);
00090                         CoreObj d = self[ATTRID_DERIVED], d2;
00091                         if(d) {
00092                                 while((d2 = d[ATTRID_DERIVED]) != NULL) d <<= d2;
00093                                 ObjForCore(d)->getinterface(pVal);
00094                         }
00095                 } COMCATCH(; )
00096 }
00097 
00098 HRESULT FCO::get_IsInstance( VARIANT_BOOL *pVal) {
00099                 COMTRY {
00100                         CheckRead();
00101                         CHECK_OUTPAR(pVal);
00102                         *pVal = self[ATTRID_PERMISSIONS] & INSTANCE_FLAG ? VARIANT_TRUE : VARIANT_FALSE;
00103                 } COMCATCH(; )
00104 }
00105 
00106 HRESULT FCO::get_IsLibObject( VARIANT_BOOL *pVal) {
00107                 COMTRY {
00108                         CheckRead();
00109                         CHECK_OUTPAR(pVal);
00110                         *pVal = self[ATTRID_PERMISSIONS] & LIBRARY_FLAG ? VARIANT_TRUE : VARIANT_FALSE;
00111                 } COMCATCH(; )
00112 }
00113 
00114 HRESULT FCO::get_IsPrimaryDerived( VARIANT_BOOL *pVal) {
00115                 COMTRY {
00116                         CheckRead();
00117                         CHECK_OUTPAR(pVal);
00118                         CoreObj d = self[ATTRID_DERIVED];
00119                         if(d && self[ATTRID_RELID] < RELIDSPACE) {
00120                                 *pVal = VARIANT_TRUE;
00121                         }
00122                         else *pVal = VARIANT_FALSE;
00123                 } COMCATCH(; )
00124 }
00125 
00126 
00127 HRESULT FCO::get_AllBaseTypes(IMgaFCOs **bases) {       // retuns itself if root model
00128         COMTRY {
00129                 CoreObj cur = self;
00130                 CREATEEXCOLLECTION_FOR(MgaFCO, q);
00131                 while(GetMetaID(cur) != DTID_FOLDER) {
00132                         if(cur[ATTRID_RELID] < RELIDSPACE) {
00133                                 CoreObj base = cur[ATTRID_DERIVED];
00134                                 if(base) {
00135                                         CComPtr<IMgaFCO> ff;
00136                                         ObjForCore(base)->getinterface(&ff);
00137                                         q->Add(ff);
00138                                 }
00139                         }
00140                         cur = cur[ATTRID_FCOPARENT];
00141                         ASSERT(cur);
00142                 }
00143                 *bases = q.Detach();
00144         } COMCATCH(;)
00145 }
00146 
00147 
00148 HRESULT FCO::get_ChildDerivedFrom(IMgaFCO *baseobj, IMgaFCO **pVal) {
00149         COMTRY {
00150                 CHECK_MYINPTRPAR(baseobj);
00151                 CHECK_OUTPTRPAR(pVal);
00152                 CoreObj bchild(baseobj);
00153                 CoreObj bparent = self[ATTRID_DERIVED];
00154                 if(!bparent || !COM_EQUAL(bparent, CoreObj(bchild[ATTRID_FCOPARENT]))) COMTHROW(E_MGA_NOT_DERIVED);
00155                 CoreObj selfchild;
00156                 GetDerivedEquivalent(bchild, self, selfchild, 1);
00157                 if(!selfchild)  COMTHROW(E_MGA_META_VIOLATION);
00158                 ObjForCore(selfchild)->getinterface(pVal);
00159         } COMCATCH(;)
00160 }
00161 
00162 
00163 
00164 // ----------------------------------------
00165 // NON-members that use CoreObjs 
00166 // ----------------------------------------
00167 
00168 // check if the original master of this relation is internal or external
00169 // does not check the internality of references within connections!
00170 bool IsInternalRelation(CoreObj src) {
00171         CoreObj m;
00172         while((m = src.GetMaster()) != NULL) src = m;
00173         attrid_type a = 0;
00174         switch(src.GetMetaID()) {
00175         case DTID_REFERENCE: a = ATTRID_REFERENCE; break;       
00176         case DTID_CONNROLE:      a = ATTRID_XREF; break;        
00177         case DTID_SETNODE:       a = ATTRID_XREF; break;        
00178         case DTID_REFATTR:       a = ATTRID_XREF; break;        
00179         case DTID_CONNROLESEG:   a = ATTRID_SEGREF;     break;
00180         default: COMTHROW(E_MGA_DATA_INCONSISTENCY);
00181         }
00182         CoreObj target = src[a];
00183         if(!target) return false;
00184         CoreObj p1, p2;
00185         GetRootOfDeriv(target, p1);
00186         GetRootOfDeriv(src.GetMgaObj(), p2);
00187         return p1 && COM_EQUAL(p1,p2);
00188 }
00189 
00190 // in the diagram below a model M is instantiated/subtyped into Mi
00191 // M contains reference r, pointing to A
00192 // Mi will contain derived reference ri, and derived target object Ai
00193 // Mj will contain derived reference rj, and derived target object Aj
00194 // this is the internal reference redirection scenario, so when MGA detects
00195 // that secondary derived references (r) have their targets set like here to 
00196 // another secondary derived object (A) it must perform the redirect job
00197 // i.e.: ri->Ai, rj->Aj
00198 // external references (let's suppose p refers to B, p->B) can't be redirected
00199 // automatically because there is no clue how Mi, Mj relate to B1, B2
00200 //
00201 //        M-------------                  B       
00202 //        |             |               /   \     
00203 //        | r--->A      |              /     \    
00204 //        | p           |            / \     / \  
00205 //         -------------            /I/S\   /I/S\ 
00206 //          /           \           ----    ----- 
00207 //         |             |           |        |   
00208 //        / \           / \          B1       B2  
00209 //       /I/S\         /I/S\              
00210 //       -----         -----              
00211 //         |              |               
00212 //  Mi------------     Mj------------     
00213 //  |             |    |             |    
00214 //  | ri---->Ai   |    | rj---->Aj   |    
00215 //  |             |    |             |    
00216 //   -------------      -------------     
00217 //
00218 // this method GetDerivedEquivalent gives back/finds Ai [corresponding for A] in Mi
00219 // and is called like:
00220 // GetDerivedEquivalent( A, Mi, [out] Ai, [in] level = -1)
00221 // the corresponding parameters are (names taken from the diagram above)
00222 void GetDerivedEquivalent(CoreObj const &objinbase, CoreObj const &subtype, CoreObj &objinsubtype, int level) {
00223         CoreObj basetype= subtype[ATTRID_DERIVED];
00224         ASSERT(basetype);
00225         CoreObj o = objinbase;
00226         
00227         if(!objinbase || (level < 0 && !IsContained(o,basetype, &level)) ) {
00228                 objinsubtype = objinbase;
00229                 return;
00230         }
00231         CoreObjs subs = objinbase[ATTRID_DERIVED + ATTRID_COLLECTION];
00232         ITERATE_THROUGH(subs) {
00233                 if( COM_EQUAL(subtype, ITER.FollowChain(ATTRID_FCOPARENT, level))) {
00234                         objinsubtype = ITER;
00235                         return;
00236                 }
00237         }
00238         COMTHROW(E_MGA_DATA_INCONSISTENCY);
00239 }
00240 
00241 
00242 // ----------------------------------------
00243 // DeriveTreeTask
00244 // ----------------------------------------
00245 void DeriveTreeTask::_DoWithDeriveds(CoreObj self, std::vector<CoreObj> *peers) {
00246                 CoreObjs chds = self[masterattr + ATTRID_COLLECTION];  // do it first to enable delete operations...
00247                 if(!Do(self, peers))
00248                         return;
00249                 ITERATE_THROUGH(chds) {
00250                         if(peercnt) {
00251                                 CoreObj r = ITER.FollowChain(ATTRID_FCOPARENT, selfdepth);
00252                                 std::vector<CoreObj> subpeers(peercnt);
00253                                 int i;
00254                                 for(i = 0; i < internalpeercnt; i++) {                  // first the internals
00255                                         GetDerivedEquivalent((*peers)[i], r, subpeers[i], peerdepths[i]);
00256                                 }
00257                                 for(; i < peercnt; i++) subpeers[i] = (*peers)[i];  // the rest are externals
00258                                 _DoWithDeriveds(ITER, &subpeers);
00259                         }
00260                         else  _DoWithDeriveds(ITER, peers);             
00261                 }
00262 }
00263 
00264 // before starting with the initial object it is determined 
00265 // which targets are 'internal' i.e. to be adjusted for the subtypes
00266 // internal refs always preceed external refs in the peers list.
00267 // 'false internals' (references into the same derive tree, but inherited 
00268 // from a basetype) are rare, but they can be avoided through setting 
00269 // the 'endreserve' data member (e.g. at RevertToBase) 
00270 
00271 // masterattr the attribute followed recuresively. It can either be ATTRID_DERIVEDS
00272 // or ATTRID_MASTEROBJ. It is usually determined by the objecttype, but in case of 
00273 // references, it can be preset by the user.
00274 void DeriveTreeTask::DoWithDeriveds(CoreObj self, std::vector<CoreObj> *peers) {
00275                 if(GetMetaID(self) == DTID_FOLDER) Do(self, peers);  // no derived objects
00276                 else {
00277                         ASSERT(!masterattr || self.GetMetaID() == DTID_REFERENCE);
00278                         if(!masterattr) {
00279                                 if(self.IsFCO()) masterattr = ATTRID_DERIVED;
00280                                 else {
00281                                         ASSERT(GetMetaID(self) == DTID_CONNROLE || GetMetaID(self) == DTID_SETNODE);
00282                                         masterattr = ATTRID_MASTEROBJ;
00283                                 }
00284                         }
00285                         CoreObjs chds = self[masterattr + ATTRID_COLLECTION];
00286                         if(!peers) peercnt = internalpeercnt = 0;
00287                         else if(!chds.Count()) {
00288                                 peercnt = (*peers).size();
00289                                 internalpeercnt = 0;
00290                         }
00291                         else {
00292                                 CoreObj r;
00293                                 GetRootOfDeriv(self, r, &selfdepth);
00294                                 ASSERT(r);
00295                                 peercnt = (*peers).size();
00296                                 peerdepths.resize(peercnt);   // only internalpeercnt will be used, but we do not know that number yet
00297                                 int i;
00298                                 for(i = 0; i < peercnt-endreserve; i++) {
00299                                         int l;
00300                                         CoreObj r2;
00301                                         if((*peers)[i] == NULL) break;
00302                                         GetRootOfDeriv((*peers)[i], r2, &l);
00303                                         if(COM_EQUAL(r,r2)) peerdepths[i] = l;
00304                                         else break; 
00305                                 }
00306                                 internalpeercnt = i;
00307                         }
00308                         _DoWithDeriveds(self, peers);
00309                 }
00310 }
00311 
00312 
00313 // ----------------------------------------
00314 // Attach/detach
00315 // ----------------------------------------
00316 HRESULT FCO::DetachFromArcheType ()
00317 {
00318         COMTRY_IN_TRANSACTION {
00319                 CheckWrite();
00320                 CoreObj d = self[ATTRID_DERIVED], d2;
00321                 if(d) { // if self is really derived from something (d)
00322                         while((d2 = d[ATTRID_DERIVED]) != NULL) 
00323                                 d <<= d2;
00324 
00325                         // copy/merge/detach from parent to self (overwrite the derivation)
00326                         // almost like ObjTreeCopy, copies from 'd' (the archetype) to 'self' (the derived)
00327                         coreobjpairhash crealist2;
00328                         ObjDetachAndMerge(mgaproject, d, self, crealist2, 0, true);
00329 
00330                 }
00331                 SelfMark(OBJEVENT_SUBT_INST);
00332 
00333                 // Need to run this check: "inherited ref can only refer to a derived instance of the target of its base"
00334                 {
00335                         CoreObjs segs = self[ATTRID_REFERENCE + ATTRID_COLLECTION];
00336                         ITERATE_THROUGH(segs) {
00337                                 CComPtr<IMgaFCO> ffco;
00338                                 ObjForCore(ITER)->getinterface(&ffco);
00339                                 COMTHROW(ffco->Check());
00340                         }
00341                 }
00342 
00343                 CComPtr<IMgaFCO> selfFco;
00344                 ObjForCore(self)->getinterface(&selfFco);
00345                 COMTHROW(selfFco->Check());
00346 
00347                 CoreObjMark(self[ATTRID_PARENT], OBJEVENT_LOSTCHILD);
00348         } COMCATCH_IN_TRANSACTION(;);
00349 
00350         return S_OK;
00351 }
00352 
00353 // if instance is needed all inner objects in 'self' must be attachable to a corresponding object in 'newtype'
00354 // if subtype is needed then attachment happens with (name & kind) matchable elements [these become secondary derived]
00355 // and any other object in 'self' will become additional plain object
00356 HRESULT FCO::AttachToArcheType( IMgaFCO *newtype,  VARIANT_BOOL instance) {
00357         COMTRY_IN_TRANSACTION {
00358                 CHECK_MYINPTRPAR(newtype);
00359                 CoreObj ntype(newtype);
00360                 coreobjpairhash crealist2;
00361                 // attaches self to nettype (the new base) if possible
00362                 ObjAttach( mgaproject, ntype, self, crealist2, instance, true );
00363                 CoreObjMark( ntype, OBJEVENT_SUBT_INST);
00364         } COMCATCH_IN_TRANSACTION(;)
00365 }