/*
 * 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
 *
 * --------------------------------------------------------------------------
 * $Id$
 * --------------------------------------------------------------------------
 */

// BaseCommon.java

package org.objectweb.jonas.jtests.beans.secured;

import java.io.Serializable;
import java.rmi.RemoteException;
import java.security.Principal;
import java.util.Hashtable;

import javax.ejb.EJBContext;
import javax.ejb.EJBException;
import javax.ejb.TimedObject;
import javax.ejb.Timer;
import javax.ejb.TimerService;
import javax.naming.Context;
import javax.naming.InitialContext;
import javax.rmi.PortableRemoteObject;

import org.objectweb.util.monolog.api.BasicLevel;
import org.objectweb.util.monolog.api.Logger;

public abstract class BaseCommon implements TimedObject {

    static Logger logger = null;
    static protected int timercount = 0;

    public abstract EJBContext   getEJBContext();

    /**
     * Name of the principal 1
     */
    protected static String PRINCIPAL1_NAME = "principal1";


    /**
     * Name of the role 1
     */
    protected static String ROLE1_NAME = "role1";

    // ------------------------------------------------------------------
    // Base implementation
    // ------------------------------------------------------------------

    public String getPrincipalName() throws RemoteException {

        Principal callerPrincipal = getEJBContext().getCallerPrincipal();
        logger.log(BasicLevel.DEBUG, "principal = "+callerPrincipal.getName());
        return callerPrincipal.getName();
    }

    public String localGetPrincipalName() {
        Principal callerPrincipal = getEJBContext().getCallerPrincipal();
        logger.log(BasicLevel.DEBUG, "principal = "+callerPrincipal.getName());
        return callerPrincipal.getName();
    }

    /*
     * Access to the Derived bean
     */

