+++ /dev/null
-/*
- * 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.api.cache.ICachedCommonService;
-import eu.etaxonomy.cdm.model.common.CdmBase;
-
-/**
- * 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();
-
- 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 = CdmBase.deproxy(cachedCommonService.find(clazz,classid),clazz);
- setImplementation(cdmBase);
-
- }
- }
-
- public static boolean isInitialized(AbstractLazyInitializer obj) {
- return obj.initialized;
- }
-}