# AbstractQi4jServletBootstrap.java

    /*
     * Copyright (c) 2010, Paul Merlin. All Rights Reserved.
     *
     * Licensed under the Apache License, Version 2.0 (the "License");
     * you may not use this file except in compliance with the License.
     * You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
     * Unless required by applicable law or agreed to in writing, software
     * distributed under the License is distributed on an "AS IS" BASIS,
     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     * See the License for the specific language governing permissions and
     * limitations under the License.
     *
     */
    package org.qi4j.library.servlet.lifecycle;

    import javax.servlet.ServletContext;
    import javax.servlet.ServletContextEvent;
    import javax.servlet.ServletContextListener;
    import org.qi4j.api.Qi4j;
    import org.qi4j.api.common.InvalidApplicationException;
    import org.qi4j.api.structure.Application;
    import org.qi4j.api.structure.ApplicationDescriptor;
    import org.qi4j.bootstrap.ApplicationAssembler;
    import org.qi4j.bootstrap.Energy4Java;
    import org.qi4j.library.servlet.Qi4jServlet;
    import org.qi4j.library.servlet.Qi4jServletSupport;
    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;

    /**
     * Abstract ServletContextListener implementing ApplicationAssembler.
     *
     * Extends this class to easily bind a Zest Application activation/passivation to your webapp lifecycle.
     *
     * The {@link Application} is set as a {@link ServletContext} attribute named using a constant.
     * In your servlets, filters, whatever has access to the {@link ServletContext} use the following code to get a
     * handle on the {@link Application}:
     *
     * <pre>
     *  org.qi4j.api.structure.Application application;
     *
     *  application = ( Application ) servletContext.getAttribute( Qi4jServletSupport.APP_IN_CTX );
     *
     *  // Or, shorter:
     *
     *  application = Qi4jServletSupport.application( servletContext );
     *
     * </pre>
     *
     * Rembember that the servlet specification states:
     *
     * In cases where the container is distributed over many virtual machines, a Web application will have an instance of
     * the ServletContext for each JVM.
     *
     * Context attributes are local to the JVM in which they were created. This prevents ServletContext attributes from
     * being a shared memory store in a distributed container. When information needs to be shared between servlets running
     * in a distributed environment, the information should be placed into a session, stored in a database, or set in an
     * Enterprise JavaBeans component.
     */
    public abstract class AbstractQi4jServletBootstrap
            implements ServletContextListener, ApplicationAssembler
    {

        private static final Logger LOGGER = LoggerFactory.getLogger( Qi4jServlet.class.getPackage().getName() );
        // Zest Runtime
        protected Qi4j api;
        protected Energy4Java qi4j;
        // Zest Application
        protected ApplicationDescriptor applicationModel;
        protected Application application;

        @Override
        public final void contextInitialized( ServletContextEvent sce )
        {
            try {

                ServletContext context = sce.getServletContext();

                LOGGER.trace( "Assembling Application" );
                qi4j = new Energy4Java();
                applicationModel = qi4j.newApplicationModel( this );

                LOGGER.trace( "Instanciating and activating Application" );
                application = applicationModel.newInstance( qi4j.api() );
                api = qi4j.api();
                beforeApplicationActivation( application );
                application.activate();
                afterApplicationActivation( application );

                LOGGER.trace( "Storing Application in ServletContext" );
                context.setAttribute( Qi4jServletSupport.APP_IN_CTX, application );

            } catch ( Exception ex ) {
                if ( application != null ) {
                    try {
                        beforeApplicationPassivation( application );
                        application.passivate();
                        afterApplicationPassivation( application );
                    } catch ( Exception ex1 ) {
                        LOGGER.warn( "Application not null and could not passivate it.", ex1 );
                    }
                }
                throw new InvalidApplicationException( "Unexpected error during ServletContext initialization, see previous log for errors.", ex );
            }
        }

        protected void beforeApplicationActivation( Application app )
        {
        }

        protected void afterApplicationActivation( Application app )
        {
        }

        @Override
        public final void contextDestroyed( ServletContextEvent sce )
        {
            try {
                if ( application != null ) {
                    beforeApplicationPassivation( application );
                    application.passivate();
                    afterApplicationPassivation( application );
                }
            } catch ( Exception ex ) {
                LOGGER.warn( "Unable to passivate Zest Application.", ex );
            }
        }

        protected void beforeApplicationPassivation( Application app )
        {
        }

        protected void afterApplicationPassivation( Application app )
        {
        }

    }