/*
 * JOnAS: Java(TM) Open Application Server
 * Copyright (C) 1999 Bull S.A.
 * Contact: jonas-team@objectweb.org
 * 
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or any later version.
 * 
 * This library 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 library; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307
 * USA
 *
 * Initial developer(s): Philippe Coq
 * Contributor(s): Jeff Mesnil (security)
 *
 * --------------------------------------------------------------------------
 * $Id$
 * --------------------------------------------------------------------------
 */

package org.objectweb.jonas_ejb.container;

import java.lang.IllegalStateException;
import java.util.Properties;
import java.security.Identity;
import java.security.Principal;
import java.security.Guard;
import java.util.Properties;
import javax.ejb.EJBContext;
import javax.ejb.EJBHome;
import javax.ejb.EJBLocalHome;
import javax.ejb.EnterpriseBean;
import javax.transaction.Status;
import javax.transaction.SystemException;
import javax.transaction.TransactionManager;
import javax.transaction.UserTransaction;

/**
 * This class implements javax.ejb.EJBContext class.
 * It may be extended in JSessionContext or JEntityContext
 */
public class JContext implements EJBContext { 

    protected EnterpriseBean instance = null;
    protected JFactory bf = null;
    protected JHome home = null;
    protected JLocalHome localhome = null;
    protected JContainer cont = null;
    protected Guard roleGuard = null;
    protected TransactionManager tm = null;

    // ------------------------------------------------------------------
    // constructors
    // ------------------------------------------------------------------

    /**
     * Constructs a JContext
     * @param bf -  the BeanFactory
     */
    public JContext(JFactory bf, EnterpriseBean i) {
	this.bf = bf;
	this.instance = i;
	if (i == null) {
	    TraceEjb.error("JContext constructor: null EnterpriseBean!");
	}
	this.cont = bf.getContainer();
	this.tm = bf.getTransactionManager();
	this.roleGuard = cont.getRoleGuard();
    }

    // ------------------------------------------------------------------
    // EJBContext implementation
    // ------------------------------------------------------------------

    /**
     * Obtains the java.security.Identity of the caller. 
     * DEPRECATED
     * @return The Identity object that identifies the caller.
     */
    public Identity getCallerIdentity() {
	throw new RuntimeException ("getCallerIdentity() method deprecated. use instead getCallerPrincipal()");
    }


    /**
     * Obtain the java.security.Principal that identifies the caller.
     * throws a java.lang.IllegalStateException if there is no security context available 
     * @return The Principal object that identifies the caller.
     */
    public Principal getCallerPrincipal() throws IllegalStateException {
	
	Principal principal = cont.getPrincipalFactory().getCallerPrincipal();
	if (principal == null) {
	    throw new IllegalStateException("no security context exists");
	}
	return principal;
    } 

    /** 
     * the enterprise bean's home interface. 
     * @return The enterprise bean's home interface. 
     * @throws IllegalStateException - if the enterprise bean does not have a local home interface.
     */
    public EJBHome getEJBHome() throws IllegalStateException {
	return home;
    }

    /**
     * Obtain the enterprise bean's local home interface.
     * @return The enterprise bean's local home interface.
     * @throws IllegalStateException if the enterprise bean does not have a local home interface.
     */
    public EJBLocalHome getEJBLocalHome() throws IllegalStateException {
	return localhome;
    }

    /**
     * Obtains the enterprise bean's environment properties for EJB 1.0 style.
     * (Conform to EJB 1.1 specification for a container chooses to provide support
     *  for EJB 1.0 style environment properties. Cf EJB 1.1 Chapter 14.5, pages 216-217)
     *  Note: If the enterprise bean has no environment properties, this method returns an empty 
     *        java.util.Properties object. This method never returns null. 
     * @return The environment properties for the enterprise bean. 
     */
    public Properties getEnvironment() {
	TraceEjb.debugIc("JContext.getEnvironment");
	return bf.getEjb10Environment();
    }
	
    /** 
     * Tests if the transaction has been marked for rollback only.
     */
    public boolean getRollbackOnly() {
	TraceEjb.debugIc("JContext.getRollbackOnly() ");

	try {
	    switch (tm.getStatus()) {
	    case Status.STATUS_MARKED_ROLLBACK:
	    case Status.STATUS_ROLLEDBACK:
	    case Status.STATUS_ROLLING_BACK:
		return true;
	    default:
		return false;
	    } 
	} catch (SystemException e) {
	    TraceEjb.error("Cannot get status:", e);
	}
	return true;
    }
 	
    /**
     * Obtains the transaction demarcation interface. 
     * @return The UserTransaction interface that the enterprise bean instance 
     *         can use for transaction demarcation.  
     * @exception IllegalStateException: Thrown if the instance container does 
     *            not make the UserTransaction interface available to the 
     *            instance. (not bean managed)
     */
    public UserTransaction getUserTransaction() throws IllegalStateException {

	TraceEjb.debugIc("JContext.getUserTransaction() ");

	if (bf.isTxBeanManaged() == false) {
	    throw  new IllegalStateException("This bean is not allowed to use UserTransaction interface");
	}
	return (UserTransaction) tm;
    }

    /**
     * Deprecated. Use boolean isCallerInRole(String roleName) instead.
     * Tests if the caller has a given role.
     * @param role - The java.security.Identity of the role to be tested. 
     * @return True if the caller has the specified role. 
     */
    public boolean isCallerInRole(Identity role) {
	throw new RuntimeException ("isCallerInRole(Identity) method deprecated. use instead isCallerInRole(String)");
    }

    /**
     * Test if the caller has a given role.
     *
     * @param roleName The name of the security role. 
     * The role must be one of the security-role-ref  that is defined in the 
     * deployment descriptor.
     *
     * @return True if the caller has the specified role.
     */
    public boolean isCallerInRole(java.lang.String roleLink) throws IllegalStateException {
	TraceEjb.debugSecurity("JContext.isCallerInRole() ");
	if (roleGuard == null)
	    throw new IllegalStateException("Security service not started");
	try {
	    roleGuard.checkGuard(roleLink);
	    return true;
	} catch (SecurityException e) {
	    TraceEjb.verbose("isCallerInRole: No!");
	    return false;
	}
    }

    /** 
     * Marks the current transaction for rollback.
     * The transaction will become permanently marked for rollback.
     *
     */
    public void setRollbackOnly() {

	TraceEjb.debugIc("JContext.setRollbackOnly() ");

	try {
	    tm.setRollbackOnly();
	} catch (IllegalStateException e) {
	    TraceEjb.error("Current thread not associated with transaction");
	} catch (SystemException e) {
	    TraceEjb.error("setRollbackOnly unexpected exception:", e);
	}
    }

}
