Skip to contentMethod: calculateChanges()
1: /*
2: * JOPA
3: * Copyright (C) 2024 Czech Technical University in Prague
4: *
5: * This library is free software; you can redistribute it and/or
6: * modify it under the terms of the GNU Lesser General Public
7: * License as published by the Free Software Foundation; either
8: * version 3.0 of the License, or (at your option) any later version.
9: *
10: * This library is distributed in the hope that it will be useful,
11: * but WITHOUT ANY WARRANTY; without even the implied warranty of
12: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13: * Lesser General Public License for more details.
14: *
15: * You should have received a copy of the GNU Lesser General Public
16: * License along with this library.
17: */
18: package cz.cvut.kbss.jopa.sessions;
19:
20: import cz.cvut.kbss.jopa.exceptions.OWLEntityExistsException;
21: import cz.cvut.kbss.jopa.model.descriptors.Descriptor;
22: import cz.cvut.kbss.jopa.model.lifecycle.LifecycleEvent;
23: import cz.cvut.kbss.jopa.model.metamodel.FieldSpecification;
24: import cz.cvut.kbss.jopa.model.metamodel.IdentifiableEntityType;
25: import cz.cvut.kbss.jopa.sessions.change.ChangeSetFactory;
26: import cz.cvut.kbss.jopa.sessions.change.ObjectChangeSet;
27: import cz.cvut.kbss.jopa.sessions.validator.AttributeModificationValidator;
28: import cz.cvut.kbss.jopa.utils.Configuration;
29: import cz.cvut.kbss.jopa.utils.EntityPropertiesUtils;
30:
31: import java.lang.reflect.Field;
32: import java.net.URI;
33:
34: public class OnCommitChangePropagatingUnitOfWork extends AbstractUnitOfWork {
35:
36: OnCommitChangePropagatingUnitOfWork(AbstractSession parent, Configuration configuration) {
37: super(parent, configuration);
38: }
39:
40: @Override
41: void detachAllManagedInstances() {
42: cloneMapping.forEach(this::removeLazyLoadingProxies);
43: }
44:
45: @Override
46: void commitToStorage() {
47: calculateChanges();
48: if (this.hasNew) {
49: persistNewObjects();
50: }
51: uowChangeSet.getExistingObjectsChanges().forEach(chSet -> {
52: final IdentifiableEntityType<?> et = entityType(chSet.getObjectClass());
53: final Object entity = chSet.getClone();
54: et.getLifecycleListenerManager().invokePreUpdateCallbacks(entity);
55: if (et.getLifecycleListenerManager().hasLifecycleCallback(LifecycleEvent.PRE_UPDATE)) {
56: // Recalculate changes if a preUpdate callback was called as it may have altered the entity state
57: changeCalculator.calculateChanges(chSet);
58: }
59: chSet.getChanges()
60: .forEach(record -> {
61: AttributeModificationValidator.verifyCanModify(record.getAttribute());
62: preventCachingIfReferenceIsNotLoaded(record);
63: storage.merge(entity, (FieldSpecification<? super Object, ?>) record.getAttribute(), chSet.getDescriptor());
64: });
65: et.getLifecycleListenerManager().invokePostUpdateCallbacks(entity);
66: });
67: uowChangeSet.getDeletedObjects().forEach(chSet -> {
68: final IdentifiableEntityType<?> et = entityType(chSet.getObjectClass());
69: final Object identifier = getIdentifier(chSet.getClone());
70: storage.remove(identifier, chSet.getObjectClass(), chSet.getDescriptor());
71: et.getLifecycleListenerManager().invokePostRemoveCallbacks(chSet.getClone());
72: });
73: validateIntegrityConstraints();
74: storage.commit();
75: }
76:
77: @Override
78: void calculateChanges() {
79: super.calculateChanges();
80: cloneToOriginals.entrySet().stream().filter(e -> !deletedObjects.containsKey(e.getKey())).forEach(e -> {
81: final Object original = e.getValue();
82: final Object clone = e.getKey();
83: ObjectChangeSet chSet = ChangeSetFactory.createObjectChangeSet(original, clone, getDescriptor(clone));
84: changeCalculator.calculateChanges(chSet);
85: processInferredValueChanges(chSet);
86: if (chSet.hasChanges()) {
87: uowChangeSet.addObjectChangeSet(chSet);
88: }
89: });
90:• if (uowChangeSet.hasChanges()) {
91: setHasChanges();
92: }
93: }
94:
95: @Override
96: <T> T mergeDetachedInternal(T toMerge, Descriptor descriptor) {
97: assert toMerge != null;
98: final IdentifiableEntityType<T> et = (IdentifiableEntityType<T>) entityType(toMerge.getClass());
99: final URI idUri = EntityPropertiesUtils.getIdentifier(toMerge, et);
100:
101: final T clone = getInstanceForMerge(idUri, et, descriptor);
102: try {
103: ObjectChangeSet chSet = ChangeSetFactory.createObjectChangeSet(clone, toMerge, descriptor);
104: changeCalculator.calculateChanges(chSet);
105: chSet = processInferredValueChanges(chSet);
106: if (chSet.hasChanges()) {
107: final DetachedInstanceMerger merger = new DetachedInstanceMerger(this);
108: merger.mergeChangesFromDetachedToManagedInstance(chSet, descriptor);
109: uowChangeSet.addObjectChangeSet(copyChangeSet(chSet, getOriginal(clone), clone, descriptor));
110: }
111: } catch (OWLEntityExistsException e) {
112: unregisterObject(clone);
113: throw e;
114: }
115: evictAfterMerge(et, idUri, descriptor);
116: setHasChanges();
117: return et.getJavaType().cast(clone);
118: }
119:
120: @Override
121: public void removeObject(Object entity) {
122: assert entity != null;
123: ensureManaged(entity);
124:
125: final Object identifier = getIdentifier(entity);
126: markCloneForDeletion(entity, identifier);
127: }
128:
129: @Override
130: public void unregisterObject(Object object) {
131: super.unregisterObject(object);
132: removeLazyLoadingProxies(object);
133: }
134:
135: @Override
136: public void attributeChanged(Object entity, Field f) {
137: // Do nothing
138: }
139:
140: @Override
141: public void attributeChanged(Object entity, FieldSpecification<?, ?> fieldSpec) {
142: // Do nothing
143: }
144:
145: @Override
146: public Object createIndirectCollection(Object collection, Object owner, Field field) {
147: // Do not create any special kind of collection, just return the argument
148: return collection;
149: }
150: }