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

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

import java.io.Serializable;
import java.rmi.RemoteException;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.Enumeration;

import javax.ejb.CreateException;
import javax.ejb.EJBException;
import javax.ejb.FinderException;
import javax.ejb.NoSuchObjectLocalException;
import javax.ejb.RemoveException;
import javax.ejb.SessionBean;
import javax.ejb.SessionSynchronization;
import javax.ejb.SessionContext;
import javax.ejb.Timer;
import javax.ejb.TimerHandle;
import javax.naming.Context;
import javax.naming.InitialContext;
import javax.naming.NamingException;
import javax.rmi.PortableRemoteObject;
import javax.sql.DataSource;
import org.objectweb.jonas.common.Log;
import org.objectweb.util.monolog.api.Logger;
import org.objectweb.util.monolog.api.BasicLevel;

/**
 * FolderSY implementation
 * This bean is a stateful session bean that implements SessionSynchronization
 * @author Philippe Durieux, Philippe Coq
 */
public class FolderSY implements SessionBean, SessionSynchronization {

    protected static Logger logger = null;
    SessionContext ejbContext;
    transient InitialContext ictx;
    Context myEnv;
    FileHome filehome;
    PaperLocalHome paperhome;
    Paper2LocalHome paper2home;
    Paper3LocalHome paper3home;
    boolean rollbackOnly;

    /**
     * Check environment variables
     */
    void checkEnv(String method) {

        // Check directly in my context
        logger.log(BasicLevel.DEBUG, "Check directly in my context");
        try {
            String value = (String) myEnv.lookup("myname");
            if (!value.equals("mysession")) {
                logger.log(BasicLevel.ERROR, ": myEnv.lookup failed: myname=" + value);
                throw new EJBException("FolderSY 1: " + method);
            }
        } catch (Exception e) {
            logger.log(BasicLevel.ERROR, ": myEnv.lookup raised exception:\n" + e);
            throw new EJBException("FolderSY 2: " + method);
        }
        // Idem with compound name
        logger.log(BasicLevel.DEBUG, "Idem with compound name");
        try {
            String value = (String) myEnv.lookup("dir1/dir2/name");
            if (!value.equals("sessionvalue")) {
                logger.log(BasicLevel.ERROR, ": myEnv.lookup failed: dir1/dir2/name=" + value);
                throw new EJBException("FolderSY 3: " + method);
            }
        } catch (Exception e) {
            logger.log(BasicLevel.ERROR, ": myEnv.lookup raised exception:\n" + e);
            throw new EJBException("FolderSY 4: " + method);
        }
        // Check from initial Context
        logger.log(BasicLevel.DEBUG, "Check from initial Context");
        try {
            String value = (String) ictx.lookup("java:comp/env/myname");
            if (!value.equals("mysession")) {
                logger.log(BasicLevel.ERROR, ": ictx.lookup failed: myname=" + value);
                throw new EJBException("FolderSY 6: " + method);
            }
        } catch (Exception e) {
            logger.log(BasicLevel.ERROR, ": ictx.lookup raised exception:\n" + e);
            throw new EJBException("FolderSY 7: " + method);
        }

        // Check datasource directly
        logger.log(BasicLevel.DEBUG, "Check datasource directly");
        DataSource ds1 = null;
        try {
            ds1 = (DataSource) ictx.lookup("jdbc_1");
        } catch (Exception e) {
            logger.log(BasicLevel.ERROR, ": ictx.lookup raised exception:\n" + e);
            throw new EJBException("FolderSY 8: " + method);
        }
        Connection con = null;
        if (!method.equals("afterCompletion")) {
            try {
                con = (Connection) ds1.getConnection();
                if (con.isClosed()) {
                    logger.log(BasicLevel.ERROR, ": connection is closed");
                    throw new EJBException("FolderSY 8a: " + method);
                }
                con.close();
            } catch (Exception e) {
                logger.log(BasicLevel.ERROR, ": getConnection:\n" + e);
                throw new EJBException("FolderSY 8b: " + method);
            }
        }

        // Check DataSource from resource ref in bean environment
        logger.log(BasicLevel.DEBUG, "Check DataSource from resource ref");
        DataSource ds2 = null;
        try {
            // The name is the one defined in FolderSY.xml
            ds2 = (DataSource) myEnv.lookup("jdbc/mydb");
        } catch (Exception e) {
            logger.log(BasicLevel.ERROR, ": ictx.lookup raised exception:\n" + e);
            throw new EJBException("FolderSY 9: " + method);
        }
        if (!method.equals("afterCompletion")) {
            try {
                con = (Connection) ds2.getConnection();
                if (con.isClosed()) {
                    logger.log(BasicLevel.ERROR, ": connection is closed");
                    throw new EJBException("FolderSY 9a: " + method);
                }
                con.close();
            } catch (Exception e) {
                logger.log(BasicLevel.ERROR, ": getConnection:\n" + e);
                throw new EJBException("FolderSY 9b: " + method);
            }
        }

        // Check boolean values
        logger.log(BasicLevel.DEBUG, "Check boolean values");
        try {
            Boolean value = (Boolean) ictx.lookup("java:comp/env/bVrai");
            if (!value.booleanValue()) {
                logger.log(BasicLevel.ERROR, ": ictx.lookup failed: bVrai=" + value);
                throw new EJBException("FolderSY 10a: " + method);
            }
        } catch (Exception e) {
            logger.log(BasicLevel.ERROR, ": ictx.lookup raised exception:\n" + e);
            throw new EJBException("FolderSY10a: " + method);
        }
        try {
            Boolean value = (Boolean) ictx.lookup("java:comp/env/bFaux");
            if (value.booleanValue()) {
                logger.log(BasicLevel.ERROR, ": ictx.lookup failed: bFaux=" + value);
                throw new EJBException("FolderSY 10b: " + method);
            }
            // lookup char in env-entry
            Character c =  (Character) ictx.lookup("java:comp/env/testChar");


        } catch (Exception e) {
            logger.log(BasicLevel.ERROR, ": ictx.lookup raised exception:\n" + e);
            throw new EJBException("FolderSY10b: " + method);
        }

        logger.log(BasicLevel.DEBUG, ": checkEnv OK");
    }

