/**
 * High Availability Service (HA) for JOnAS
 *
 * Copyright (C) 2007,2008 Bull S.A.S.
 * Copyright (C) 2006 Distributed Systems Lab.
 * Universidad Politecnica de Madrid (Spain)
 * Contact: http://lsd.ls.fi.upm.es/lsd
 *
 * 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.ow2.jonas.lib.ejb21.ha;


import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.Method;
import java.rmi.RemoteException;

import javax.ejb.EJBException;

import org.objectweb.util.monolog.api.BasicLevel;
import org.objectweb.util.monolog.api.Logger;
import org.ow2.jonas.lib.ejb21.JLocalHome;
import org.ow2.jonas.lib.ejb21.JSessionContext;
import org.ow2.jonas.lib.ejb21.JSessionFactory;
import org.ow2.jonas.lib.ejb21.JStatefulContext;
import org.ow2.jonas.lib.ejb21.JStatefulInputStream;
import org.ow2.jonas.lib.ejb21.JStatefulSwitch;
import org.ow2.jonas.lib.ejb21.JWrapper;
import org.ow2.jonas.lib.ejb21.TraceEjb;
import org.ow2.jonas.lib.util.Log;


public class JRepStatefulInputStream extends JStatefulInputStream {

    /**
     * Logger for traces
     */
    protected static Logger cmilogger = Log.getLogger("org.ow2.jonas.lib.ejb21.ha");

    /**
     * Constructor.
     * @throws IOException
     */
    public JRepStatefulInputStream(final InputStream in, final JStatefulSwitch jss) throws IOException {
        super(in, jss);
    }

    /**
     * We must care about some object types.
     * @param obj serialized field
     * @return resolved object
     */
    @Override
    protected Object resolveObject(final Object obj) throws IOException {
        Object ret;
        if (obj instanceof JWrapper) {
            int type = ((JWrapper) obj).getType();
            switch (type) {
            /*case JWrapper.DATASOURCE:
                String dsname = (String) ((JWrapper) obj).getObject();
                ret = ConnectionManager.getConnectionManager(dsname);
                break;*/
            case JWrapper.LOCAL_ENTITY:
                TraceEjb.ssfpool.log(BasicLevel.DEBUG, "JEntityLocal");
                String jndiname = (String) ((JWrapper) obj).getObject();
                Object pk = ((JWrapper) obj).getPK();
                Object o = JLocalHome.getLocalHome(jndiname);
                ret = null;
                try {
                    ret = getFindByPKMethod(o.getClass(), pk.getClass()).invoke(o, (new Object[] {pk}) );
                } catch (Exception e) {
                    cmilogger.log(BasicLevel.ERROR, "Cannot find an object with the primary key " + pk, e);
                    throw new IOException("Cannot find an object with the primary key " + pk);
                }
                break;
            default:
                ret = super.resolveObject(obj);
            break;
            }
        } else if (obj instanceof JRepStatefulObjectId) {
            // Wrapper -> Local stateful
            // Recreate the bean in local
            JRepStatefulObjectId jrsoi = (JRepStatefulObjectId) obj;
            JRepStatefulLocalHome jrslh = (JRepStatefulLocalHome) JLocalHome.getLocalHome(jrsoi.getJndi());
            JRepStatefulLocal jrsl = null;

            JStatefulSwitch bs = null;
            JSessionFactory sf = (JSessionFactory) jrslh.getBeanFactory();

            try {
                bs = (JStatefulSwitch) sf.createEJB();
                JSessionContext bctx = sf.getJContext(bs);
                bs.bindICtx(null, (JStatefulContext) bctx);
                bctx.setState(2);
            } catch (javax.ejb.AccessLocalException e) {
                throw new EJBException("Security Exception thrown by an enterprise Bean", e);
            } catch (EJBException e) {
                throw e;
            } catch (RuntimeException e) {
                throw new EJBException("RuntimeException thrown by an enterprise Bean", e);
            } catch (Error e) {
                throw new EJBException("Error thrown by an enterprise Bean"+e);
            } catch (RemoteException e) {
                throw new EJBException("Remote Exception raised:", e);
            }

            jrsl = (JRepStatefulLocal) bs.getLocal();
            jrsl.setClusterOId(jrsoi.getClusterOId());
            ret = jrsl;
        } else {
            ret = super.resolveObject(obj);
        }
        return ret;
    }

    private Method getFindByPKMethod(final Class<?> c, final Class<?> pk) throws SecurityException {

        // Find first findByPrimaryKey method
        for (Method method : c.getMethods()) {
            if (method.getName().equals("findByPrimaryKey")) {
                return method;
            }
        }
        return null;
    }
}
