Search in sources :

Example 1 with MutableStateTrackable

use of com.blazebit.persistence.view.spi.type.MutableStateTrackable in project blaze-persistence by Blazebit.

the class IndexedListAttributeFlusher method addFlatViewElementFlushActions.

@Override
protected void addFlatViewElementFlushActions(UpdateContext context, TypeDescriptor typeDescriptor, List<CollectionAction<?>> actions, V current) {
    final ViewToEntityMapper mapper = typeDescriptor.getViewToEntityMapper();
    for (int i = 0; i < current.size(); i++) {
        Object o = current.get(i);
        if (o instanceof MutableStateTrackable) {
            MutableStateTrackable element = (MutableStateTrackable) o;
            @SuppressWarnings("unchecked") DirtyAttributeFlusher<?, E, V> flusher = (DirtyAttributeFlusher<?, E, V>) (DirtyAttributeFlusher) mapper.getNestedDirtyFlusher(context, element, (DirtyAttributeFlusher) null);
            if (flusher != null) {
                // At this point, we have to check the collection actions to determine if the view was added through actions somehow
                // We will register a special ListSetAction if the view was not added through actions to issue an UPDATE statement
                // By default, since the view is dirty, we start with the state UPDATED and go through state transitions
                // based on the containment of the view in the added/removed objects collections of the actions
                EntryState state = EntryState.UPDATED;
                Object replacedObject = element;
                for (CollectionAction<?> action : actions) {
                    Collection<Object> removedObjects = action.getRemovedObjects();
                    if (identityContains(removedObjects, element)) {
                        if (identityContains(action.getAddedObjects(), element)) {
                            // This is a ListSetAction where the old and new object are the same instances
                            replacedObject = element;
                            state = EntryState.UPDATED;
                        } else {
                            state = state.onRemove();
                        }
                    } else if (identityContains(action.getAddedObjects(), element)) {
                        if (removedObjects.isEmpty()) {
                            state = state.onAdd();
                        } else {
                            // This is a ListSetAction which has only a single element, so this is safe
                            replacedObject = removedObjects.iterator().next();
                            state = EntryState.UPDATED;
                        }
                    }
                }
                // and there is no action that would flush the object changes already
                if (state == EntryState.UPDATED && replacedObject == element) {
                    // Using last = false is intentional to actually get a proper update instead of a delete and insert
                    actions.add(new ListSetAction<>(i, false, element, element));
                }
            }
        }
    }
}
Also used : MutableStateTrackable(com.blazebit.persistence.view.spi.type.MutableStateTrackable) ViewToEntityMapper(com.blazebit.persistence.view.impl.entity.ViewToEntityMapper)

Example 2 with MutableStateTrackable

use of com.blazebit.persistence.view.spi.type.MutableStateTrackable in project blaze-persistence by Blazebit.

the class ResetInitialStateSynchronization method afterCompletion.

