/*******************************************************************************
 * This file is part of GECAMed.
 * 
 * GECAMed is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License (L-GPL) as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 * 
 * GECAMed 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 (L-GPL)
 * along with GECAMed.  If not, see <http://www.gnu.org/licenses/>.
 * 
 * GECAMed is Copyrighted by the Centre de Recherche Public Henri Tudor (http://www.tudor.lu)
 * (c) CRP Henri Tudor, Luxembourg, 2008
 *******************************************************************************/
package lu.tudor.santec.gecamed.core.ejb.session.beans;

import javax.annotation.Resource;
import javax.ejb.SessionContext;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.transaction.Status;

import org.apache.log4j.Level;
import org.apache.log4j.Logger;

//***************************************************************************
//* Interface Definition and Members                                        *
//***************************************************************************

/**
 * The GECAMedSessionBean class implements commonly used methods and defines
 * commonly used class members for typical GECAMed session beans.
 * @author nico.mack@tudor.lu
 * @created 08/02/01
 */

public class GECAMedSessionBean 
	{
	private int	m_TransactionTimeout;
	
	@PersistenceContext (unitName="gecam")
	protected EntityManager m_EntityManager;

	@Resource 
	protected SessionContext m_Session;
	
	private static Logger m_Logger = Logger.getLogger(GECAMedSessionBean.class);

//***************************************************************************
//* Constants		                                                        *
//***************************************************************************

	private static final int	c_TransactionTimeout	= 300; // 5 Minutes

//***************************************************************************
//* Constructor(s)                                                          *
//***************************************************************************
//---------------------------------------------------------------------------
	
	public GECAMedSessionBean ()
		{
		m_TransactionTimeout = 	c_TransactionTimeout;
		this.setLoggerForClass (this.getClass());
		}
		
	//---------------------------------------------------------------------------
	/**
	 * The postConstruct method is part of the bean lifecycle interface and its
	 * being called just after the bean has been created. The RuleBean uses this
	 * moment to compile the packaged rules and to initialize the Rule Engine
	 * itself.
	 */
	//---------------------------------------------------------------------------
		    
	//@PostConstruct
	//public void postConstruct ()
	//	{
	//	
	//	}
	
	//---------------------------------------------------------------------------
	//***************************************************************************
	//* Class Primitives                                                        *
	//***************************************************************************
	//---------------------------------------------------------------------------
	
		/**
		 * Logs in info level
		 * 
		 * @param message
		 */
		protected void info(String message) {
			/* ================================================== */
			log(Level.INFO, message);
			/* ================================================== */
		}
	
	/**
	 * writes the specified message with the specified log level into the log
	 * file.
	 * @param p_Level specifies the log level the specified message should have.
	 * @param p_Message specifies the message to be written to log file.
	 */
	//---------------------------------------------------------------------------
	
	protected void log (Level p_Level, String p_Message)
		{
		this.log(p_Level,p_Message,null);
		}
	
	//---------------------------------------------------------------------------
	/**
	 * writes the specified message with the specified log level into the log
	 * file. The stack trace of the specified exception will be logged to.
	 * @param p_Level specifies the log level the specified message should have.
	 * @param p_Message specifies the message to be written to log file.
	 * @param p_Exception specifies the exception to log stack trace of.
	 */
	//---------------------------------------------------------------------------
	
	protected void log (Level p_Level, String p_Message, Exception p_Exception)
		{
		StackTraceElement[] l_StackTrace; 
		String				l_MethodName;
			                  
		l_StackTrace = new Throwable().getStackTrace();
		l_MethodName = l_StackTrace[1].getMethodName();
			
		if (l_MethodName.equals("log")) l_MethodName = l_StackTrace[2].getMethodName();
		p_Message = "\n" + l_MethodName + " => " + p_Message;
				
		if (p_Exception != null) m_Logger.log (p_Level,p_Message,p_Exception);
							else m_Logger.log (p_Level,p_Message);
		}
	
	//---------------------------------------------------------------------------
	/**
	 * Since this bean is a stateful session bean we will manage database transaction
	 * by ourselves. The openTransaction method opens a new transaction and MUST be
	 * called before executing any query. If a previous transaction is still pending,
	 * the method will rollback that query before beginning a new one.
	 */
	//---------------------------------------------------------------------------
	
	protected void openTransaction ()
		{
		try	{
			if (m_Session.getUserTransaction().getStatus() == Status.STATUS_ACTIVE)
				{
				this.log(Level.DEBUG, "Pending open Transaction! Rolling back now!");
				m_Session.getUserTransaction().rollback();
				}
	
			this.log(Level.DEBUG, "Beginning new transaction!");
			m_Session.getUserTransaction().setTransactionTimeout(m_TransactionTimeout);
			m_Session.getUserTransaction().begin ();
			}
		catch (Exception p_Exception)
			{
			this.log(Level.ERROR, "Failed to begin Transaction", p_Exception);
			}
		}
	
	//---------------------------------------------------------------------------
	/**
	 * Closes a previously opened transaction. Depending on the state of the specified
	 * success flag, the method will either commit or rollback the transaction.
	 * @param p_Success specifies how to close the transaction. <code>true</code>
	 * will commit the transaction whereas <code>false</code> will rollback.
	 */
	//---------------------------------------------------------------------------
	
	protected void closeTransaction (boolean p_Success)
		{
		try	{
			if (m_Session.getUserTransaction().getStatus() == Status.STATUS_ACTIVE)
				{
				if (p_Success)
					{	
					this.log(Level.DEBUG, "Commiting Transaction!");
					m_Session.getUserTransaction().commit();
					}
				else	
					{
					this.log(Level.DEBUG, "Rolling back Transaction!");
					m_Session.getUserTransaction().rollback();
					}
				}
			else this.log(Level.DEBUG, "No open Transaction to close!");
			}
		catch (Exception p_Exception)
			{
			this.log(Level.ERROR, "Failed to close Transaction", p_Exception);
			}
		}
	
	//---------------------------------------------------------------------------
	/**
	 * sets the logger for the specified class.
	 * @param p_ExtendingClass specfies the extending class to set logger for.
	 */
	//---------------------------------------------------------------------------
	
	protected void setLoggerForClass (Class<?> p_ExtendingClass)
		{
		m_Logger = Logger.getLogger(p_ExtendingClass);
		}
	
	//---------------------------------------------------------------------------
	/**
	 * Returns the logger object for this bean.
	 * @return the current logger object.
	 */
	//---------------------------------------------------------------------------
	
	protected Logger getLogger ()
		{
		return m_Logger;
		}
	
	//---------------------------------------------------------------------------
	/**
	 * Sets the logger for this bean.
	 * @param p_Logger specifies the new logger for this bean.
	 */
	//---------------------------------------------------------------------------
	
	protected void setLogger (Logger p_Logger)
		{
		m_Logger = p_Logger;
		if (m_Logger == null) m_Logger = Logger.getLogger(GECAMedSessionBean.class);
		}
	
	//---------------------------------------------------------------------------
	/**
	 * Returns the entity manager of this bean.
	 * @return the entity manager.
	 */
	//---------------------------------------------------------------------------
	
	protected EntityManager getEntityManager ()
		{
		return m_EntityManager;
		}
	
	//---------------------------------------------------------------------------
	/**
	 * Sets the entity manager for this bean.
	 * @param p_EntityManager specifies the new entity manager for this bean.
	 */
	//---------------------------------------------------------------------------
	
	protected void setEntityManager (EntityManager p_EntityManager)
		{
		m_EntityManager = p_EntityManager;
		}
	
	//---------------------------------------------------------------------------
	/**
	 * Returns the session context of this bean.
	 * @return the session context.
	 */
	//---------------------------------------------------------------------------
	
	protected SessionContext getSessionContext ()
		{
		return m_Session;
		}
	
	//---------------------------------------------------------------------------
	/**
	 * Sets the session context for this bean.
	 * @param p_Session specifies the new session context for this bean.
	 */
	//---------------------------------------------------------------------------
	
	protected void setSessionContext (SessionContext p_Session)
		{
		m_Session = p_Session;
		}
	
	//---------------------------------------------------------------------------
	/**
	 * Returns the transaction timeout for this bean. Value is only of interest
	 * if transaction type of bean is set to TransactionManagementType.BEAN and
	 * bean uses openTransaction and closeTransaction methods.
	 * @return the transaction timeout expressed in seconds.
	 */
	//---------------------------------------------------------------------------
	
	protected int getTransactionTimeout ()
		{
		return m_TransactionTimeout;
		}
	
	//---------------------------------------------------------------------------
	/**
	 * Sets the transaction timeout for this bean. Value will only be considered
	 * if transaction type of bean is set to TransactionManagementType.BEAN and
	 * bean uses openTransaction and closeTransaction methods.
	 * @param p_Timeout specifies the new session timeout expressed in seconds.
	 */
	//---------------------------------------------------------------------------
	
	protected void setTransactionTimeout (int p_Timeout)
		{
		m_TransactionTimeout = p_Timeout;
		}
	
	
	 
	
//	public static <T extends GECAMedEntityBean> T find (Class<T> clazz, Integer id)
//	{
//		return getListManager().getBean(clazz, id);
//	}
//	
//	
//	public static <T extends GECAMedEntityBean> T merge (T bean)
//	{
//		return getListManager().saveBean(bean);
//	}
//	
//	
//	private static ListManagerInterface getListManager ()
//	{
//		ListManagerInterface manager;
//		try
//		{
//			manager = (ListManagerInterface) ManagerFactory.getRemote(ListManagerBean.class);
//		}
//		catch (Throwable outer)
//		{
//			try
//			{
//				manager = (ListManagerInterface) ManagerFactory.getLocal(ListManagerBean.class);
//			}
//			catch (Throwable inner)
//			{
//				m_Logger.error("First attempt to load manager failed, because of following Exception:", outer);
//				m_Logger.error("Second attempt to load manager failed, because of following Exception:", inner);
//				
//				return null;
//			}
//		}
//		
//		return listManager;
//	}
	
	//---------------------------------------------------------------------------
	//***************************************************************************
	//* End of Class															*
	//***************************************************************************
	//---------------------------------------------------------------------------
}