    public String getPrincipalNameOfAnotherBean() throws RemoteException {
        logger.log(BasicLevel.DEBUG, "");
        try {
            Context it = new InitialContext();
            DerivedHome h = (DerivedHome) PortableRemoteObject.narrow(it.lookup("securedDerivedSFHome"), 
                                                                      DerivedHome.class);
            Derived other = h.create();
            return other.getPrincipalName();
        } catch (RemoteException e) {
            throw e;
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }

    /**
     * This method is in excluded list in DD 
     * @throws RemoteException if access failed
     */
    public void excludedMethod() throws RemoteException {
        logger.log(BasicLevel.DEBUG, "");
    }
        
    /**
     * Access to a local interface of a bean
     * we must catch access denied exception 
     */
    public boolean  callAnotherMethod() throws RemoteException {
       	logger.log(BasicLevel.DEBUG, ""); 
        try {
	    Context it = new InitialContext();
	    DerivedLocalHome h = (DerivedLocalHome)it.lookup("java:comp/env/ejb/derivedlocal");
	    DerivedLocal  other = h.create();
	    other.anotherMethod();
        } catch (EJBException e) {
	    return false;
        }catch (Exception e) {
	    e.printStackTrace();
            return false;
	}
        return true;
    }

    public boolean isCallerInRole(String role) throws RemoteException {
        logger.log(BasicLevel.DEBUG, "isCallerInRole "+role);
        return getEJBContext().isCallerInRole(role);
    }

    public boolean localIsCallerInRole(String role) {
        logger.log(BasicLevel.DEBUG, "isCallerInRole "+role);
        return getEJBContext().isCallerInRole(role);
    }

    public void simpleMethod() throws RemoteException {
        logger.log(BasicLevel.DEBUG, "");
    }

    public void complexMethod(Hashtable h, Object[] o) throws RemoteException {
        logger.log(BasicLevel.DEBUG, "");
    }
 
    public int getTimerCount() throws RemoteException {
        logger.log(BasicLevel.DEBUG, "");
        return timercount;
    }

    public int setTimer(int dur, int period, int action) throws RemoteException {
        logger.log(BasicLevel.DEBUG, "");
        TimerService timerservice = getEJBContext().getTimerService();
        if (period > 0) {
            timerservice.createTimer(dur * 1000, period * 1000, new Integer(action));
        } else {
            timerservice.createTimer(dur * 1000, new Integer(action));
        }
        return action;
    }

    // -----------------------------------------------------------
    // TimedObject implementation
    // -----------------------------------------------------------

    /**
     * A timer is expired.
     */
    public void ejbTimeout(Timer timer) {
        logger.log(BasicLevel.DEBUG, "");
        Serializable sz = timer.getInfo();
        if (!(sz instanceof Integer)) {
            logger.log(BasicLevel.ERROR, "Bad Info");
            return;
        }
        int action = ((Integer)sz).intValue();
        boolean ok = true;
        switch (action) {
            case 0:
                try {
                    simpleMethod();
                } catch (RemoteException e) {
                    logger.log(BasicLevel.ERROR, "Can't call a simple Method");
                    return;
                }
                break;
            case 1:
                try {
                    ok = callBeanNoRunAsWithRole1();
                } catch (RemoteException e) {
                    logger.log(BasicLevel.ERROR, "run as role1 failed");
                    return;
                }
                break;
            case 2:
                try {
                    ok = callBeanNoRunAsWithRole2();
                } catch (RemoteException e) {
                    logger.log(BasicLevel.ERROR, "run as role2 failed");
                    return;
                }
                break;
        }
        if (ok) {
            timercount++;
        }
    }

    // ------------------------------------------------------------------
    // Methods for runAs test
    // ------------------------------------------------------------------
    

    // Execute a method without runAs on the derived bean
    public boolean callBeanNoRunAsWithRole1() throws RemoteException {
       	logger.log(BasicLevel.DEBUG, ""); 
        try {
            Context ictx = new InitialContext();
            DerivedLocalHome h = (DerivedLocalHome) ictx.lookup("java:comp/env/ejb/derivednorunaslocal");
            DerivedLocal  other = h.create();
            other.noRunAsWithRole1();
            if (!(getPrincipalName().equals(other.localGetPrincipalName()))) {
                throw new Exception("Principal of the other bean must be the same");
            }
            if (!other.localIsCallerInRole("role1")) {
                throw new Exception("Role of the other bean must be role1");
            }
        } catch (EJBException e) {
            return false;
        }catch (Exception e) {
            e.printStackTrace();
            return false;
        }
        return true;
    }

    // Execute a method with runAs on the derived bean
    public boolean callBeanNoRunAsWithRole2() throws RemoteException {
       	logger.log(BasicLevel.DEBUG, ""); 
        try {
            Context ictx = new InitialContext();
            DerivedLocalHome h = (DerivedLocalHome) ictx.lookup("java:comp/env/ejb/derivednorunaslocal");
            DerivedLocal  other = h.create();
            other.noRunAsWithRole2();
            // run as is executed with principal = (runas role) = role1
            if (!("role1".equals(other.localGetPrincipalName()))) {
                throw new Exception("Principal of the other bean must be the same");
            }
            // run as is executed with role role1
            if (!other.localIsCallerInRole("role1")) {
                throw new Exception("Role of the other bean must be role2");
            }
        } catch (EJBException e) {
            return false;
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
        return true;
    }


    // Execute a method without being in runAs mode on a runAs derived bean
    public boolean callBeanRunAsWithRole1() throws RemoteException {
       	logger.log(BasicLevel.DEBUG, ""); 
        try {
            Context ictx = new InitialContext();
            DerivedLocalHome h = (DerivedLocalHome)ictx.lookup("java:comp/env/ejb/derivedrunaslocal");
            try {
                DerivedLocal  other = h.create();
            } catch (EJBException e) {
                // Can't create a bean which require role2 with role1
                // It's ok
                return true;
            }
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
        // Must not work
        return false;
    }


    // Execute a method without being in runAs mode on a runAs derived bean
    public boolean callBeanRunAsWithRole2() throws RemoteException {
       	logger.log(BasicLevel.DEBUG, ""); 
        try {
            Context ictx = new InitialContext();
            DerivedLocalHome h = (DerivedLocalHome) ictx.lookup("java:comp/env/ejb/derivedrunas2local");
            try {
                DerivedLocal  other = h.create();
                other.runAsWithRole2();
                if (!(getPrincipalName().equals(other.localGetPrincipalName()))) {
                    throw new Exception("Principal of the other bean must be the same");
                }
                if (!other.localIsCallerInRole("role2")) {
                    throw new Exception("Role of the other bean must be role2");
                }
            } catch (EJBException e) {
                // Can't call bean which need role2 as we run with role1 (run-as role)
                return true;
            }
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
        return false;
    }

   
}
