/**
 * JOnAS: Java(TM) Open Application Server
 * Copyright (C) 2011 Bull S.A.S.
 * Contact: jonas-team@ow2.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 (at your option) 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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
 *
 * --------------------------------------------------------------------------
 * $Id$
 * --------------------------------------------------------------------------
 */

package org.ow2.jonas.jsf.mojarra20.vendor;

import com.sun.faces.spi.DiscoverableInjectionProvider;
import com.sun.faces.spi.InjectionProviderException;

import javax.servlet.ServletContext;
import java.lang.reflect.Method;


/**
 * Manages Injection for Tomcat7.
 * @author Florent Benoit
 */
public class Tomcat7InjectionProvider extends DiscoverableInjectionProvider {

    private ServletContext servletContext;
    
    /**
     * Instance Manager.
     */
    private Object instanceManager = null;


    /**
     * newInstance method.
     */
    private Method newInstanceMethod = null;

    /**
     * destroyInstance method.
     */
    private Method destroyInstanceMethod = null;


    public Tomcat7InjectionProvider(ServletContext servletContext) {
        this.servletContext = servletContext;

        this.instanceManager = servletContext.getAttribute("org.apache.tomcat.InstanceManager");

        // try to init the method object
        if (instanceManager != null) {
            try {
                this.newInstanceMethod = instanceManager.getClass().getMethod("newInstance", Object.class);
            } catch (Exception e) {
                throw new IllegalStateException("Unable to get method", e);
            }
            try {
                this.destroyInstanceMethod = instanceManager.getClass().getMethod("destroyInstance", Object.class);
            } catch (Exception e) {
                throw new IllegalStateException("Unable to get method", e);
            }
        }
    }


    /**
     * <p>The implementation of this method must perform the following
     * steps:
     * <ul>
     * <li>Inject the supported resources per the Servlet 2.5
     * specification into the provided object</li>
     * </ul>
     * </p>
     * <p>This method <em>must not</em> invoke any methods
     * annotated with <code>@PostConstruct</code>
     *
     * @param managedBean the target managed bean
     * @throws com.sun.faces.spi.InjectionProviderException
     *          if an error occurs during
     *          resource injection
     */
    public void inject(Object managedBean) throws InjectionProviderException {
        if (newInstanceMethod == null) {
            throw new InjectionProviderException(new Exception("The newInstance method has not been initialized. Check that you're using Tomcat7"));
        }
        try {
            newInstanceMethod.invoke(instanceManager, managedBean);
        } catch (Exception e) {
            throw new InjectionProviderException(e);
        }
    }

    /**
     * <p>The implemenation of this method must invoke any
     * method marked with the <code>@PreDestroy</code> annotation
     * (per the Common Annotations Specification).
     *
     * @param managedBean the target managed bean
     * @throws com.sun.faces.spi.InjectionProviderException
     *          if an error occurs when invoking
     *          the method annotated by the <code>@PreDestroy</code> annotation
     */
    public void invokePreDestroy(Object managedBean) throws InjectionProviderException {
        if (destroyInstanceMethod == null) {
            throw new InjectionProviderException(new Exception("The destroyInstance method has not been initialized. Check that you're using Tomcat7"));
        }
        try {
            destroyInstanceMethod.invoke(instanceManager, managedBean);
        } catch (Exception e) {
            throw new InjectionProviderException(e);
        }

    }

    /**
     * <p>The implemenation of this method must invoke any
     * method marked with the <code>@PostConstruct</code> annotation
     * (per the Common Annotations Specification).
     *
     * @param managedBean the target managed bean
     * @throws com.sun.faces.spi.InjectionProviderException
     *          if an error occurs when invoking
     *          the method annotated by the <code>@PostConstruct</code> annotation
     */
    public void invokePostConstruct(Object managedBean) throws InjectionProviderException {
        // Already done by inject/newInstance method
    }

}

