/**
 * JOnAS: Java(TM) Open Application Server
 * Copyright (C) 2007-2009 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: JOnASLauncher.java 19510 2010-03-24 08:09:35Z benoitf $
 * --------------------------------------------------------------------------
 */

package org.ow2.jonas.itests.intravm;

import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantReadWriteLock;

import org.osgi.framework.BundleContext;
import org.osgi.framework.ServiceReference;
import org.ow2.jonas.depmonitor.MonitoringService;
import org.ow2.jonas.launcher.felix.JOnAS;
import org.ow2.util.log.Log;
import org.ow2.util.log.LogFactory;
import org.testng.annotations.AfterClass;
import org.testng.annotations.BeforeClass;

/**
 * Abstract class for starting/stopping JOnAS and providing an access to OSGi
 * through BundleContext.
 * @author Florent Benoit
 */
public class JOnASLauncher {

    /**
     * One second delay.
     */
    private static final long ONE_SECOND = 1000L;

    /**
     * Waiting time = 30 seconds.
     */
    private static final long WAITING_SERVCICES_TIME = 30 * ONE_SECOND;

    /**
     * Lock.
     */
    private volatile static Lock lock = new ReentrantReadWriteLock().writeLock();

    /**
     * Counter of start of JOnAS.
     */
    private static int count = 0;

    /**
     * JOnAS instance.
     */
    private static JOnAS jonas = null;

    /**
     * OSGi bundle context.
     */
    private static BundleContext bundleContext = null;

    /**
     * Server ready.
     */
    private static boolean ready = false;

    /**
     * Server is stopping.
     */
    private static boolean stopping = false;

    /**
     * Server is stopping soon.
     */
    private  static boolean lastCallStopping = false;

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

    /**
     * Start the JOnAS server.
     * @throws Exception if server cannot be started.
     */
    @BeforeClass
    public void startServer() throws Exception {
        try {
            lock.lock();

            if (jonas == null) {
                jonas = new JOnAS(true);
                // Get Bundle Context
                bundleContext = jonas.getFramework().getBundleContext();

                // Start JOnAS
                new Thread() {
                    @Override
                    public void run() {
                        try {
                            jonas.start();
                        } catch (Exception e) {
                            logger.error("Cannot start the server", e);
                            throw new IllegalStateException("Cannot start the server", e);
                        }
                    }
                }.start();

                // wait for depMonitor service
                final long maxWaitTime = System.currentTimeMillis() + WAITING_SERVCICES_TIME;
                ServiceReference serviceManagerServiceReference = null;
                while (serviceManagerServiceReference == null && System.currentTimeMillis() < maxWaitTime) {
                    serviceManagerServiceReference = getBundleContext().getServiceReference(MonitoringService.class.getName());
                    if (serviceManagerServiceReference == null) {
                        Thread.sleep(ONE_SECOND);
                    } else {
                        ready = true;
                    }
                }
                logger.info("The JOnAS server is ready, tests can be launched.");
            } else {
                logger.info("The JOnAS server is already launched");
            }
            count++;
        } finally {
            lock.unlock();
        }
    }

    /**
     * Stop the JOnAS server.
     * @throws Exception if server cannot be stopped
     */
    @AfterClass
    public void stopServer() throws Exception {
        count--;
        if (count == 1) {
            lastCallStopping = true;
        }
        // last call to the stop is performing the stop;
        if (count == 0) {
            if (jonas != null) {
                stopping = true;
                logger.info("The JOnAS server is being stopped.");
                jonas.stop();
            }
        }
    }

    /**
     * @return true if server is ready
     */
    public boolean isReady() {
        return ready;
    }

    /**
     * Waits that the server is ready.
     * @throws InterruptedException if exception
     */
    public void waitReady() throws InterruptedException {
        while (!ready) {
            Thread.sleep(ONE_SECOND);
        }
    }

    /**
     * Waits that the server is ready.
     * @throws InterruptedException if exception
     */
    public void waitStopping() throws InterruptedException {
        while (!stopping) {
            Thread.sleep(ONE_SECOND);
        }
    }

    /**
     * Waits that the server is ready.
     * @throws InterruptedException if exception
     */
    public void waitStoppingSoon() throws InterruptedException {
        while (!lastCallStopping) {
            Thread.sleep(ONE_SECOND);
        }
    }
    /**
     * @return the bundle context.
     */
    protected BundleContext getBundleContext() {
        return bundleContext;
    }
}
