/**
 * 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$
 * --------------------------------------------------------------------------
 */

package org.ow2.jonas.deployablemonitor;

import java.io.File;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;

import org.ow2.jonas.depmonitor.MonitoringService;
import org.ow2.jonas.jmx.JmxService;
import org.ow2.jonas.lib.bootstrap.JProp;
import org.ow2.jonas.lib.service.AbsServiceImpl;
import org.ow2.jonas.lib.util.JonasObjectName;
import org.ow2.jonas.management.J2EEServerService;
import org.ow2.jonas.service.ServiceException;
import org.ow2.util.ee.deploy.api.deployer.IDeployerManager;
import org.ow2.util.log.Log;
import org.ow2.util.log.LogFactory;
/**
 * Service that will launch the Deployable Monitor.
 * @author Florent BENOIT
 */
public class DeployableMonitorService extends AbsServiceImpl implements MonitoringService {

    /**
     * Property for the development mode.
     */
    public static final String DEVELOPMENT_MODE_PROPERTY = "development";

    /**
     * Property for the list of extra directories to analyze.
     */
    public static final String DIRECTORIES_LIST_PROPERTY = "directories";

    /**
     * The name of the JONAS_BASE directory.
     */
    protected static final String JONAS_BASE = JProp.getJonasBase();

    /**
     * Default directory to analyze.
     */
    public static final String DEFAULT_DIRECTORY = JONAS_BASE + File.separator + "deploy";

    /**
     * Logger.
     */
    private Log logger = LogFactory.getLog(DeployableMonitor.class);

    /**
     * Development mode or not ? Default is true.
     */
    private boolean developmentMode = true;

    /**
     * JMX Service.
     */
    private JmxService jmxService = null;

    /**
     * List of directories.
     */
    private List<File> directories = null;

    /**
     * Link to the deployable monitor.
     */
    private DeployableMonitor deployableMonitor = null;

    /**
     * Reference to the J2EEServer service.
     */
    private J2EEServerService j2eeServer = null;

    /**
     * Monitor interval between each directory scan.
     */
    private int monitorInterval;

    /**
     * Default constructor.
     */
    public DeployableMonitorService() {
        this.directories = new LinkedList<File>();
        this.deployableMonitor = new DeployableMonitor(this);
    }

    /**
     * Start the Deployable Monitor service.
     * @throws ServiceException if the startup failed.
     */
    @Override
    protected void doStart() throws ServiceException {
        logger.info("Use the deploy directories ''{0}'', development mode is ''{1}''", directories, developmentMode);

        // Add the default directory
        File defaultDirectory = new File(DEFAULT_DIRECTORY);
        if (!defaultDirectory.exists()) {
            logger.info("Creating default deploy directory ''{0}''", defaultDirectory);
            defaultDirectory.mkdirs();
        }
        directories.add(defaultDirectory);

        // Load the Descriptors
        jmxService.loadDescriptors(getClass().getPackage().getName(), getClass().getClassLoader());

        // And register MBean
        try {
            jmxService.registerModelMBean(this, JonasObjectName.deployableMonitorService(getDomainName()));
        } catch (Exception e) {
            logger.warn("Cannot register MBean for Deployable Monitor service", e);
        } catch (Throwable t) {
            t.printStackTrace();
        }
    }

    /**
     * Starts the {@link DeployableMonitor} instance.
     */
    public void startMonitoring() {
        if (!getDeployableMonitor().isAlive()) {
            logger.debug("Start DeployableMonitor");
            deployableMonitor.start();
        }
    }

    /**
     * Stop the Deployable Monitor service.
     * @throws ServiceException if the stop failed.
     */
    @Override
    protected void doStop() throws ServiceException {
        // Unregister MBean
        if (jmxService != null) {
            try {
                jmxService.unregisterModelMBean(JonasObjectName.deployableMonitorService(getDomainName()));
            } catch (Exception e) {
                logger.warn("Cannot unregister MBean for Deployable Monitor service", e);
            }
        }
        // Stop deploy monitor
        deployableMonitor.stopOrder();
        /**
         * Don't keep the resources.
         */
        deployableMonitor = null;

        logger.info("DeployableMonitor stopped successfully");

    }

