Skip to contentMethod: {...}
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.OWLEntityExistsException;
18: import cz.cvut.kbss.jopa.exceptions.OWLPersistenceException;
19: import cz.cvut.kbss.jopa.exceptions.TransactionRequiredException;
20: import cz.cvut.kbss.jopa.model.annotations.CascadeType;
21: import cz.cvut.kbss.jopa.model.descriptors.Descriptor;
22: import cz.cvut.kbss.jopa.model.descriptors.EntityDescriptor;
23: import cz.cvut.kbss.jopa.model.metamodel.Attribute;
24: import cz.cvut.kbss.jopa.model.metamodel.Metamodel;
25: import cz.cvut.kbss.jopa.model.query.Query;
26: import cz.cvut.kbss.jopa.model.query.TypedQuery;
27: import cz.cvut.kbss.jopa.sessions.ServerSession;
28: import cz.cvut.kbss.jopa.sessions.UnitOfWorkImpl;
29: import cz.cvut.kbss.jopa.transactions.EntityTransaction;
30: import cz.cvut.kbss.jopa.transactions.EntityTransactionWrapper;
31: import cz.cvut.kbss.jopa.transactions.TransactionWrapper;
32: import cz.cvut.kbss.jopa.utils.*;
33: import org.slf4j.Logger;
34: import org.slf4j.LoggerFactory;
35:
36: import java.net.URI;
37: import java.util.Collection;
38: import java.util.List;
39: import java.util.Objects;
40:
41: public class EntityManagerImpl extends AbstractEntityManager implements Wrapper {
42:
43: private static final Logger LOG = LoggerFactory.getLogger(EntityManagerImpl.class);
44:
45: private EntityManagerFactoryImpl emf;
46:
47: private boolean open;
48:
49: private TransactionWrapper transaction;
50: private UnitOfWorkImpl persistenceContext;
51: private ServerSession serverSession;
52: private final Configuration configuration;
53:
54: public EntityManagerImpl(EntityManagerFactoryImpl emf, Configuration configuration,
55: ServerSession serverSession) {
56: this.emf = emf;
57: this.serverSession = serverSession;
58: this.configuration = configuration;
59:
60: this.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: ensureOpen();
79: Objects.requireNonNull(entity, ErrorUtils.constructNPXMessage("entity"));
80: Objects.requireNonNull(descriptor, ErrorUtils.constructNPXMessage("descriptor"));
81:
82: switch (getState(entity, descriptor)) {
83: case NOT_MANAGED:
84: try {
85: getCurrentPersistenceContext().registerNewObject(entity, descriptor);
86: } catch (RuntimeException e) {
87: if (getTransaction().isActive()) {
88: getTransaction().setRollbackOnly();
89: }
90: throw e;
91: }
92: case MANAGED:
93: new OneLevelCascadeExplorer() {
94: @Override
95: protected void exploreCascaded(Attribute<?, ?> at, Object o) {
96: try {
97: Object ox = EntityPropertiesUtils.getAttributeValue(at, o);
98: LOG.trace("object={}, attribute={}, value={}", o, at.getName(), ox);
99: if (ox == null) {
100: return;
101: }
102: final Descriptor attDescriptor = descriptor.getAttributeDescriptor(at);
103: if (at.isCollection()) {
104: for (final Object ox2 : (Collection<?>) ox) {
105: persist(ox2, attDescriptor);
106: }
107: } else {
108: persist(ox, attDescriptor);
109: }
110: } catch (Exception e) {
111: if (getTransaction().isActive()) {
112: getTransaction().setRollbackOnly();
113: }
114: throw new OWLPersistenceException(
115: "A problem occured when persisting attribute " + at.getName()
116: + " of with value " + o + " of object " + entity, e);
117: }
118: }
119: }.start(this, entity, CascadeType.PERSIST);
120: break;
121: case MANAGED_NEW:
122: throw new OWLEntityExistsException("Entity " + entity
123: + " is already managed in this persistence context.");
124: case REMOVED:
125: getCurrentPersistenceContext().revertObject(entity);
126: break;
127: }
128: }
129:
130: @Override
131: public <T> T merge(final T entity) {
132: final Descriptor d = new EntityDescriptor();
133: return merge(entity, d);
134: }
135:
136: @Override
137: public <T> T merge(final T entity, final Descriptor descriptor) {
138: Objects.requireNonNull(entity, ErrorUtils.constructNPXMessage("entity"));
139: Objects.requireNonNull(descriptor, ErrorUtils.constructNPXMessage("descriptor"));
140:
141: return mergeInternal(entity, descriptor);
142: }
143:
144: /**
145: * Merges state of the specified entity into the current persistence context. </p>
146: *
147: * @param entity Entity instance
148: * @param descriptor Contains information about contexts into which the entity and its field should be merged
149: * @return Managed instance of the merged entity
150: */
151: private <T> T mergeInternal(final T entity, final Descriptor descriptor) {
152: assert entity != null;
153: assert descriptor != null;
154: LOG.trace("Merging {}", entity);
155: ensureOpen();
156:
157: switch (getState(entity, descriptor)) {
158: case MANAGED_NEW:
159: case MANAGED:
160: new OneLevelCascadeExplorer() {
161: @Override
162: protected void exploreCascaded(Attribute<?, ?> at, Object o) {
163: mergeX(at, o, descriptor);
164: }
165: }.start(this, entity, CascadeType.MERGE);
166: return entity;
167: case NOT_MANAGED:
168: final T merged;
169: merged = getCurrentPersistenceContext().mergeDetached(entity, descriptor);
170:
171: new OneLevelCascadeExplorer() {
172: @Override
173: protected void exploreCascaded(Attribute<?, ?> at, Object o) {
174: final Descriptor attDescriptor = descriptor.getAttributeDescriptor(at);
175: mergeX(at, o, attDescriptor);
176: }
177:
178: @Override
179: protected void exploreNonCascaded(Attribute<?, ?> at, Object o) {
180: final Object attVal = EntityPropertiesUtils.getAttributeValue(at, o);
181: EntityPropertiesUtils.setFieldValue(at.getJavaField(), o, attVal);
182: }
183: }.start(this, merged, CascadeType.MERGE);
184: return merged;
185: case REMOVED:
186: default:
187: throw new IllegalArgumentException();
188: }
189: }
190:
191: private void mergeX(Attribute<?, ?> at, Object o, Descriptor descriptor) {
192: Object attVal = EntityPropertiesUtils.getAttributeValue(at, o);
193: if (attVal == null) {
194: return;
195: }
196: if (at.isCollection()) {
197: Collection c = (Collection) attVal;
198: Collection merged = CollectionFactory.createInstance(c);
199: for (final Object ox2 : c) {
200: merged.add(mergeInternal(ox2, descriptor));
201: }
202: attVal = getCurrentPersistenceContext().createIndirectCollection(merged, o, at.getJavaField());
203: } else {
204: attVal = mergeInternal(attVal, descriptor);
205: }
206: EntityPropertiesUtils.setFieldValue(at.getJavaField(), o, attVal);
207: }
208:
209: @Override
210: public void remove(Object object) {
211: ensureOpen();
212:
213: switch (getState(object)) {
214: case MANAGED_NEW:
215: case MANAGED:
216: getCurrentPersistenceContext().removeObject(object);
217: // Intentional fall-through
218: case REMOVED:
219: new SimpleOneLevelCascadeExplorer() {
220: @Override
221: protected void runCascadedForEach(Object ox2) {
222: remove(ox2);
223: }
224: }.start(this, object, CascadeType.REMOVE);
225: break;
226: case NOT_MANAGED:
227: throw new IllegalArgumentException("Entity " + object
228: + " is not managed and cannot be removed.");
229: }
230: }
231:
232: @Override
233: public <T> T find(Class<T> cls, Object primaryKey) {
234: final EntityDescriptor d = new EntityDescriptor();
235: return find(cls, primaryKey, d);
236: }
237:
238: @Override
239: public <T> T find(Class<T> cls, Object primaryKey, Descriptor descriptor) {
240: Objects.requireNonNull(cls, ErrorUtils.constructNPXMessage("cls"));
241: Objects.requireNonNull(primaryKey, ErrorUtils.constructNPXMessage("primaryKey"));
242: Objects.requireNonNull(descriptor, ErrorUtils.constructNPXMessage("descriptor"));
243:
244: ensureOpen();
245: LOG.trace("Finding instance of {} with identifier {} in context ", cls, primaryKey, descriptor);
246: final URI uri = (primaryKey instanceof URI) ? (URI) primaryKey : URI.create(primaryKey.toString());
247:
248: return getCurrentPersistenceContext().readObject(cls, uri, descriptor);
249: }
250:
251: @Override
252: public void flush() {
253: ensureOpen();
254:
255: LOG.trace("Flushing changes...");
256: if (!getTransaction().isActive()) {
257: throw new TransactionRequiredException();
258: }
259: this.getCurrentPersistenceContext().writeUncommittedChanges();
260: }
261:
262: @Override
263: public void refresh(Object entity) {
264: ensureOpen();
265: Objects.requireNonNull(entity, ErrorUtils.constructNPXMessage("entity"));
266:
267: this.getCurrentPersistenceContext().revertObject(entity);
268: new SimpleOneLevelCascadeExplorer() {
269: @Override
270: protected void runCascadedForEach(Object ox2) {
271: refresh(ox2);
272: }
273: }.start(this, entity, CascadeType.REFRESH);
274: }
275:
276: @Override
277: public void clear() {
278: getCurrentPersistenceContext().clear();
279: }
280:
281: @Override
282: public void detach(Object entity) {
283: ensureOpen();
284:
285: switch (getState(entity)) {
286: case MANAGED_NEW:
287: case MANAGED:
288: getCurrentPersistenceContext().unregisterObject(entity);
289: new SimpleOneLevelCascadeExplorer() {
290: @Override
291: protected void runCascadedForEach(Object ox2) {
292: detach(ox2);
293: }
294: }.start(this, entity, CascadeType.DETACH);
295: break;
296: default:
297: break;
298: }
299: }
300:
301: @Override
302: public boolean contains(Object entity) {
303: ensureOpen();
304: return getCurrentPersistenceContext().contains(entity);
305: }
306:
307: @Override
308: public void close() {
309: ensureOpen();
310: removeCurrentPersistenceContext();
311: open = false;
312: }
313:
314: public boolean isOpen() {
315: return open;
316: }
317:
318: @Override
319: public EntityTransaction getTransaction() {
320: return transaction.getTransaction();
321: }
322:
323: @Override
324: public EntityManagerFactoryImpl getEntityManagerFactory() {
325: return emf;
326: }
327:
328: @Override
329: public Metamodel getMetamodel() {
330: return emf.getMetamodel();
331: }
332:
333: @Override
334: public boolean isLoaded(final Object object, final String attributeName) {
335: // TODO
336: return false;
337: }
338:
339: @Override
340: public Query createQuery(String qlString) {
341: return getCurrentPersistenceContext().createQuery(qlString);
342: }
343:
344: @Override
345: public <T> TypedQuery<T> createQuery(String query, Class<T> resultClass) {
346: return getCurrentPersistenceContext().createQuery(query, resultClass);
347: }
348:
349: @Override
350: public Query createNativeQuery(String sqlString) {
351: return getCurrentPersistenceContext().createNativeQuery(sqlString);
352: }
353:
354: @Override
355: public <T> TypedQuery<T> createNativeQuery(String sqlString, Class<T> resultClass) {
356: return getCurrentPersistenceContext().createNativeQuery(sqlString, resultClass);
357: }
358:
359: @Override
360: public boolean isConsistent(URI context) {
361: return getCurrentPersistenceContext().isConsistent(context);
362: }
363:
364: @Override
365: public List<URI> getContexts() {
366: return getCurrentPersistenceContext().getContexts();
367: }
368:
369: @Override
370: public void setUseTransactionalOntologyForQueryProcessing() {
371: getCurrentPersistenceContext().setUseTransactionalOntologyForQueryProcessing();
372: }
373:
374: @Override
375: public boolean useTransactionalOntologyForQueryProcessing() {
376: return getCurrentPersistenceContext().useTransactionalOntologyForQueryProcessing();
377: }
378:
379: @Override
380: public void setUseBackupOntologyForQueryProcessing() {
381: getCurrentPersistenceContext().setUseBackupOntologyForQueryProcessing();
382: }
383:
384: @Override
385: public boolean useBackupOntologyForQueryProcessing() {
386: return getCurrentPersistenceContext().useBackupOntologyForQueryProcessing();
387: }
388:
389: @Override
390: public <T> T unwrap(Class<T> cls) {
391: if (cls.isAssignableFrom(this.getClass())) {
392: return cls.cast(this);
393: }
394: return getCurrentPersistenceContext().unwrap(cls);
395: }
396:
397: @Override
398: public Object getDelegate() {
399: return unwrap(EntityManagerImpl.class);
400: }
401:
402: private void ensureOpen() {
403: if (!isOpen()) {
404: throw new OWLPersistenceException("The entity manager is closed !");
405: }
406: }
407:
408: private State getState(Object entity) {
409: return getCurrentPersistenceContext().getState(entity);
410: }
411:
412: private State getState(Object entity, Descriptor descriptor) {
413: return getCurrentPersistenceContext().getState(entity, descriptor);
414: }
415:
416: @Override
417: protected void finalize() throws Throwable {
418: if (isOpen()) {
419: close();
420: }
421: super.finalize();
422: }
423:
424: @Override
425: public UnitOfWorkImpl getCurrentPersistenceContext() {
426: if (this.persistenceContext == null) {
427: this.persistenceContext = (UnitOfWorkImpl) this.serverSession.acquireUnitOfWork();
428: persistenceContext.setEntityManager(this);
429: }
430: return this.persistenceContext;
431: }
432:
433: /**
434: * Called from EntityTransaction in case of a rollback. Releasing the UoW is up to the EntityTransaction.
435: */
436: @Override
437: public void removeCurrentPersistenceContext() {
438: if (persistenceContext != null && persistenceContext.isActive()) {
439: persistenceContext.release();
440: }
441: this.persistenceContext = null;
442: }
443:
444: @Override
445: public void transactionStarted(EntityTransaction t) {
446: this.serverSession.transactionStarted(t, this);
447: }
448:
449: @Override
450: public void transactionFinished(EntityTransaction t) {
451: this.serverSession.transactionFinished(t);
452: }
453:
454: /**
455: * Since we support only EntityTransactions, we set the TransactionWrapper to EntityTransactionWrapper. In the
456: * future, if JTA transactions are supported, JTATransactionWrapper should be set instead of the
457: * EntityTransactionWrapper.
458: */
459: private void setTransactionWrapper() {
460: this.transaction = new EntityTransactionWrapper(this);
461: }
462:
463: @Override
464: public Configuration getConfiguration() {
465: return configuration;
466: }
467: }