/**
 * 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 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307
 * USA
 *
 * --------------------------------------------------------------------------
 * $Id$
 * --------------------------------------------------------------------------
 */

package org.ow2.jonas.workmanager.internal;

import javax.management.ObjectName;
import javax.resource.spi.work.WorkManager;

import org.objectweb.util.monolog.api.BasicLevel;
import org.objectweb.util.monolog.api.Logger;
import org.ow2.jonas.jmx.JmxService;
import org.ow2.jonas.lib.service.AbsServiceImpl;
import org.ow2.jonas.lib.util.JonasObjectName;
import org.ow2.jonas.lib.util.Log;
import org.ow2.jonas.service.ServiceException;
import org.ow2.jonas.tm.TransactionService;
import org.ow2.jonas.workmanager.WorkManagerService;

/**
 * The JOnAS {@link WorkManager} is returned by this service.
 * @author Guillaume Sauthier
 */
public class JOnASWorkManagerService extends AbsServiceImpl implements WorkManagerService {

    /**
     * Logger for this service.
     */
    private static Logger logger = Log.getLogger(Log.JONAS_WORK_MGR_PREFIX);

    // ------------------------------------------------------------
    // WorkManager thread pool parameters default values
    // ------------------------------------------------------------

    /** Min Work Thread default value. */
    private static final int MIN_WORK_THREADS_DEFAULT = 3;

    /** Max Work Thread default value. */
    private static final int MAX_WORK_THREADS_DEFAULT = 80;

    /** Thread Wait Timeout default value. */
    private static final int THREAD_WAIT_TIMEOUT_DEFAULT = 60;

    /**
     * The JOnAS {@link WorkManager} implementation.
     */
    private JWorkManager workManager = null;

    // Configuration properties -----------------------

    /**
     * Minimum pool size.
     */
    private int minPoolSize = MIN_WORK_THREADS_DEFAULT;

    /**
     * Maximum pool size.
     */
    private int maxPoolSize = MAX_WORK_THREADS_DEFAULT;

    /**
     * Thread wait timeout.
     */
    private long threadWaitingTime = THREAD_WAIT_TIMEOUT_DEFAULT;

    // Service dependencies -------------------------

    /**
     * JMX Services for MBeans registration.
     */
    private JmxService jmxService;

    /**
     * {@link TransactionService} service.
     */
    private TransactionService transactionService;

    /**
     * @param waitingTime Thread wait timeout.
     */
    public void setThreadwaittimeout(final long waitingTime) {
        this.threadWaitingTime = waitingTime;
    }

    /**
     * @param minPoolSize Minimum pool size.
     */
    public void setMinworkthreads(final int minPoolSize) {
        this.minPoolSize = minPoolSize;
    }

    /**
     * @param maxPoolSize Maximum pool size.
     */
    public void setMaxworkthreads(final int maxPoolSize) {
        this.maxPoolSize = maxPoolSize;
    }

    /**
     * Start a new {@link WorkManager}.
     * {@inheritDoc}
     */
    @Override
    protected void doStart() throws ServiceException {
        // Instanciate the WorkManager
        workManager = new JWorkManager(minPoolSize,
                                       maxPoolSize,
                                       transactionService,
                                       threadWaitingTime);

        // register the MBean
        registerWorkManagerMBean(getDomainName(), workManager);

        logger.log(BasicLevel.INFO, "WorkManager Service started.");
    }

    /**
     * Stop the {@link WorkManager}.
     * {@inheritDoc}
     */
    @Override
    protected void doStop() throws ServiceException {
        // stop WorkManager threads
        workManager.stopThreads();
        workManager = null;

        if (jmxService != null) {
            // unregister the MBean
            unregisterWorkManagerMBean(getDomainName());
        }

        logger.log(BasicLevel.INFO, "WorkManager Service stopped.");
    }

    /**
     * {@inheritDoc}
     */
    public WorkManager getWorkManager() {
        return workManager;
    }

    /**
     * Create an MBean for the JOnAS WorkManager.
     * @param domainName domain name
     * @param workManager JOnAS WorkManager to be managed
     */
    private void registerWorkManagerMBean(final String domainName,
                                          final JWorkManager workManager) {
        // Create and register the MBean for this WorkManager
        ObjectName on = JonasObjectName.workManager(domainName);
        try {
            jmxService.registerModelMBean(workManager, on);
        } catch (Exception e) {
            logger.log(BasicLevel.WARN, "Could not register WorkManager MBean", e);
        }
    }

    /**
     * Unregister the WorkManager MBean.
     * @param domainName WorkManager ObjectName.
     */
    private void unregisterWorkManagerMBean(final String domainName) {
        ObjectName on = JonasObjectName.workManager(domainName);
        try {
            jmxService.unregisterModelMBean(on);
        } catch (Exception e) {
            logger.log(BasicLevel.WARN, "Could not unregister WorkManager MBean", e);
        }
    }

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

    /**
     * @param transactionService the transactionService to set
     */
    public void setTransactionService(final TransactionService transactionService) {
        this.transactionService = transactionService;
    }
}
