/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package com.fitbank.bpmserver;

import java.util.HashSet;
import java.util.Set;

import javax.servlet.ServletConfig;
import javax.servlet.http.HttpServlet;


import com.fitbank.common.Runner;
import com.fitbank.common.conectivity.HbSession;
import com.fitbank.common.logger.FitbankLogger;
import org.apache.log4j.Logger;
import org.apache.commons.configuration.Configuration;

/**
 * Clase que inicia el core de FitBank. Levanta los diferentes servicios
 * que deben correr dentro del core, en especial el servidor de sockets para
 * recibir transacciones.
 *
 * @author Bantec Inc.
 */
public class StartupServletBPM extends HttpServlet {

    private static final Logger LOGGER = FitbankLogger.getLogger();

    private static final Configuration CONFIG = FitBpmServerParam.getConfig();

    private static final Set<Thread> THREADS = new HashSet<Thread>();

    /**
     * Método que Permite iniciar todos los servicios del Bpm
     *
     * @param config Valor del cobjeto de configuración
     */
    @Override
    public void init(ServletConfig config) {
        HbSession.build(config.getServletContext().getRealPath("")
                + "/WEB-INF/lib");
        this.startThreads();
    }

    private void startThreads() {
        String[] services = CONFIG.getString("fitbpmserver.services").split(",");

        for (String className : services) {
            try {
                Class<?> service = Class.forName(className.trim());
                Runnable runnable = (Runnable) service.newInstance();

                Thread thread = Thread.class.isAssignableFrom(service)
                        ? (Thread) runnable
                        : new RunnableThreadWrapper(runnable);
                THREADS.add(thread);
                thread.start();
            } catch (InstantiationException ex) {
                LOGGER.error(ex);
            } catch (IllegalAccessException ex) {
                LOGGER.error(ex);
            } catch (ClassNotFoundException ex) {
                LOGGER.error(ex);
            } catch (ClassCastException ex) {
                LOGGER.error(ex);
            }
        }
    }

    @Override
    public void destroy() {
        for (Thread thread : THREADS) {
            thread.interrupt();
        }
        super.destroy();
    }

    /**
     * Clase usada para iniciar un thread.
     */
    private class RunnableThreadWrapper extends Thread {

        private Runnable runnable;

        public RunnableThreadWrapper(Runnable runnable) {
            this.runnable = runnable;

            setName(runnable.getClass().getSimpleName() + "-Thread");
        }

        @Override
        public void run() {
            LOGGER.info("Iniciando thread " + getName());

            if (runnable instanceof Runner) {
                ((Runner) runnable).setRunning(true);
            }

            runnable.run();
        }

        @Override
        public void interrupt() {
            LOGGER.info("Parando thread " + getName());

            if (runnable instanceof Runner) {
                ((Runner) runnable).setRunning(false);
            }

            super.interrupt();
        }

    }

}