public void ApplyChangesToOriginals(ICUDResult cudResult, IOriCollection oriCollection, ICache cache) { if (GuiThreadHelper.IsInGuiThread()) { ApplyChangesToOriginalsIntern(cudResult, oriCollection, cache); return; } GuiThreadHelper.InvokeInGuiAndWait(new IBackgroundWorkerDelegate(delegate() { ApplyChangesToOriginalsIntern(cudResult, oriCollection, cache); })); }
protected void ApplyChangesToOriginalsIntern(ICUDResult cudResult, IOriCollection oriCollection, ICache cache) { ICacheModification cacheModification = this.CacheModification; IConversionHelper conversionHelper = this.ConversionHelper; IEntityMetaDataProvider entityMetaDataProvider = this.EntityMetaDataProvider; IList <Object> originalRefs = cudResult.GetOriginalRefs(); IList <IObjRef> allChangeORIs = oriCollection.AllChangeORIs; String[] allChangedBy = oriCollection.AllChangedBy; long[] allChangedOn = oriCollection.AllChangedOn; String singleChangedBy = oriCollection.ChangedBy; long? singleChangedOn = oriCollection.ChangedOn; bool newInstanceOnCall = CacheProvider.IsNewInstanceOnCall; IList <Object> validObjects = new List <Object>(originalRefs.Count); bool oldCacheModificationValue = CacheModification.Active; CacheModification.Active = true; try { for (int a = originalRefs.Count; a-- > 0;) { Object originalRef = originalRefs[a]; IObjRef ori = allChangeORIs[a]; if (originalRef == null) { // Object has been deleted by cascade delete contraints on server merge or simply a "not specified" original ref continue; } if (originalRef is IObjRef) { continue; } long? changedOn = allChangedOn != null ? allChangedOn[a] : singleChangedOn; String changedBy = allChangedBy != null ? allChangedBy[a] : singleChangedBy; IEntityMetaData metaData = ((IEntityMetaDataHolder)originalRef).Get__EntityMetaData(); PrimitiveMember versionMember = metaData.VersionMember; PrimitiveMember keyMember = metaData.IdMember; PrimitiveMember onMember, byMember; if (keyMember.GetValue(originalRef, false) == null) { onMember = metaData.CreatedOnMember; byMember = metaData.CreatedByMember; } else { onMember = metaData.UpdatedOnMember; byMember = metaData.UpdatedByMember; } if (onMember != null && changedOn != null) { Object createdOn = ConversionHelper.ConvertValueToType(onMember.ElementType, changedOn); onMember.SetValue(originalRef, createdOn); } if (byMember != null && changedBy != null) { Object createdBy = ConversionHelper.ConvertValueToType(byMember.ElementType, changedBy); byMember.SetValue(originalRef, createdBy); } if (ori == null) { keyMember.SetValue(originalRef, null); if (versionMember != null) { versionMember.SetValue(originalRef, null); } if (originalRef is IDataObject) { ((IDataObject)originalRef).ToBeUpdated = false; ((IDataObject)originalRef).ToBeDeleted = false; } continue; // Object has been deleted directly } keyMember.SetValue(originalRef, ConversionHelper.ConvertValueToType(keyMember.RealType, ori.Id)); if (versionMember != null) { if (AlwaysUpdateVersionInChangedEntities) { versionMember.SetValue(originalRef, ConversionHelper.ConvertValueToType(versionMember.RealType, ori.Version)); } else { // We INTENTIONALLY do NOT set the version and let it on its old value, to force the following DCE to refresh the cached object with 'real' data // If we set the version here to the ori.getVersion(), the DCE will 'see' a already valid object - but is IS NOT valid // because it may not contain bi-directional information which can only be resolved by reloading the object from persistence layer //versionMember.SetValue(originalRef, null); } } if (originalRef is IDataObject) { ((IDataObject)originalRef).ToBeUpdated = false; ((IDataObject)originalRef).ToBeDeleted = false; } validObjects.Add(originalRef); } PutInstancesToCurrentCache(validObjects, cache); } finally { CacheModification.Active = oldCacheModificationValue; } }
protected IOriCollection MergeIntern(ICUDResult cudResultOriginal, IMethodDescription methodDescription) { IResultingBackgroundWorkerDelegate <IOriCollection> runnable = new IResultingBackgroundWorkerDelegate <IOriCollection>(delegate() { IDisposableCache childCache = CacheFactory.CreatePrivileged(CacheFactoryDirective.SubscribeTransactionalDCE, false, false, "MergeServiceRegistry.STATE"); try { IncrementalMergeState state = null; ICUDResult cudResultOfCache; if (MergeProcess.IsAddNewlyPersistedEntities() || (Log.DebugEnabled && CudResultPrinter != null)) { childCache = CacheFactory.CreatePrivileged(CacheFactoryDirective.SubscribeTransactionalDCE, false, false, "MergeServiceRegistry.STATE"); state = (IncrementalMergeState)CudResultApplier.AcquireNewState(childCache); cudResultOfCache = CudResultApplier.ApplyCUDResultOnEntitiesOfCache(cudResultOriginal, true, state); } else { cudResultOfCache = cudResultOriginal; } if (Log.DebugEnabled) { if (CudResultPrinter != null) { Log.Debug("Initial merge [" + RuntimeHelpers.GetHashCode(state) + "]:\n" + CudResultPrinter.PrintCUDResult(cudResultOfCache, state)); } else { Log.Debug("Initial merge [" + RuntimeHelpers.GetHashCode(state) + "]. No Details available"); } } List <MergeOperation> mergeOperationSequence = new List <MergeOperation>(); ICUDResult extendedCudResult = WhatIfMerged(cudResultOfCache, methodDescription, mergeOperationSequence, state); if (Log.DebugEnabled) { Log.Debug("Merge finished [" + RuntimeHelpers.GetHashCode(state) + "]"); } if (MergeSecurityManager != null) { SecurityActive.ExecuteWithSecurityDirective(SecurityDirective.ENABLE_ENTITY_CHECK, delegate() { MergeSecurityManager.CheckMergeAccess(extendedCudResult, methodDescription); }); } List <Object> originalRefsOfCache = new List <Object>(cudResultOfCache.GetOriginalRefs()); List <Object> originalRefsExtended = new List <Object>(extendedCudResult.GetOriginalRefs()); IOriCollection oriCollExtended = Intern(extendedCudResult, methodDescription, mergeOperationSequence, state); IList <IChangeContainer> allChangesOriginal = cudResultOriginal.AllChanges; IList <IObjRef> allChangedObjRefsExtended = oriCollExtended.AllChangeORIs; IObjRef[] allChangedObjRefsResult = new IObjRef[allChangesOriginal.Count]; IdentityHashMap <Object, int?> originalRefOfCacheToIndexMap = new IdentityHashMap <Object, int?>(); for (int a = originalRefsOfCache.Count; a-- > 0;) { originalRefOfCacheToIndexMap.Put(originalRefsOfCache[a], a); } for (int a = originalRefsExtended.Count; a-- > 0;) { int?indexOfCache = originalRefOfCacheToIndexMap.Get(originalRefsExtended[a]); if (indexOfCache == null) { // this is a change implied by a rule or an persistence-implicit change // we do not know about it in the outer original CUDResult continue; } IObjRef objRefExtended = allChangedObjRefsExtended[a]; IObjRef objRefOriginal = allChangesOriginal[indexOfCache.Value].Reference; if (objRefExtended == null) { // entity has been deleted objRefOriginal.Id = null; objRefOriginal.Version = null; } else { objRefOriginal.Id = objRefExtended.Id; objRefOriginal.Version = objRefExtended.Version; } if (objRefOriginal is IDirectObjRef) { ((IDirectObjRef)objRefOriginal).Direct = null; } allChangedObjRefsResult[indexOfCache.Value] = objRefOriginal; } OriCollection oriCollection = new OriCollection(new List <IObjRef>(allChangedObjRefsResult)); return(oriCollection); } finally { childCache.Dispose(); } }); if (SecurityActive == null || !SecurityActive.FilterActivated) { return(runnable()); } else { return(SecurityActive.ExecuteWithoutFiltering(runnable)); } }
protected IOriCollection Intern(ICUDResult cudResult, IMethodDescription methodDescription, IList <MergeOperation> mergeOperationSequence, IncrementalMergeState state) { IList <IChangeContainer> allChanges = cudResult.AllChanges; IList <Object> originalRefs = cudResult.GetOriginalRefs(); IdentityHashMap <IChangeContainer, int> changeToChangeIndexDict = new IdentityHashMap <IChangeContainer, int>(); for (int a = allChanges.Count; a-- > 0;) { changeToChangeIndexDict.Put(allChanges[a], a); } IObjRef[] objRefs = new IObjRef[allChanges.Count]; long[] allChangedOn = new long[allChanges.Count]; String[] allChangedBy = new String[allChanges.Count]; CHashSet <long> changedOnSet = new CHashSet <long>(); CHashSet <String> changedBySet = new CHashSet <String>(); for (int a = 0, size = mergeOperationSequence.Count; a < size; a++) { MergeOperation mergeOperation = mergeOperationSequence[a]; IMergeServiceExtension mergeServiceExtension = mergeOperation.MergeServiceExtension; IList <IChangeContainer> changesForMergeService = mergeOperation.ChangeContainer; ICUDResult msCudResult = BuildCUDResult(changesForMergeService, changeToChangeIndexDict, originalRefs); IOriCollection msOriCollection = mergeServiceExtension.Merge(msCudResult, methodDescription); MergeController.ApplyChangesToOriginals(msCudResult, msOriCollection, state.GetStateCache()); IList <IObjRef> allChangeORIs = msOriCollection.AllChangeORIs; long? msDefaultChangedOn = msOriCollection.ChangedOn; String msDefaultChangedBy = msOriCollection.ChangedBy; long[] msAllChangedOn = msOriCollection.AllChangedOn; String[] msAllChangedBy = msOriCollection.AllChangedBy; for (int b = changesForMergeService.Count; b-- > 0;) { int index = changeToChangeIndexDict.Get(changesForMergeService[b]); objRefs[index] = allChangeORIs[b]; if (msAllChangedOn != null) { long msChangedOn = msAllChangedOn[b]; allChangedOn[index] = msChangedOn; changedOnSet.Add(msChangedOn); } else { allChangedOn[index] = msDefaultChangedOn.Value; } if (msAllChangedBy != null) { String msChangedBy = msAllChangedBy[b]; allChangedBy[index] = msChangedBy; changedBySet.Add(msChangedBy); } else { allChangedBy[index] = msDefaultChangedBy; } } if (msDefaultChangedOn != null) { changedOnSet.Add(msDefaultChangedOn.Value); } if (msDefaultChangedBy != null) { changedBySet.Add(msDefaultChangedBy); } } OriCollection oriCollection = new OriCollection(); oriCollection.AllChangeORIs = new List <IObjRef>(objRefs); if (changedBySet.Count == 1) { Iterator <String> iter = changedBySet.Iterator(); iter.MoveNext(); oriCollection.ChangedBy = iter.Current; } else { oriCollection.AllChangedBy = allChangedBy; } if (changedOnSet.Count == 1) { Iterator <long> iter = changedOnSet.Iterator(); iter.MoveNext(); oriCollection.ChangedOn = iter.Current; } else { oriCollection.AllChangedOn = allChangedOn; } foreach (IMergeListener mergeListener in mergeListeners.GetExtensions()) { mergeListener.PostMerge(cudResult, objRefs); } if (originalRefs != null) { // Set each original ref to null in order to suppress a post-processing in a potentially calling IMergeProcess for (int a = originalRefs.Count; a-- > 0;) { originalRefs[a] = null; } } // TODO DCE must be fired HERE <--- return(oriCollection); }
protected virtual void ProcessCUDResult(Object objectToMerge, ICUDResult cudResult, IList <Object> unpersistedObjectsToDelete, ProceedWithMergeHook proceedHook, bool addNewEntitiesToCache) { if (cudResult.AllChanges.Count > 0 || (unpersistedObjectsToDelete != null && unpersistedObjectsToDelete.Count > 0)) { if (proceedHook != null) { bool proceed = proceedHook.Invoke(cudResult, unpersistedObjectsToDelete); if (!proceed) { return; } } } if (cudResult.AllChanges.Count == 0) { if (Log.InfoEnabled) { Log.Info("Service call skipped early because there is nothing to merge"); } } else { IOriCollection oriColl; EventDispatcher.EnableEventQueue(); try { EventDispatcher.Pause(Cache); try { bool?oldNewlyPersistedEntities = addNewlyPersistedEntitiesTL.Value; addNewlyPersistedEntitiesTL.Value = addNewEntitiesToCache; try { IResultingBackgroundWorkerDelegate <IOriCollection> runnable = new IResultingBackgroundWorkerDelegate <IOriCollection>(delegate() { IOriCollection oriColl2 = MergeService.Merge(cudResult, null); MergeController.ApplyChangesToOriginals(cudResult, oriColl2, null); return(oriColl2); }); if (Transaction == null || Transaction.Active) { oriColl = runnable(); } else { oriColl = Transaction.RunInLazyTransaction(runnable); } } finally { addNewlyPersistedEntitiesTL.Value = oldNewlyPersistedEntities; } } finally { EventDispatcher.Resume(Cache); } } finally { EventDispatcher.FlushEventQueue(); } DataChangeEvent dataChange = DataChangeEvent.Create(-1, -1, -1); // This is intentionally a remote source dataChange.IsLocalSource = false; if (IsNetworkClientMode) { IList <IChangeContainer> allChanges = cudResult.AllChanges; IList <IObjRef> orisInReturn = oriColl.AllChangeORIs; for (int a = allChanges.Count; a-- > 0;) { IChangeContainer changeContainer = allChanges[a]; IObjRef reference = changeContainer.Reference; IObjRef referenceInReturn = orisInReturn[a]; if (changeContainer is CreateContainer) { if (referenceInReturn.IdNameIndex != ObjRef.PRIMARY_KEY_INDEX) { throw new ArgumentException("Implementation error: Only PK references are allowed in events"); } dataChange.Inserts.Add(new DataChangeEntry(referenceInReturn.RealType, referenceInReturn.IdNameIndex, referenceInReturn.Id, referenceInReturn.Version)); } else if (changeContainer is UpdateContainer) { if (referenceInReturn.IdNameIndex != ObjRef.PRIMARY_KEY_INDEX) { throw new ArgumentException("Implementation error: Only PK references are allowed in events"); } dataChange.Updates.Add(new DataChangeEntry(referenceInReturn.RealType, referenceInReturn.IdNameIndex, referenceInReturn.Id, referenceInReturn.Version)); } else if (changeContainer is DeleteContainer) { if (reference.IdNameIndex != ObjRef.PRIMARY_KEY_INDEX) { throw new ArgumentException("Implementation error: Only PK references are allowed in events"); } dataChange.Deletes.Add(new DataChangeEntry(reference.RealType, reference.IdNameIndex, reference.Id, reference.Version)); } } //EventDispatcher.DispatchEvent(dataChange, DateTime.Now, -1); } } if (unpersistedObjectsToDelete != null && unpersistedObjectsToDelete.Count > 0) { // Create a DCE for all objects without an id but which should be deleted... // This is the case for newly created objects on client side, which should be // "cancelled". The DCE notifies all models which contain identity references to the related // objects to erase their existence in all controls. They are not relevant in the previous // server merge process DataChangeEvent dataChange = DataChangeEvent.Create(0, 0, unpersistedObjectsToDelete.Count); for (int a = unpersistedObjectsToDelete.Count; a-- > 0;) { Object unpersistedObject = unpersistedObjectsToDelete[a]; dataChange.Deletes.Add(new DirectDataChangeEntry(unpersistedObject)); } EventDispatcher.DispatchEvent(dataChange, DateTime.Now, -1); } RevertChangesHelper.RevertChanges(objectToMerge); }