Skip to content

Package: PendingReferenceRegistry$PendingListReference

PendingReferenceRegistry$PendingListReference

nameinstructionbranchcomplexitylinemethod
PendingReferenceRegistry.PendingListReference(ListValueDescriptor, List)
M: 0 C: 9
100%
M: 0 C: 0
100%
M: 0 C: 1
100%
M: 0 C: 4
100%
M: 0 C: 1
100%
getDescriptor()
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%
getValues()
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%

Coverage

1: /**
2: * Copyright (C) 2020 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.oom;
16:
17: import cz.cvut.kbss.ontodriver.descriptor.ListValueDescriptor;
18: import cz.cvut.kbss.ontodriver.model.Assertion;
19: import cz.cvut.kbss.ontodriver.model.NamedResource;
20: import org.slf4j.Logger;
21: import org.slf4j.LoggerFactory;
22:
23: import java.net.URI;
24: import java.util.*;
25: import java.util.function.Predicate;
26:
27: /**
28: * Used to track references to unpersisted instances during transaction.
29: * <p>
30: * The general rule is that on commit, this registry must be empty.
31: */
32: class PendingReferenceRegistry {
33:
34: private static final Logger LOG = LoggerFactory.getLogger(PendingReferenceRegistry.class);
35:
36: private final Map<Object, Set<PendingAssertion>> pendingAssertions = new HashMap<>();
37:
38: private Map<Object, Set<PendingListReference>> pendingLists;
39: /**
40: * Counts number of pending items per each list
41: */
42: private Map<ListValueDescriptor, Integer> pendingListItems;
43:
44: /**
45: * Registers a new pending assertion.
46: *
47: * @param owner Subject of the assertion
48: * @param assertion The assertion representation
49: * @param object The value of the assertion. Always an individual identifier
50: * @param context Context into which the assertion will be added
51: */
52: void addPendingAssertion(NamedResource owner, Assertion assertion, Object object, URI context) {
53: assert owner != null;
54: assert assertion != null;
55: assert object != null;
56:
57: final PendingAssertion pa = new PendingAssertion(owner, assertion, context);
58: if (!pendingAssertions.containsKey(object)) {
59: pendingAssertions.put(object, new HashSet<>());
60: }
61: pendingAssertions.get(object).add(pa);
62: }
63:
64: /**
65: * Registers a pending reference to a sequence (simple or referenced).
66: *
67: * @param item The pending (unpersisted) item
68: * @param valueDescriptor Descriptor containing info about list owner, linking property etc.
69: * @param values Values of the sequence
70: */
71: void addPendingListReference(Object item, ListValueDescriptor valueDescriptor, List<?> values) {
72: if (pendingLists == null) {
73: this.pendingLists = new HashMap<>();
74: this.pendingListItems = new HashMap<>();
75: }
76: pendingLists.putIfAbsent(item, new HashSet<>());
77: pendingLists.get(item).add(new PendingListReference(valueDescriptor, values));
78: pendingListItems.compute(valueDescriptor, (k, v) -> v == null ? 1 : v + 1);
79: }
80:
81: /**
82: * Removes any pending persists with the specified object (value of the assertion).
83: *
84: * @param object Object which is no longer considered pending, so all assertions referencing it should be removed
85: * from this registry
86: */
87: Set<PendingAssertion> removeAndGetPendingAssertionsWith(Object object) {
88: assert object != null;
89: final Set<PendingAssertion> pending = pendingAssertions.remove(object);
90: return pending != null ? pending : Collections.emptySet();
91: }
92:
93: Set<PendingListReference> removeAndGetPendingListReferencesWith(Object object) {
94: assert object != null;
95: final Set<PendingListReference> refs = pendingLists == null ? null : pendingLists.remove(object);
96: if (refs == null) {
97: return Collections.emptySet();
98: }
99: final Iterator<PendingListReference> it = refs.iterator();
100: while (it.hasNext()) {
101: final PendingListReference ref = it.next();
102: pendingListItems.compute(ref.descriptor, (k, v) -> v - 1);
103: if (pendingListItems.get(ref.descriptor) == 0) {
104: pendingListItems.remove(ref.descriptor);
105: } else {
106: it.remove();
107: }
108: }
109: return refs;
110: }
111:
112: Set<Object> getPendingResources() {
113: final Set<Object> pending = new HashSet<>(pendingAssertions.keySet());
114: if (pendingLists != null) {
115: pending.addAll(pendingLists.keySet());
116: }
117: return pending;
118: }
119:
120: boolean hasPendingResources() {
121: return !pendingAssertions.isEmpty() || pendingLists != null && !pendingLists.isEmpty();
122: }
123:
124: /**
125: * Removes all pending assertions which have the same subject (owner).
126: *
127: * @param subject The subject of assertions to remove
128: */
129: void removePendingReferences(NamedResource subject) {
130: if (LOG.isTraceEnabled()) {
131: LOG.trace("Removing pending assertions for subject {}.", subject);
132: }
133: for (Set<PendingAssertion> pending : pendingAssertions.values()) {
134: pending.removeIf(item -> item.getOwner().equals(subject));
135: }
136: pendingAssertions.entrySet().removeIf(e -> e.getValue().isEmpty());
137: removePendingListReferences(desc -> desc.getListOwner().equals(subject));
138: }
139:
140: private void removePendingListReferences(Predicate<ListValueDescriptor> condition) {
141: if (pendingLists == null) {
142: return;
143: }
144: final Set<ListValueDescriptor> removed = new HashSet<>();
145: for (Set<PendingListReference> pending : pendingLists.values()) {
146: final Iterator<PendingListReference> it = pending.iterator();
147: while (it.hasNext()) {
148: final ListValueDescriptor desc = it.next().descriptor;
149: if (condition.test(desc)) {
150: it.remove();
151: removed.add(desc);
152: }
153: }
154: }
155: pendingLists.entrySet().removeIf(e -> e.getValue().isEmpty());
156: removed.forEach(pendingListItems::remove);
157: }
158:
159: /**
160: * Removes pending references representing the specified assertion about the specified subject.
161: *
162: * @param subject Assertion subject
163: * @param assertion The assertion
164: */
165: void removePendingReferences(NamedResource subject, Assertion assertion) {
166: if (LOG.isTraceEnabled()) {
167: LOG.trace("Removing pending assertions {} for subject {}.", assertion, subject);
168: }
169: for (Set<PendingAssertion> pending : pendingAssertions.values()) {
170: pending.removeIf(item -> item.getOwner().equals(subject) && item.getAssertion().equals(assertion));
171: }
172: pendingAssertions.entrySet().removeIf(e -> e.getValue().isEmpty());
173: removePendingListReferences(
174: desc -> desc.getListOwner().equals(subject) && desc.getListProperty().equals(assertion));
175: }
176:
177: static class PendingListReference {
178: private final ListValueDescriptor descriptor;
179: private final List<?> values;
180:
181: private PendingListReference(ListValueDescriptor descriptor, List<?> values) {
182: this.descriptor = descriptor;
183: this.values = values;
184: }
185:
186: public ListValueDescriptor getDescriptor() {
187: return descriptor;
188: }
189:
190: public List<?> getValues() {
191: return values;
192: }
193: }
194: }