@Override
@SuppressWarnings("unchecked")
public void afterCompletion(int status) {
    if (status != Status.STATUS_COMMITTED) {
        Map<EntityViewProxy, ViewTransition> objects;
        if (listenerManager.hasPostRollbackListeners()) {
            objects = new IdentityHashMap<>();
        } else {
            objects = null;
        }
        if (coalescedInitialStates != null) {
            for (int i = 0; i < coalescedInitialStates.size(); i += 2) {
                Object[] initialState = coalescedInitialStates.get(i);
                Object[] originalInitialState = coalescedInitialStates.get(i + 1);
                for (int j = 0; j < initialState.length; j++) {
                    initialState[j] = originalInitialState[j];
                }
            }
        }
        if (coalescedRecordingActions != null) {
            for (int i = 0; i < coalescedRecordingActions.size(); i += 4) {
                Object collectionReference = coalescedRecordingActions.get(i);
                Object actionList = coalescedRecordingActions.get(i + 1);
                Map<Object, Object> added = (Map<Object, Object>) coalescedRecordingActions.get(i + 2);
                Map<Object, Object> removed = (Map<Object, Object>) coalescedRecordingActions.get(i + 3);
                if (collectionReference instanceof RecordingCollection<?, ?>) {
                    RecordingCollection<Collection<Object>, Object> collection = (RecordingCollection<Collection<Object>, Object>) collectionReference;
                    collection.setActions((List<CollectionAction<Collection<Object>>>) (List<?>) actionList, added, removed);
                    collection.$$_markDirty(-1);
                } else {
                    Map<Object, Object> addedElements = (Map<Object, Object>) coalescedRecordingActions.get(i + 4);
                    Map<Object, Object> removedElements = (Map<Object, Object>) coalescedRecordingActions.get(i + 5);
                    RecordingMap<Map<Object, Object>, Object, Object> collection = (RecordingMap<Map<Object, Object>, Object, Object>) collectionReference;
                    collection.setActions((List<MapAction<Map<Object, Object>>>) (List<?>) actionList, added, removed, addedElements, removedElements);
                    collection.$$_markDirty(-1);
                    i += 2;
                }
            }
        }
        if (persistedViews != null) {
            for (int i = 0; i < persistedViews.size(); i += 7) {
                MutableStateTrackable view = (MutableStateTrackable) persistedViews.get(i);
                Object newObject = persistedViews.get(i + 1);
                view.$$_setIsNew(true);
                Object id = persistedViews.get(i + 2);
                DirtyTracker parent = (DirtyTracker) persistedViews.get(i + 3);
                int parentIndex = (int) persistedViews.get(i + 4);
                List<Object> readOnlyParents = (List<Object>) persistedViews.get(i + 5);
                if (id != NO_ID_MARKER) {
                    view.$$_setId(id);
                }
                if (parent != null) {
                    // This is not needed as this will happen when rolling back collection actions already
                    if (!(parent instanceof RecordingCollection<?, ?> || parent instanceof RecordingMap<?, ?, ?>)) {
                        parent.$$_replaceAttribute(newObject, parentIndex, view);
                    }
                    for (int j = 0; j < readOnlyParents.size(); j += 2) {
                        DirtyTracker readOnlyParent = (DirtyTracker) readOnlyParents.get(j);
                        int readOnlyParentIndex = (int) readOnlyParents.get(j + 1);
                        readOnlyParent.$$_replaceAttribute(newObject, readOnlyParentIndex, view);
                    }
                }
                view.$$_setDirty((long[]) persistedViews.get(i + 6));
                if (objects != null) {
                    objects.put(view, ViewTransition.PERSIST);
                }
            }
        }
        if (updatedViews != null) {
            for (int i = 0; i < updatedViews.size(); i += 2) {
                MutableStateTrackable view = (MutableStateTrackable) updatedViews.get(i);
                view.$$_setDirty((long[]) updatedViews.get(i + 1));
                if (objects != null) {
                    objects.put(view, ViewTransition.UPDATE);
                }
            }
        }
        if (removedViews != null) {
            for (int i = 0; i < removedViews.size(); i += 4) {
                EntityViewProxy view = (EntityViewProxy) removedViews.get(i);
                if (view instanceof MutableStateTrackable) {
                    MutableStateTrackable removedView = (MutableStateTrackable) view;
                    DirtyTracker parent = (DirtyTracker) removedViews.get(i + 1);
                    if (parent != null) {
                        removedView.$$_setParent(parent, (Integer) removedViews.get(i + 2));
                    }
                    long[] dirtyArray = (long[]) removedViews.get(i + 3);
                    if (dirtyArray != null) {
                        removedView.$$_setDirty(dirtyArray);
                    }
                }
                if (objects != null) {
                    objects.put(view, ViewTransition.REMOVE);
                }
            }
        }
        if (versionedViews != null) {
            for (int i = 0; i < versionedViews.size(); i += 2) {
                MutableStateTrackable view = (MutableStateTrackable) versionedViews.get(i);
                view.$$_setVersion(versionedViews.get(i + 1));
            }
        }
        if (objects != null) {
            PostRollbackInvoker postRollbackInvoker = new PostRollbackInvoker(updateContext, listenerManager, objects);
            TransactionSupport txSupport = updateContext.getEntityViewManager().getService(TransactionSupport.class);
            if (txSupport == null) {
                TransactionAccess transactionAccess = updateContext.getTransactionAccess();
                if (transactionAccess instanceof SynchronizationRegistry) {
                    transactionAccess = ((SynchronizationRegistry) transactionAccess).getTransactionAccess();
                }
                if (transactionAccess instanceof TransactionSupport) {
                    ((TransactionSupport) transactionAccess).transactional(postRollbackInvoker);
                } else {
                    // Log warning that querying doesn't work because we can't run in a new transaction?
                    postRollbackInvoker.run();
                }
            } else {
                txSupport.transactional(postRollbackInvoker);
            }
        }
    } else {
        if (listenerManager.hasPostCommitListeners()) {
            if (persistedViews != null) {
                for (int i = 0; i < persistedViews.size(); i += 7) {
                    listenerManager.invokePostCommit(updateContext, (MutableStateTrackable) persistedViews.get(i), ViewTransition.PERSIST);
                }
            }
            if (updatedViews != null) {
                for (int i = 0; i < updatedViews.size(); i += 2) {
                    listenerManager.invokePostCommit(updateContext, (MutableStateTrackable) updatedViews.get(i), ViewTransition.UPDATE);
                }
            }
            if (removedViews != null) {
                for (int i = 0; i < removedViews.size(); i += 4) {
                    listenerManager.invokePostCommit(updateContext, (EntityViewProxy) removedViews.get(i), ViewTransition.REMOVE);
                }
            }
        }
    }
}
Also used : MutableStateTrackable(com.blazebit.persistence.view.spi.type.MutableStateTrackable) ViewTransition(com.blazebit.persistence.view.ViewTransition) RecordingCollection(com.blazebit.persistence.view.impl.collection.RecordingCollection) TransactionSupport(com.blazebit.persistence.view.spi.TransactionSupport) EntityViewProxy(com.blazebit.persistence.view.spi.type.EntityViewProxy) ArrayList(java.util.ArrayList) List(java.util.List) DirtyTracker(com.blazebit.persistence.view.spi.type.DirtyTracker) RecordingMap(com.blazebit.persistence.view.impl.collection.RecordingMap) MapAction(com.blazebit.persistence.view.impl.collection.MapAction) SynchronizationRegistry(com.blazebit.persistence.view.impl.tx.SynchronizationRegistry) TransactionAccess(com.blazebit.persistence.view.spi.TransactionAccess) CollectionAction(com.blazebit.persistence.view.impl.collection.CollectionAction) RecordingCollection(com.blazebit.persistence.view.impl.collection.RecordingCollection) Collection(java.util.Collection) IdentityHashMap(java.util.IdentityHashMap) Map(java.util.Map) RecordingMap(com.blazebit.persistence.view.impl.collection.RecordingMap)

