Skip to content

Package: EntityManagerImpl$1

EntityManagerImpl$1

nameinstructionbranchcomplexitylinemethod
exploreCascaded(Attribute, Object)
M: 28 C: 56
67%
M: 1 C: 5
83%
M: 1 C: 3
75%
M: 5 C: 11
69%
M: 0 C: 1
100%
{...}
M: 0 C: 12
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) 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.model;
16:
17: import cz.cvut.kbss.jopa.exceptions.OWLPersistenceException;
18: import cz.cvut.kbss.jopa.exceptions.TransactionRequiredException;
19: import cz.cvut.kbss.jopa.model.annotations.CascadeType;
20: import cz.cvut.kbss.jopa.model.descriptors.Descriptor;
21: import cz.cvut.kbss.jopa.model.descriptors.EntityDescriptor;
22: import cz.cvut.kbss.jopa.model.metamodel.Attribute;
23: import cz.cvut.kbss.jopa.model.metamodel.Metamodel;
24: import cz.cvut.kbss.jopa.model.query.Query;
25: import cz.cvut.kbss.jopa.model.query.TypedQuery;
26: import cz.cvut.kbss.jopa.sessions.ServerSession;
27: import cz.cvut.kbss.jopa.sessions.UnitOfWorkImpl;
28: import cz.cvut.kbss.jopa.transactions.EntityTransaction;
29: import cz.cvut.kbss.jopa.transactions.EntityTransactionWrapper;
30: import cz.cvut.kbss.jopa.transactions.TransactionWrapper;
31: import cz.cvut.kbss.jopa.utils.*;
32: import org.slf4j.Logger;
33: import org.slf4j.LoggerFactory;
34:
35: import java.net.URI;
36: import java.util.*;
37:
38: public class EntityManagerImpl extends AbstractEntityManager implements Wrapper {
39:
40: private static final Logger LOG = LoggerFactory.getLogger(EntityManagerImpl.class);
41:
42: private static final Object MAP_VALUE = new Object();
43:
44: private EntityManagerFactoryImpl emf;
45:
46: private boolean open;
47:
48: private TransactionWrapper transaction;
49: private UnitOfWorkImpl persistenceContext;
50: private ServerSession serverSession;
51: private final Configuration configuration;
52:
53: private final Map<Object, Object> cascadingRegistry = new IdentityHashMap<>();
54:
55: EntityManagerImpl(EntityManagerFactoryImpl emf, Configuration configuration, ServerSession serverSession) {
56: this.emf = emf;
57: this.serverSession = serverSession;
58: this.configuration = configuration;
59:
60: setTransactionWrapper();
61:
62: this.open = true;
63: }
64:
65: public enum State {
66: MANAGED, MANAGED_NEW, NOT_MANAGED, REMOVED
67: }
68:
69: @Override
70: public void persist(final Object entity) {
71: final Descriptor d = new EntityDescriptor();
72: persist(entity, d);
73: }
74:
75: @Override
76: public void persist(final Object entity, final Descriptor descriptor) {
77: LOG.trace("Persisting {}", entity);
78: try {
79: Objects.requireNonNull(entity, ErrorUtils.getNPXMessageSupplier("entity"));
80: Objects.requireNonNull(descriptor, ErrorUtils.getNPXMessageSupplier("descriptor"));
81: ensureOpen();
82: checkClassIsValidEntity(entity.getClass());
83:
84: switch (getState(entity, descriptor)) {
85: case NOT_MANAGED:
86: getCurrentPersistenceContext().registerNewObject(entity, descriptor);
87: // Intentional fall-through
88: case MANAGED:
89: cascadePersist(entity, descriptor);
90: break;
91: case REMOVED:
92: getCurrentPersistenceContext().revertObject(entity);
93: break;
94: default:
95: break;
96: }
97: } catch (RuntimeException e) {
98: markTransactionForRollback();
99: throw e;
100: }
101: }
102:
103: private void checkClassIsValidEntity(Class<?> cls) {
104: getMetamodel().entity(cls);
105: }
106:
107: private void registerProcessedInstance(Object instance) {
108: cascadingRegistry.put(instance, MAP_VALUE);
109: }
110:
111: private boolean isCascadingCycle(Object instance) {
112: return cascadingRegistry.containsKey(instance);
113: }
114:
115: private void resetCascadingRegistry() {
116: cascadingRegistry.clear();
117: }
118:
119: private void markTransactionForRollback() {
120: if (getTransaction().isActive()) {
121: getTransaction().setRollbackOnly();
122: }
123: }
124:
125: private void cascadePersist(final Object entity, final Descriptor descriptor) {
126: new OneLevelCascadeExplorer() {
127: @Override
128: protected void exploreCascaded(Attribute<?, ?> at, Object o) {
129: try {
130: Object ox = EntityPropertiesUtils.getAttributeValue(at, o);
131: LOG.trace("object={}, attribute={}, value={}", o, at.getName(), ox);
132:• if (ox == null) {
133: return;
134: }
135: final Descriptor attDescriptor = descriptor.getAttributeDescriptor(at);
136:• if (at.isCollection()) {
137:• for (final Object ox2 : (Collection<?>) ox) {
138: persist(ox2, attDescriptor);
139: }
140: } else {
141: persist(ox, attDescriptor);
142: }
143: } catch (Exception e) {
144: markTransactionForRollback();
145: throw new OWLPersistenceException(
146: "A problem occurred when persisting attribute " + at.getName()
147: + " of with value " + o + " of object " + entity, e);
148: }
149: }
150: }.start(this, entity, CascadeType.PERSIST);
151: }
152:
153: @Override
154: public <T> T merge(final T entity) {
155: final Descriptor d = new EntityDescriptor();
156: return merge(entity, d);
157: }
158:
159: @Override
160: public <T> T merge(final T entity, final Descriptor descriptor) {
161: try {
162: Objects.requireNonNull(entity, ErrorUtils.getNPXMessageSupplier("entity"));
163: Objects.requireNonNull(descriptor, ErrorUtils.getNPXMessageSupplier("descriptor"));
164: ensureOpen();
165: checkClassIsValidEntity(entity.getClass());
166:
167: return mergeInternal(entity, descriptor);
168: } catch (RuntimeException e) {
169: markTransactionForRollback();
170: throw e;
171: } finally {
172: resetCascadingRegistry();
173: }
174: }
175:
176: /**
177: * Merges state of the specified entity into the current persistence context. </p>
178: *
179: * @param entity Entity instance
180: * @param descriptor Contains information about contexts into which the entity and its field should be merged
181: * @return Managed instance of the merged entity
182: */
183: private <T> T mergeInternal(final T entity, final Descriptor descriptor) {
184: assert entity != null;
185: assert descriptor != null;
186: LOG.trace("Merging {}.", entity);
187: if (isCascadingCycle(entity)) {
188: LOG.warn("Merge cascading cycle detected in entity {}.", entity);
189: return (T) getCurrentPersistenceContext().getCloneForOriginal(entity);
190: }
191:
192: switch (getState(entity, descriptor)) {
193: case MANAGED_NEW:
194: case MANAGED:
195: registerProcessedInstance(entity);
196: cascadeMerge(entity, entity, descriptor);
197: return entity;
198: case NOT_MANAGED:
199: final T merged = getCurrentPersistenceContext().mergeDetached(entity, descriptor);
200: registerProcessedInstance(entity);
201: cascadeMerge(merged, entity, descriptor);
202: return merged;
203: case REMOVED:
204: default:
205: throw new IllegalArgumentException("Cannot merge instance which is not an entity or is removed.");
206: }
207: }
208:
209: private <T> void cascadeMerge(T merged, T toMerge, Descriptor descriptor) {
210: new OneLevelMergeCascadeExplorer() {
211: @Override
212: protected void exploreCascaded(Attribute<?, ?> at, Object merged, Object toMerge) {
213: final Descriptor attDescriptor = descriptor.getAttributeDescriptor(at);
214: mergeX(at, merged, toMerge, attDescriptor);
215: }
216: }.start(this, merged, toMerge);
217: }
218:
219: private void mergeX(Attribute<?, ?> at, Object merged, Object toMerge, Descriptor descriptor) {
220: Object attVal = EntityPropertiesUtils.getAttributeValue(at, toMerge);
221: if (attVal == null) {
222: return;
223: }
224: if (at.isCollection()) {
225: Collection c = (Collection) attVal;
226: Collection result = CollectionFactory.createInstance(c);
227: for (final Object ox2 : c) {
228: result.add(mergeInternal(ox2, descriptor));
229: }
230: attVal = getCurrentPersistenceContext().createIndirectCollection(result, merged, at.getJavaField());
231: } else {
232: attVal = mergeInternal(attVal, descriptor);
233: }
234: EntityPropertiesUtils.setFieldValue(at.getJavaField(), merged, attVal);
235: }
236:
237: @Override
238: public void remove(Object object) {
239: try {
240: ensureOpen();
241: Objects.requireNonNull(object);
242: checkClassIsValidEntity(object.getClass());
243: if (isCascadingCycle(object)) {
244: LOG.warn("Remove cascading cycle detected in instance {}.", object);
245: return;
246: }
247:
248: switch (getState(object)) {
249: case MANAGED_NEW:
250: case MANAGED:
251: getCurrentPersistenceContext().removeObject(object);
252: registerProcessedInstance(object);
253: // Intentional fall-through
254: case REMOVED:
255: new SimpleOneLevelCascadeExplorer() {
256: @Override
257: protected void runCascadedForEach(Object ox2) {
258: remove(ox2);
259: }
260: }.start(this, object, CascadeType.REMOVE);
261: break;
262: default:
263: throw new IllegalArgumentException("Entity " + object + " is not managed and cannot be removed.");
264: }
265: } catch (RuntimeException e) {
266: markTransactionForRollback();
267: throw e;
268: } finally {
269: resetCascadingRegistry();
270: }
271: }
272:
273: @Override
274: public <T> T find(Class<T> cls, Object primaryKey) {
275: final EntityDescriptor d = new EntityDescriptor();
276: return find(cls, primaryKey, d);
277: }
278:
279: @Override
280: public <T> T find(Class<T> cls, Object primaryKey, Descriptor descriptor) {
281: try {
282: Objects.requireNonNull(cls, ErrorUtils.getNPXMessageSupplier("cls"));
283: Objects.requireNonNull(primaryKey, ErrorUtils.getNPXMessageSupplier("primaryKey"));
284: Objects.requireNonNull(descriptor, ErrorUtils.getNPXMessageSupplier("descriptor"));
285: ensureOpen();
286: checkClassIsValidEntity(cls);
287:
288: LOG.trace("Finding instance of {} with identifier {} in context ", cls, primaryKey, descriptor);
289: final URI uri = (primaryKey instanceof URI) ? (URI) primaryKey : URI.create(primaryKey.toString());
290:
291: return getCurrentPersistenceContext().readObject(cls, uri, descriptor);
292: } catch (RuntimeException e) {
293: markTransactionForRollback();
294: throw e;
295: }
296: }
297:
298: @Override
299: public void flush() {
300: try {
301: ensureOpen();
302: LOG.trace("Flushing changes...");
303: if (!getTransaction().isActive()) {
304: throw new TransactionRequiredException();
305: }
306: this.getCurrentPersistenceContext().writeUncommittedChanges();
307: } catch (RuntimeException e) {
308: markTransactionForRollback();
309: throw e;
310: }
311: }
312:
313: @Override
314: public void refresh(Object entity) {
315: try {
316: ensureOpen();
317: Objects.requireNonNull(entity);
318: checkClassIsValidEntity(entity.getClass());
319:
320: this.getCurrentPersistenceContext().revertObject(entity);
321: new SimpleOneLevelCascadeExplorer() {
322: @Override
323: protected void runCascadedForEach(Object ox2) {
324: refresh(ox2);
325: }
326: }.start(this, entity, CascadeType.REFRESH);
327: } catch (RuntimeException e) {
328: markTransactionForRollback();
329: throw e;
330: }
331: }
332:
333: @Override
334: public void clear() {
335: try {
336: ensureOpen();
337: getCurrentPersistenceContext().clear();
338: } catch (RuntimeException e) {
339: markTransactionForRollback();
340: throw e;
341: }
342: }
343:
344: @Override
345: public void detach(Object entity) {
346: try {
347: ensureOpen();
348:
349: switch (getState(entity)) {
350: case MANAGED_NEW:
351: case MANAGED:
352: getCurrentPersistenceContext().unregisterObject(entity);
353: new SimpleOneLevelCascadeExplorer() {
354: @Override
355: protected void runCascadedForEach(Object ox2) {
356: detach(ox2);
357: }
358: }.start(this, entity, CascadeType.DETACH);
359: break;
360: default:
361: break;
362: }
363: } catch (RuntimeException e) {
364: markTransactionForRollback();
365: throw e;
366: }
367: }
368:
369: @Override
370: public boolean contains(Object entity) {
371: try {
372: ensureOpen();
373: Objects.requireNonNull(entity);
374: checkClassIsValidEntity(entity.getClass());
375: return getCurrentPersistenceContext().contains(entity);
376: } catch (RuntimeException e) {
377: markTransactionForRollback();
378: throw e;
379: }
380: }
381:
382: @Override
383: public void close() {
384: ensureOpen();
385: removeCurrentPersistenceContext();
386: emf.entityManagerClosed(this);
387: open = false;
388: }
389:
390: @Override
391: public boolean isOpen() {
392: return open;
393: }
394:
395: @Override
396: public EntityTransaction getTransaction() {
397: return transaction.getTransaction();
398: }
399:
400: @Override
401: public EntityManagerFactoryImpl getEntityManagerFactory() {
402: return emf;
403: }
404:
405: @Override
406: public Metamodel getMetamodel() {
407: return emf.getMetamodel();
408: }
409:
410: @Override
411: public boolean isLoaded(final Object object, final String attributeName) {
412: // TODO
413: return false;
414: }
415:
416: @Override
417: public Query createQuery(String qlString) {
418: final QueryImpl q = getCurrentPersistenceContext().createQuery(qlString);
419: q.setRollbackOnlyMarker(this::markTransactionForRollback);
420: return q;
421: }
422:
423: @Override
424: public <T> TypedQuery<T> createQuery(String query, Class<T> resultClass) {
425: final TypedQueryImpl<T> q = getCurrentPersistenceContext().createQuery(query, resultClass);
426: q.setRollbackOnlyMarker(this::markTransactionForRollback);
427: return q;
428: }
429:
430: @Override
431: public Query createNativeQuery(String sparql) {
432: final QueryImpl q = getCurrentPersistenceContext().createNativeQuery(sparql);
433: q.setRollbackOnlyMarker(this::markTransactionForRollback);
434: return q;
435: }
436:
437: @Override
438: public <T> TypedQuery<T> createNativeQuery(String sparql, Class<T> resultClass) {
439: final TypedQueryImpl<T> q = getCurrentPersistenceContext().createNativeQuery(sparql, resultClass);
440: q.setRollbackOnlyMarker(this::markTransactionForRollback);
441: return q;
442: }
443:
444: @Override
445: public Query createNamedQuery(String name) {
446: final QueryImpl q = getCurrentPersistenceContext().createNamedQuery(name);
447: q.setRollbackOnlyMarker(this::markTransactionForRollback);
448: return q;
449: }
450:
451: @Override
452: public <T> TypedQuery<T> createNamedQuery(String name, Class<T> resultClass) {
453: final TypedQueryImpl<T> q = getCurrentPersistenceContext().createNamedQuery(name, resultClass);
454: q.setRollbackOnlyMarker(this::markTransactionForRollback);
455: return q;
456: }
457:
458: @Override
459: public boolean isConsistent(URI context) {
460: return getCurrentPersistenceContext().isConsistent(context);
461: }
462:
463: @Override
464: public List<URI> getContexts() {
465: return getCurrentPersistenceContext().getContexts();
466: }
467:
468: @Override
469: public void setUseTransactionalOntologyForQueryProcessing() {
470: getCurrentPersistenceContext().setUseTransactionalOntologyForQueryProcessing();
471: }
472:
473: @Override
474: public boolean useTransactionalOntologyForQueryProcessing() {
475: return getCurrentPersistenceContext().useTransactionalOntologyForQueryProcessing();
476: }
477:
478: @Override
479: public void setUseBackupOntologyForQueryProcessing() {
480: getCurrentPersistenceContext().setUseBackupOntologyForQueryProcessing();
481: }
482:
483: @Override
484: public boolean useBackupOntologyForQueryProcessing() {
485: return getCurrentPersistenceContext().useBackupOntologyForQueryProcessing();
486: }
487:
488: @Override
489: public <T> T unwrap(Class<T> cls) {
490: if (cls.isAssignableFrom(this.getClass())) {
491: return cls.cast(this);
492: }
493: return getCurrentPersistenceContext().unwrap(cls);
494: }
495:
496: @Override
497: public Object getDelegate() {
498: return unwrap(EntityManagerImpl.class);
499: }
500:
501: private void ensureOpen() {
502: if (!isOpen()) {
503: throw new OWLPersistenceException("The entity manager is closed !");
504: }
505: }
506:
507: private State getState(Object entity) {
508: return getCurrentPersistenceContext().getState(entity);
509: }
510:
511: private State getState(Object entity, Descriptor descriptor) {
512: return getCurrentPersistenceContext().getState(entity, descriptor);
513: }
514:
515: @Override
516: protected void finalize() throws Throwable {
517: if (isOpen()) {
518: close();
519: }
520: super.finalize();
521: }
522:
523: @Override
524: public UnitOfWorkImpl getCurrentPersistenceContext() {
525: if (this.persistenceContext == null) {
526: this.persistenceContext = (UnitOfWorkImpl) serverSession.acquireUnitOfWork();
527: persistenceContext.setEntityManager(this);
528: }
529: return this.persistenceContext;
530: }
531:
532: /**
533: * Called from EntityTransaction in case of a rollback. Releasing the UoW is up to the EntityTransaction.
534: */
535: @Override
536: public void removeCurrentPersistenceContext() {
537: if (persistenceContext != null && persistenceContext.isActive()) {
538: persistenceContext.release();
539: }
540: this.persistenceContext = null;
541: }
542:
543: @Override
544: public void transactionStarted(EntityTransaction t) {
545: this.serverSession.transactionStarted(t, this);
546: }
547:
548: @Override
549: public void transactionFinished(EntityTransaction t) {
550: this.serverSession.transactionFinished(t);
551: }
552:
553: /**
554: * Since we support only EntityTransactions, we set the TransactionWrapper to EntityTransactionWrapper.
555: * <p>
556: * In the future, if JTA transactions are supported, JTATransactionWrapper should be set instead of the
557: * EntityTransactionWrapper.
558: */
559: private void setTransactionWrapper() {
560: this.transaction = new EntityTransactionWrapper(this);
561: }
562:
563: @Override
564: public Configuration getConfiguration() {
565: return configuration;
566: }
567: }