    // ------------------------------------------------------------------
    // SessionBean implementation
    // ------------------------------------------------------------------

    public void setSessionContext(SessionContext ctx) {
        if (logger == null) {
            logger = Log.getLogger(Log.JONAS_TESTS_PREFIX);
        }
        logger.log(BasicLevel.DEBUG, "");
        ejbContext = ctx;
        try {
            // Get initial Context
            ictx = new InitialContext();
            myEnv = (Context) ictx.lookup("java:comp/env");
            // lookup filehome in JNDI
            filehome = (FileHome) PortableRemoteObject.narrow(ictx.lookup("java:comp/env/ejb/file"), FileHome.class);
            paperhome = (PaperLocalHome) PortableRemoteObject.narrow(ictx.lookup("java:comp/env/ejb/paperec2"), PaperLocalHome.class);
            paper2home = (Paper2LocalHome) PortableRemoteObject.narrow(ictx.lookup("java:comp/env/ejb/paper2"), Paper2LocalHome.class);
            paper3home = (Paper3LocalHome) PortableRemoteObject.narrow(ictx.lookup("java:comp/env/ejb/paper3"), Paper3LocalHome.class);
        } catch (NamingException e) {
            throw new EJBException("FolderSY: Cannot get filehome:" + e);
        }
        checkEnv("setSessionContext");
    }

    public void ejbRemove() {
        logger.log(BasicLevel.DEBUG, "");
        checkEnv("ejbRemove");
    }

    public void ejbCreate() throws CreateException {
        logger.log(BasicLevel.DEBUG, "");
        checkEnv("ejbCreate");
        rollbackOnly = false;
    }

    public void ejbCreateForRollback() throws CreateException {
        logger.log(BasicLevel.DEBUG, "");
        checkEnv("ejbCreate");
        rollbackOnly = true;
    }

    public void ejbPassivate() {
        logger.log(BasicLevel.DEBUG, "");
        checkEnv("ejbPassivate");
        ictx = null;
    }

    public void ejbActivate() {
        logger.log(BasicLevel.DEBUG, "");
        try {
            // Get initial Context
            ictx = new InitialContext();
       } catch (NamingException e) {
            throw new EJBException("FolderSY: Cannot get Initial Context:" + e);
        }
        checkEnv("ejbActivate");
    }