Example 3 with MutableStateTrackable

use of com.blazebit.persistence.view.spi.type.MutableStateTrackable in project blaze-persistence by Blazebit.

the class MapAttributeFlusher method addFlatViewElementFlushActions.

@Override
protected void addFlatViewElementFlushActions(UpdateContext context, TypeDescriptor typeDescriptor, List<MapAction<?>> actions, V current) {
    final ViewToEntityMapper mapper = typeDescriptor.getViewToEntityMapper();
    for (Map.Entry<?, ?> entry : current.entrySet()) {
        Object o = entry.getValue();
        if (o instanceof MutableStateTrackable) {
            MutableStateTrackable element = (MutableStateTrackable) o;
            @SuppressWarnings("unchecked") DirtyAttributeFlusher<?, E, V> flusher = (DirtyAttributeFlusher<?, E, V>) (DirtyAttributeFlusher) mapper.getNestedDirtyFlusher(context, element, (DirtyAttributeFlusher) null);
            if (flusher != null) {
                // At this point, we have to check the collection actions to determine if the element was added through actions somehow
                // We will register a special MapPutAction if the element was not added through actions to issue an UPDATE statement
                // By default, since the element is dirty, we start with the state UPDATED and go through state transitions
                // based on the containment of the element in the added/removed objects collections of the actions
                EntryState state = EntryState.UPDATED;
                Object replacedObject = element;
                for (MapAction<?> action : actions) {
                    Collection<Object> removedElements = action.getRemovedElements();
                    Collection<Object> addedElements = action.getAddedElements();
                    if (removedElements.isEmpty()) {
                        if (identityContains(addedElements, element)) {
                            state = state.onAdd();
                        }
                    } else if (addedElements.isEmpty()) {
                        if (identityContains(removedElements, element)) {
                            state = state.onRemove();
                        }
                    } else {
                        // Here we have a MapPutAction or MapPutAllAction where added/removed have the same cardinality
                        Iterator<Object> addedIter = addedElements.iterator();
                        Iterator<Object> removedIter = removedElements.iterator();
                        while (addedIter.hasNext()) {
                            Object added = addedIter.next();
                            Object removed = removedIter.next();
                            if (removed == element) {
                                if (added == element) {
                                    // This is a MapPutAction or MapPutAllAction where the old and new object are the same instances
                                    replacedObject = element;
                                    state = EntryState.UPDATED;
                                } else {
                                    state = state.onRemove();
                                }
                                break;
                            } else if (added == element) {
                                replacedObject = removed;
                                state = EntryState.UPDATED;
                                break;
                            }
                        }
                    }
                }
                // and there is no action that would flush the object changes already
                if (state == EntryState.UPDATED && replacedObject == element) {
                    actions.add(new MapPutAction<>(entry.getKey(), element, element));
                }
            }
        }
    }
}
Also used : MutableStateTrackable(com.blazebit.persistence.view.spi.type.MutableStateTrackable) Iterator(java.util.Iterator) MapViewToEntityMapper(com.blazebit.persistence.view.impl.entity.MapViewToEntityMapper) ViewToEntityMapper(com.blazebit.persistence.view.impl.entity.ViewToEntityMapper) HashMap(java.util.HashMap) LinkedHashMap(java.util.LinkedHashMap) Map(java.util.Map) IdentityHashMap(java.util.IdentityHashMap) AbstractMap(java.util.AbstractMap) RecordingMap(com.blazebit.persistence.view.impl.collection.RecordingMap)

