/**
 * JOnAS: Java(TM) Open Application Server
 * Copyright (C) 2007 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: JOnASContextConfig.java 21832 2011-10-23 22:48:37Z cazauxj $
 * --------------------------------------------------------------------------
 */

package org.ow2.jonas.web.tomcat7;

import java.lang.reflect.Field;
import java.util.HashSet;
import java.util.Set;

import javax.servlet.ServletContainerInitializer;
import javax.servlet.annotation.HandlesTypes;

import org.apache.catalina.deploy.WebXml;
import org.apache.catalina.startup.ContextConfig;
import org.apache.tomcat.util.digester.Digester;
import org.ow2.jonas.security.SecurityService;
import org.xml.sax.InputSource;

/**
 * Own JOnAS context config object in order to change some default values.
 * @author Florent BENOIT
 */
public class JOnASContextConfig extends ContextConfig {

    /**
     * {@link SecurityService} instance to pass to the {@link org.ow2.jonas.web.tomcat7.security.Realm}s.
     */
    private SecurityService service = null;

    /**
     * Path to the default Context for Tomcat6 (can use /).
     */
    public static final String DEFAULT_CONTEXT_XML = "conf/tomcat7-context.xml";

    /**
     * Path to the default Web.xml object for Tomcat6 (can use /).
     */
    public static final String DEFAULT_WEB_XML = "conf/tomcat7-web.xml";

    /**
     * @return the location of the default deployment descriptor
     */
    @Override
    public String getDefaultWebXml() {
        if (defaultWebXml == null) {
            defaultWebXml = DEFAULT_WEB_XML;
        }

        return (this.defaultWebXml);

    }

    /**
     * @return the location of the default context file
     */
    @Override
    public String getDefaultContextXml() {
        if (defaultContextXml == null) {
            defaultContextXml = DEFAULT_CONTEXT_XML;
        }

        return (this.defaultContextXml);

    }

    /**
     * Extend META-INF/Context.xml Digester with JOnAS {@link SecurityService} setup.
     * @return an extended Digester.
     */
    @Override
    protected Digester createContextDigester() {
        // Get base Digester
        Digester digester =  super.createContextDigester();
        // If a JOnAS Realm is found, inject the SecurityService
        digester.addRule("Context/Realm", new SetSecurityServiceRule(service));
        return digester;
    }

    /**
     * @param service {@link SecurityService} instance to assign.
     */
    public void setSecurityService(final SecurityService service) {
        this.service = service;
    }

    /**
     * Always nullify the 'contextDigeste'r static reference.
     * @see org.apache.catalina.startup.ContextConfig#init()
     */
    @Override
    protected synchronized void init() {
        // nullify the digester Object
        // was holding a reference on a discarded security service.
        contextDigester = null;
        super.init();
    }


    /**
     * Process the application configuration file, if it exists.
     */
    @Override
    protected void webConfig() {
        super.webConfig();


            // Keep value of the ignoreAnnotations flag
            boolean ignore = context.getIgnoreAnnotations();
            if (ignore) {
                org.apache.tomcat.InstanceManager instanceManager = ((org.apache.catalina.core.StandardContext) context).getInstanceManager();
                Class clazz= instanceManager.getClass();
                Field f = null;
                try {
                    f = clazz.getDeclaredField("ignoreAnnotations");
                    f.setAccessible(true);
                    f.set(instanceManager, Boolean.TRUE);
                } catch (IllegalAccessException e) {
                    throw new IllegalStateException("Unable to find the field", e);
                } catch (NoSuchFieldException e) {
                    throw new IllegalStateException("Unable to find the field", e);
                }

                // Enable annotation processing
                context.setIgnoreAnnotations(false);

            }


    }

    /**
     * Allows to check the publicId of the WebXML file if it needs to be applied on the context.
     * It is used as convertJsp method on the super class will check if publicId is 2.2 before throwing error but this is done before setPublicid is done which is wrong !
     */
    @Override
    protected void parseWebXml(final InputSource source, final WebXml dest,
            final boolean fragment) {
        super.parseWebXml(source, dest, fragment);
        if (dest != null) {
            if (dest.getPublicId() != null) {
                context.setPublicId(dest.getPublicId());
            }
        }



    }
    public void addServletContainerInitializer(final ServletContainerInitializer initializer) {

        // TODO Try to have Tomcat method refactored so we could use it

        // Copy/Paste from ContextConfig.processServletContainerInitializers(Set<WebXml> fragments)
        // Start --------------------------------------
        initializerClassMap.put(initializer, new HashSet<Class<?>>());

        HandlesTypes ht =initializer.getClass().getAnnotation(HandlesTypes.class);
        if (ht != null) {
            Class<?>[] types = ht.value();
            if (types != null) {
                for (Class<?> type : types) {
                    Set<ServletContainerInitializer> scis = typeInitializerMap.get(type);
                    if (scis == null) {
                        scis = new HashSet<ServletContainerInitializer>();
                        typeInitializerMap.put(type, scis);
                    }
                    scis.add(initializer);
                }
            }
        }
        // End --------------------------------------

    }

    /**
     * @param tomcat7ContextConfPath The path to the tomcat 7 configuration file to set
     */
    public void setDefaultContextXml(final String tomcat7ContextConfPath) {
        this.defaultContextXml = tomcat7ContextConfPath;
    }

    /**
     * @param tomcat7WebConfPath Path to the tomcat 7 web configuration file to set
     */
    public void setDefaultWebXml(final String tomcat7WebConfPath) {
        this.defaultWebXml = tomcat7WebConfPath;
    }
}
