Skip to content

Package: UnitOfWorkImpl

UnitOfWorkImpl

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