Example 4 with MutableStateTrackable

use of com.blazebit.persistence.view.spi.type.MutableStateTrackable in project blaze-persistence by Blazebit.

the class CompositeAttributeFlusher method flushEntity.

@Override
@SuppressWarnings("unchecked")
public boolean flushEntity(UpdateContext context, Object entity, Object ownerView, Object view, Object value, Runnable postReplaceListener) {
    if (element != null) {
        value = element;
    }
    if (!(value instanceof MutableStateTrackable)) {
        // Pass-through i.e. read-only id attributes
        for (int i = 0; i < flushers.length; i++) {
            DirtyAttributeFlusher<?, Object, Object> flusher = flushers[i];
            if (flusher != null) {
                flusher.flushEntity(context, entity, ownerView, value, flusher.getViewAttributeAccessor().getValue(value), null);
            }
        }
        return false;
    }
    MutableStateTrackable updatableProxy = (MutableStateTrackable) value;
    // The root object, which is given when view == value, is the exception
    if (context.isRemovedObject(updatableProxy) || !updatableProxy.$$_hasParent() && view != value) {
        return false;
    }
    final boolean shouldPersist = persist == Boolean.TRUE || persist == null && updatableProxy.$$_isNew();
    final boolean doPersist = shouldPersist && persistable;
    final Object oldId = determineOldId(context, updatableProxy, postReplaceListener);
    int parentIndex = updatableProxy.$$_getParentIndex();
    DirtyTracker parent = updatableProxy.$$_getParent();
    RecordingCollection<?, Object> recordingCollection = null;
    RecordingMap<?, Object, Object> recordingMap = null;
    Object removedValue = null;
    Set<Object> removedKeys = null;
    List<Integer> afterPersistFlushers = null;
    List<Integer> deferredFlushers = null;
    boolean successful = false;
    try {
        Object id = updatableProxy.$$_getId();
        if (doPersist) {
            // In case of nested attributes, the entity instance we get is the container of the attribute
            if (!entityClass.isInstance(entity)) {
                entity = entityLoader.toEntity(context, null, null);
            }
            context.invokePrePersist(updatableProxy, entity);
            // Or we are in the elementFlusher case where we don't iterate through the backing collection and thus can operate on the backing collection directly
            if (parent != null) {
                if (parent instanceof RecordingCollection<?, ?> && ((recordingCollection = (RecordingCollection<?, Object>) parent).isHashBased() || persistViewMapper != null)) {
                    if (recordingCollection.getCurrentIterator() == null) {
                        recordingCollection.getDelegate().remove(updatableProxy);
                    } else {
                        recordingCollection.getCurrentIterator().replace();
                    }
                } else if (parent instanceof RecordingMap<?, ?, ?> && (persistViewMapper != null || updatableProxy.$$_getParentIndex() == 1 && (recordingMap = (RecordingMap<?, Object, Object>) parent).isHashBased())) {
                    recordingMap = (RecordingMap<?, Object, Object>) parent;
                    // Parent index 1 in a recording map means it is part of the key
                    if (updatableProxy.$$_getParentIndex() == 1) {
                        if (recordingMap.getCurrentIterator() == null) {
                            removedValue = recordingMap.getDelegate().remove(updatableProxy);
                        } else {
                            removedValue = recordingMap.getCurrentIterator().replace();
                        }
                    } else {
                        if (removedKeys == null) {
                            removedKeys = new HashSet<>();
                        }
                        // Not sure if a creatable view should be allowed to occur multiple times in the map as value..
                        if (recordingMap.getCurrentIterator() == null) {
                            for (Map.Entry<Object, Object> entry : recordingMap.getDelegate().entrySet()) {
                                if (entry.getValue().equals(updatableProxy)) {
                                    removedKeys.add(entry.getKey());
                                }
                            }
                        } else {
                            recordingMap.getCurrentIterator().replaceValue(removedKeys);
                        }
                    }
                }
            }
            // A version 2.0 or 3.0 might improve on this when redesigning for operation queueing
            if (postReplaceListener != null) {
                postReplaceListener.run();
            }
            if (id != null) {
                idFlusher.flushEntity(context, entity, ownerView, updatableProxy, id, null);
            }
            context.getInitialStateResetter().addUpdatedView(updatableProxy);
        } else {
            // In case of nested attributes, the entity instance we get is the container of the attribute
            if ((loadForEntityFlush || viewIdAccessor == null) && !entityClass.isInstance(entity)) {
                entity = entityLoader.toEntity(context, view, id);
            }
            // After Pre-Update the dirtyness could change
            preUpdate(context, updatableProxy);
        }
        Object[] state = updatableProxy.$$_getMutableState();
        boolean wasDirty = false;
        boolean optimisticLock = false;
        if (updatableProxy instanceof DirtyStateTrackable) {
            Object[] initialState = ((DirtyStateTrackable) updatableProxy).$$_getInitialState();
            context.getInitialStateResetter().addState(initialState, initialState.clone());
            for (int i = 0; i < state.length; i++) {
                final DirtyAttributeFlusher<?, Object, Object> flusher = flushers[i];
                if (flusher != null) {
                    if (doPersist && flusher.requiresFlushAfterPersist(state[i])) {
                        if (afterPersistFlushers == null) {
                            afterPersistFlushers = new ArrayList<>();
                        }
                        afterPersistFlushers.add(i);
                        wasDirty = true;
                        optimisticLock |= flusher.isOptimisticLockProtected();
                    } else if (flusher.requiresDeferredFlush(state[i])) {
                        if (deferredFlushers == null) {
                            deferredFlushers = new ArrayList<>();
                        }
                        deferredFlushers.add(i);
                        wasDirty = true;
                        optimisticLock |= flusher.isOptimisticLockProtected();
                    } else {
                        Object newInitialValue = flusher.cloneDeep(value, initialState[i], state[i]);
                        if (flusher.flushEntity(context, entity, ownerView, value, state[i], null)) {
                            wasDirty = true;
                            optimisticLock |= flusher.isOptimisticLockProtected();
                        }
                        initialState[i] = flusher.getNewInitialValue(context, newInitialValue, state[i]);
                    }
                }
            }
        } else {
            for (int i = 0; i < state.length; i++) {
                final DirtyAttributeFlusher<?, Object, Object> flusher = flushers[i];
                if (flusher != null) {
                    if (doPersist && flusher.requiresFlushAfterPersist(state[i])) {
                        if (afterPersistFlushers == null) {
                            afterPersistFlushers = new ArrayList<>();
                        }
                        afterPersistFlushers.add(i);
                        wasDirty = true;
                        optimisticLock |= flusher.isOptimisticLockProtected();
                    } else if (flusher.requiresDeferredFlush(state[i])) {
                        if (deferredFlushers == null) {
                            deferredFlushers = new ArrayList<>();
                        }
                        deferredFlushers.add(i);
                        wasDirty = true;
                        optimisticLock |= flusher.isOptimisticLockProtected();
                    } else {
                        if (flusher.flushEntity(context, entity, ownerView, value, state[i], null)) {
                            wasDirty = true;
                            optimisticLock |= flusher.isOptimisticLockProtected();
                        }
                    }
                }
            }
        }
        // Pass through flushers
        for (int i = state.length; i < flushers.length; i++) {
            final DirtyAttributeFlusher<?, Object, Object> flusher = flushers[i];
            if (flusher != null) {
                if (flusher.flushEntity(context, entity, ownerView, value, flusher.getViewAttributeAccessor().getValue(value), null)) {
                    wasDirty = true;
                    optimisticLock |= flusher.isOptimisticLockProtected();
                }
            }
        }
        if (versionFlusher != null && optimisticLockProtected && optimisticLock) {
            context.getInitialStateResetter().addVersionedView(updatableProxy, updatableProxy.$$_getVersion());
            // We might have to load the entity for optimistic locking
            if (!entityClass.isInstance(entity)) {
                entity = entityLoader.toEntity(context, view, id);
            }
            versionFlusher.flushEntity(context, entity, ownerView, value, updatableProxy.$$_getVersion(), null);
        }
        if (deferredFlushers != null) {
            deferredFlushEntity(context, entity, ownerView, updatableProxy, deferredFlushers);
        }
        if (doPersist) {
            // If the class of the object is an entity, we persist the object
            context.getEntityManager().persist(entity);
            id = createViewIdByEntityId(entityLoader.getEntityId(context, entity));
            viewIdAccessor.setValue(updatableProxy, id);
        }
        successful = true;
        return wasDirty;
    } finally {
        int newObjectIndex = -1;
        if (shouldPersist) {
            if (idFlusher == null) {
                // Embeddables don't have an id
                newObjectIndex = context.getInitialStateResetter().addPersistedView(updatableProxy);
            } else {
                newObjectIndex = context.getInitialStateResetter().addPersistedView(updatableProxy, oldId);
            }
            if (successful && afterPersistFlushers != null) {
                deferredFlushEntity(context, entity, ownerView, updatableProxy, afterPersistFlushers);
            }
        } else if (successful && afterPersistFlushers != null) {
            deferredFlushEntity(context, entity, ownerView, updatableProxy, afterPersistFlushers);
        }
        Object newObject = null;
        if (doPersist) {
            newObject = updatableProxy;
            if (persistViewMapper != null) {
                newObject = persistViewMapper.map(newObject, context.getEntityViewManager().getOptionalParameters());
                context.getInitialStateResetter().addPersistedViewNewObject(newObjectIndex, newObject);
            }
            if (recordingCollection != null && (recordingCollection.isHashBased() || persistViewMapper != null)) {
                // Reset the parent accordingly
                resetParents(updatableProxy, parentIndex, parent, newObject);
                if (recordingCollection.getCurrentIterator() == null) {
                    recordingCollection.getDelegate().add(newObject);
                } else {
                    recordingCollection.getCurrentIterator().add(newObject);
                }
            } else if (recordingMap != null && (persistViewMapper != null || updatableProxy.$$_getParentIndex() == 1 && recordingMap.isHashBased())) {
                // Reset the parent accordingly
                resetParents(updatableProxy, parentIndex, parent, newObject);
                if (updatableProxy.$$_getParentIndex() == 1) {
                    if (recordingMap.getCurrentIterator() == null) {
                        recordingMap.getDelegate().put(newObject, removedValue);
                    } else {
                        recordingMap.getCurrentIterator().add(newObject, removedValue);
                    }
                } else {
                    for (Object removedKey : removedKeys) {
                        if (recordingMap.getCurrentIterator() == null) {
                            recordingMap.getDelegate().put(removedKey, newObject);
                        } else {
                            recordingMap.getCurrentIterator().add(removedKey, newObject);
                        }
                    }
                }
            } else if (parent != null && persistViewMapper != null) {
                // In case of a singular attribute, we replace the mutable state object to signal the parent flusher
                // SubviewAttributeFlusher is the parent, that uses this object for setting the actual and initial state
                ((MutableStateTrackable) parent).$$_getMutableState()[parentIndex] = newObject;
                updatableProxy.$$_unsetParent();
            }
            context.invokePostPersist(updatableProxy, entity);
        } else {
            context.invokePostUpdate(updatableProxy);
        }
    }
}
Also used : MutableStateTrackable(com.blazebit.persistence.view.spi.type.MutableStateTrackable) RecordingCollection(com.blazebit.persistence.view.impl.collection.RecordingCollection) ArrayList(java.util.ArrayList) DirtyStateTrackable(com.blazebit.persistence.view.spi.type.DirtyStateTrackable) DirtyTracker(com.blazebit.persistence.view.spi.type.DirtyTracker) BasicDirtyTracker(com.blazebit.persistence.view.spi.type.BasicDirtyTracker) RecordingMap(com.blazebit.persistence.view.impl.collection.RecordingMap) HashSet(java.util.HashSet)

