Skip to content

Package: UnitOfWorkImpl

UnitOfWorkImpl

nameinstructionbranchcomplexitylinemethod
UnitOfWorkImpl(AbstractSession)
M: 0 C: 80
100%
M: 0 C: 0
100%
M: 0 C: 1
100%
M: 0 C: 18
100%
M: 0 C: 1
100%
acquireConnection()
M: 0 C: 9
100%
M: 0 C: 0
100%
M: 0 C: 1
100%
M: 0 C: 3
100%
M: 0 C: 1
100%
acquireUnitOfWork()
M: 2 C: 0
0%
M: 0 C: 0
100%
M: 1 C: 0
0%
M: 1 C: 0
0%
M: 1 C: 0
0%
attributeChanged(Object, Field)
M: 0 C: 46
100%
M: 0 C: 4
100%
M: 0 C: 3
100%
M: 0 C: 10
100%
M: 0 C: 1
100%
calculateChanges()
M: 0 C: 16
100%
M: 0 C: 4
100%
M: 0 C: 3
100%
M: 0 C: 6
100%
M: 0 C: 1
100%
calculateDeletedObjects(UnitOfWorkChangeSet)
M: 5 C: 30
86%
M: 1 C: 3
75%
M: 1 C: 2
67%
M: 1 C: 7
88%
M: 0 C: 1
100%
calculateNewObjects(UnitOfWorkChangeSet)
M: 5 C: 50
91%
M: 2 C: 4
67%
M: 2 C: 2
50%
M: 1 C: 11
92%
M: 0 C: 1
100%
checkForCollections(Object)
M: 0 C: 25
100%
M: 0 C: 2
100%
M: 0 C: 2
100%
M: 0 C: 4
100%
M: 0 C: 1
100%
clear()
M: 0 C: 31
100%
M: 0 C: 0
100%
M: 0 C: 1
100%
M: 0 C: 11
100%
M: 0 C: 1
100%
cloneLoadedFieldValue(Object, Field, Descriptor, Object)
M: 0 C: 36
100%
M: 0 C: 4
100%
M: 0 C: 3
100%
M: 0 C: 9
100%
M: 0 C: 1
100%
commit()
M: 0 C: 20
100%
M: 0 C: 2
100%
M: 0 C: 2
100%
M: 0 C: 7
100%
M: 0 C: 1
100%
commitToOntology()
M: 0 C: 22
100%
M: 0 C: 8
100%
M: 0 C: 5
100%
M: 0 C: 6
100%
M: 0 C: 1
100%
commitUnitOfWork()
M: 0 C: 7
100%
M: 0 C: 0
100%
M: 0 C: 1
100%
M: 0 C: 4
100%
M: 0 C: 1
100%
contains(Object)
M: 0 C: 9
100%
M: 0 C: 0
100%
M: 0 C: 1
100%
M: 0 C: 2
100%
M: 0 C: 1
100%
containsOriginal(Object)
M: 0 C: 11
100%
M: 0 C: 4
100%
M: 0 C: 3
100%
M: 0 C: 1
100%
M: 0 C: 1
100%
createChangeRecord(Object, Field, Descriptor)
M: 0 C: 34
100%
M: 1 C: 3
75%
M: 1 C: 2
67%
M: 0 C: 9
100%
M: 0 C: 1
100%
createIndirectCollection(Object, Object, Field)
M: 0 C: 7
100%
M: 0 C: 0
100%
M: 0 C: 1
100%
M: 0 C: 1
100%
M: 0 C: 1
100%
createMap()
M: 0 C: 4
100%
M: 0 C: 0
100%
M: 0 C: 1
100%
M: 0 C: 1
100%
M: 0 C: 1
100%
createNativeQuery(String)
M: 0 C: 5
100%
M: 0 C: 0
100%
M: 0 C: 1
100%
M: 0 C: 1
100%
M: 0 C: 1
100%
createNativeQuery(String, Class)
M: 0 C: 6
100%
M: 0 C: 0
100%
M: 0 C: 1
100%
M: 0 C: 1
100%
M: 0 C: 1
100%
createQuery(String)
M: 5 C: 0
0%
M: 0 C: 0
100%
M: 1 C: 0
0%
M: 1 C: 0
0%
M: 1 C: 0
0%
createQuery(String, Class)
M: 6 C: 0
0%
M: 0 C: 0
100%
M: 1 C: 0
0%
M: 1 C: 0
0%
M: 1 C: 0
0%
deregisterEntityFromPersistenceContext(Object, UnitOfWork)
M: 0 C: 6
100%
M: 0 C: 0
100%
M: 0 C: 1
100%
M: 0 C: 2
100%
M: 0 C: 1
100%
doesEntityExist(Object, Object, Descriptor)
M: 10 C: 36
78%
M: 4 C: 10
71%
M: 4 C: 4
50%
M: 0 C: 7
100%
M: 0 C: 1
100%
getCloneForOriginal(Object)
M: 2 C: 20
91%
M: 1 C: 3
75%
M: 1 C: 2
67%
M: 1 C: 4
80%
M: 0 C: 1
100%
getConfiguration()
M: 0 C: 4
100%
M: 0 C: 0
100%
M: 0 C: 1
100%
M: 0 C: 1
100%
M: 0 C: 1
100%
getContexts()
M: 0 C: 4
100%
M: 0 C: 0
100%
M: 0 C: 1
100%
M: 0 C: 1
100%
M: 0 C: 1
100%
getDeletedObjects()
M: 0 C: 10
100%
M: 0 C: 2
100%
M: 0 C: 2
100%
M: 0 C: 3
100%
M: 0 C: 1
100%
getDescriptor(Object)
M: 4 C: 8
67%
M: 1 C: 1
50%
M: 1 C: 1
50%
M: 0 C: 2
100%
M: 0 C: 1
100%
getFieldDescriptor(Object, Field, Descriptor)
M: 0 C: 15
100%
M: 0 C: 0
100%
M: 0 C: 1
100%
M: 0 C: 4
100%
M: 0 C: 1
100%
getIdentifier(Object)
M: 4 C: 8
67%
M: 1 C: 1
50%
M: 1 C: 1
50%
M: 0 C: 2
100%
M: 0 C: 1
100%
getLiveObjectCache()
M: 0 C: 4
100%
M: 0 C: 0
100%
M: 0 C: 1
100%
M: 0 C: 1
100%
M: 0 C: 1
100%
getManagedOriginal(Class, Object, Descriptor)
M: 2 C: 31
94%
M: 1 C: 5
83%
M: 1 C: 3
75%
M: 1 C: 7
88%
M: 0 C: 1
100%
getMetamodel()
M: 0 C: 4
100%
M: 0 C: 0
100%
M: 0 C: 1
100%
M: 0 C: 1
100%
M: 0 C: 1
100%
getNewObjectsCloneToOriginal()
M: 0 C: 10
100%
M: 0 C: 2
100%
M: 0 C: 2
100%
M: 0 C: 3
100%
M: 0 C: 1
100%
getNewObjectsKeyToClone()
M: 0 C: 11
100%
M: 0 C: 2
100%
M: 0 C: 2
100%
M: 0 C: 3
100%
M: 0 C: 1
100%
getNewObjectsOriginalToClone()
M: 0 C: 10
100%
M: 0 C: 2
100%
M: 0 C: 2
100%
M: 0 C: 3
100%
M: 0 C: 1
100%
getObjectFromCache(Class, Object, URI)
M: 8 C: 13
62%
M: 2 C: 2
50%
M: 2 C: 1
33%
M: 0 C: 3
100%
M: 0 C: 1
100%
getOriginal(Object)
M: 0 C: 18
100%
M: 0 C: 4
100%
M: 0 C: 3
100%
M: 0 C: 6
100%
M: 0 C: 1
100%
getState(Object)
M: 0 C: 28
100%
M: 0 C: 6
100%
M: 0 C: 4
100%
M: 0 C: 8
100%
M: 0 C: 1
100%
getState(Object, Descriptor)
M: 0 C: 38
100%
M: 0 C: 8
100%
M: 0 C: 5
100%
M: 0 C: 9
100%
M: 0 C: 1
100%
getUowChangeSet()
M: 0 C: 9
100%
M: 0 C: 2
100%
M: 0 C: 2
100%
M: 0 C: 3
100%
M: 0 C: 1
100%
hasChanges()
M: 0 C: 13
100%
M: 0 C: 6
100%
M: 0 C: 4
100%
M: 0 C: 1
100%
M: 0 C: 1
100%
hasDeleted()
M: 0 C: 3
100%
M: 0 C: 0
100%
M: 0 C: 1
100%
M: 0 C: 1
100%
M: 0 C: 1
100%
hasNew()
M: 0 C: 3
100%
M: 0 C: 0
100%
M: 0 C: 1
100%
M: 0 C: 1
100%
M: 0 C: 1
100%
isActive()
M: 0 C: 3
100%
M: 0 C: 0
100%
M: 0 C: 1
100%
M: 0 C: 1
100%
M: 0 C: 1
100%
isConsistent(URI)
M: 0 C: 5
100%
M: 0 C: 0
100%
M: 0 C: 1
100%
M: 0 C: 1
100%
M: 0 C: 1
100%
isInCommit()
M: 0 C: 3
100%
M: 0 C: 0
100%
M: 0 C: 1
100%
M: 0 C: 1
100%
M: 0 C: 1
100%
isInRepository(Descriptor, Object)
M: 8 C: 12
60%
M: 2 C: 2
50%
M: 2 C: 1
33%
M: 0 C: 3
100%
M: 0 C: 1
100%
isInTransaction()
M: 0 C: 12
100%
M: 1 C: 3
75%
M: 1 C: 2
67%
M: 0 C: 1
100%
M: 0 C: 1
100%
isObjectManaged(Object)
M: 0 C: 19
100%
M: 0 C: 4
100%
M: 0 C: 3
100%
M: 0 C: 2
100%
M: 0 C: 1
100%
isObjectNew(Object)
M: 0 C: 11
100%
M: 0 C: 4
100%
M: 0 C: 3
100%
M: 0 C: 1
100%
M: 0 C: 1
100%
isTypeManaged(Class)
M: 0 C: 5
100%
M: 0 C: 0
100%
M: 0 C: 1
100%
M: 0 C: 1
100%
M: 0 C: 1
100%
lambda$validateIntegrityConstraints$0(IntegrityConstraintsValidator, ObjectChangeSet)
M: 0 C: 6
100%
M: 0 C: 0
100%
M: 0 C: 1
100%
M: 0 C: 1
100%
M: 0 C: 1
100%
loadEntityField(Object, Field)
M: 0 C: 73
100%
M: 1 C: 5
83%
M: 1 C: 3
75%
M: 0 C: 16
100%
M: 0 C: 1
100%
mergeChangesIntoParent()
M: 0 C: 9
100%
M: 1 C: 1
50%
M: 1 C: 1
50%
M: 0 C: 3
100%
M: 0 C: 1
100%
mergeDetached(Object, Descriptor)
M: 0 C: 33
100%
M: 0 C: 2
100%
M: 0 C: 2
100%
M: 0 C: 7
100%
M: 0 C: 1
100%
mergeDetachedInternal(Object, Descriptor)
M: 20 C: 101
83%
M: 2 C: 8
80%
M: 2 C: 4
67%
M: 5 C: 21
81%
M: 0 C: 1
100%
postCommit()
M: 0 C: 63
100%
M: 0 C: 2
100%
M: 0 C: 2
100%
M: 0 C: 20
100%
M: 0 C: 1
100%
putObjectIntoCache(Object, Object, URI)
M: 0 C: 7
100%
M: 0 C: 0
100%
M: 0 C: 1
100%
M: 0 C: 2
100%
M: 0 C: 1
100%
readObject(Class, Object, Descriptor)
M: 0 C: 21
100%
M: 0 C: 0
100%
M: 0 C: 1
100%
M: 0 C: 4
100%
M: 0 C: 1
100%
readObjectInternal(Class, Object, Descriptor)
M: 12 C: 84
88%
M: 5 C: 15
75%
M: 5 C: 6
55%
M: 0 C: 18
100%
M: 0 C: 1
100%
registerClone(Object, Object, Descriptor)
M: 0 C: 32
100%
M: 0 C: 0
100%
M: 0 C: 1
100%
M: 0 C: 7
100%
M: 0 C: 1
100%
registerEntityWithOntologyContext(Descriptor, Object)
M: 8 C: 18
69%
M: 2 C: 2
50%
M: 2 C: 1
33%
M: 0 C: 5
100%
M: 0 C: 1
100%
registerEntityWithPersistenceContext(Object, UnitOfWorkImpl)
M: 0 C: 6
100%
M: 0 C: 0
100%
M: 0 C: 1
100%
M: 0 C: 2
100%
M: 0 C: 1
100%
registerExistingObject(Object, Descriptor)
M: 6 C: 27
82%
M: 2 C: 4
67%
M: 2 C: 2
50%
M: 1 C: 7
88%
M: 0 C: 1
100%
registerNewObject(Object, Descriptor)
M: 0 C: 15
100%
M: 0 C: 0
100%
M: 0 C: 1
100%
M: 0 C: 4
100%
M: 0 C: 1
100%
registerNewObjectInternal(Object, Descriptor)
M: 4 C: 89
96%
M: 2 C: 8
80%
M: 2 C: 4
67%
M: 0 C: 18
100%
M: 0 C: 1
100%
release()
M: 0 C: 12
100%
M: 0 C: 0
100%
M: 0 C: 1
100%
M: 0 C: 5
100%
M: 0 C: 1
100%
removeIndirectCollections(Object)
M: 0 C: 39
100%
M: 0 C: 6
100%
M: 0 C: 4
100%
M: 0 C: 9
100%
M: 0 C: 1
100%
removeObject(Object)
M: 2 C: 58
97%
M: 2 C: 8
80%
M: 2 C: 4
67%
M: 2 C: 13
87%
M: 0 C: 1
100%
removeObjectFromCache(Object, URI)
M: 0 C: 17
100%
M: 0 C: 0
100%
M: 0 C: 1
100%
M: 0 C: 4
100%
M: 0 C: 1
100%
revertObject(Object)
M: 20 C: 58
74%
M: 3 C: 5
63%
M: 3 C: 2
40%
M: 3 C: 12
80%
M: 0 C: 1
100%
rollback()
M: 0 C: 17
100%
M: 0 C: 2
100%
M: 0 C: 2
100%
M: 0 C: 6
100%
M: 0 C: 1
100%
setEntityManager(AbstractEntityManager)
M: 0 C: 4
100%
M: 0 C: 0
100%
M: 0 C: 1
100%
M: 0 C: 2
100%
M: 0 C: 1
100%
setHasChanges()
M: 0 C: 4
100%
M: 0 C: 0
100%
M: 0 C: 1
100%
M: 0 C: 2
100%
M: 0 C: 1
100%
setIndirectCollectionIfPresent(Object, Field)
M: 0 C: 35
100%
M: 0 C: 8
100%
M: 0 C: 5
100%
M: 0 C: 8
100%
M: 0 C: 1
100%
setShouldClearAfterCommit(boolean)
M: 0 C: 4
100%
M: 0 C: 0
100%
M: 0 C: 1
100%
M: 0 C: 2
100%
M: 0 C: 1
100%
setUseBackupOntologyForQueryProcessing()
M: 0 C: 4
100%
M: 0 C: 0
100%
M: 0 C: 1
100%
M: 0 C: 2
100%
M: 0 C: 1
100%
setUseTransactionalOntologyForQueryProcessing()
M: 0 C: 4
100%
M: 0 C: 0
100%
M: 0 C: 1
100%
M: 0 C: 2
100%
M: 0 C: 1
100%
shouldReleaseAfterCommit()
M: 0 C: 3
100%
M: 0 C: 0
100%
M: 0 C: 1
100%
M: 0 C: 1
100%
M: 0 C: 1
100%
static {...}
M: 0 C: 1
100%
M: 0 C: 0
100%
M: 0 C: 1
100%
M: 0 C: 1
100%
M: 0 C: 1
100%
storageCommit()
M: 0 C: 11
100%
M: 0 C: 0
100%
M: 0 C: 1
100%
M: 0 C: 6
100%
M: 0 C: 1
100%
unregisterEntityFromOntologyContext(Object)
M: 16 C: 20
56%
M: 2 C: 2
50%
M: 2 C: 1
33%
M: 1 C: 6
86%
M: 0 C: 1
100%
unregisterObject(Object)
M: 6 C: 38
86%
M: 2 C: 4
67%
M: 2 C: 2
50%
M: 2 C: 11
85%
M: 0 C: 1
100%
unwrap(Class)
M: 0 C: 14
100%
M: 0 C: 2
100%
M: 0 C: 2
100%
M: 0 C: 3
100%
M: 0 C: 1
100%
useBackupOntologyForQueryProcessing()
M: 0 C: 7
100%
M: 0 C: 2
100%
M: 0 C: 2
100%
M: 0 C: 1
100%
M: 0 C: 1
100%
useTransactionalOntologyForQueryProcessing()
M: 0 C: 3
100%
M: 0 C: 0
100%
M: 0 C: 1
100%
M: 0 C: 1
100%
M: 0 C: 1
100%
validateIntegrityConstraints()
M: 0 C: 37
100%
M: 0 C: 4
100%
M: 0 C: 3
100%
M: 0 C: 9
100%
M: 0 C: 1
100%
writeUncommittedChanges()
M: 7 C: 0
0%
M: 2 C: 0
0%
M: 2 C: 0
0%
M: 4 C: 0
0%
M: 1 C: 0
0%