    // ------------------------------------------------------------------
    // SessionSynchronization implementation
    // ------------------------------------------------------------------

    public void afterBegin() {
        logger.log(BasicLevel.DEBUG, "");
        checkEnv("afterBegin");
        try {
            ejbContext.getRollbackOnly();
        } catch (IllegalStateException e) {
            throw new EJBException("Cannot call getRollbackOnly in afterBegin");
        }
        if (rollbackOnly) {
            try {
                ejbContext.setRollbackOnly();
            } catch (IllegalStateException e) {
                throw new EJBException("Cannot call setRollbackOnly in afterBegin");
            }
        }
    }

    public void beforeCompletion() {
        logger.log(BasicLevel.DEBUG, "");
        checkEnv("beforeCompletion");
        try {
            ejbContext.getRollbackOnly();
        } catch (IllegalStateException e) {
            throw new EJBException("Cannot call getRollbackOnly in beforeCompletion");
        }
        if (rollbackOnly) {
            try {
                ejbContext.setRollbackOnly();
            } catch (IllegalStateException e) {
                throw new EJBException("Cannot call setRollbackOnly in afterBegin");
            }
        }
    }

    public void afterCompletion(boolean committed) {
        logger.log(BasicLevel.DEBUG, "");
        checkEnv("afterCompletion");
        // Should not be able to call set or get RollbackOnly here.
        try {
            ejbContext.getRollbackOnly();
            throw new EJBException("getRollbackOnly forbidden in afterCompletion");
        } catch (IllegalStateException e) {
        }
        if (rollbackOnly) {
            try {
                ejbContext.setRollbackOnly();
                throw new EJBException("setRollbackOnly forbidden in afterCompletion");
            } catch (IllegalStateException e) {
            }
        }
    }

    // ------------------------------------------------------------------
    // Folder implementation
    // ------------------------------------------------------------------

    public File newFile(String fname) throws RemoteException, CreateException {
        logger.log(BasicLevel.DEBUG, "");
        checkEnv("newFile");
        File ret = filehome.create(fname);
        return ret;
    }

    public File getFile(String fname) throws RemoteException, FinderException {
        logger.log(BasicLevel.DEBUG, "");
        checkEnv("getFile");
        File ret = filehome.findByPrimaryKey(fname);
        return ret;
    }

    public boolean testTimerCancel(String fname) throws RemoteException, CreateException {
        logger.log(BasicLevel.DEBUG, "");
        boolean ret = true;

        // Create a bean implementing TimedObject
        File file = filehome.create(fname);

        // Create a Timer on this bean and get its Handle
        TimerHandle th = file.getTimerHandle();
        if (th == null) {
            logger.log(BasicLevel.WARN, "Null Handle returned");
            return false;
        }

        // Check that Timer Info can be read and is correct.
        Timer t = th.getTimer();
        Serializable sz = t.getInfo();
        if (!(sz instanceof Integer)) {
            logger.log(BasicLevel.WARN, "Non-integer info value returned");
            return false;
        }

        // Cancel the timer
        file.cancelTimer(th);

        // Check that the TimerHandle cannot be used any longer
        try {
            th.getTimer();
            logger.log(BasicLevel.WARN, "Timer still accessible after bean remove");
            ret = false;
        } catch (NoSuchObjectLocalException e) {
        }

        // Remove the bean
        try {
            file.remove();
        } catch (Exception e) {
            logger.log(BasicLevel.WARN, "Cannot remove the bean after use.");
            return false;
        }
        return ret;
    }

    public boolean testTimerRemoved(String fname) throws RemoteException, CreateException, RemoveException {
        logger.log(BasicLevel.DEBUG, "");
        boolean ret = true;

        // Create a bean implementing TimedObject
        File file = filehome.create(fname);

        // Create a Timer on this bean and get its Handle
        TimerHandle th = file.getTimerHandle();
        if (th == null) {
            logger.log(BasicLevel.WARN, "Null Handle returned");
            return false;
        }

        // Check that Timer Info can be read and is correct.
        Serializable sz = th.getTimer().getInfo();
        if (!(sz instanceof Integer)) {
            logger.log(BasicLevel.WARN, "Non-integer info value returned");
            return false;
        }

        // Remove the bean (and the timer!)
        file.remove();

        // Check that the TimerHandle cannot be used any longer
        try {
            th.getTimer();
            logger.log(BasicLevel.WARN, "Timer still accessible after bean remove");
            ret = false;
        } catch (NoSuchObjectLocalException e) {
        }
        return ret;
    }