Example 5 with MutableStateTrackable

use of com.blazebit.persistence.view.spi.type.MutableStateTrackable in project blaze-persistence by Blazebit.

the class CompositeAttributeFlusher method remove.

@Override
public List<PostFlushDeleter> remove(UpdateContext context, Object entity, Object view, Object value) {
    EntityViewProxy entityView = (EntityViewProxy) value;
    if (entityView instanceof MutableStateTrackable && !entityView.$$_isReference()) {
        MutableStateTrackable updatableProxy = (MutableStateTrackable) entityView;
        // 3. Aren't new i.e. only existing objects, no need to delete object that hasn't been persisted yet
        if (persistable && context.addRemovedObject(entityView) && !updatableProxy.$$_isNew()) {
            if (context.invokePreRemove(entityView)) {
                Object[] state = updatableProxy.$$_getMutableState();
                List<PostFlushDeleter> postFlushDeleters = new ArrayList<>();
                for (int i = 0; i < state.length; i++) {
                    final DirtyAttributeFlusher<?, Object, Object> flusher = flushers[i];
                    if (flusher != null && !flusher.requiresDeleteCascadeAfterRemove()) {
                        postFlushDeleters.addAll(flusher.remove(context, entity, entityView, state[i]));
                    }
                }
                remove(context, entity, updatableProxy, updatableProxy, updatableProxy.$$_getId(), updatableProxy.$$_getVersion(), false);
                for (PostFlushDeleter postFlushDeleter : postFlushDeleters) {
                    postFlushDeleter.execute(context);
                }
                for (int i = 0; i < state.length; i++) {
                    final DirtyAttributeFlusher<?, Object, Object> flusher = flushers[i];
                    if (flusher != null && flusher.requiresDeleteCascadeAfterRemove()) {
                        flusher.remove(context, entity, entityView, state[i]);
                    }
                }
            } else {
                context.removeRemovedObject(entityView);
                context.getEntityViewManager().update(context, entityView);
            }
        }
    } else {
        if (context.addRemovedObject(entityView)) {
            if (context.invokePreRemove(entityView)) {
                remove(context, entity, entityView, entityView, entityView.$$_getId(), entityView.$$_getVersion(), true);
            } else {
                context.removeRemovedObject(entityView);
                context.getEntityViewManager().update(context, entityView);
            }
        }
    }
    return Collections.emptyList();
}
Also used : MutableStateTrackable(com.blazebit.persistence.view.spi.type.MutableStateTrackable) ArrayList(java.util.ArrayList) EntityViewProxy(com.blazebit.persistence.view.spi.type.EntityViewProxy)

