/*
 * Copyright (c) 2013 Team Trinidad and contributors http://github.com/trinidad
 *
 * Permission is hereby granted, free of charge, to any person obtaining
 * a copy of this software and associated documentation files (the
 * "Software"), to deal in the Software without restriction, including
 * without limitation the rights to use, copy, modify, merge, publish,
 * distribute, sublicense, and/or sell copies of the Software, and to
 * permit persons to whom the Software is furnished to do so, subject to
 * the following conditions:
 *
 * The above copyright notice and this permission notice shall be
 * included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
 * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
 * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
 * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

package rb.trinidad.context;

import org.apache.catalina.LifecycleException;
import org.apache.catalina.LifecycleState;
import org.apache.catalina.session.ManagerBase;
import org.apache.catalina.session.StandardManager;
import org.apache.catalina.util.SessionIdGenerator;
import org.apache.juli.logging.Log;
import org.apache.juli.logging.LogFactory;
import org.apache.tomcat.util.ExceptionUtils;

/**
 * Trinidad's default session manager implementation (for Rails/Rack web-apps).
 * It's been introduced to cut down startup cost while initializing the (Java)
 * session id generator which might take a second or few. Since most Rack/Rails
 * applications do not use the JavaSessionStore or access the Java session it
 * should be fine to only initialize on-demand.
 *
 * @see org.apache.catalina.session.ManagerBase
 * @see org.apache.catalina.session.StandardManager
 *
 * @author kares
 */
public class DefaultManager extends StandardManager {

    public DefaultManager() {
        super();
    }

    @Override
    public String getName() {
        return getClass().getSimpleName();
    }

    @Override
    public String getInfo() {
        return getName() + "/1.0";
    }

    @Override
    protected String generateSessionId() {
        if ( sessionIdGenerator == null ) { // we're lazy here
            synchronized(this) {
                if ( sessionIdGenerator == null ) {
                    initSessionIdGenerator();
                }
            }
        }
        return super.generateSessionId();
    }

    /**
     * Start this component and implement the requirements
     * of {@link org.apache.catalina.util.LifecycleBase#startInternal()}.
     *
     * @exception LifecycleException if this component detects a fatal error
     *  that prevents this component from being used
     */
    @Override
    protected synchronized void startInternal() throws LifecycleException {
        // super.startInternal() :

        // Load unloaded sessions, if any
        try {
            load();
        }
        catch (Throwable t) {
            ExceptionUtils.handleThrowable(t);
            final Log log = LogFactory.getLog(StandardManager.class);
            log.error(sm.getString("standardManager.managerLoad"), t);
        }

        setState(LifecycleState.STARTING);
    }

    @Override
    protected synchronized void stopInternal() throws LifecycleException {
        super.stopInternal(); // will set this.sessionIdGenerator = null;
    }

    private synchronized void initSessionIdGenerator() {
        // super.startInternal();
        // sets sessionIdGenerator = new SessionIdGenerator();

        // ManagerBase#startInternal :

        while (sessionCreationTiming.size() < TIMING_STATS_CACHE_SIZE) {
            sessionCreationTiming.add(null);
        }
        while (sessionExpirationTiming.size() < TIMING_STATS_CACHE_SIZE) {
            sessionExpirationTiming.add(null);
        }

        sessionIdGenerator = new SessionIdGenerator();
        sessionIdGenerator.setJvmRoute(getJvmRoute());
        sessionIdGenerator.setSecureRandomAlgorithm(getSecureRandomAlgorithm());
        sessionIdGenerator.setSecureRandomClass(getSecureRandomClass());
        sessionIdGenerator.setSecureRandomProvider(getSecureRandomProvider());
        sessionIdGenerator.setSessionIdLength(getSessionIdLength());

        // Force initialization of the random number generator
        //if (log.isDebugEnabled()) log.debug("Force random number initialization starting");
        sessionIdGenerator.generateSessionId();
        //if (log.isDebugEnabled()) log.debug("Force random number initialization completed");
    }

}
introduce a DefaultManager class that we'll use with context.setManager