    public void sendRef(Folder f) throws RemoteException {
    }

    public void sendInt(int i) throws RemoteException {
    }

    public void sendRefTS(Folder f) throws RemoteException {
    }

    public void sendIntTS(int i) throws RemoteException {
    }

    public Folder getRef(Folder f) throws RemoteException {
        return f;
    }

    public int getInt(int i) throws RemoteException {
        return i;
    }

    public Folder getRefTS(Folder f) throws RemoteException {
        return f;
    }

    public int getIntTS(int i) throws RemoteException {
        return i;
    }

    public void sendArray(long[] x) throws RemoteException {
    }

    public long[] getArray() throws RemoteException {
        long[] anArray;
        anArray = new long [100];
        for (int i = 0; i < anArray.length; i++) {
            anArray[i] = i;
        }
        return anArray;
    }
    public int modify(String pname, int val) throws RemoteException  {
        logger.log(BasicLevel.DEBUG, "");
        int sum=0;
        try {
            PaperLocal plocal = paperhome.findByPrimaryKey(pname);
            logger.log(BasicLevel.DEBUG, "findByPrimaryKey OK ");
            int valb = plocal.getValue();
            logger.log(BasicLevel.DEBUG, "valb= "+valb);
            plocal.setValue(val);
            sum = paperhome.getTotalValeur();
            logger.log(BasicLevel.DEBUG, "sum= "+sum);

        } catch (FinderException fe) {

        } finally {
            // to clean up the changes
            ejbContext.setRollbackOnly();
        }
        return sum;
    }

    public int modifypaper2And3(String pid, int val) throws RemoteException  {
        logger.log(BasicLevel.DEBUG, "");
        int sum=0;
        try {
            Paper2Local plocal2 = paper2home.findByPrimaryKey(pid);
            logger.log(BasicLevel.DEBUG, "findByPrimaryKey OK ");
            int valb = plocal2.getValeur();
            logger.log(BasicLevel.DEBUG, "valb= "+valb);
            plocal2.setValeur(val);

            Paper3Local plocal3 = paper3home.findByPrimaryKey("2");
            String v1 = plocal3.getValide();
            if ( v1 == "1") {
                plocal3.setValide("0");
            } else {
                plocal3.setValide("1");

            }

            sum = paper2home.getSumOfValeurs();
            logger.log(BasicLevel.DEBUG, "sum= "+sum);

        } catch (FinderException fe) {

        }finally {
            // to clean up the changes
            ejbContext.setRollbackOnly();
        }
        return sum;
    }


    public int modifypaper2And3WithFinder(String pid, int val) throws RemoteException  {
        logger.log(BasicLevel.DEBUG, "");
        int nb=0;
        Enumeration eList = null;
        try {
            Paper2Local plocal2 = paper2home.findByPrimaryKey(pid);
            logger.log(BasicLevel.DEBUG, "findByPrimaryKey OK ");
            int valb = plocal2.getValeur();
            logger.log(BasicLevel.DEBUG, "valb= "+valb);
            plocal2.setValeur(val);

            Paper3Local plocal3 = paper3home.findByPrimaryKey("2");
            String v1 = plocal3.getValide();
            if ( v1 == "1") {
                plocal3.setValide("0");
            } else {
                plocal3.setValide("1");

            }
            Paper2Local paper2local = null;
            eList  = paper2home.findAllValide();
            while (eList.hasMoreElements()) {
                paper2local =(Paper2Local)javax.rmi.PortableRemoteObject.narrow(eList.nextElement(), Paper2Local.class);
                nb++;
            }
            logger.log(BasicLevel.DEBUG, "nb= "+nb);

        } catch (FinderException fe) {

        }finally {
            // to clean up the changes
            ejbContext.setRollbackOnly();
        }
        return nb;
    }
}