Aggregations

MutableStateTrackable (com.blazebit.persistence.view.spi.type.MutableStateTrackable)24 ArrayList (java.util.ArrayList)6 EntityViewUpdater (com.blazebit.persistence.view.impl.update.EntityViewUpdater)5 EntityViewProxy (com.blazebit.persistence.view.spi.type.EntityViewProxy)5 Test (org.junit.Test)5 ViewToEntityMapper (com.blazebit.persistence.view.impl.entity.ViewToEntityMapper)4 DirtyStateTrackable (com.blazebit.persistence.view.spi.type.DirtyStateTrackable)4 DirtyTracker (com.blazebit.persistence.view.spi.type.DirtyTracker)4 RecordingMap (com.blazebit.persistence.view.impl.collection.RecordingMap)3 AssertStatementBuilder (com.blazebit.persistence.testsuite.base.jpa.assertion.AssertStatementBuilder)2 RecordingCollection (com.blazebit.persistence.view.impl.collection.RecordingCollection)2 AbstractEntityViewUpdateDocumentTest (com.blazebit.persistence.view.testsuite.update.AbstractEntityViewUpdateDocumentTest)2 IdentityHashMap (java.util.IdentityHashMap)2 List (java.util.List)2 Map (java.util.Map)2 OptimisticLockException (com.blazebit.persistence.view.OptimisticLockException)1 ViewTransition (com.blazebit.persistence.view.ViewTransition)1 AttributeAccessor (com.blazebit.persistence.view.impl.accessor.AttributeAccessor)1 InitialValueAttributeAccessor (com.blazebit.persistence.view.impl.accessor.InitialValueAttributeAccessor)1 PassthroughAttributeAccessor (com.blazebit.persistence.view.impl.accessor.PassthroughAttributeAccessor)1