Coverage

1: /**
2: * Copyright (C) 2016 Czech Technical University in Prague
3: *
4: * This program is free software: you can redistribute it and/or modify it under
5: * the terms of the GNU General Public License as published by the Free Software
6: * Foundation, either version 3 of the License, or (at your option) any
7: * later version.
8: *
9: * This program is distributed in the hope that it will be useful, but WITHOUT
10: * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
11: * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
12: * details. You should have received a copy of the GNU General Public License
13: * along with this program. If not, see <http://www.gnu.org/licenses/>.
14: */
15: package cz.cvut.kbss.jopa.sessions;
16:
17: import cz.cvut.kbss.jopa.adapters.IndirectCollection;
18: import cz.cvut.kbss.jopa.exceptions.OWLEntityExistsException;
19: import cz.cvut.kbss.jopa.exceptions.OWLPersistenceException;
20: import cz.cvut.kbss.jopa.model.AbstractEntityManager;
21: import cz.cvut.kbss.jopa.model.EntityManagerImpl.State;
22: import cz.cvut.kbss.jopa.model.descriptors.Descriptor;
23: import cz.cvut.kbss.jopa.model.metamodel.EntityType;
24: import cz.cvut.kbss.jopa.model.metamodel.FieldSpecification;
25: import cz.cvut.kbss.jopa.model.metamodel.Metamodel;
26: import cz.cvut.kbss.jopa.model.query.Query;
27: import cz.cvut.kbss.jopa.model.query.TypedQuery;
28: import cz.cvut.kbss.jopa.query.sparql.SparqlQueryFactory;
29: import cz.cvut.kbss.jopa.sessions.change.ChangeManagerImpl;
30: import cz.cvut.kbss.jopa.sessions.change.ChangeRecordImpl;
31: import cz.cvut.kbss.jopa.sessions.change.ChangeSetFactory;
32: import cz.cvut.kbss.jopa.sessions.validator.IntegrityConstraintsValidator;
33: import cz.cvut.kbss.jopa.utils.*;
34:
35: import java.lang.reflect.Field;
36: import java.net.URI;
37: import java.util.*;
38: import java.util.Map.Entry;
39:
40: public class UnitOfWorkImpl extends AbstractSession implements UnitOfWork, QueryFactory, ConfigurationHolder, Wrapper {
41:
42: private final Map<Object, Object> cloneMapping;
43: private final Map<Object, Object> cloneToOriginals;
44: private final Map<Object, Object> keysToClones;
45: private Map<Object, Object> deletedObjects;
46: private Map<Object, Object> newObjectsCloneToOriginal;
47: private Map<Object, Object> newObjectsOriginalToClone;
48: private Map<Object, Object> newObjectsKeyToClone;
49: private RepositoryMap repoMap;
50:
51: private boolean hasChanges;
52: private boolean hasNew;
53: private boolean hasDeleted;
54: private boolean shouldReleaseAfterCommit;
55: private boolean shouldClearCacheAfterCommit;
56: private boolean useTransactionalOntology;
57:
58: private boolean isActive;
59: private boolean inCommit;
60:
61: private UnitOfWorkChangeSet uowChangeSet;
62:
63: private AbstractSession parent;
64: private AbstractEntityManager entityManager;
65: private final ConnectionWrapper storage;
66:
67: private final MergeManager mergeManager;
68: private final CloneBuilder cloneBuilder;
69: private final ChangeManager changeManager;
70: private final QueryFactory queryFactory;
71: private final CollectionFactory collectionFactory;
72: /**
73: * This is a shortcut for the second level cache.
74: */
75: private final CacheManager cacheManager;
76:
77: public UnitOfWorkImpl(AbstractSession parent) {
78: this.parent = Objects.requireNonNull(parent, ErrorUtils.constructNPXMessage("parent"));
79: this.cloneMapping = createMap();
80: this.cloneToOriginals = createMap();
81: this.keysToClones = new HashMap<>();
82: this.repoMap = new RepositoryMap();
83: repoMap.initDescriptors();
84: this.cloneBuilder = new CloneBuilderImpl(this);
85: this.collectionFactory = new CollectionFactory(this);
86: this.cacheManager = parent.getLiveObjectCache();
87: this.storage = acquireConnection();
88: this.queryFactory = new SparqlQueryFactory(this, storage);
89: this.mergeManager = new MergeManagerImpl(this);
90: this.changeManager = new ChangeManagerImpl(this);
91: this.inCommit = false;
92: this.useTransactionalOntology = true;
93: this.isActive = true;
94: }
95:
96: /**
97: * This method returns null, since we don't support nested Units of Work yet.
98: */
99: @Override
100: public UnitOfWork acquireUnitOfWork() {
101: return null;
102: }
103:
104: @Override
105: protected ConnectionWrapper acquireConnection() {
106: final ConnectionWrapper conn = parent.acquireConnection();
107: conn.setUnitOfWork(this);
108: return conn;
109: }
110:
111: @Override
112: public <T> T readObject(Class<T> cls, Object primaryKey, Descriptor descriptor) {
113: Objects.requireNonNull(cls, ErrorUtils.constructNPXMessage("cls"));
114: Objects.requireNonNull(primaryKey, ErrorUtils.constructNPXMessage("primaryKey"));
115: Objects.requireNonNull(descriptor, ErrorUtils.constructNPXMessage("descriptor"));
116:
117: return readObjectInternal(cls, primaryKey, descriptor);
118: }
119:
120: private <T> T readObjectInternal(Class<T> cls, Object primaryKey, Descriptor descriptor) {
121:• assert cls != null;
122:• assert primaryKey != null;
123:• assert descriptor != null;
124: // First try to find the object among new uncommitted objects
125: Object result = getNewObjectsKeyToClone().get(primaryKey);
126:• if (result != null && (isInRepository(descriptor, result))) {
127: // The result can be returned, since it is already registered in
128: // this UOW
129: return cls.cast(result);
130: }
131: // Object is already managed
132: result = keysToClones.get(primaryKey);
133:• if (result != null && isInRepository(descriptor, result) && !getDeletedObjects().containsKey(result)) {
134: return cls.cast(result);
135: }
136: // Search the cache
137: result = getObjectFromCache(cls, primaryKey, descriptor.getContext());
138:• if (result == null) {
139: // The object is not in the session cache, so search the ontology
140: final URI pkUri = EntityPropertiesUtils.getValueAsURI(primaryKey);
141: result = storage.find(new LoadingParameters<>(cls, pkUri, descriptor));
142: }
143:• if (result == null) {
144: return null;
145: }
146: Object clone = registerExistingObject(result, descriptor);
147: checkForCollections(clone);
148: return cls.cast(clone);
149: }
150:
151: /**
152: * This method calculates the changes that were to the registered entities and adds these changes into the given
153: * change set for future commit to the ontology.
154: */
155: private void calculateChanges() {
156: final UnitOfWorkChangeSet changeSet = getUowChangeSet();
157:• if (hasNew()) {
158: calculateNewObjects(changeSet);
159: }
160:• if (hasDeleted()) {
161: calculateDeletedObjects(changeSet);
162: }
163: }
164:
165: /**
166: * Create object change sets for the new objects and adds them into our UnitOfWorkChangeSet.
167: *
168: * @param changeSet UnitOfWorkChangeSet
169: */
170: private void calculateNewObjects(UnitOfWorkChangeSet changeSet) {
171:• for (Object clone : getNewObjectsCloneToOriginal().keySet()) {
172: final Descriptor c = getDescriptor(clone);
173: Object original = getNewObjectsCloneToOriginal().get(clone);
174:• if (original == null) {
175: original = this.cloneBuilder.buildClone(clone, c);
176: }
177:• if (original == null) {
178: throw new OWLPersistenceException(
179: "Error while calculating changes for new objects. Original not found.");
180: }
181: getNewObjectsCloneToOriginal().put(clone, original);
182: getNewObjectsOriginalToClone().put(original, clone);
183: changeSet.addNewObjectChangeSet(ChangeSetFactory.createObjectChangeSet(original, clone,
184: c));
185: }
186: }
187:
188: private void calculateDeletedObjects(final UnitOfWorkChangeSet changeSet) {
189:• for (Object clone : getDeletedObjects().keySet()) {
190: Object original = cloneToOriginals.get(clone);
191:• if (original == null) {
192: throw new OWLPersistenceException("Cannot find an original for clone!");
193: }
194: Descriptor descriptor = getDescriptor(clone);
195: changeSet.addDeletedObjectChangeSet(ChangeSetFactory.createObjectChangeSet(original, clone,
196: descriptor));
197: }
198: }
199:
200: public void clear() {
201: cloneMapping.clear();
202: cloneToOriginals.clear();
203: keysToClones.clear();
204: this.deletedObjects = null;
205: this.newObjectsCloneToOriginal = null;
206: this.newObjectsOriginalToClone = null;
207: this.newObjectsKeyToClone = null;
208: this.hasChanges = false;
209: this.hasDeleted = false;
210: this.hasNew = false;
211: }
212:
213: public boolean contains(Object entity) {
214: Objects.requireNonNull(entity, ErrorUtils.constructNPXMessage("entity"));
215:
216: return isObjectManaged(entity);
217: }
218:
219: public void commit() {
220: LOG.trace("UnitOfWork commit started.");
221:• if (!isActive()) {
222: throw new IllegalStateException("Cannot commit inactive Unit of Work!");
223: }
224: this.inCommit = true;
225: commitUnitOfWork();
226: LOG.trace("UnitOfWork commit finished.");
227: }
228:
229: public void rollback() {
230: LOG.trace("UnitOfWork rollback started.");
231:• if (!isActive()) {
232: throw new IllegalStateException("Cannot rollback inactive Unit of Work!");
233: }
234: storage.rollback();
235: clear();
236: }
237:
238: /**
239: * Commit this Unit of Work.
240: */
241: protected void commitUnitOfWork() {
242: commitToOntology();
243: mergeChangesIntoParent();
244: postCommit();
245: }
246:
247: /**
248: * Clean up after the commit.
249: */
250: private void postCommit() {
251: // Remove indirect collections from clones
252: cloneMapping.keySet().forEach(this::removeIndirectCollections);
253: getNewObjectsCloneToOriginal().clear();
254: getNewObjectsOriginalToClone().clear();
255: getNewObjectsKeyToClone().clear();
256: getDeletedObjects().clear();
257: cloneToOriginals.clear();
258: cloneMapping.clear();
259: keysToClones.clear();
260: this.hasChanges = false;
261: this.hasDeleted = false;
262: this.hasNew = false;
263: this.inCommit = false;
264: cloneBuilder.reset();
265: this.repoMap = new RepositoryMap();
266: repoMap.initDescriptors();
267: this.uowChangeSet = null;
268:• if (shouldClearCacheAfterCommit) {
269: cacheManager.evictAll();
270: this.shouldReleaseAfterCommit = true;
271: }
272: }
273:
274: /**
275: * If there are any changes, commit them to the ontology.
276: */
277: protected void commitToOntology() {
278:• boolean hasChanges = this.hasNew || this.hasChanges || this.hasDeleted;
279:• if (hasChanges) {
280: calculateChanges();
281: }
282: validateIntegrityConstraints();
283: storageCommit();
284: }
285:
286: private void validateIntegrityConstraints() {
287:• if (uowChangeSet == null) {
288: return;
289: }
290: final IntegrityConstraintsValidator validator = IntegrityConstraintsValidator.getValidator();
291:• for (ObjectChangeSet changeSet : uowChangeSet.getNewObjects()) {
292: validator.validate(changeSet.getCloneObject(),
293: getMetamodel().entity((Class<Object>) changeSet.getObjectClass()), false);
294: }
295: uowChangeSet.getExistingObjectsChanges().forEach(changeSet -> validator.validate(changeSet, getMetamodel()));
296: }
297:
298: private Map<Object, Object> createMap() {
299: return new IdentityHashMap<>();
300: }
301:
302: /**
303: * Gets current state of the specified entity. </p>
304: * <p>
305: * Note that since no repository is specified we can only determine if the entity is managed or removed. Therefore
306: * if the case is different this method returns State#NOT_MANAGED.
307: *
308: * @param entity The entity to check
309: * @return State of the entity
310: */
311: public State getState(Object entity) {
312: Objects.requireNonNull(entity, ErrorUtils.constructNPXMessage("entity"));
313:
314:• if (getDeletedObjects().containsKey(entity)) {
315: return State.REMOVED;
316:• } else if (getNewObjectsCloneToOriginal().containsKey(entity)) {
317: return State.MANAGED_NEW;
318:• } else if (cloneMapping.containsKey(entity)) {
319: return State.MANAGED;
320: } else {
321: return State.NOT_MANAGED;
322: }
323: }
324:
325: /**
326: * Checks the state of the specified entity with regards to the specified repository.
327: *
328: * @param entity Object
329: * @param descriptor Entity descriptor
330: * @return The state of the specified entity
331: */
332: public State getState(Object entity, Descriptor descriptor) {
333: Objects.requireNonNull(entity, ErrorUtils.constructNPXMessage("entity"));
334: Objects.requireNonNull(descriptor, ErrorUtils.constructNPXMessage("descriptor"));
335:
336:• if (getDeletedObjects().containsKey(entity)) {
337: return State.REMOVED;
338:• } else if (cloneMapping.containsKey(entity) && isInRepository(descriptor, entity)) {
339:• if (getNewObjectsCloneToOriginal().containsKey(entity)) {
340: return State.MANAGED_NEW;
341: }
342: return State.MANAGED;
343: } else {
344: return State.NOT_MANAGED;
345: }
346: }
347:
348: /**
349: * Tries to find the original object for the given clone. It searches the existing objects, new objects and deleted
350: * objects.
351: *
352: * @param clone Object
353: * @return The original object for the given clone
354: */
355: public Object getOriginal(Object clone) {
356:• if (clone == null) {
357: return null;
358: }
359: Object original = cloneToOriginals.get(clone);
360:• if (original == null) {
361: original = getNewObjectsCloneToOriginal().get(clone);
362: }
363: return original;
364: }
365:
366: /**
367: * Gets managed original with the specified identifier or {@code null} if there is none matching.
368: * <p>
369: * Descriptor is used to check repository context validity.
370: *
371: * @param cls Return type of the original
372: * @param identifier Instance identifier
373: * @param descriptor Repository descriptor
374: * @return Original object managed by this UoW or {@code null} if this UoW doesn't contain a matching instance
375: */
376: public <T> T getManagedOriginal(Class<T> cls, Object identifier, Descriptor descriptor) {
377:• if (!keysToClones.containsKey(identifier)) {
378: return null;
379: }
380: final Object clone = keysToClones.get(identifier);
381:• if (!cls.isAssignableFrom(clone.getClass())) {
382: return null;
383: }
384:• if (!isInRepository(descriptor, clone)) {
385: return null;
386: }
387: return cls.cast(cloneToOriginals.get(clone));
388: }
389:
390: /**
391: * Check if this UnitOfWork contains this original entity. This method is used by the CloneBuilder so it does not
392: * have to clone already managed referenced objects.
393: *
394: * @param entity The original entity.
395: * @return True if the original is managed in this UnitOfWork.
396: */
397: boolean containsOriginal(Object entity) {
398:• return entity != null && cloneToOriginals.containsValue(entity);
399: }
400:
401: /**
402: * Finds clone for the specified original. This method assumes that the original is managed in this persistence
403: * context (UnitOfWork). However, if not, this method just goes through all the managed objects and if it does not
404: * find match, returns null.
405: *
406: * @param original The original object whose clone we are looking for.
407: * @return The clone or null, if there is none.
408: */
409: Object getCloneForOriginal(Object original) {
410:• for (Entry<Object, Object> entry : cloneToOriginals.entrySet()) {
411: // We use IdentityMap, so we can use ==
412:• if (entry.getValue() == original) {
413: return entry.getKey();
414: }
415: }
416: return null;
417: }
418:
419: public boolean hasDeleted() {
420: return hasDeleted;
421: }
422:
423: public boolean hasChanges() {
424:• return hasChanges || hasDeleted || hasNew;
425: }
426:
427: public boolean hasNew() {
428: return hasNew;
429: }
430:
431: public void setHasChanges() {
432: this.hasChanges = true;
433: }
434:
435: public Map<Object, Object> getDeletedObjects() {
436:• if (deletedObjects == null) {
437: this.deletedObjects = createMap();
438: }
439: return deletedObjects;
440: }
441:
442: public Map<Object, Object> getNewObjectsCloneToOriginal() {
443:• if (newObjectsCloneToOriginal == null) {
444: this.newObjectsCloneToOriginal = createMap();
445: }
446: return newObjectsCloneToOriginal;
447: }
448:
449: public Map<Object, Object> getNewObjectsOriginalToClone() {
450:• if (newObjectsOriginalToClone == null) {
451: this.newObjectsOriginalToClone = createMap();
452: }
453: return newObjectsOriginalToClone;
454: }
455:
456: public Map<Object, Object> getNewObjectsKeyToClone() {
457:• if (newObjectsKeyToClone == null) {
458: // Cannot use identity map, since it compares the key references
459: // which may not be the same
460: this.newObjectsKeyToClone = new HashMap<>();
461: }
462: return newObjectsKeyToClone;
463: }
464:
465: @Override
466: public CacheManager getLiveObjectCache() {
467: return parent.getLiveObjectCache();
468: }
469:
470: public UnitOfWorkChangeSet getUowChangeSet() {
471:• if (uowChangeSet == null) {
472: this.uowChangeSet = ChangeSetFactory.createUoWChangeSet();
473: }
474: return uowChangeSet;
475: }
476:
477: public boolean isActive() {
478: return this.isActive;
479: }
480:
481: /**
482: * Returns true if the given clone represents a newly created object. Otherwise returns false.
483: *
484: * @param clone Object
485: * @return boolean
486: */
487: public boolean isObjectNew(Object clone) {
488:• return clone != null && getNewObjectsCloneToOriginal().containsKey(clone);
489: }
490:
491: /**
492: * Returns true if the given object is already managed.
493: *
494: * @param entity Object
495: * @return boolean
496: */
497: public boolean isObjectManaged(Object entity) {
498: Objects.requireNonNull(entity, ErrorUtils.constructNPXMessage("entity"));
499:
500:• return (cloneMapping.containsKey(entity) && !getDeletedObjects().containsKey(entity));
501: }
502:
503: private boolean doesEntityExist(Object entity, Object primaryKey, Descriptor descriptor) {
504:• assert entity != null;
505:• assert descriptor != null;
506:• if (cloneMapping.containsKey(entity) && !getDeletedObjects().containsKey(entity)
507:• && isInRepository(descriptor, entity)) {
508: return true;
509: }
510:• return primaryKey != null
511:• && cacheManager.contains(entity.getClass(), primaryKey, descriptor.getContext());
512: }
513:
514: /**
515: * Persists changed value of the specified field.
516: *
517: * @param entity Entity with changes (the clone)
518: * @param f The field whose value has changed
519: * @throws IllegalStateException If this UoW is not in transaction
520: */
521: public void attributeChanged(Object entity, Field f) {
522:• if (!isInTransaction()) {
523: throw new IllegalStateException("This unit of work is not in a transaction.");
524: }
525: final Descriptor descriptor = getDescriptor(entity);
526:• if (descriptor == null) {
527: throw new OWLPersistenceException("Unable to find repository for entity " + entity
528: + ". Is it registered in this UoW?");
529: }
530: storage.merge(entity, f, descriptor);
531: createChangeRecord(entity, f, descriptor);
532: setHasChanges();
533: setIndirectCollectionIfPresent(entity, f);
534: }
535:
536: private void createChangeRecord(Object clone, Field field, Descriptor descriptor) {
537: final Object orig = getOriginal(clone);
538:• if (orig == null) {
539: return;
540: }
541: ObjectChangeSet chSet = getUowChangeSet().getExistingObjectChanges(orig);
542:• if (chSet == null) {
543: chSet = ChangeSetFactory.createObjectChangeSet(orig, clone, descriptor);
544: getUowChangeSet().addObjectChangeSet(chSet);
545: }
546: chSet.addChangeRecord(new ChangeRecordImpl(field.getName(), EntityPropertiesUtils.getFieldValue(field, clone)));
547: }
548:
549: /**
550: * Merge the changes from this Unit of Work's change set into the server session.
551: */
552: public void mergeChangesIntoParent() {
553:• if (hasChanges()) {
554: mergeManager.mergeChangesFromChangeSet(getUowChangeSet());
555: }
556: }
557:
558: @Override
559: public <T> T mergeDetached(T entity, Descriptor descriptor) {
560: Objects.requireNonNull(entity, ErrorUtils.constructNPXMessage("entity"));
561: Objects.requireNonNull(descriptor, ErrorUtils.constructNPXMessage("descriptor"));
562:
563: final Object pk = getIdentifier(entity);
564:• if (!storage.contains(pk, entity.getClass(), descriptor)) {
565: registerNewObject(entity, descriptor);
566: return entity;
567: } else {
568: return mergeDetachedInternal(entity, descriptor);
569: }
570: }
571:
572: private <T> T mergeDetachedInternal(T entity, Descriptor descriptor) {
573:• assert entity != null;
574: final Object iri = getIdentifier(entity);
575: final Class<T> entityCls = (Class<T>) entity.getClass();
576: // Search the cache
577: T original = getObjectFromCache(entityCls, iri, descriptor.getContext());
578:• if (original == null) {
579: // The object is not in the session cache, so search the ontology
580: final URI idUri = EntityPropertiesUtils.getValueAsURI(iri);
581: original = storage.find(new LoadingParameters<>(entityCls, idUri, descriptor, true));
582: }
583:• assert original != null;
584: registerClone(entity, original, descriptor);
585: try {
586: // Merge only the changed attributes
587: final ObjectChangeSet chSet = ChangeSetFactory.createObjectChangeSet(original, entity, descriptor);
588: changeManager.calculateChanges(chSet);
589: final EntityType<?> et = getMetamodel().entity(entityCls);
590:• for (ChangeRecord record : chSet.getChanges().values()) {
591: final Field field = et.getFieldSpecification(record.getAttributeName()).getJavaField();
592: storage.merge(entity, field, descriptor);
593: }
594: } catch (OWLEntityExistsException e) {
595: unregisterObject(entity);
596: throw e;
597: } catch (IllegalAccessException e) {
598: throw new OWLPersistenceException(e);
599: }
600:• if (cacheManager.contains(entityCls, iri, descriptor.getContext())) {
601: cacheManager.evict(entityCls, iri, descriptor.getContext());
602: }
603: setHasChanges();
604: return entity;
605: }
606:
607: /**
608: * {@inheritDoc}
609: */
610: @Override
611: void registerEntityWithPersistenceContext(Object entity, UnitOfWorkImpl uow) {
612: parent.registerEntityWithPersistenceContext(entity, uow);
613: }
614:
615: @Override
616: void deregisterEntityFromPersistenceContext(Object entity, UnitOfWork uow) {
617: parent.deregisterEntityFromPersistenceContext(entity, uow);
618: }
619:
620: /**
621: * {@inheritDoc}
622: */
623: public Object registerExistingObject(Object entity, Descriptor descriptor) {
624:• if (entity == null) {
625: return null;
626: }
627:• if (cloneToOriginals.containsValue(entity)) {
628: return getCloneForOriginal(entity);
629: }
630: Object clone = this.cloneBuilder.buildClone(entity, descriptor);
631:• assert clone != null;
632: registerClone(clone, entity, descriptor);
633: return clone;
634: }
635:
636: private void registerClone(Object clone, Object original, Descriptor descriptor) {
637: cloneMapping.put(clone, clone);
638: cloneToOriginals.put(clone, original);
639: final Object identifier = EntityPropertiesUtils.getPrimaryKey(clone, getMetamodel());
640: keysToClones.put(identifier, clone);
641: registerEntityWithPersistenceContext(clone, this);
642: registerEntityWithOntologyContext(descriptor, clone);
643: }
644:
645: /**
646: * Release this Unit of Work. Releasing an active Unit of Work with uncommitted changes causes all pending changes
647: * to be discarded.
648: */
649: public void release() {
650: clear();
651: storage.close();
652: this.isActive = false;
653: LOG.debug("UnitOfWork released.");
654: }
655:
656: @Override
657: public <T> void revertObject(T object) {
658: Objects.requireNonNull(object, ErrorUtils.constructNPXMessage("object"));
659:
660:• if (!isObjectManaged(object) && !getDeletedObjects().containsKey(object)) {
661: throw new IllegalArgumentException("The specified enity " + object
662: + " is not managed by this persistence context.");
663: }
664: final Descriptor descriptor = getDescriptor(object);
665:• if (descriptor == null) {
666: throw new IllegalArgumentException("Unable to find entity " + object
667: + " in this persistence context.");
668: }
669: // To revert the object's state, just swap original and clone for change
670: // calculation and merging so that the state of the original is merged
671: // into the state of the clone
672: final Object original = getOriginal(object);
673: final ObjectChangeSet chSet = ChangeSetFactory.createObjectChangeSet(object, original,
674: descriptor);
675: try {
676: final boolean anyChanges = changeManager.calculateChanges(chSet);
677:• if (anyChanges) {
678: mergeManager.mergeChangesOnObject(original, chSet);
679: }
680: } catch (IllegalAccessException | IllegalArgumentException e) {
681: throw new OWLPersistenceException(e);
682: }
683: }
684:
685: @Override
686: public void registerNewObject(Object entity, Descriptor descriptor) {
687: Objects.requireNonNull(entity, ErrorUtils.constructNPXMessage("entity"));
688: Objects.requireNonNull(descriptor, ErrorUtils.constructNPXMessage("descriptor"));
689:
690: registerNewObjectInternal(entity, descriptor);
691: }
692:
693: /**
694: * Registers the specified entity for persist in this Unit of Work.
695: *
696: * @param entity The entity to register
697: * @param descriptor Entity descriptor, specifying optionally contexts into which the entity will be persisted
698: */
699: private void registerNewObjectInternal(Object entity, Descriptor descriptor) {
700:• assert entity != null;
701: Object id = getIdentifier(entity);
702:• if (id == null) {
703: final EntityType<?> eType = getMetamodel().entity(entity.getClass());
704: EntityPropertiesUtils.verifyIdentifierIsGenerated(entity, eType);
705: }
706:• if (doesEntityExist(entity, id, descriptor) && !entity.getClass().isEnum()) {
707: throw new OWLEntityExistsException("An entity with URI " + id
708: + " is already persisted in repository " + descriptor);
709: }
710: storage.persist(id, entity, descriptor);
711:• if (id == null) {
712: // If the ID was null, extract it from the entity
713: // It is present now
714: id = getIdentifier(entity);
715: }
716: // Original is null until commit
717: cloneMapping.put(entity, entity);
718: getNewObjectsCloneToOriginal().put(entity, null);
719: registerEntityWithPersistenceContext(entity, this);
720: registerEntityWithOntologyContext(descriptor, entity);
721: getNewObjectsKeyToClone().put(id, entity);
722: checkForCollections(entity);
723: this.hasNew = true;
724: }
725:
726: /**
727: * Remove the specified entity from the ontology.
728: *
729: * @param entity Managed entity to delete
730: */
731: public void removeObject(Object entity) {
732:• if (entity == null) {
733: return;
734: }
735:• if (!isObjectManaged(entity)) {
736: throw new IllegalArgumentException(
737: "Cannot remove entity which is not managed in the current persistence context.");
738: }
739:• if (getDeletedObjects().containsKey(entity)) {
740: return;
741: }
742: final Object primaryKey = getIdentifier(entity);
743: final Descriptor descriptor = getDescriptor(entity);
744:
745:• if (hasNew() && getNewObjectsCloneToOriginal().containsKey(entity)) {
746: unregisterObject(entity);
747: getNewObjectsKeyToClone().remove(primaryKey);
748: } else {
749: getDeletedObjects().put(entity, entity);
750: this.hasDeleted = true;
751: }
752: //                unregisterEntityFromOntologyContext(entity);
753: storage.remove(primaryKey, entity.getClass(), descriptor);
754: }
755:
756: /**
757: * Remove the registered object from this Unit of Work.
758: *
759: * @param object Clone of the original object
760: */
761: public void unregisterObject(Object object) {
762:• if (object == null) {
763: return;
764: }
765: cloneMapping.remove(object);
766: cloneToOriginals.remove(object);
767:
768: getDeletedObjects().remove(object);
769:• if (hasNew()) {
770: Object newOriginal = getNewObjectsCloneToOriginal().remove(object);
771:• if (newOriginal != null) {
772: getNewObjectsOriginalToClone().remove(newOriginal);
773: }
774: }
775: removeIndirectCollections(object);
776: deregisterEntityFromPersistenceContext(object, this);
777: unregisterEntityFromOntologyContext(object);
778: }
779:
780: public boolean shouldReleaseAfterCommit() {
781: return shouldReleaseAfterCommit;
782: }
783:
784: public void setShouldClearAfterCommit(boolean shouldClearCache) {
785: this.shouldClearCacheAfterCommit = shouldClearCache;
786: }
787:
788: public void setEntityManager(AbstractEntityManager entityManager) {
789: this.entityManager = entityManager;
790: }
791:
792: public void writeUncommittedChanges() {
793:• if (!hasChanges()) {
794: return;
795: }
796: commitUnitOfWork();
797: }
798:
799: @Override
800: public Metamodel getMetamodel() {
801: return parent.getMetamodel();
802: }
803:
804: @Override
805: public boolean isTypeManaged(Class<?> cls) {
806: return parent.isTypeManaged(cls);
807: }
808:
809: @Override
810: public boolean isInTransaction() {
811:• return entityManager != null && entityManager.getTransaction().isActive();
812: }
813:
814: /**
815: * Returns {@code true} if this UoW is currently committing changes.
816: */
817: public boolean isInCommit() {
818: return inCommit;
819: }
820:
821: @Override
822: public <T> void loadEntityField(T entity, Field field) {
823: Objects.requireNonNull(entity, ErrorUtils.constructNPXMessage("entity"));
824: Objects.requireNonNull(field, ErrorUtils.constructNPXMessage("field"));
825:
826:• if (EntityPropertiesUtils.getFieldValue(field, entity) != null) {
827: return;
828: }
829: final Descriptor entityDescriptor = getDescriptor(entity);
830:• if (entityDescriptor == null) {
831: throw new OWLPersistenceException(
832: "Unable to find repository identifier for entity " + entity
833: + ". Is it managed by this UoW?");
834: }
835: storage.loadFieldValue(entity, field, entityDescriptor);
836: final Object orig = EntityPropertiesUtils.getFieldValue(field, entity);
837: final Object entityOriginal = getOriginal(entity);
838:• if (entityOriginal != null) {
839: EntityPropertiesUtils.setFieldValue(field, entityOriginal, orig);
840: }
841: final Descriptor fieldDescriptor = getFieldDescriptor(entity, field, entityDescriptor);
842: final Object clone = cloneLoadedFieldValue(entity, field, fieldDescriptor, orig);
843: EntityPropertiesUtils.setFieldValue(field, entity, clone);
844: }
845:
846: private <T> Descriptor getFieldDescriptor(T entity, Field field, Descriptor entityDescriptor) {
847: final EntityType<?> et = getMetamodel().entity(entity.getClass());
848: final FieldSpecification<?, ?> fieldSpec = et
849: .getFieldSpecification(field.getName());
850: return entityDescriptor.getAttributeDescriptor(fieldSpec);
851: }
852:
853: private <T> Object cloneLoadedFieldValue(T entity, Field field, final Descriptor fieldDescriptor,
854: final Object fieldValueOrig) {
855: Object clone;
856:• if (fieldValueOrig == null) {
857: clone = null;
858: } else {
859:• if (isTypeManaged(field.getType())) {
860: clone = registerExistingObject(fieldValueOrig, fieldDescriptor);
861: final URI fieldContext = fieldDescriptor.getContext();
862: putObjectIntoCache(getIdentifier(clone), fieldValueOrig, fieldContext);
863: } else {
864: clone = cloneBuilder.buildClone(entity, field, fieldValueOrig, fieldDescriptor);
865: }
866: }
867: return clone;
868: }
869:
870: @Override
871: public void removeObjectFromCache(Object toRemove, URI context) {
872: Objects.requireNonNull(toRemove, ErrorUtils.constructNPXMessage("toRemove"));
873:
874: final Object primaryKey = getIdentifier(toRemove);
875: cacheManager.evict(toRemove.getClass(), primaryKey, context);
876: }
877:
878: @Override
879: public boolean isConsistent(URI context) {
880: return storage.isConsistent(context);
881: }
882:
883: @Override
884: public List<URI> getContexts() {
885: return storage.getContexts();
886: }
887:
888: @Override
889: public void setUseTransactionalOntologyForQueryProcessing() {
890: this.useTransactionalOntology = true;
891: }
892:
893: @Override
894: public boolean useTransactionalOntologyForQueryProcessing() {
895: return useTransactionalOntology;
896: }
897:
898: @Override
899: public void setUseBackupOntologyForQueryProcessing() {
900: this.useTransactionalOntology = false;
901: }
902:
903: @Override
904: public boolean useBackupOntologyForQueryProcessing() {
905:• return !useTransactionalOntology;
906: }
907:
908: @Override
909: public Query createNativeQuery(String sparql) {
910: return queryFactory.createNativeQuery(sparql);
911: }
912:
913: @Override
914: public <T> TypedQuery<T> createNativeQuery(String sparql, Class<T> resultClass) {
915: return queryFactory.createNativeQuery(sparql, resultClass);
916: }
917:
918: @Override
919: public Query createQuery(String query) {
920: return queryFactory.createQuery(query);
921: }
922:
923: @Override
924: public <T> TypedQuery<T> createQuery(String query, Class<T> resultClass) {
925: return queryFactory.createQuery(query, resultClass);
926: }
927:
928: /**
929: * Check if the specified entity contains a collection. If so, replace it with its indirect representation so that
930: * changes in that collection can be tracked.
931: *
932: * @param entity The entity to check
933: */
934: private void checkForCollections(Object entity) {
935: Field[] fields = entity.getClass().getDeclaredFields();
936:• for (Field f : fields) {
937: setIndirectCollectionIfPresent(entity, f);
938: }
939: }
940:
941: /**
942: * Create and set indirect collection on the specified entity field.</p>
943: * <p>
944: * If the specified field is of Collection type and it is not already an indirect collection, create new one and set
945: * it as the value of the specified field on the specified entity.
946: *
947: * @param entity The entity collection will be set on
948: * @param field The field to set
949: * @throws IllegalArgumentException Reflection
950: */
951: public void setIndirectCollectionIfPresent(Object entity, Field field) {
952: Objects.requireNonNull(entity, ErrorUtils.constructNPXMessage("entity"));
953: Objects.requireNonNull(field, ErrorUtils.constructNPXMessage("field"));
954:
955: Object value = EntityPropertiesUtils.getFieldValue(field, entity);
956:• if (value == null || value instanceof IndirectCollection) {
957: return;
958: }
959:• if (value instanceof Collection || value instanceof Map) {
960: EntityPropertiesUtils.setFieldValue(field, entity, createIndirectCollection(value, entity, field));
961: }
962: }
963:
964: /**
965: * Creates an indirect collection, which wraps the specified collection instance and propagates changes to the
966: * persistence context.
967: *
968: * @param collection Collection to be proxied
969: * @param owner Collection owner instance
970: * @param field Field filled with the collection
971: * @return Indirect collection
972: */
973: public IndirectCollection<?> createIndirectCollection(Object collection, Object owner, Field field) {
974: return collectionFactory.createIndirectCollection(collection, owner, field);
975: }
976:
977: /**
978: * Remove indirect collection implementations from the specified entity (if present).
979: *
980: * @param entity The entity to remove indirect collections from
981: */
982: private void removeIndirectCollections(Object entity) {
983: Field[] fields = entity.getClass().getDeclaredFields();
984:• for (Field f : fields) {
985: final Object ob = EntityPropertiesUtils.getFieldValue(f, entity);
986:• if (ob == null) {
987: continue;
988: }
989:• if (ob instanceof IndirectCollection) {
990: IndirectCollection<?> indCol = (IndirectCollection<?>) ob;
991: EntityPropertiesUtils.setFieldValue(f, entity, indCol.getReferencedCollection());
992: }
993: }
994: }
995:
996: /**
997: * Get entity with the specified primary key from the cache. </p>
998: * <p>
999: * If the cache does not contain any object with the specified primary key and class, null is returned. This method
1000: * is just a delegate for the cache methods, it handles locks.
1001: *
1002: * @return Cached object or null
1003: */
1004: private <T> T getObjectFromCache(Class<T> cls, Object primaryKey, URI context) {
1005:• assert cls != null;
1006:• assert primaryKey != null;
1007: return cacheManager.get(cls, primaryKey, context);
1008: }
1009:
1010: public void putObjectIntoCache(Object primaryKey, Object entity, URI context) {
1011: cacheManager.add(primaryKey, entity, context);
1012: }
1013:
1014: private Object getIdentifier(Object entity) {
1015:• assert entity != null;
1016: return EntityPropertiesUtils.getPrimaryKey(entity, getMetamodel());
1017: }
1018:
1019: private void unregisterEntityFromOntologyContext(Object entity) {
1020:• assert entity != null;
1021:
1022: final Descriptor descriptor = repoMap.getEntityDescriptor(entity);
1023:• if (descriptor == null) {
1024: throw new OWLPersistenceException("Fatal error, unable to find descriptor for entity " + entity);
1025: }
1026:
1027: repoMap.remove(descriptor, entity);
1028: repoMap.removeEntityToRepository(entity);
1029: }
1030:
1031: private void registerEntityWithOntologyContext(Descriptor repository, Object entity) {
1032:• assert repository != null;
1033:• assert entity != null;
1034:
1035: repoMap.add(repository, entity, null);
1036: repoMap.addEntityToRepository(entity, repository);
1037: }
1038:
1039: private boolean isInRepository(Descriptor descriptor, Object entity) {
1040:• assert descriptor != null;
1041:• assert entity != null;
1042:
1043: return repoMap.contains(descriptor, entity);
1044: }
1045:
1046: private Descriptor getDescriptor(Object entity) {
1047:• assert entity != null;
1048:
1049: return repoMap.getEntityDescriptor(entity);
1050: }
1051:
1052: private void storageCommit() {
1053: try {
1054: storage.commit();
1055: } catch (OWLPersistenceException e) {
1056: entityManager.removeCurrentPersistenceContext();
1057: throw e;
1058: }
1059: }
1060:
1061: @Override
1062: public Configuration getConfiguration() {
1063: return entityManager.getConfiguration();
1064: }
1065:
1066: @Override
1067: public <T> T unwrap(Class<T> cls) {
1068:• if (cls.isAssignableFrom(getClass())) {
1069: return cls.cast(this);
1070: }
1071: return storage.unwrap(cls);
1072: }
1073: }