/*
 * JBoss, the OpenSource J2EE webOS
 *
 * Distributable under LGPL license.
 * See terms of license at gnu.org.
 */
package org.jboss.ejb;

import java.rmi.RemoteException;

import javax.ejb.EJBContext;
import javax.ejb.EJBHome;
import javax.ejb.EJBObject;
import javax.ejb.EJBLocalObject;
import javax.ejb.EJBLocalObject;
import javax.ejb.EJBObject;
import javax.ejb.EntityBean;
import javax.ejb.EntityContext;

import javax.transaction.Transaction;

/**
 * The EntityEnterpriseContext is used to associate EntityBean instances
 * with metadata about it.
 *
 * @see EnterpriseContext
 * 
 * @author <a href="mailto:rickard.oberg@telkel.com">Rickard Öberg</a>
 * @author <a href="mailto:marc.fleury@telkel.com">Marc Fleury</a>
 * @author <a href="mailto:docodan@mvcsoft.com">Daniel OConnor</a>
 * @version $Revision: 1.18.4.5 $
 *
 * <p><b>Revisions</b>
 * <p>20010703 marcf
 * <ol>
 * <li>setInvoked replaced by "hasTxSynchronization", the reason being that we
 *     use it for Tx registration.
 * </ol>
 */
public class EntityEnterpriseContext
   extends EnterpriseContext
{
   // Attributes ----------------------------------------------------
   
   EJBObject ejbObject;
   EJBLocalObject ejbLocalObject;
   EntityContext ctx;
	
   /**
    * True if this instance has been registered with the TM for transactional
    * demarcation.
    */
   boolean hasTxSynchronization = false;
	
   /**
    * True if this instances' state is valid when a bean is called the state
    * is not synchronized with the DB but "valid" as long as the transaction
    * runs.
    */
   boolean valid = false;
	
   /**
    * The persistence manager may attach any metadata it wishes to this
    * context here.
    */
   private Object persistenceCtx;
	
   /** The cacheKey for this context */
   CacheKey key;
	
   // Constructors --------------------------------------------------
   
   public EntityEnterpriseContext(Object instance, Container con)
      throws RemoteException
   {
      super(instance, con);
      ctx = new EntityContextImpl();
      ((EntityBean)instance).setEntityContext(ctx);
   }
	
   // Public --------------------------------------------------------
	
   public void clear()
   {
      if( log.isTraceEnabled() )
         log.trace("clear, key="+key);
      super.clear();

      this.hasTxSynchronization = false;
      this.valid = false;
      key = null;
      persistenceCtx = null;
      ejbObject = null;
   }

   public void discard() throws RemoteException
   {
      if( log.isTraceEnabled() )
         log.trace("discard, key="+key);
      EntityBean bean = (EntityBean) getInstance();
      bean.unsetEntityContext();
      ctx = null;
   }

   public EJBContext getEJBContext()
   {
      return ctx;
   }

   public void setEJBObject(EJBObject eo)
   {
      ejbObject = eo;
   }
	
   public EJBObject getEJBObject()
   {
      // Context can have no EJBObject (created by finds) in which case
      // we need to wire it at call time
      return ejbObject;
   }
	
   public void setEJBLocalObject(EJBLocalObject eo)
   {
      ejbLocalObject = eo;
   }
	
   public EJBLocalObject getEJBLocalObject()
   {
      return ejbLocalObject;
   }
	
   public void setCacheKey(Object key)
   {
      this.key = (CacheKey) key;
   }
	
   public CacheKey getCacheKey()
   {
      return key;
   }

   public void setPersistenceContext(Object ctx)
   {
      this.persistenceCtx = ctx;
   }
	
   public Object getPersistenceContext()
   {
      return persistenceCtx;
   }

   public void hasTxSynchronization(boolean value)
   {
      hasTxSynchronization = value;
   }
	
   public boolean hasTxSynchronization()
   {
      return hasTxSynchronization;
   }
	
   public void setValid(boolean valid)
   {
      this.valid = valid;
   }
	
   public boolean isValid()
   {
      return valid;
   }
	
   // Inner classes -------------------------------------------------
   
   protected class EntityContextImpl
      extends EJBContextImpl
      implements EntityContext
   {
      private EntityContainer getEntityContainer()
      {
         return (EntityContainer) getContainer();
      }

      public EJBObject getEJBObject()
      {
         if( getEntityContainer().getContainerInvoker()==null )
            throw new IllegalStateException( "No remote interface defined." );
         
         if (ejbObject == null)
         {
            try
            {
               // Create a new CacheKey
               EntityCache cache = (EntityCache) getEntityContainer().getInstanceCache();
               Object cacheKey = cache.createCacheKey(id);
               ejbObject = getEntityContainer().getContainerInvoker().getEntityEJBObject(cacheKey);
            }
            catch (RemoteException re)
            {
               throw new IllegalStateException();
            }
         }

         return ejbObject;
      }
		
      public EJBLocalObject getEJBLocalObject()
      {
         if (getEntityContainer().getLocalHomeClass()==null)
            throw new IllegalStateException( "No local interface for bean." );

         if (ejbLocalObject == null)
         {
            EntityCache cache = (EntityCache) getEntityContainer().getInstanceCache();
            Object cacheKey = cache.createCacheKey(id);            
            ejbLocalObject = getEntityContainer().getLocalContainerInvoker().getEntityEJBLocalObject(cacheKey);
         }
         return ejbLocalObject;
      }
		
      public Object getPrimaryKey()
      {
         return id;
      }
   }
}
