/* | |
* Licensed to the Apache Software Foundation (ASF) under one | |
* or more contributor license agreements. See the NOTICE file | |
* distributed with this work for additional information | |
* regarding copyright ownership. The ASF licenses this file | |
* to you under the Apache License, Version 2.0 (the | |
* "License"); you may not use this file except in compliance | |
* with the License. You may obtain a copy of the License at | |
* | |
* http://www.apache.org/licenses/LICENSE-2.0 | |
* | |
* Unless required by applicable law or agreed to in writing, | |
* software distributed under the License is distributed on an | |
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY | |
* KIND, either express or implied. See the License for the | |
* specific language governing permissions and limitations | |
* under the License. | |
*/ | |
package org.apache.openjpa.persistence; | |
import java.io.ByteArrayInputStream; | |
import java.io.ByteArrayOutputStream; | |
import java.io.Externalizable; | |
import java.io.IOException; | |
import java.io.ObjectInput; | |
import java.io.ObjectInputStream; | |
import java.io.ObjectOutput; | |
import java.io.ObjectOutputStream; | |
import java.io.ObjectStreamClass; | |
import java.lang.reflect.Array; | |
import java.util.Arrays; | |
import java.util.Collection; | |
import java.util.EnumSet; | |
import java.util.Map; | |
import java.util.HashMap; | |
import java.util.IdentityHashMap; | |
import javax.persistence.EntityManager; | |
import javax.persistence.FlushModeType; | |
import javax.persistence.LockModeType; | |
import javax.persistence.Query; | |
import org.apache.commons.lang.StringUtils; | |
import org.apache.openjpa.conf.OpenJPAConfiguration; | |
import org.apache.openjpa.ee.ManagedRuntime; | |
import org.apache.openjpa.enhance.PCEnhancer; | |
import org.apache.openjpa.enhance.PCRegistry; | |
import org.apache.openjpa.kernel.AbstractBrokerFactory; | |
import org.apache.openjpa.kernel.Broker; | |
import org.apache.openjpa.kernel.DelegatingBroker; | |
import org.apache.openjpa.kernel.FindCallbacks; | |
import org.apache.openjpa.kernel.LockLevels; | |
import org.apache.openjpa.kernel.OpCallbacks; | |
import org.apache.openjpa.kernel.OpenJPAStateManager; | |
import org.apache.openjpa.kernel.QueryFlushModes; | |
import org.apache.openjpa.kernel.QueryLanguages; | |
import org.apache.openjpa.kernel.Seq; | |
import org.apache.openjpa.kernel.FetchConfiguration; | |
import org.apache.openjpa.kernel.jpql.JPQLParser; | |
import org.apache.openjpa.lib.util.Closeable; | |
import org.apache.openjpa.lib.util.Localizer; | |
import org.apache.openjpa.meta.ClassMetaData; | |
import org.apache.openjpa.meta.FieldMetaData; | |
import org.apache.openjpa.meta.QueryMetaData; | |
import org.apache.openjpa.meta.SequenceMetaData; | |
import org.apache.openjpa.util.Exceptions; | |
import org.apache.openjpa.util.ImplHelper; | |
import org.apache.openjpa.util.RuntimeExceptionTranslator; | |
import org.apache.openjpa.util.UserException; | |
/** | |
* Implementation of {@link EntityManager} interface. | |
* | |
* @author Patrick Linskey | |
* @author Abe White | |
* @nojavadoc | |
*/ | |
public class EntityManagerImpl | |
implements OpenJPAEntityManagerSPI, Externalizable, | |
FindCallbacks, OpCallbacks, Closeable, OpenJPAEntityTransaction { | |
private static final Localizer _loc = Localizer.forPackage | |
(EntityManagerImpl.class); | |
private static final Object[] EMPTY_OBJECTS = new Object[0]; | |
private DelegatingBroker _broker; | |
private EntityManagerFactoryImpl _emf; | |
private Map<FetchConfiguration,FetchPlan> _plans = | |
new IdentityHashMap<FetchConfiguration,FetchPlan>(1); | |
private RuntimeExceptionTranslator ret = | |
PersistenceExceptions.getRollbackTranslator(this); | |
public EntityManagerImpl() { | |
// for Externalizable | |
} | |
/** | |
* Constructor; supply factory and delegate. | |
*/ | |
public EntityManagerImpl(EntityManagerFactoryImpl factory, | |
Broker broker) { | |
initialize(factory, broker); | |
} | |
private void initialize(EntityManagerFactoryImpl factory, Broker broker) { | |
_emf = factory; | |
_broker = new DelegatingBroker(broker, ret); | |
_broker.setImplicitBehavior(this, ret); | |
} | |
/** | |
* Broker delegate. | |
*/ | |
public Broker getBroker() { | |
return _broker.getDelegate(); | |
} | |
public OpenJPAEntityManagerFactory getEntityManagerFactory() { | |
return _emf; | |
} | |
public OpenJPAConfiguration getConfiguration() { | |
return _broker.getConfiguration(); | |
} | |
public FetchPlan getFetchPlan() { | |
assertNotCloseInvoked(); | |
_broker.lock(); | |
try { | |
FetchConfiguration fc = _broker.getFetchConfiguration(); | |
FetchPlan fp = _plans.get(fc); | |
if (fp == null) { | |
fp = _emf.toFetchPlan(_broker, fc); | |
_plans.put(fc, fp); | |
} | |
return fp; | |
} finally { | |
_broker.unlock(); | |
} | |
} | |
public FetchPlan pushFetchPlan() { | |
assertNotCloseInvoked(); | |
_broker.lock(); | |
try { | |
_broker.pushFetchConfiguration(); | |
return getFetchPlan(); | |
} finally { | |
_broker.unlock(); | |
} | |
} | |
public void popFetchPlan() { | |
assertNotCloseInvoked(); | |
_broker.lock(); | |
try { | |
_broker.popFetchConfiguration(); | |
} finally { | |
_broker.unlock(); | |
} | |
} | |
public ConnectionRetainMode getConnectionRetainMode() { | |
return ConnectionRetainMode.fromKernelConstant( | |
_broker.getConnectionRetainMode()); | |
} | |
public boolean isTransactionManaged() { | |
return _broker.isManaged(); | |
} | |
public boolean isManaged() { | |
return _broker.isManaged(); | |
} | |
public ManagedRuntime getManagedRuntime() { | |
return _broker.getManagedRuntime(); | |
} | |
public boolean getSyncWithManagedTransactions() { | |
return _broker.getSyncWithManagedTransactions(); | |
} | |
public void setSyncWithManagedTransactions(boolean sync) { | |
assertNotCloseInvoked(); | |
_broker.setSyncWithManagedTransactions(sync); | |
} | |
public ClassLoader getClassLoader() { | |
return _broker.getClassLoader(); | |
} | |
public String getConnectionUserName() { | |
return _broker.getConnectionUserName(); | |
} | |
public String getConnectionPassword() { | |
return _broker.getConnectionPassword(); | |
} | |
public boolean getMultithreaded() { | |
return _broker.getMultithreaded(); | |
} | |
public void setMultithreaded(boolean multithreaded) { | |
assertNotCloseInvoked(); | |
_broker.setMultithreaded(multithreaded); | |
} | |
public boolean getIgnoreChanges() { | |
return _broker.getIgnoreChanges(); | |
} | |
public void setIgnoreChanges(boolean val) { | |
assertNotCloseInvoked(); | |
_broker.setIgnoreChanges(val); | |
} | |
public boolean getNontransactionalRead() { | |
return _broker.getNontransactionalRead(); | |
} | |
public void setNontransactionalRead(boolean val) { | |
assertNotCloseInvoked(); | |
_broker.setNontransactionalRead(val); | |
} | |
public boolean getNontransactionalWrite() { | |
return _broker.getNontransactionalWrite(); | |
} | |
public void setNontransactionalWrite(boolean val) { | |
assertNotCloseInvoked(); | |
_broker.setNontransactionalWrite(val); | |
} | |
public boolean getOptimistic() { | |
return _broker.getOptimistic(); | |
} | |
public void setOptimistic(boolean val) { | |
assertNotCloseInvoked(); | |
_broker.setOptimistic(val); | |
} | |
public RestoreStateType getRestoreState() { | |
return RestoreStateType.fromKernelConstant(_broker.getRestoreState()); | |
} | |
public void setRestoreState(RestoreStateType val) { | |
assertNotCloseInvoked(); | |
_broker.setRestoreState(val.toKernelConstant()); | |
} | |
public void setRestoreState(int restore) { | |
assertNotCloseInvoked(); | |
_broker.setRestoreState(restore); | |
} | |
public boolean getRetainState() { | |
return _broker.getRetainState(); | |
} | |
public void setRetainState(boolean val) { | |
assertNotCloseInvoked(); | |
_broker.setRetainState(val); | |
} | |
public AutoClearType getAutoClear() { | |
return AutoClearType.fromKernelConstant(_broker.getAutoClear()); | |
} | |
public void setAutoClear(AutoClearType val) { | |
assertNotCloseInvoked(); | |
_broker.setAutoClear(val.toKernelConstant()); | |
} | |
public void setAutoClear(int autoClear) { | |
assertNotCloseInvoked(); | |
_broker.setAutoClear(autoClear); | |
} | |
public DetachStateType getDetachState() { | |
return DetachStateType.fromKernelConstant(_broker.getDetachState()); | |
} | |
public void setDetachState(DetachStateType type) { | |
assertNotCloseInvoked(); | |
_broker.setDetachState(type.toKernelConstant()); | |
} | |
public void setDetachState(int detach) { | |
assertNotCloseInvoked(); | |
_broker.setDetachState(detach); | |
} | |
public EnumSet<AutoDetachType> getAutoDetach() { | |
return AutoDetachType.toEnumSet(_broker.getAutoDetach()); | |
} | |
public void setAutoDetach(AutoDetachType flag) { | |
assertNotCloseInvoked(); | |
_broker.setAutoDetach(AutoDetachType.fromEnumSet(EnumSet.of(flag))); | |
} | |
public void setAutoDetach(EnumSet<AutoDetachType> flags) { | |
assertNotCloseInvoked(); | |
_broker.setAutoDetach(AutoDetachType.fromEnumSet(flags)); | |
} | |
public void setAutoDetach(int autoDetachFlags) { | |
assertNotCloseInvoked(); | |
_broker.setAutoDetach(autoDetachFlags); | |
} | |
public void setAutoDetach(AutoDetachType value, boolean on) { | |
assertNotCloseInvoked(); | |
_broker.setAutoDetach(AutoDetachType.fromEnumSet(EnumSet.of(value)),on); | |
} | |
public void setAutoDetach(int flag, boolean on) { | |
assertNotCloseInvoked(); | |
_broker.setAutoDetach(flag, on); | |
} | |
public boolean getEvictFromStoreCache() { | |
return _broker.getEvictFromDataCache(); | |
} | |
public void setEvictFromStoreCache(boolean evict) { | |
assertNotCloseInvoked(); | |
_broker.setEvictFromDataCache(evict); | |
} | |
public boolean getPopulateStoreCache() { | |
return _broker.getPopulateDataCache(); | |
} | |
public void setPopulateStoreCache(boolean cache) { | |
assertNotCloseInvoked(); | |
_broker.setPopulateDataCache(cache); | |
} | |
public boolean isTrackChangesByType() { | |
return _broker.isTrackChangesByType(); | |
} | |
public void setTrackChangesByType(boolean trackByType) { | |
assertNotCloseInvoked(); | |
_broker.setTrackChangesByType(trackByType); | |
} | |
public boolean isLargeTransaction() { | |
return isTrackChangesByType(); | |
} | |
public void setLargeTransaction(boolean value) { | |
setTrackChangesByType(value); | |
} | |
public Object getUserObject(Object key) { | |
return _broker.getUserObject(key); | |
} | |
public Object putUserObject(Object key, Object val) { | |
assertNotCloseInvoked(); | |
return _broker.putUserObject(key, val); | |
} | |
public void addTransactionListener(Object listener) { | |
assertNotCloseInvoked(); | |
_broker.addTransactionListener(listener); | |
} | |
public void removeTransactionListener(Object listener) { | |
assertNotCloseInvoked(); | |
_broker.removeTransactionListener(listener); | |
} | |
public EnumSet<CallbackMode> getTransactionListenerCallbackModes() { | |
return CallbackMode.toEnumSet( | |
_broker.getTransactionListenerCallbackMode()); | |
} | |
public void setTransactionListenerCallbackMode(CallbackMode mode) { | |
assertNotCloseInvoked(); | |
_broker.setTransactionListenerCallbackMode( | |
CallbackMode.fromEnumSet(EnumSet.of(mode))); | |
} | |
public void setTransactionListenerCallbackMode(EnumSet<CallbackMode> modes){ | |
assertNotCloseInvoked(); | |
_broker.setTransactionListenerCallbackMode( | |
CallbackMode.fromEnumSet(modes)); | |
} | |
public int getTransactionListenerCallbackMode() { | |
return _broker.getTransactionListenerCallbackMode(); | |
} | |
public void setTransactionListenerCallbackMode(int callbackMode) { | |
throw new UnsupportedOperationException(); | |
} | |
public void addLifecycleListener(Object listener, Class... classes) { | |
assertNotCloseInvoked(); | |
_broker.addLifecycleListener(listener, classes); | |
} | |
public void removeLifecycleListener(Object listener) { | |
assertNotCloseInvoked(); | |
_broker.removeLifecycleListener(listener); | |
} | |
public EnumSet<CallbackMode> getLifecycleListenerCallbackModes() { | |
return CallbackMode.toEnumSet( | |
_broker.getLifecycleListenerCallbackMode()); | |
} | |
public void setLifecycleListenerCallbackMode(CallbackMode mode) { | |
assertNotCloseInvoked(); | |
_broker.setLifecycleListenerCallbackMode( | |
CallbackMode.fromEnumSet(EnumSet.of(mode))); | |
} | |
public void setLifecycleListenerCallbackMode(EnumSet<CallbackMode> modes) { | |
assertNotCloseInvoked(); | |
_broker.setLifecycleListenerCallbackMode( | |
CallbackMode.fromEnumSet(modes)); | |
} | |
public int getLifecycleListenerCallbackMode() { | |
return _broker.getLifecycleListenerCallbackMode(); | |
} | |
public void setLifecycleListenerCallbackMode(int callbackMode) { | |
assertNotCloseInvoked(); | |
_broker.setLifecycleListenerCallbackMode(callbackMode); | |
} | |
@SuppressWarnings("unchecked") | |
public <T> T getReference(Class<T> cls, Object oid) { | |
assertNotCloseInvoked(); | |
oid = _broker.newObjectId(cls, oid); | |
return (T) _broker.find(oid, false, this); | |
} | |
@SuppressWarnings("unchecked") | |
public <T> T find(Class<T> cls, Object oid) { | |
assertNotCloseInvoked(); | |
oid = _broker.newObjectId(cls, oid); | |
return (T) _broker.find(oid, true, this); | |
} | |
@SuppressWarnings("unchecked") | |
public <T> T[] findAll(Class<T> cls, Object... oids) { | |
if (oids.length == 0) | |
return (T[]) Array.newInstance(cls, 0); | |
Collection<T> ret = findAll(cls, Arrays.asList(oids)); | |
return ret.toArray((T[]) Array.newInstance(cls, ret.size())); | |
} | |
@SuppressWarnings("unchecked") | |
public <T> Collection<T> findAll(final Class<T> cls, Collection oids) { | |
assertNotCloseInvoked(); | |
Object[] objs = _broker.findAll(oids, true, new FindCallbacks() { | |
public Object processArgument(Object oid) { | |
return _broker.newObjectId(cls, oid); | |
} | |
public Object processReturn(Object oid, OpenJPAStateManager sm) { | |
return EntityManagerImpl.this.processReturn(oid, sm); | |
} | |
}); | |
return (Collection<T>) Arrays.asList(objs); | |
} | |
@SuppressWarnings("unchecked") | |
public <T> T findCached(Class<T> cls, Object oid) { | |
assertNotCloseInvoked(); | |
return (T) _broker.findCached(_broker.newObjectId(cls, oid), this); | |
} | |
public Class getObjectIdClass(Class cls) { | |
assertNotCloseInvoked(); | |
if (cls == null) | |
return null; | |
return JPAFacadeHelper.fromOpenJPAObjectIdClass | |
(_broker.getObjectIdType(cls)); | |
} | |
public OpenJPAEntityTransaction getTransaction() { | |
if (_broker.isManaged()) | |
throw new InvalidStateException(_loc.get("get-managed-trans"), | |
null, null, false); | |
return this; | |
} | |
public void joinTransaction() { | |
assertNotCloseInvoked(); | |
if (!_broker.syncWithManagedTransaction()) | |
throw new TransactionRequiredException(_loc.get | |
("no-managed-trans"), null, null, false); | |
} | |
public void begin() { | |
_broker.begin(); | |
} | |
public void commit() { | |
try { | |
_broker.commit(); | |
} catch (RollbackException e) { | |
throw e; | |
} catch (IllegalStateException e) { | |
throw e; | |
} catch (Exception e) { | |
// RollbackExceptions are special and aren't handled by the | |
// normal exception translator, since the spec says they | |
// should be thrown whenever the commit fails for any reason at | |
// all, wheras the exception translator handles exceptions that | |
// are caused for specific reasons | |
throw new RollbackException(e); | |
} | |
} | |
public void rollback() { | |
_broker.rollback(); | |
} | |
public void commitAndResume() { | |
_broker.commitAndResume(); | |
} | |
public void rollbackAndResume() { | |
_broker.rollbackAndResume(); | |
} | |
public Throwable getRollbackCause() { | |
if (!isActive()) | |
throw new IllegalStateException(_loc.get("no-transaction") | |
.getMessage()); | |
return _broker.getRollbackCause(); | |
} | |
public boolean getRollbackOnly() { | |
if (!isActive()) | |
throw new IllegalStateException(_loc.get("no-transaction") | |
.getMessage()); | |
return _broker.getRollbackOnly(); | |
} | |
public void setRollbackOnly() { | |
_broker.setRollbackOnly(); | |
} | |
public void setRollbackOnly(Throwable cause) { | |
_broker.setRollbackOnly(cause); | |
} | |
public void setSavepoint(String name) { | |
assertNotCloseInvoked(); | |
_broker.setSavepoint(name); | |
} | |
public void rollbackToSavepoint() { | |
assertNotCloseInvoked(); | |
_broker.rollbackToSavepoint(); | |
} | |
public void rollbackToSavepoint(String name) { | |
assertNotCloseInvoked(); | |
_broker.rollbackToSavepoint(name); | |
} | |
public void releaseSavepoint() { | |
assertNotCloseInvoked(); | |
_broker.releaseSavepoint(); | |
} | |
public void releaseSavepoint(String name) { | |
assertNotCloseInvoked(); | |
_broker.releaseSavepoint(name); | |
} | |
public void flush() { | |
assertNotCloseInvoked(); | |
_broker.assertOpen(); | |
_broker.assertActiveTransaction(); | |
_broker.flush(); | |
} | |
public void preFlush() { | |
assertNotCloseInvoked(); | |
_broker.preFlush(); | |
} | |
public void validateChanges() { | |
assertNotCloseInvoked(); | |
_broker.validateChanges(); | |
} | |
public boolean isActive() { | |
return isOpen() && _broker.isActive(); | |
} | |
public boolean isStoreActive() { | |
return _broker.isStoreActive(); | |
} | |
public void beginStore() { | |
_broker.beginStore(); | |
} | |
public boolean contains(Object entity) { | |
assertNotCloseInvoked(); | |
if (entity == null) | |
return false; | |
OpenJPAStateManager sm = _broker.getStateManager(entity); | |
if (sm == null | |
&& !ImplHelper.isManagedType(getConfiguration(), entity.getClass())) | |
throw new ArgumentException(_loc.get("not-entity", | |
entity.getClass()), null, null, true); | |
return sm != null && !sm.isDeleted(); | |
} | |
public boolean containsAll(Object... entities) { | |
for (Object entity : entities) | |
if (!contains(entity)) | |
return false; | |
return true; | |
} | |
public boolean containsAll(Collection entities) { | |
for (Object entity : entities) | |
if (!contains(entity)) | |
return false; | |
return true; | |
} | |
public void persist(Object entity) { | |
assertNotCloseInvoked(); | |
_broker.persist(entity, this); | |
} | |
public void persistAll(Object... entities) { | |
persistAll(Arrays.asList(entities)); | |
} | |
public void persistAll(Collection entities) { | |
assertNotCloseInvoked(); | |
_broker.persistAll(entities, this); | |
} | |
public void remove(Object entity) { | |
assertNotCloseInvoked(); | |
_broker.delete(entity, this); | |
} | |
public void removeAll(Object... entities) { | |
removeAll(Arrays.asList(entities)); | |
} | |
public void removeAll(Collection entities) { | |
assertNotCloseInvoked(); | |
_broker.deleteAll(entities, this); | |
} | |
public void release(Object entity) { | |
assertNotCloseInvoked(); | |
_broker.release(entity, this); | |
} | |
public void releaseAll(Collection entities) { | |
assertNotCloseInvoked(); | |
_broker.releaseAll(entities, this); | |
} | |
public void releaseAll(Object... entities) { | |
releaseAll(Arrays.asList(entities)); | |
} | |
public void refresh(Object entity) { | |
assertNotCloseInvoked(); | |
_broker.assertWriteOperation(); | |
_broker.refresh(entity, this); | |
} | |
public void refreshAll() { | |
assertNotCloseInvoked(); | |
_broker.assertWriteOperation(); | |
_broker.refreshAll(_broker.getTransactionalObjects(), this); | |
} | |
public void refreshAll(Collection entities) { | |
assertNotCloseInvoked(); | |
_broker.assertWriteOperation(); | |
_broker.refreshAll(entities, this); | |
} | |
public void refreshAll(Object... entities) { | |
refreshAll(Arrays.asList(entities)); | |
} | |
public void retrieve(Object entity) { | |
assertNotCloseInvoked(); | |
_broker.retrieve(entity, true, this); | |
} | |
public void retrieveAll(Collection entities) { | |
assertNotCloseInvoked(); | |
_broker.retrieveAll(entities, true, this); | |
} | |
public void retrieveAll(Object... entities) { | |
retrieveAll(Arrays.asList(entities)); | |
} | |
public void evict(Object entity) { | |
assertNotCloseInvoked(); | |
_broker.evict(entity, this); | |
} | |
public void evictAll(Collection entities) { | |
assertNotCloseInvoked(); | |
_broker.evictAll(entities, this); | |
} | |
public void evictAll(Object... entities) { | |
evictAll(Arrays.asList(entities)); | |
} | |
public void evictAll() { | |
assertNotCloseInvoked(); | |
_broker.evictAll(this); | |
} | |
public void evictAll(Class cls) { | |
assertNotCloseInvoked(); | |
_broker.evictAll(_broker.newExtent(cls, true), this); | |
} | |
public void evictAll(Extent extent) { | |
assertNotCloseInvoked(); | |
_broker.evictAll(((ExtentImpl) extent).getDelegate(), this); | |
} | |
@SuppressWarnings("unchecked") | |
public <T> T detach(T entity) { | |
assertNotCloseInvoked(); | |
return (T) _broker.detach(entity, this); | |
} | |
public Object[] detachAll(Object... entities) { | |
assertNotCloseInvoked(); | |
return _broker.detachAll(Arrays.asList(entities), this); | |
} | |
public Collection detachAll(Collection entities) { | |
assertNotCloseInvoked(); | |
return Arrays.asList(_broker.detachAll(entities, this)); | |
} | |
@SuppressWarnings("unchecked") | |
public <T> T merge(T entity) { | |
assertNotCloseInvoked(); | |
return (T) _broker.attach(entity, true, this); | |
} | |
public Object[] mergeAll(Object... entities) { | |
if (entities.length == 0) | |
return EMPTY_OBJECTS; | |
return mergeAll(Arrays.asList(entities)).toArray(); | |
} | |
public Collection mergeAll(Collection entities) { | |
assertNotCloseInvoked(); | |
return Arrays.asList(_broker.attachAll(entities, true, this)); | |
} | |
public void transactional(Object entity, boolean updateVersion) { | |
assertNotCloseInvoked(); | |
_broker.transactional(entity, updateVersion, this); | |
} | |
public void transactionalAll(Collection objs, boolean updateVersion) { | |
assertNotCloseInvoked(); | |
_broker.transactionalAll(objs, updateVersion, this); | |
} | |
public void transactionalAll(Object[] objs, boolean updateVersion) { | |
assertNotCloseInvoked(); | |
_broker.transactionalAll(Arrays.asList(objs), updateVersion, this); | |
} | |
public void nontransactional(Object entity) { | |
assertNotCloseInvoked(); | |
_broker.nontransactional(entity, this); | |
} | |
public void nontransactionalAll(Collection objs) { | |
assertNotCloseInvoked(); | |
_broker.nontransactionalAll(objs, this); | |
} | |
public void nontransactionalAll(Object[] objs) { | |
assertNotCloseInvoked(); | |
_broker.nontransactionalAll(Arrays.asList(objs), this); | |
} | |
public Generator getNamedGenerator(String name) { | |
assertNotCloseInvoked(); | |
try { | |
SequenceMetaData meta = _broker.getConfiguration(). | |
getMetaDataRepositoryInstance().getSequenceMetaData(name, | |
_broker.getClassLoader(), true); | |
Seq seq = meta.getInstance(_broker.getClassLoader()); | |
return new GeneratorImpl(seq, name, _broker, null); | |
} catch (RuntimeException re) { | |
throw PersistenceExceptions.toPersistenceException(re); | |
} | |
} | |
public Generator getIdGenerator(Class forClass) { | |
assertNotCloseInvoked(); | |
try { | |
ClassMetaData meta = _broker.getConfiguration(). | |
getMetaDataRepositoryInstance().getMetaData(forClass, | |
_broker.getClassLoader(), true); | |
Seq seq = _broker.getIdentitySequence(meta); | |
return (seq == null) ? null : new GeneratorImpl(seq, null, _broker, | |
meta); | |
} catch (Exception e) { | |
throw PersistenceExceptions.toPersistenceException(e); | |
} | |
} | |
public Generator getFieldGenerator(Class forClass, String fieldName) { | |
assertNotCloseInvoked(); | |
try { | |
ClassMetaData meta = _broker.getConfiguration(). | |
getMetaDataRepositoryInstance().getMetaData(forClass, | |
_broker.getClassLoader(), true); | |
FieldMetaData fmd = meta.getField(fieldName); | |
if (fmd == null) | |
throw new ArgumentException(_loc.get("no-named-field", | |
forClass, fieldName), null, null, false); | |
Seq seq = _broker.getValueSequence(fmd); | |
return (seq == null) ? null : new GeneratorImpl(seq, null, _broker, | |
meta); | |
} catch (Exception e) { | |
throw PersistenceExceptions.toPersistenceException(e); | |
} | |
} | |
public <T> Extent<T> createExtent(Class<T> cls, boolean subclasses) { | |
assertNotCloseInvoked(); | |
return new ExtentImpl<T>(this, _broker.newExtent(cls, subclasses)); | |
} | |
public OpenJPAQuery createQuery(String query) { | |
return createQuery(JPQLParser.LANG_JPQL, query); | |
} | |
public OpenJPAQuery createQuery(String language, String query) { | |
assertNotCloseInvoked(); | |
return new QueryImpl(this, ret, _broker.newQuery(language, query)); | |
} | |
public OpenJPAQuery createQuery(Query query) { | |
if (query == null) | |
return createQuery((String) null); | |
assertNotCloseInvoked(); | |
org.apache.openjpa.kernel.Query q = ((QueryImpl) query).getDelegate(); | |
return new QueryImpl(this, ret, _broker.newQuery(q.getLanguage(), | |
q)); | |
} | |
public OpenJPAQuery createNamedQuery(String name) { | |
assertNotCloseInvoked(); | |
_broker.assertOpen(); | |
try { | |
QueryMetaData meta = _broker.getConfiguration(). | |
getMetaDataRepositoryInstance().getQueryMetaData(null, name, | |
_broker.getClassLoader(), true); | |
org.apache.openjpa.kernel.Query del = | |
_broker.newQuery(meta.getLanguage(), null); | |
meta.setInto(del); | |
del.compile(); | |
OpenJPAQuery q = new QueryImpl(this, ret, del); | |
String[] hints = meta.getHintKeys(); | |
Object[] values = meta.getHintValues(); | |
for (int i = 0; i < hints.length; i++) | |
q.setHint(hints[i], values[i]); | |
return q; | |
} catch (RuntimeException re) { | |
throw PersistenceExceptions.toPersistenceException(re); | |
} | |
} | |
public OpenJPAQuery createNativeQuery(String query) { | |
validateSQL(query); | |
return createQuery(QueryLanguages.LANG_SQL, query); | |
} | |
public OpenJPAQuery createNativeQuery(String query, Class cls) { | |
return createNativeQuery(query).setResultClass(cls); | |
} | |
public OpenJPAQuery createNativeQuery(String query, String mappingName) { | |
assertNotCloseInvoked(); | |
validateSQL(query); | |
org.apache.openjpa.kernel.Query kernelQuery = _broker.newQuery( | |
QueryLanguages.LANG_SQL, query); | |
kernelQuery.setResultMapping(null, mappingName); | |
return new QueryImpl(this, ret, kernelQuery); | |
} | |
/** | |
* Validate that the user provided SQL. | |
*/ | |
private static void validateSQL(String query) { | |
if (StringUtils.trimToNull(query) == null) | |
throw new ArgumentException(_loc.get("no-sql"), null, null, false); | |
} | |
public void setFlushMode(FlushModeType flushMode) { | |
assertNotCloseInvoked(); | |
_broker.assertOpen(); | |
_broker.getFetchConfiguration().setFlushBeforeQueries | |
(toFlushBeforeQueries(flushMode)); | |
} | |
public FlushModeType getFlushMode() { | |
assertNotCloseInvoked(); | |
_broker.assertOpen(); | |
return fromFlushBeforeQueries(_broker.getFetchConfiguration(). | |
getFlushBeforeQueries()); | |
} | |
/** | |
* Translate our internal flush constant to a flush mode enum value. | |
*/ | |
static FlushModeType fromFlushBeforeQueries(int flush) { | |
switch (flush) { | |
case QueryFlushModes.FLUSH_TRUE: | |
return FlushModeType.AUTO; | |
case QueryFlushModes.FLUSH_FALSE: | |
return FlushModeType.COMMIT; | |
default: | |
return null; | |
} | |
} | |
/** | |
* Translate a flush mode enum value to our internal flush constant. | |
*/ | |
static int toFlushBeforeQueries(FlushModeType flushMode) { | |
// choose default for null | |
if (flushMode == null) | |
return QueryFlushModes.FLUSH_WITH_CONNECTION; | |
if (flushMode == FlushModeType.AUTO) | |
return QueryFlushModes.FLUSH_TRUE; | |
if (flushMode == FlushModeType.COMMIT) | |
return QueryFlushModes.FLUSH_FALSE; | |
throw new ArgumentException(flushMode.toString(), null, null, false); | |
} | |
public void clear() { | |
assertNotCloseInvoked(); | |
_broker.detachAll(this, false); | |
} | |
public Object getDelegate() { | |
_broker.assertOpen(); | |
assertNotCloseInvoked(); | |
return this; | |
} | |
public LockModeType getLockMode(Object entity) { | |
assertNotCloseInvoked(); | |
return fromLockLevel(_broker.getLockLevel(entity)); | |
} | |
public void lock(Object entity, LockModeType mode) { | |
assertNotCloseInvoked(); | |
_broker.lock(entity, toLockLevel(mode), -1, this); | |
} | |
public void lock(Object entity) { | |
assertNotCloseInvoked(); | |
_broker.lock(entity, this); | |
} | |
public void lock(Object entity, LockModeType mode, int timeout) { | |
assertNotCloseInvoked(); | |
_broker.lock(entity, toLockLevel(mode), timeout, this); | |
} | |
public void lockAll(Collection entities) { | |
assertNotCloseInvoked(); | |
_broker.lockAll(entities, this); | |
} | |
public void lockAll(Collection entities, LockModeType mode, int timeout) { | |
assertNotCloseInvoked(); | |
_broker.lockAll(entities, toLockLevel(mode), timeout, this); | |
} | |
public void lockAll(Object... entities) { | |
lockAll(Arrays.asList(entities)); | |
} | |
public void lockAll(Object[] entities, LockModeType mode, int timeout) { | |
lockAll(Arrays.asList(entities), mode, timeout); | |
} | |
/** | |
* Translate our internal lock level to a javax.persistence enum value. | |
*/ | |
static LockModeType fromLockLevel(int level) { | |
if (level < LockLevels.LOCK_READ) | |
return null; | |
if (level < LockLevels.LOCK_WRITE) | |
return LockModeType.READ; | |
return LockModeType.WRITE; | |
} | |
/** | |
* Translate the javax.persistence enum value to our internal lock level. | |
*/ | |
static int toLockLevel(LockModeType mode) { | |
if (mode == null) | |
return LockLevels.LOCK_NONE; | |
if (mode == LockModeType.READ) | |
return LockLevels.LOCK_READ; | |
if (mode == LockModeType.WRITE) | |
return LockLevels.LOCK_WRITE; | |
throw new ArgumentException(mode.toString(), null, null, true); | |
} | |
public boolean cancelAll() { | |
return _broker.cancelAll(); | |
} | |
public Object getConnection() { | |
return _broker.getConnection(); | |
} | |
public Collection getManagedObjects() { | |
return _broker.getManagedObjects(); | |
} | |
public Collection getTransactionalObjects() { | |
return _broker.getTransactionalObjects(); | |
} | |
public Collection getPendingTransactionalObjects() { | |
return _broker.getPendingTransactionalObjects(); | |
} | |
public Collection getDirtyObjects() { | |
return _broker.getDirtyObjects(); | |
} | |
public boolean getOrderDirtyObjects() { | |
return _broker.getOrderDirtyObjects(); | |
} | |
public void setOrderDirtyObjects(boolean order) { | |
assertNotCloseInvoked(); | |
_broker.setOrderDirtyObjects(order); | |
} | |
public void dirtyClass(Class cls) { | |
assertNotCloseInvoked(); | |
_broker.dirtyType(cls); | |
} | |
@SuppressWarnings("unchecked") | |
public Collection<Class> getPersistedClasses() { | |
return (Collection<Class>) _broker.getPersistedTypes(); | |
} | |
@SuppressWarnings("unchecked") | |
public Collection<Class> getUpdatedClasses() { | |
return (Collection<Class>) _broker.getUpdatedTypes(); | |
} | |
@SuppressWarnings("unchecked") | |
public Collection<Class> getRemovedClasses() { | |
return (Collection<Class>) _broker.getDeletedTypes(); | |
} | |
public <T> T createInstance(Class<T> cls) { | |
assertNotCloseInvoked(); | |
return (T) _broker.newInstance(cls); | |
} | |
public void close() { | |
assertNotCloseInvoked(); | |
_broker.close(); | |
} | |
public boolean isOpen() { | |
return !_broker.isCloseInvoked(); | |
} | |
public void dirty(Object o, String field) { | |
assertNotCloseInvoked(); | |
OpenJPAStateManager sm = _broker.getStateManager(o); | |
try { | |
if (sm != null) | |
sm.dirty(field); | |
} catch (Exception e) { | |
throw PersistenceExceptions.toPersistenceException(e); | |
} | |
} | |
public Object getObjectId(Object o) { | |
assertNotCloseInvoked(); | |
return JPAFacadeHelper.fromOpenJPAObjectId(_broker.getObjectId(o)); | |
} | |
public boolean isDirty(Object o) { | |
assertNotCloseInvoked(); | |
return _broker.isDirty(o); | |
} | |
public boolean isTransactional(Object o) { | |
assertNotCloseInvoked(); | |
return _broker.isTransactional(o); | |
} | |
public boolean isPersistent(Object o) { | |
assertNotCloseInvoked(); | |
return _broker.isPersistent(o); | |
} | |
public boolean isNewlyPersistent(Object o) { | |
assertNotCloseInvoked(); | |
return _broker.isNew(o); | |
} | |
public boolean isRemoved(Object o) { | |
assertNotCloseInvoked(); | |
return _broker.isDeleted(o); | |
} | |
public boolean isDetached(Object entity) { | |
assertNotCloseInvoked(); | |
return _broker.isDetached(entity); | |
} | |
public Object getVersion(Object o) { | |
assertNotCloseInvoked(); | |
return _broker.getVersion(o); | |
} | |
/** | |
* Throw appropriate exception if close has been invoked but the broker | |
* is still open. We test only for this because if the broker is already | |
* closed, it will throw its own more informative exception when we | |
* delegate the pending operation to it. | |
*/ | |
void assertNotCloseInvoked() { | |
if (!_broker.isClosed() && _broker.isCloseInvoked()) | |
throw new InvalidStateException(_loc.get("close-invoked"), null, | |
null, true); | |
} | |
//////////////////////////////// | |
// FindCallbacks implementation | |
//////////////////////////////// | |
public Object processArgument(Object arg) { | |
return arg; | |
} | |
public Object processReturn(Object oid, OpenJPAStateManager sm) { | |
return (sm == null || sm.isDeleted()) ? null : sm.getManagedInstance(); | |
} | |
////////////////////////////// | |
// OpCallbacks implementation | |
////////////////////////////// | |
public int processArgument(int op, Object obj, OpenJPAStateManager sm) { | |
switch (op) { | |
case OP_DELETE: | |
// cascade through non-persistent non-detached instances | |
if (sm == null && !_broker.isDetached(obj)) | |
return ACT_CASCADE; | |
if (sm != null && !sm.isDetached() && !sm.isPersistent()) | |
return ACT_CASCADE; | |
// ignore deleted instances | |
if (sm != null && sm.isDeleted()) | |
return ACT_NONE; | |
break; | |
case OP_ATTACH: | |
// die on removed | |
if (sm != null && sm.isDeleted()) | |
throw new UserException(_loc.get("removed", | |
Exceptions.toString(obj))).setFailedObject(obj); | |
// cascade through managed instances | |
if (sm != null && !sm.isDetached()) | |
return ACT_CASCADE; | |
break; | |
case OP_REFRESH: | |
// die on unmanaged instances | |
if (sm == null) | |
throw new UserException(_loc.get("not-managed", | |
Exceptions.toString(obj))).setFailedObject(obj); | |
break; | |
} | |
return ACT_RUN | ACT_CASCADE; | |
} | |
public int hashCode() { | |
return _broker.hashCode(); | |
} | |
public boolean equals(Object other) { | |
if (other == this) | |
return true; | |
if (!(other instanceof EntityManagerImpl)) | |
return false; | |
return _broker.equals(((EntityManagerImpl) other)._broker); | |
} | |
public void readExternal(ObjectInput in) | |
throws IOException, ClassNotFoundException { | |
try { | |
ret = PersistenceExceptions.getRollbackTranslator(this); | |
// this assumes that serialized Brokers are from something | |
// that extends AbstractBrokerFactory. | |
Object factoryKey = in.readObject(); | |
AbstractBrokerFactory factory = | |
AbstractBrokerFactory.getPooledFactoryForKey(factoryKey); | |
byte[] brokerBytes = (byte[]) in.readObject(); | |
ObjectInputStream innerIn = new BrokerBytesInputStream(brokerBytes, | |
factory.getConfiguration()); | |
Broker broker = (Broker) innerIn.readObject(); | |
EntityManagerFactoryImpl emf = (EntityManagerFactoryImpl) | |
JPAFacadeHelper.toEntityManagerFactory( | |
broker.getBrokerFactory()); | |
broker.putUserObject(JPAFacadeHelper.EM_KEY, this); | |
initialize(emf, broker); | |
} catch (RuntimeException re) { | |
try { | |
re = ret.translate(re); | |
} catch (Exception e) { | |
// ignore | |
} | |
throw re; | |
} | |
} | |
public void writeExternal(ObjectOutput out) throws IOException { | |
try { | |
// this requires that only AbstractBrokerFactory-sourced | |
// brokers can be serialized | |
Object factoryKey = ((AbstractBrokerFactory) _broker | |
.getBrokerFactory()).getPoolKey(); | |
out.writeObject(factoryKey); | |
ByteArrayOutputStream baos = new ByteArrayOutputStream(); | |
ObjectOutputStream innerOut = new ObjectOutputStream(baos); | |
innerOut.writeObject(_broker.getDelegate()); | |
innerOut.flush(); | |
out.writeObject(baos.toByteArray()); | |
} catch (RuntimeException re) { | |
try { | |
re = ret.translate(re); | |
} catch (Exception e) { | |
// ignore | |
} | |
throw re; | |
} | |
} | |
private static class BrokerBytesInputStream extends ObjectInputStream { | |
private OpenJPAConfiguration conf; | |
BrokerBytesInputStream(byte[] bytes, OpenJPAConfiguration conf) | |
throws IOException { | |
super(new ByteArrayInputStream(bytes)); | |
if (conf == null) | |
throw new IllegalArgumentException( | |
"Illegal null argument to ObjectInputStreamWithLoader"); | |
this.conf = conf; | |
} | |
/** | |
* Make a primitive array class | |
*/ | |
private Class primitiveType(char type) { | |
switch (type) { | |
case 'B': return byte.class; | |
case 'C': return char.class; | |
case 'D': return double.class; | |
case 'F': return float.class; | |
case 'I': return int.class; | |
case 'J': return long.class; | |
case 'S': return short.class; | |
case 'Z': return boolean.class; | |
default: return null; | |
} | |
} | |
protected Class resolveClass(ObjectStreamClass classDesc) | |
throws IOException, ClassNotFoundException { | |
String cname = classDesc.getName(); | |
if (cname.startsWith("[")) { | |
// An array | |
Class component; // component class | |
int dcount; // dimension | |
for (dcount=1; cname.charAt(dcount)=='['; dcount++) ; | |
if (cname.charAt(dcount) == 'L') { | |
component = lookupClass(cname.substring(dcount+1, | |
cname.length()-1)); | |
} else { | |
if (cname.length() != dcount+1) { | |
throw new ClassNotFoundException(cname);// malformed | |
} | |
component = primitiveType(cname.charAt(dcount)); | |
} | |
int dim[] = new int[dcount]; | |
for (int i=0; i<dcount; i++) { | |
dim[i]=0; | |
} | |
return Array.newInstance(component, dim).getClass(); | |
} else { | |
return lookupClass(cname); | |
} | |
} | |
/** | |
* If this is a generated subclass, look up the corresponding Class | |
* object via metadata. | |
*/ | |
private Class lookupClass(String className) | |
throws ClassNotFoundException { | |
try { | |
return Class.forName(className); | |
} catch (ClassNotFoundException e) { | |
if (PCEnhancer.isPCSubclassName(className)) { | |
String superName = PCEnhancer.toManagedTypeName(className); | |
ClassMetaData[] metas = conf.getMetaDataRepositoryInstance() | |
.getMetaDatas(); | |
for (int i = 0; i < metas.length; i++) { | |
if (superName.equals( | |
metas[i].getDescribedType().getName())) { | |
return PCRegistry.getPCType( | |
metas[i].getDescribedType()); | |
} | |
} | |
// if it's not found, try to look for it anyways | |
return Class.forName(className); | |
} else { | |
throw e; | |
} | |
} | |
} | |
} | |
} |