-/*
- * Hibernate, Relational Persistence for Idiomatic Java
- *
- * Copyright (c) 2008-2011, Red Hat Inc. or third-party contributors as
- * indicated by the @author tags or express copyright attribution
- * statements applied by the authors. All third-party contributions are
- * distributed under license by Red Hat Inc.
- *
- * This copyrighted material is made available to anyone wishing to use, modify,
- * copy, or redistribute it subject to the terms and conditions of the GNU
- * Lesser General Public License, as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
- * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
- * for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this distribution; if not, write to:
- * Free Software Foundation, Inc.
- * 51 Franklin Street, Fifth Floor
- * Boston, MA 02110-1301 USA
- */
-package org.hibernate.proxy;
-
-import java.io.Serializable;
-
-import javax.naming.NamingException;
-
-import org.hibernate.HibernateException;
-import org.hibernate.LazyInitializationException;
-import org.hibernate.Session;
-import org.hibernate.SessionException;
-import org.hibernate.TransientObjectException;
-import org.hibernate.engine.spi.EntityKey;
-import org.hibernate.engine.spi.SessionFactoryImplementor;
-import org.hibernate.engine.spi.SessionImplementor;
-import org.hibernate.internal.SessionFactoryRegistry;
-import org.hibernate.persister.entity.EntityPersister;
-import org.jboss.logging.Logger;
-
-import eu.etaxonomy.cdm.api.application.CdmApplicationRemoteConfiguration;
-import eu.etaxonomy.cdm.cache.ProxyUtils;
-import eu.etaxonomy.cdm.model.common.CdmBase;
-import eu.etaxonomy.taxeditor.service.ICachedCommonService;
-
-/**
- * Convenience base class for lazy initialization handlers. Centralizes the basic plumbing of doing lazy
- * initialization freeing subclasses to acts as essentially adapters to their intended entity mode and/or
- * proxy generation strategy.
- *
- * @author Gavin King
- */
-public abstract class AbstractLazyInitializer implements LazyInitializer {
- private static final Logger log = Logger.getLogger( AbstractLazyInitializer.class );
-
- private String entityName;
- private Serializable id;
- private Object target;
- private boolean initialized;
- private boolean readOnly;
- private boolean unwrap;
- private transient SessionImplementor session;
- private Boolean readOnlyBeforeAttachedToSession;
-
- private String sessionFactoryUuid;
- private boolean specjLazyLoad = false;
-
- /**
- * For serialization from the non-pojo initializers (HHH-3309)
- */
- protected AbstractLazyInitializer() {
- }
-
- /**
- * Main constructor.
- *
- * @param entityName The name of the entity being proxied.
- * @param id The identifier of the entity being proxied.
- * @param session The session owning the proxy.
- */
- protected AbstractLazyInitializer(String entityName, Serializable id, SessionImplementor session) {
- this.entityName = entityName;
- this.id = id;
- // initialize other fields depending on session state
- if ( session == null ) {
- unsetSession();
- }
- else {
- setSession( session );
- }
- }
-
- @Override
- public final String getEntityName() {
- return entityName;
- }
-
- @Override
- public final Serializable getIdentifier() {
- return id;
- }
-
- @Override
- public final void setIdentifier(Serializable id) {
- this.id = id;
- }
-
- @Override
- public final boolean isUninitialized() {
- return !initialized;
- }
-
- @Override
- public final SessionImplementor getSession() {
- return session;
- }
-
- @Override
- public final void setSession(SessionImplementor s) throws HibernateException {
- if ( s != session ) {
- // check for s == null first, since it is least expensive
- if ( s == null ) {
- unsetSession();
- }
- else if ( isConnectedToSession() ) {
- //TODO: perhaps this should be some other RuntimeException...
- throw new HibernateException( "illegally attempted to associate a proxy with two open Sessions" );
- }
- else {
- // s != null
- session = s;
- if ( readOnlyBeforeAttachedToSession == null ) {
- // use the default read-only/modifiable setting
- final EntityPersister persister = s.getFactory().getEntityPersister( entityName );
- setReadOnly( s.getPersistenceContext().isDefaultReadOnly() || !persister.isMutable() );
- }
- else {
- // use the read-only/modifiable setting indicated during deserialization
- setReadOnly( readOnlyBeforeAttachedToSession.booleanValue() );
- readOnlyBeforeAttachedToSession = null;
- }
- }
- }
- }
-
- private static EntityKey generateEntityKeyOrNull(Serializable id, SessionImplementor s, String entityName) {
- if ( id == null || s == null || entityName == null ) {
- return null;
- }
- return s.generateEntityKey( id, s.getFactory().getEntityPersister( entityName ) );
- }
-
- @Override
- public final void unsetSession() {
- prepareForPossibleSpecialSpecjInitialization();
- session = null;
- readOnly = false;
- readOnlyBeforeAttachedToSession = null;
- }
-
- @Override
- public final void initialize() throws HibernateException {
- // In remoting we are sure that session is null
- // both when using property paths and switching off conversations
- if(session == null && remoting) {
- remoteInitialize();
- }
- if ( !initialized ) {
- if ( specjLazyLoad ) {
- specialSpecjInitialization();
- }
- else if ( session == null ) {
- throw new LazyInitializationException( "could not initialize proxy - no Session" );
- }
- else if ( !session.isOpen() ) {
- throw new LazyInitializationException( "could not initialize proxy - the owning Session was closed" );
- }
- else if ( !session.isConnected() ) {
- throw new LazyInitializationException( "could not initialize proxy - the owning Session is disconnected" );
- }
- else {
- target = session.immediateLoad( entityName, id );
- initialized = true;
- checkTargetState();
- }
- }
- else {
- checkTargetState();
- }
- }
-
- protected void specialSpecjInitialization() {
- if ( session == null ) {
- //we have a detached collection thats set to null, reattach
- if ( sessionFactoryUuid == null ) {
- throw new LazyInitializationException( "could not initialize proxy - no Session" );
- }
- try {
- SessionFactoryImplementor sf = (SessionFactoryImplementor)
- SessionFactoryRegistry.INSTANCE.getSessionFactory( sessionFactoryUuid );
- SessionImplementor session = (SessionImplementor) sf.openSession();
-
- // TODO: On the next major release, add an
- // 'isJTA' or 'getTransactionFactory' method to Session.
- /*boolean isJTA = session.getTransactionCoordinator()
- .getTransactionContext().getTransactionEnvironment()
- .getTransactionFactory()
- .compatibleWithJtaSynchronization();
- */
- boolean isJTA = session.getTransactionCoordinator().getTransactionCoordinatorBuilder().isJta();
-
- if ( !isJTA ) {
- // Explicitly handle the transactions only if we're not in
- // a JTA environment. A lazy loading temporary session can
- // be created even if a current session and transaction are
- // open (ex: session.clear() was used). We must prevent
- // multiple transactions.
- ( ( Session) session ).beginTransaction();
- }
-
- try {
- target = session.immediateLoad( entityName, id );
- }
- finally {
- // make sure the just opened temp session gets closed!
- try {
- if ( !isJTA ) {
- ( ( Session) session ).getTransaction().commit();
- }
- ( (Session) session ).close();
- }
- catch (Exception e) {
- log.warn( "Unable to close temporary session used to load lazy proxy associated to no session" );
- }
- }
- initialized = true;
- checkTargetState();
- }
- catch (Exception e) {
- e.printStackTrace();
- throw new LazyInitializationException( e.getMessage() );
- }
- }
- else if ( session.isOpen() && session.isConnected() ) {
- target = session.immediateLoad( entityName, id );
- initialized = true;
- checkTargetState();
- }
- else {
- throw new LazyInitializationException( "could not initialize proxy - Session was closed or disced" );
- }
- }
-
- protected void prepareForPossibleSpecialSpecjInitialization() {
- if ( session != null ) {
- specjLazyLoad = session.getFactory().getSettings().isInitializeLazyStateOutsideTransactionsEnabled();
-
- if ( specjLazyLoad && sessionFactoryUuid == null ) {
- try {
- sessionFactoryUuid = (String) session.getFactory().getReference().get( "uuid" ).getContent();
- }
- catch (NamingException e) {
- //not much we can do if this fails...
- }
- }
- }
- }
-
- private void checkTargetState() {
- if ( !unwrap ) {
- if ( target == null ) {
- getSession().getFactory().getEntityNotFoundDelegate().handleEntityNotFound( entityName, id );
- }
- }
- }
-
- /**
- * Getter for property 'connectedToSession'.
- *
- * @return Value for property 'connectedToSession'.
- */
- protected final boolean isConnectedToSession() {
- return getProxyOrNull() != null;
- }
-
- private Object getProxyOrNull() {
- final EntityKey entityKey = generateEntityKeyOrNull( getIdentifier(), session, getEntityName() );
- if ( entityKey != null && session != null && session.isOpen() ) {
- return session.getPersistenceContext().getProxy( entityKey );
- }
- return null;
- }
-
- @Override
- public final Object getImplementation() {
- initialize();
- return target;
- }
-
- @Override
- public final void setImplementation(Object target) {
- this.target = target;
- initialized = true;
- }
-
- @Override
- public final Object getImplementation(SessionImplementor s) throws HibernateException {
- final EntityKey entityKey = generateEntityKeyOrNull( getIdentifier(), s, getEntityName() );
- return (entityKey == null ? null : s.getPersistenceContext().getEntity( entityKey ));
- }
-
- /**
- * Getter for property 'target'.
- * <p/>
- * Same as {@link #getImplementation()} except that this method will not force initialization.
- *
- * @return Value for property 'target'.
- */
- protected final Object getTarget() {
- return target;
- }
-
- @Override
- public final boolean isReadOnlySettingAvailable() {
- return (session != null && !session.isClosed());
- }
-
- private void errorIfReadOnlySettingNotAvailable() {
- if ( session == null ) {
- throw new TransientObjectException(
- "Proxy is detached (i.e, session is null). The read-only/modifiable setting is only accessible when the proxy is associated with an open session."
- );
- }
- if ( session.isClosed() ) {
- throw new SessionException(
- "Session is closed. The read-only/modifiable setting is only accessible when the proxy is associated with an open session."
- );
- }
- }
-
- @Override
- public final boolean isReadOnly() {
- errorIfReadOnlySettingNotAvailable();
- return readOnly;
- }
-
- @Override
- public final void setReadOnly(boolean readOnly) {
- errorIfReadOnlySettingNotAvailable();
- // only update if readOnly is different from current setting
- if ( this.readOnly != readOnly ) {
- final EntityPersister persister = session.getFactory().getEntityPersister( entityName );
- if ( !persister.isMutable() && !readOnly ) {
- throw new IllegalStateException( "cannot make proxies for immutable entities modifiable" );
- }
- this.readOnly = readOnly;
- if ( initialized ) {
- EntityKey key = generateEntityKeyOrNull( getIdentifier(), session, getEntityName() );
- if ( key != null && session.getPersistenceContext().containsEntity( key ) ) {
- session.getPersistenceContext().setReadOnly( target, readOnly );
- }
- }
- }
- }
-
- /**
- * Get the read-only/modifiable setting that should be put in affect when it is
- * attached to a session.
- * <p/>
- * This method should only be called during serialization when read-only/modifiable setting
- * is not available (i.e., isReadOnlySettingAvailable() == false)
- *
- * @return null, if the default setting should be used;
- * true, for read-only;
- * false, for modifiable
- *
- * @throws IllegalStateException if isReadOnlySettingAvailable() == true
- */
- protected final Boolean isReadOnlyBeforeAttachedToSession() {
- if ( isReadOnlySettingAvailable() ) {
- throw new IllegalStateException(
- "Cannot call isReadOnlyBeforeAttachedToSession when isReadOnlySettingAvailable == true"
- );
- }
- return readOnlyBeforeAttachedToSession;
- }
-
- /**
- * Set the read-only/modifiable setting that should be put in affect when it is
- * attached to a session.
- * <p/>
- * This method should only be called during deserialization, before associating
- * the proxy with a session.
- *
- * @param readOnlyBeforeAttachedToSession, the read-only/modifiable setting to use when
- * associated with a session; null indicates that the default should be used.
- *
- * @throws IllegalStateException if isReadOnlySettingAvailable() == true
- */
- /* package-private */
- final void setReadOnlyBeforeAttachedToSession(Boolean readOnlyBeforeAttachedToSession) {
- if ( isReadOnlySettingAvailable() ) {
- throw new IllegalStateException(
- "Cannot call setReadOnlyBeforeAttachedToSession when isReadOnlySettingAvailable == true"
- );
- }
- this.readOnlyBeforeAttachedToSession = readOnlyBeforeAttachedToSession;
- }
-
- @Override
- public boolean isUnwrap() {
- return unwrap;
- }
-
- @Override
- public void setUnwrap(boolean unwrap) {
- this.unwrap = unwrap;
- }
-
- /** Below is section of code which makes remote service calls */
-
- private static CdmApplicationRemoteConfiguration configuration;
- private static boolean remoting = false;
-
- public static void setConfiguration(CdmApplicationRemoteConfiguration conf) {
- remoting = true;
- configuration = conf;
- }
-
-
- private void remoteInitialize() {
-
- if(!initialized) {
- int classid = ((Integer)getIdentifier()).intValue();
- log.info("--> Remote Lazy Initializing Object " + getEntityName() + " with id " + classid);
- Class clazz;
- try {
- clazz = Class.forName(getEntityName());
- } catch (ClassNotFoundException e) {
- throw new HibernateException("Class for " + getEntityName() + " not found", e);
- }
- if(configuration == null) {
- throw new HibernateException("CdmApplicationRemoteConfiguration not initialized (null)");
- }
- ICachedCommonService cachedCommonService = configuration.getCachedCommonService();
- if(cachedCommonService == null) {
- throw new HibernateException("commonService not initialized (null)");
- }
-
- CdmBase cdmBase = cachedCommonService.find(clazz,classid);
- if(ProxyUtils.isUninitializedProxy(cdmBase)) {
- throw new HibernateException("CdmBase Object initialized but is still a proxy");
- }
- setImplementation(cdmBase);
-
- }
- }
-
- public static boolean isInitialized(AbstractLazyInitializer obj) {
- return obj.initialized;
- }
-}
+/* Hibernate, Relational Persistence for Idiomatic Java\r
+ *\r
+ * License: GNU Lesser General Public License (LGPL), version 2.1 or later.\r
+ * See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.\r
+ */\r
+package org.hibernate.proxy;\r
+\r
+import java.io.Serializable;\r
+\r
+import org.hibernate.FlushMode;\r
+import org.hibernate.HibernateException;\r
+import org.hibernate.LazyInitializationException;\r
+import org.hibernate.SessionException;\r
+import org.hibernate.TransientObjectException;\r
+import org.hibernate.boot.spi.SessionFactoryOptions;\r
+import org.hibernate.engine.spi.EntityKey;\r
+import org.hibernate.engine.spi.PersistenceContext;\r
+import org.hibernate.engine.spi.SessionFactoryImplementor;\r
+import org.hibernate.engine.spi.SharedSessionContractImplementor;\r
+import org.hibernate.internal.CoreLogging;\r
+import org.hibernate.internal.CoreMessageLogger;\r
+import org.hibernate.internal.SessionFactoryRegistry;\r
+import org.hibernate.persister.entity.EntityPersister;\r
+\r
+/**\r
+ * Convenience base class for lazy initialization handlers. Centralizes the basic plumbing of doing lazy\r
+ * initialization freeing subclasses to acts as essentially adapters to their intended entity mode and/or\r
+ * proxy generation strategy.\r
+ *\r
+ * @author Gavin King\r
+ */\r
+public abstract class AbstractLazyInitializer implements LazyInitializer {\r
+ private static final CoreMessageLogger LOG = CoreLogging.messageLogger( AbstractLazyInitializer.class );\r
+\r
+ private String entityName;\r
+ private Serializable id;\r
+ private Object target;\r
+ private boolean initialized;\r
+ private boolean readOnly;\r
+ private boolean unwrap;\r
+ private transient SharedSessionContractImplementor session;\r
+ private Boolean readOnlyBeforeAttachedToSession;\r
+\r
+ private String sessionFactoryUuid;\r
+ private boolean allowLoadOutsideTransaction;\r
+\r
+ /**\r
+ * @deprecated This constructor was initially intended for serialization only, and is not useful anymore.\r
+ * In any case it should not be relied on by user code.\r
+ * Subclasses should rather implement Serializable with an {@code Object writeReplace()} method returning\r
+ * a subclass of {@link AbstractSerializableProxy},\r
+ * which in turn implements Serializable and an {@code Object readResolve()} method\r
+ * instantiating the {@link AbstractLazyInitializer} subclass\r
+ * and calling {@link AbstractSerializableProxy#afterDeserialization(AbstractLazyInitializer)} on it.\r
+ * See {@link org.hibernate.proxy.pojo.bytebuddy.ByteBuddyInterceptor} and\r
+ * {@link org.hibernate.proxy.pojo.bytebuddy.SerializableProxy} for examples.\r
+ */\r
+ @Deprecated\r
+ protected AbstractLazyInitializer() {\r
+ }\r
+\r
+ /**\r
+ * Main constructor.\r
+ *\r
+ * @param entityName The name of the entity being proxied.\r
+ * @param id The identifier of the entity being proxied.\r
+ * @param session The session owning the proxy.\r
+ */\r
+ protected AbstractLazyInitializer(String entityName, Serializable id, SharedSessionContractImplementor session) {\r
+ this.entityName = entityName;\r
+ this.id = id;\r
+ // initialize other fields depending on session state\r
+ if ( session == null ) {\r
+ unsetSession();\r
+ }\r
+ else {\r
+ setSession( session );\r
+ }\r
+ }\r
+\r
+ @Override\r
+ public final String getEntityName() {\r
+ return entityName;\r
+ }\r
+\r
+ @Override\r
+ public final Serializable getInternalIdentifier() {\r
+ return id;\r
+ }\r
+\r
+ @Override\r
+ public final Serializable getIdentifier() {\r
+ if ( isUninitialized() && isInitializeProxyWhenAccessingIdentifier() ) {\r
+ initialize();\r
+ }\r
+ return id;\r
+ }\r
+\r
+ private boolean isInitializeProxyWhenAccessingIdentifier() {\r
+ return getSession() != null && getSession().getFactory()\r
+ .getSessionFactoryOptions()\r
+ .getJpaCompliance().isJpaProxyComplianceEnabled();\r
+ }\r
+\r
+ @Override\r
+ public final void setIdentifier(Serializable id) {\r
+ this.id = id;\r
+ }\r
+\r
+ @Override\r
+ public final boolean isUninitialized() {\r
+ return !initialized;\r
+ }\r
+\r
+ @Override\r
+ public final SharedSessionContractImplementor getSession() {\r
+ return session;\r
+ }\r
+\r
+ @Override\r
+ public final void setSession(SharedSessionContractImplementor s) throws HibernateException {\r
+ if ( s != session ) {\r
+ // check for s == null first, since it is least expensive\r
+ if ( s == null ) {\r
+ unsetSession();\r
+ }\r
+ else if ( isConnectedToSession() ) {\r
+ //TODO: perhaps this should be some other RuntimeException...\r
+ LOG.attemptToAssociateProxyWithTwoOpenSessions(\r
+ entityName,\r
+ id\r
+ );\r
+ throw new HibernateException( "illegally attempted to associate proxy [" + entityName + "#" + id + "] with two open Sessions" );\r
+ }\r
+ else {\r
+ // s != null\r
+ session = s;\r
+ if ( readOnlyBeforeAttachedToSession == null ) {\r
+ // use the default read-only/modifiable setting\r
+ final EntityPersister persister = s.getFactory().getEntityPersister( entityName );\r
+ setReadOnly( s.getPersistenceContext().isDefaultReadOnly() || !persister.isMutable() );\r
+ }\r
+ else {\r
+ // use the read-only/modifiable setting indicated during deserialization\r
+ setReadOnly( readOnlyBeforeAttachedToSession );\r
+ readOnlyBeforeAttachedToSession = null;\r
+ }\r
+ }\r
+ }\r
+ }\r
+\r
+ private static EntityKey generateEntityKeyOrNull(Serializable id, SharedSessionContractImplementor s, String entityName) {\r
+ if ( id == null || s == null || entityName == null ) {\r
+ return null;\r
+ }\r
+ return s.generateEntityKey( id, s.getFactory().getEntityPersister( entityName ) );\r
+ }\r
+\r
+ @Override\r
+ public final void unsetSession() {\r
+ prepareForPossibleLoadingOutsideTransaction();\r
+ session = null;\r
+ readOnly = false;\r
+ readOnlyBeforeAttachedToSession = null;\r
+ }\r
+\r
+ @Override\r
+ public final void initialize() throws HibernateException {\r
+ if ( !initialized ) {\r
+ if ( allowLoadOutsideTransaction ) {\r
+ permissiveInitialization();\r
+ }\r
+ else if ( session == null ) {\r
+ throw new LazyInitializationException( "could not initialize proxy [" + entityName + "#" + id + "] - no Session" );\r
+ }\r
+ else if ( !session.isOpenOrWaitingForAutoClose() ) {\r
+ throw new LazyInitializationException( "could not initialize proxy [" + entityName + "#" + id + "] - the owning Session was closed" );\r
+ }\r
+ else if ( !session.isConnected() ) {\r
+ throw new LazyInitializationException( "could not initialize proxy [" + entityName + "#" + id + "] - the owning Session is disconnected" );\r
+ }\r
+ else {\r
+ target = session.immediateLoad( entityName, id );\r
+ initialized = true;\r
+ checkTargetState(session);\r
+ }\r
+ }\r
+ else {\r
+ checkTargetState(session);\r
+ }\r
+ }\r
+\r
+ protected void permissiveInitialization() {\r
+ if ( session == null ) {\r
+ //we have a detached collection that is set to null, reattach\r
+ if ( sessionFactoryUuid == null ) {\r
+ throw new LazyInitializationException( "could not initialize proxy [" + entityName + "#" + id + "] - no Session" );\r
+ }\r
+ try {\r
+ SessionFactoryImplementor sf = (SessionFactoryImplementor)\r
+ SessionFactoryRegistry.INSTANCE.getSessionFactory( sessionFactoryUuid );\r
+ SharedSessionContractImplementor session = (SharedSessionContractImplementor) sf.openSession();\r
+ session.getPersistenceContext().setDefaultReadOnly( true );\r
+ session.setFlushMode( FlushMode.MANUAL );\r
+\r
+ boolean isJTA = session.getTransactionCoordinator().getTransactionCoordinatorBuilder().isJta();\r
+\r
+ if ( !isJTA ) {\r
+ // Explicitly handle the transactions only if we're not in\r
+ // a JTA environment. A lazy loading temporary session can\r
+ // be created even if a current session and transaction are\r
+ // open (ex: session.clear() was used). We must prevent\r
+ // multiple transactions.\r
+ session.beginTransaction();\r
+ }\r
+\r
+ try {\r
+ target = session.immediateLoad( entityName, id );\r
+ initialized = true;\r
+ checkTargetState(session);\r
+ }\r
+ finally {\r
+ // make sure the just opened temp session gets closed!\r
+ try {\r
+ if ( !isJTA ) {\r
+ session.getTransaction().commit();\r
+ }\r
+ session.close();\r
+ }\r
+ catch (Exception e) {\r
+ LOG.warn( "Unable to close temporary session used to load lazy proxy associated to no session" );\r
+ }\r
+ }\r
+ }\r
+ catch (Exception e) {\r
+ LOG.error( "Initialization failure [" + entityName + "#" + id + "]", e );\r
+ throw new LazyInitializationException( e.getMessage() );\r
+ }\r
+ }\r
+ else if ( session.isOpenOrWaitingForAutoClose() && session.isConnected() ) {\r
+ target = session.immediateLoad( entityName, id );\r
+ initialized = true;\r
+ checkTargetState(session);\r
+ }\r
+ else {\r
+ throw new LazyInitializationException( "could not initialize proxy [" + entityName + "#" + id + "] - Session was closed or disced" );\r
+ }\r
+ }\r
+\r
+ /**\r
+ * Attempt to initialize the proxy without loading anything from the database.\r
+ *\r
+ * This will only have any effect if the proxy is still attached to a session,\r
+ * and the entity being proxied has been loaded and added to the persistence context\r
+ * of that session since the proxy was created.\r
+ */\r
+ public final void initializeWithoutLoadIfPossible() {\r
+ if ( !initialized && session != null && session.isOpenOrWaitingForAutoClose() ) {\r
+ final EntityKey key = session.generateEntityKey(\r
+ getInternalIdentifier(),\r
+ session.getFactory().getMetamodel().entityPersister( getEntityName() )\r
+ );\r
+ final Object entity = session.getPersistenceContextInternal().getEntity( key );\r
+ if ( entity != null ) {\r
+ setImplementation( entity );\r
+ }\r
+ }\r
+ }\r
+\r
+ /**\r
+ * Initialize internal state based on the currently attached session,\r
+ * in order to be ready to load data even after the proxy is detached from the session.\r
+ *\r
+ * This method only has any effect if\r
+ * {@link SessionFactoryOptions#isInitializeLazyStateOutsideTransactionsEnabled()} is {@code true}.\r
+ */\r
+ protected void prepareForPossibleLoadingOutsideTransaction() {\r
+ if ( session != null ) {\r
+ allowLoadOutsideTransaction = session.getFactory().getSessionFactoryOptions().isInitializeLazyStateOutsideTransactionsEnabled();\r
+\r
+ if ( allowLoadOutsideTransaction && sessionFactoryUuid == null ) {\r
+ sessionFactoryUuid = session.getFactory().getUuid();\r
+ }\r
+ }\r
+ }\r
+\r
+ private void checkTargetState(SharedSessionContractImplementor session) {\r
+ if ( !unwrap ) {\r
+ if ( target == null ) {\r
+ session.getFactory().getEntityNotFoundDelegate().handleEntityNotFound( entityName, id );\r
+ }\r
+ }\r
+ }\r
+\r
+ /**\r
+ * Getter for property 'connectedToSession'.\r
+ *\r
+ * @return Value for property 'connectedToSession'.\r
+ */\r
+ protected final boolean isConnectedToSession() {\r
+ return getProxyOrNull() != null;\r
+ }\r
+\r
+ private Object getProxyOrNull() {\r
+ final EntityKey entityKey = generateEntityKeyOrNull( getInternalIdentifier(), session, getEntityName() );\r
+ if ( entityKey != null && session != null && session.isOpenOrWaitingForAutoClose() ) {\r
+ return session.getPersistenceContextInternal().getProxy( entityKey );\r
+ }\r
+ return null;\r
+ }\r
+\r
+ @Override\r
+ public final Object getImplementation() {\r
+ initialize();\r
+ return target;\r
+ }\r
+\r
+ @Override\r
+ public final void setImplementation(Object target) {\r
+ this.target = target;\r
+ initialized = true;\r
+ }\r
+\r
+ @Override\r
+ public final Object getImplementation(SharedSessionContractImplementor s) throws HibernateException {\r
+ final EntityKey entityKey = generateEntityKeyOrNull( getInternalIdentifier(), s, getEntityName() );\r
+ return ( entityKey == null ? null : s.getPersistenceContext().getEntity( entityKey ) );\r
+ }\r
+\r
+ /**\r
+ * Getter for property 'target'.\r
+ * <p/>\r
+ * Same as {@link #getImplementation()} except that this method will not force initialization.\r
+ *\r
+ * @return Value for property 'target'.\r
+ */\r
+ protected final Object getTarget() {\r
+ return target;\r
+ }\r
+\r
+ @Override\r
+ public final boolean isReadOnlySettingAvailable() {\r
+ return (session != null && !session.isClosed());\r
+ }\r
+\r
+ private void errorIfReadOnlySettingNotAvailable() {\r
+ if ( session == null ) {\r
+ throw new TransientObjectException(\r
+ "Proxy [" + entityName + "#" + id + "] is detached (i.e, session is null). The read-only/modifiable setting is only accessible when the proxy is associated with an open session."\r
+ );\r
+ }\r
+ if ( !session.isOpenOrWaitingForAutoClose() ) {\r
+ throw new SessionException(\r
+ "Session is closed. The read-only/modifiable setting is only accessible when the proxy [" + entityName + "#" + id + "] is associated with an open session."\r
+ );\r
+ }\r
+ }\r
+\r
+ @Override\r
+ public final boolean isReadOnly() {\r
+ errorIfReadOnlySettingNotAvailable();\r
+ return readOnly;\r
+ }\r
+\r
+ @Override\r
+ public final void setReadOnly(boolean readOnly) {\r
+ errorIfReadOnlySettingNotAvailable();\r
+ // only update if readOnly is different from current setting\r
+ if ( this.readOnly != readOnly ) {\r
+ final EntityPersister persister = session.getFactory().getEntityPersister( entityName );\r
+ if ( !persister.isMutable() && !readOnly ) {\r
+ throw new IllegalStateException( "cannot make proxies [" + entityName + "#" + id + "] for immutable entities modifiable" );\r
+ }\r
+ this.readOnly = readOnly;\r
+ if ( initialized ) {\r
+ EntityKey key = generateEntityKeyOrNull( getInternalIdentifier(), session, getEntityName() );\r
+ final PersistenceContext persistenceContext = session.getPersistenceContext();\r
+ if ( key != null && persistenceContext.containsEntity( key ) ) {\r
+ persistenceContext.setReadOnly( target, readOnly );\r
+ }\r
+ }\r
+ }\r
+ }\r
+\r
+ /**\r
+ * Get the read-only/modifiable setting that should be put in affect when it is\r
+ * attached to a session.\r
+ * <p/>\r
+ * This method should only be called during serialization when read-only/modifiable setting\r
+ * is not available (i.e., isReadOnlySettingAvailable() == false)\r
+ *\r
+ * @return null, if the default setting should be used;\r
+ * true, for read-only;\r
+ * false, for modifiable\r
+ *\r
+ * @throws IllegalStateException if isReadOnlySettingAvailable() == true\r
+ */\r
+ public final Boolean isReadOnlyBeforeAttachedToSession() {\r
+ if ( isReadOnlySettingAvailable() ) {\r
+ throw new IllegalStateException(\r
+ "Cannot call isReadOnlyBeforeAttachedToSession when isReadOnlySettingAvailable == true [" + entityName + "#" + id + "]"\r
+ );\r
+ }\r
+ return readOnlyBeforeAttachedToSession;\r
+ }\r
+\r
+ /**\r
+ * Get whether the proxy can load data even\r
+ * if it's not attached to a session with an ongoing transaction.\r
+ *\r
+ * This method should only be called during serialization,\r
+ * and only makes sense after a call to {@link #prepareForPossibleLoadingOutsideTransaction()}.\r
+ *\r
+ * @return {@code true} if out-of-transaction loads are allowed, {@code false} otherwise.\r
+ */\r
+ protected boolean isAllowLoadOutsideTransaction() {\r
+ return allowLoadOutsideTransaction;\r
+ }\r
+\r
+ /**\r
+ * Get the session factory UUID.\r
+ *\r
+ * This method should only be called during serialization,\r
+ * and only makes sense after a call to {@link #prepareForPossibleLoadingOutsideTransaction()}.\r
+ *\r
+ * @return the session factory UUID.\r
+ */\r
+ protected String getSessionFactoryUuid() {\r
+ return sessionFactoryUuid;\r
+ }\r
+\r
+ /**\r
+ * Restore settings that are not passed to the constructor,\r
+ * but are still preserved during serialization.\r
+ *\r
+ * This method should only be called during deserialization, before associating\r
+ * the proxy with a session.\r
+ *\r
+ * @param readOnlyBeforeAttachedToSession the read-only/modifiable setting to use when\r
+ * associated with a session; null indicates that the default should be used.\r
+ * @param sessionFactoryUuid the session factory uuid, to be used if {@code allowLoadOutsideTransaction} is {@code true}.\r
+ * @param allowLoadOutsideTransaction whether the proxy can load data even\r
+ * if it's not attached to a session with an ongoing transaction.\r
+ *\r
+ * @throws IllegalStateException if isReadOnlySettingAvailable() == true\r
+ */\r
+ /* package-private */\r
+ final void afterDeserialization(Boolean readOnlyBeforeAttachedToSession,\r
+ String sessionFactoryUuid, boolean allowLoadOutsideTransaction) {\r
+ if ( isReadOnlySettingAvailable() ) {\r
+ throw new IllegalStateException(\r
+ "Cannot call afterDeserialization when isReadOnlySettingAvailable == true [" + entityName + "#" + id + "]"\r
+ );\r
+ }\r
+ this.readOnlyBeforeAttachedToSession = readOnlyBeforeAttachedToSession;\r
+\r
+ this.sessionFactoryUuid = sessionFactoryUuid;\r
+ this.allowLoadOutsideTransaction = allowLoadOutsideTransaction;\r
+ }\r
+\r
+ @Override\r
+ public boolean isUnwrap() {\r
+ return unwrap;\r
+ }\r
+\r
+ @Override\r
+ public void setUnwrap(boolean unwrap) {\r
+ this.unwrap = unwrap;\r
+ }\r
+}\r