    /**
     * @param dirs List of deployment directories to observe.
     */
    public void setDirectories(final String dirs) {
        List<String> additionalDirectories = convertToList(dirs);
        for (String dir : additionalDirectories) {
            File tmpFile = new File(dir);

            // Not an absolute file, should be relative to JONAS_BASE.
            if (!tmpFile.isAbsolute()) {
                tmpFile = new File(JONAS_BASE + File.separator + dir);
            }

            // Directory exists ?
            if (!tmpFile.exists()) {
                logger.warn("The given directory ''{0}'' is neither present on the filesystem or in JONAS_BASE ''{1}''",
                        tmpFile, JONAS_BASE);
            } else {
                // Add the directory
                directories.add(tmpFile);
            }
        }

        getDeployableMonitor().setDirectories(directories);
    }

    /**
     * The list of the directory names.
     * @return The list of the directory names.
     */
    public String[] getDirectoryNames() {
        ArrayList<String> result = new ArrayList<String>();
        Iterator<File> it = directories.iterator();
        while (it.hasNext()) {
            File directory = it.next();
            result.add(directory.getName());
        }
        String[] dirNames = new String[result.size()];
        int i = 0;
        for (String dir : result) {
            dirNames[i++] = dir;
        }
        return dirNames;
    }

    /**
     * @param exclusionList The list of exclusion patterns.
     */
    public void setExclusions(final String exclusionList) {
        List<String> exclusions = convertToList(exclusionList);
        getDeployableMonitor().setExclusionPatterns(exclusions);
    }

    /**
     * @param deployerManager the {@link IDeployerManager} to set
     */
    public void setDeployerManager(final IDeployerManager deployerManager) {
        // update the monitor object
        getDeployableMonitor().setDeployerManager(deployerManager);
    }

    /**
     * @param jmxService the jmxService to set
     */
    public void setJmxService(final JmxService jmxService) {
        this.jmxService = jmxService;
    }

    /**
     * @param j2eeServer the j2eeServer to set
     */
    public void setJ2EEServer(final J2EEServerService j2eeServer) {
        this.j2eeServer = j2eeServer;
    }

    /**
     * Called when the DeploymentMonitor has finished its first round of
     * deployment (all that was under deploy/ at startup time).
     */
    public void firstCheckEnded() {
        j2eeServer.setRunning();
    }

    /**
     * @return <tt>true</tt> if the development mode set to true.
     */
    public boolean isDevelopmentMode() {
        return developmentMode;
    }

    /**
     * Set developmentMode value to true (enable), or to false (disable).
     * "inherit" case: correspondence between the service and the server
     * development mode
     * @param mode value to set
     */
    public void setDevelopmentMode(final String mode) {
        if (mode.equals("inherit")) {
            developmentMode = getServerProperties().isDevelopment();
        } else {
            developmentMode = Boolean.parseBoolean(mode);
        }

        // update the monitor object
        getDeployableMonitor().setDevelopmentMode(developmentMode);
    }

    /**
     * Set developmentMode value to true (enable), or to false (disable).
     * @param mode value to set
     */
    public void setDevelopmentMode(final boolean mode) {
        developmentMode = mode;

        // update the monitor object
        getDeployableMonitor().setDevelopmentMode(developmentMode);
    }

    /**
     * Set the monitor interval between each directory scan.
     * @param monitorInterval value to set
     */
    public void setMonitorInterval(final int monitorInterval) {
        this.monitorInterval = monitorInterval;

        // update the monitor object
        getDeployableMonitor().setMonitorInterval(monitorInterval);
    }

    /**
     * Returns the monitor interval between each directory scan.
     */
    public int getMonitorInterval() {
        return this.monitorInterval;
    }

    /**
     * Get the deployable monitor.
     * @return the deployable monitor
     */
    private DeployableMonitor getDeployableMonitor() {
        // Create a new instance if necessary.
        if (deployableMonitor == null) {
            deployableMonitor = new DeployableMonitor(this);
        }
        return deployableMonitor;
    }
}
